// Projeto Segunda Fase
// Sistema de Segurança Estratégico Inteligente contra roubo de moto - SSPEI - Moto
//Aluno: MARIA LUCILENE DOS SANTOS PEDROSA
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "hardware/pwm.h"
#include "hardware/uart.h" // Necessário para GPS (simulado aqui)
#include "hardware/spi.h" // Necessário para LoRa (simulado aqui)
#include "pico/time.h" // Para funções de tempo mais precisas
// --- Definições de Pinos e Constantes ---
#define PIR_PIN 2 // Sensor PIR (Movimento) - Pode ser usado em conjunto, mas não é o gatilho principal da abordagem.
#define LED_ALERTA_PIN 15 // LED de alerta vermelho (para alarme ativo)
#define BUZZER_PIN 16 // Buzzer (Som)
#define SERVO_PIN 18 // Servo motor travamento (ignição/rodas)
#define SMOKE_PIN 20 // Gerador de fumaça LED Azul
// Novo: Botão de acionamento discreto
#define BOTAO_DISCRETO_PIN 21 // Pino para o botão oculto (Pull-up interno ou resistor externo)
#define LED_STATUS_PIN 22 // LED de status oculto (ex: verde para armado, piscando para atraso)
// Constantes de tempo
#define DELAY_POS_ABORDAGEM_MS 180000 // 3 minutos de atraso seguro (180 segundos)
#define ALARM_DURATION_MS 120000 // 2 minutos de alarme total (120 segundos)
#define GPS_LORA_SEND_INTERVAL_MS 10000 // Envio de localização a cada 10 segundos
// --- Enumerador de Estados do Sistema ---
typedef enum {
STATE_NORMAL, // Sistema em modo de espera, desarmado
STATE_ACIONAMENTO_DISCRETO, // Botão discreto acionado, aguardando atraso seguro
STATE_ROUBO_CONFIRMADO, // Atraso seguro esgotado, moto em movimento, alarmes ativos
STATE_ALARM_COOL_DOWN // Após alarme, aguardando reinício manual ou tempo
} SystemState;
SystemState current_state = STATE_NORMAL;
absolute_time_t state_start_time; // Tempo de início do estado atual
// --- Funções de Periféricos Existentes ---
void setup_buzzer() {
gpio_set_function(BUZZER_PIN, GPIO_FUNC_PWM);
uint slice_num = pwm_gpio_to_slice_num(BUZZER_PIN);
pwm_set_wrap(slice_num, 12500); // Frequência ~2kHz
pwm_set_chan_level(slice_num, PWM_CHAN_A, 0); // Começa sem som
pwm_set_enabled(slice_num, true);
}
void buzzer_alert(int state) {
uint slice_num = pwm_gpio_to_slice_num(BUZZER_PIN);
if (state) {
pwm_set_chan_level(slice_num, PWM_CHAN_A, 6250); // Som médio
} else {
pwm_set_chan_level(slice_num, PWM_CHAN_A, 0); // Silenciar
}
}
void setup_servo() {
gpio_set_function(SERVO_PIN, GPIO_FUNC_PWM);
uint slice_num = pwm_gpio_to_slice_num(SERVO_PIN);
pwm_set_wrap(slice_num, 2500); // Período de 20ms
pwm_set_chan_level(slice_num, PWM_CHAN_A, 125); // Posição inicial (0 graus)
pwm_set_enabled(slice_num, true);
}
void move_servo(int angle) {
uint slice_num = pwm_gpio_to_slice_num(SERVO_PIN);
uint16_t duty = 125 + (angle * 125) / 90; // Exemplo para 0 a 180 graus
pwm_set_chan_level(slice_num, PWM_CHAN_A, duty);
}
void activate_smoke(int state) {
gpio_put(SMOKE_PIN, state);
}
// --- Novas Funções de Sensores e Comunicação (Simuladas) ---
// Simula a leitura de movimento do acelerômetro
// Na prática, você leria o MPU6050 via I2C e processaria os dados.
bool read_accelerometer_movement() {
// Implementar a lógica para ler o acelerômetro e determinar movimento.
// Pode ser baseado em um limiar de alteração nos eixos X, Y, Z.
// Por exemplo, se a moto se move mais de X m/s ou vibra acima de um certo nível.
// Return true para movimento, false para parado.
// Para simulação, vamos retornar true aleatoriamente ou após um tempo:
static uint32_t last_movement_check_time = 0;
if (time_us_32() - last_movement_check_time > 5000000) { // Simula movimento após 5 segundos
last_movement_check_time = time_us_32();
// printf("SIMULANDO: Movimento detectado pelo acelerômetro.\n");
return true;
}
return false;
}
// Simula a obtenção da localização GPS
// Na prática, você leria dados NMEA de um módulo GPS (NEO-6M) via UART.
char* get_gps_location() {
static char location_data[64];
// Exemplo: "$GPGGA,123519,4807.3879,N,01131.0000,E,1,05,0.9,545.4,M,46.9,M,,*47"
// Aqui você parsearia a string NMEA para obter Lat/Lon.
// Para simulação, retorna uma localização fixa ou aleatória:
sprintf(location_data, "Lat: -23.55%c, Lon: -46.63%c", rand() % 2 == 0 ? 'X' : 'Y', rand() % 2 == 0 ? 'A' : 'B');
return location_data;
}
// Simula o envio de mensagem via LoRa
// Na prática, você usaria uma biblioteca LoRa (ex: RadioLib para SX127x) via SPI.
void send_lora_message(const char* message) {
printf("[LoRa] Enviando: %s\n", message);
// Adicionar código real de envio LoRa aqui (ex: LoRa.beginPacket(); LoRa.print(message); LoRa.endPacket();)
}
// --- Inicialização dos Periféricos ---
void setup() {
stdio_init_all();
gpio_init(PIR_PIN);
gpio_set_dir(PIR_PIN, GPIO_IN);
gpio_init(LED_ALERTA_PIN);
gpio_set_dir(LED_ALERTA_PIN, GPIO_OUT);
gpio_put(LED_ALERTA_PIN, 0);
gpio_init(SMOKE_PIN);
gpio_set_dir(SMOKE_PIN, GPIO_OUT);
gpio_put(SMOKE_PIN, 0);
gpio_init(LED_STATUS_PIN);
gpio_set_dir(LED_STATUS_PIN, GPIO_OUT);
gpio_put(LED_STATUS_PIN, 0); // Desligado inicialmente
// Configuração do botão discreto com pull-up interno
gpio_init(BOTAO_DISCRETO_PIN);
gpio_set_dir(BOTAO_DISCRETO_PIN, GPIO_IN);
gpio_pull_up(BOTAO_DISCRETO_PIN); // Ativa pull-up interno
setup_buzzer();
setup_servo();
// Inicializar GPS (UART) e LoRa (SPI) - Apenas chamadas de setup simuladas
// uart_init(GPS_UART_ID, 9600); // Exemplo
// spi_init(spi_default, 1000 * 1000); // Exemplo
printf("SSPEI - Sistema de Segurança Inicializado. Estado: NORMAL\n");
state_start_time = get_absolute_time(); // Inicia o contador de tempo
}
// --- Loop Principal do Sistema (Máquina de Estados) ---
void loop() {
uint32_t current_time_ms;
uint32_t elapsed_time_ms;
static uint32_t last_lora_send_time = 0; // Para controlar o intervalo de envio do LoRa
while (1) {
current_time_ms = to_ms_since_boot(get_absolute_time());
elapsed_time_ms = current_time_ms - to_ms_since_boot(state_start_time);
switch (current_state) {
case STATE_NORMAL:
gpio_put(LED_STATUS_PIN, 0); // LED de status desligado
gpio_put(LED_ALERTA_PIN, 0); // Garante que o LED de alerta esteja desligado
buzzer_alert(0);
activate_smoke(0);
move_servo(0); // Garante que a trava esteja desativada
// Verifica o botão discreto (acionado quando LOW)
if (!gpio_get(BOTAO_DISCRETO_PIN)) {
printf("✅ Botão Discreto Acionado! Entrando em modo de Atraso Seguro.\n");
send_lora_message("ALERTA: POSSIVEL ABORDAGEM! AGUARDANDO ACIONAMENTO.");
current_state = STATE_ACIONAMENTO_DISCRETO;
state_start_time = get_absolute_time(); // Reinicia o tempo para o novo estado
last_lora_send_time = current_time_ms; // Reinicia o tempo para o envio LoRa
gpio_put(LED_STATUS_PIN, 1); // Pode piscar ou ligar discretamente para feedback ao condutor
sleep_ms(500); // Debounce para o botão
}
break;
case STATE_ACIONAMENTO_DISCRETO:
// LED de status pode piscar para indicar atraso seguro
gpio_put(LED_STATUS_PIN, (current_time_ms / 500) % 2);
// Envia localização discretamente a cada X segundos
if (current_time_ms - last_lora_send_time >= GPS_LORA_SEND_INTERVAL_MS) {
char* loc = get_gps_location();
printf("Atraso Seguro: Enviando localização discreta: %s\n", loc);
send_lora_message(loc);
last_lora_send_time = current_time_ms;
}
// Verifica se o tempo de atraso seguro expirou
if (elapsed_time_ms >= DELAY_POS_ABORDAGEM_MS) {
// Verifica se a moto está em movimento pelo acelerômetro (ou GPS)
if (read_accelerometer_movement()) { // A moto está em movimento e o atraso passou
printf("🚨 Atraso Seguro esgotado e moto em movimento. ROUBO CONFIRMADO! 🚨\n");
send_lora_message("ROUBO CONFIRMADO! ACIONANDO ALARMES.");
current_state = STATE_ROUBO_CONFIRMADO;
state_start_time = get_absolute_time(); // Reinicia o tempo para o novo estado
last_lora_send_time = current_time_ms; // Reinicia o tempo para o envio LoRa
} else {
printf("ℹ️ Atraso Seguro esgotado, mas moto não está em movimento. Retornando ao estado NORMAL.\n");
send_lora_message("INFO: Atraso seguro esgotado, moto parada. Retornando ao normal.");
current_state = STATE_NORMAL; // Falso positivo de acionamento ou moto foi abandonada imediatamente
}
}
// Permite que o condutor desative o sistema se for um engano
if (!gpio_get(BOTAO_DISCRETO_PIN) && (elapsed_time_ms > 2000)) { // Pressione novamente para desarmar
printf("❌ Desarmando sistema de atraso seguro.\n");
current_state = STATE_NORMAL;
send_lora_message("INFO: Sistema desarmado pelo condutor.");
sleep_ms(500); // Debounce
}
break;
case STATE_ROUBO_CONFIRMADO:
gpio_put(LED_ALERTA_PIN, (current_time_ms / 200) % 2); // LED piscando rápido
buzzer_alert(1);
activate_smoke(1);
move_servo(90); // Trava o motor/ignição
// Envia localização continuamente a cada X segundos
if (current_time_ms - last_lora_send_time >= GPS_LORA_SEND_INTERVAL_MS) {
char* loc = get_gps_location();
printf("Roubo Confirmado: Enviando localização: %s\n", loc);
send_lora_message(loc);
last_lora_send_time = current_time_ms;
}
// Verifica se o tempo de alarme esgotou
if (elapsed_time_ms >= ALARM_DURATION_MS) {
printf("⏹️ Duração do alarme esgotada. Desativando alarmes.\n");
send_lora_message("ALARME FINALIZADO.");
buzzer_alert(0);
activate_smoke(0);
gpio_put(LED_ALERTA_PIN, 0);
move_servo(0); // Destrava o motor para simulação de reinício
current_state = STATE_ALARM_COOL_DOWN;
state_start_time = get_absolute_time();
}
break;
case STATE_ALARM_COOL_DOWN:
// Estado para "descansar" o sistema após um alarme
// Poderia exigir um reset manual ou esperar um tempo maior antes de voltar ao NORMAL
printf("Sistema em cool-down. Aguardando reinício.\n");
// Poderia implementar um botão de reset físico aqui para retornar ao NORMAL
// Por enquanto, retorna automaticamente após 30 segundos
if (elapsed_time_ms >= 30000) {
printf("Cool-down finalizado. Retornando ao estado NORMAL.\n");
current_state = STATE_NORMAL;
state_start_time = get_absolute_time();
}
break;
}
sleep_ms(100); // Pequeno atraso para não consumir todo o ciclo da CPU
}
}
int main() {
setup();
loop();
return 0;
}