Never Ride Alone: Sistema Inteligente de Segurança para Ciclistas
Componentes e Materiais
| LED 5mm Vermelho | 2 |
| GPS u-blox NEO-6M | 1 |
| Arduino MKR FOX 1200 | 1 |
| Bateria 3.7V | 1 |
| Buzzer | 1 |
| Chave Pushbutton 12mm SparkFun | 1 |
| Chave Deslizante | 1 |
| Resistor 1k ohm | 1 |
| Sensor de Vibração Seeed Grove (SW-420) | 1 |
Ferramentas Necessárias
- Impressora 3D (genérica)
Sobre o Projeto
Olá, sou Jesús Soriano, estudante de engenharia eletrônica, empreendedor... e ciclista!
Pedalo desde os 12 anos, geralmente sozinho. Durante treinos, tive muitas quedas, acidentes e imprevistos. Um dia percebi: se eu tivesse um acidente grave e perdesse a consciência, poderia morrer. Estava sozinho nas montanhas!
É mais fácil entender com um vídeo: imagine pedalando, curtindo a paisagem, e de repente um carro aparece e te atropela. Você cai numa ribanceira, o motorista foge. Você fica inconsciente, preso, invisível ao mundo.
Duas ou três horas depois, sua família começa a se preocupar. Serviços de emergência tentam localizá-lo, conseguem após 4-5 horas. Você provavelmente estará morto.
Pesquisei opções: Strava Summit (envia GPS para contatos em acidente), ANGi da Specialized (integrado ao capacete, pede ajuda em colisão). Mas todos precisavam de sinal de celular. Bateria, GPS e sinal móvel eram necessários.
Foi assim que nasceu o Never Ride Alone (NRA). Encontrei o Sigfox como solução para envio de dados nas montanhas, e quando descobri que existia um Arduino com módulo Sigfox... foi perfeito!
Como o NRA Funciona
O NRA funciona como um alarme invertido. Ao sair pedalando, você ativa o NRA pressionando um botão. LEDs piscam, melhorando também a visibilidade. Se o NRA detectar nenhum movimento por 30 segundos, ativa o modo emergência: começa a buzinar. Se ninguém para (você esqueceu de desligar), significa que você está ferido. Automaticamente, o GPS inicia e envia a localização via rede Sigfox para seus contatos (família/amigos).
Design Minimalista
Consultei muitos ciclistas e cheguei a um design minimalista. Ciclistas querem gadget fácil de usar e com boa bateria. Com NRA, só pressiona o botão e pedala. Após treino, para e carrega.
O gabinete é de plástico ABS, impresso em 3D na Universidade Politécnica de Valência.
Arquivos de design editáveis/baixáveis: Tinkercad
Componentes Utilizados
- Arduino MKR FOX 1200
- GPS NEO-6M
- Botão
- 2 LEDs
- Resistor 1kΩ
- Buzzer
- Sensor de vibração
- Bateria 3.7V 150mAh
Configuração no Backend Sigfox
Quando o Arduino envia dados, o servidor converte dados brutos em informação. No meu caso, uso longitude, latitude e altitude. Com isso, envio e-mail para contatos configurados com link do Google Maps para localizar o ciclista ferido.
Montagem
- Módulo GPS: apenas positivo, negativo e fio de dados. Antena colada no quadro. Arduino por cima.
- Bateria conectada ao Arduino com chave liga/desliga.
- Conector de bateria para recarga (deve estar desligado durante carga). Usei carregador de bateria de drone – funcionou perfeitamente.
- Após fiação, antena sobre o Arduino. Montagem apertada mas viável com atenção.
Nesta versão, não usei o sensor de vibração. O NRA envia posição GPS a cada 10 minutos. Resultados bons. Testado em estradas – experiência muito positiva.
É realmente fácil de usar e dá a sensação de ter um bom gadget nas mãos.
Sustentabilidade
Da equipe Never Ride Alone, também tentamos melhorar o planeta. Durante testes, recolhemos todo lixo visto nas montanhas. Segundo Objetivos de Desenvolvimento Sustentável, tentamos remover todo lixo encontrado.
Percebemos que a maior parte do lixo nas montanhas vem de ciclistas! Plásticos de barras energéticas, géis e pneus. Agora, tentamos conscientizar ciclistas. Em provas, criamos pontos de coleta onde podem jogar lixo sem parar/perder tempo. Área delimitada, limpa ao final da prova.
Obrigado por ler, e pedale seguro :)
Código
NEVER RIDE ALONE V.0.1 Arduino
Código NRA. Não usa sensores. Envia todos os dados GPS a cada 10 minutos.
///// NEVER RIDE ALONE V.0.1 /////
//.............................//
////AUTOR: JESUS SORIANO ADAM////
////////FECHA: 05/05/2019 ///////
/////////////////////////////////
#include <SigFox.h>
#include <ArduinoLowPower.h>
#include <TinyGPS.h>
#define WAITING_TIME 10 // tempo de espera entre mensagens (min)
#define GPS_PIN 2 // (pino transistor, para economia de energia. não usado agora)
#define GPS_INFO_BUFFER_SIZE 128
bool debug = true;
const int backlights = 4;
const int pulsador = 5;
const int audio = 3;
TinyGPS gps;
// Variáveis GPS
int year;
byte month, day, hour, minute, second, hundredths;
unsigned long chars;
unsigned short sentences, failed_checksum;
char GPS_info_char;
char GPS_info_buffer[GPS_INFO_BUFFER_SIZE];
unsigned int received_char;
bool message_started = false;
int i = 0;
// Estrutura coordenadas GPS, 12 bytes em plataformas 32 bits
struct gpscoord {
float a_latitude; // 4 bytes
float a_longitude; // 4 bytes
float a_altitude; // 4 bytes
};
float latitude = 0.0f;
float longitude = 0.0f;
float altitud = 0;
//////////////// Função Espera ////////////////
void Wait(int m, bool s) {
// m = minutos para esperar
// s = pulso lento do LED
if (debug) {
Serial.print("Aguardando: ");
Serial.print(m);
Serial.println(" min.");
}
digitalWrite(LED_BUILTIN, LOW);
if (s) {
int seg = m * 30;
for (int i = 0; i < seg; i++) {
digitalWrite(backlights, HIGH);
delay(500);
digitalWrite(backlights, LOW);
delay(500);
}
} else {
int seg = m * 15;
for (int i = 0; i < seg; i++) {
digitalWrite(backlights, HIGH);
delay(500);
digitalWrite(backlights, LOW);
delay(500);
}
}
}
/////////////////// Função Envio Sigfox ////////////////
void SendSigfox(String data) {
if (debug) {
Serial.print("Enviando: ");
Serial.println(data);
if (data.length() > 12) {
Serial.println("Mensagem muito longa, apenas primeiros 12 bytes serão enviados");
}
}
SigFox.begin();
delay(100);
SigFox.status();
delay(1);
if (debug) SigFox.debug();
delay(100);
SigFox.beginPacket();
SigFox.print(data);
if (debug) {
int ret = SigFox.endPacket(true);
if (ret > 0) Serial.println("Sem transmissão");
else Serial.println("Transmissão OK");
Serial.println(SigFox.status(SIGFOX));
Serial.println(SigFox.status(ATMEL));
if (SigFox.parsePacket()) {
Serial.println("Resposta do servidor:");
while (SigFox.available()) {
Serial.print("0x");
Serial.println(SigFox.read(), HEX);
}
} else {
Serial.println("Sem resposta do servidor");
Serial.println("Verifique cobertura Sigfox na sua área");
Serial.println("Se em ambiente interno, verifique cobertura 20dB ou aproxime de janela");
}
Serial.println();
} else {
SigFox.endPacket();
}
SigFox.end();
}
//////////////////// Conversão GPS ////////////////////
/* Converte dados float GPS para Char */
String ConvertGPSdata(const void* data, uint8_t len) {
uint8_t* bytes = (uint8_t*)data;
String cadena;
if (debug) {
Serial.print("Tamanho: ");
Serial.println(len);
}
for (uint8_t i = len - 1; i < len; --i) {
if (bytes[i] < 12) {
cadena.concat(byte(0));
}
cadena.concat(char(bytes[i]));
if (debug) Serial.print(bytes[i], HEX);
}
if (debug) {
Serial.println("");
Serial.print("String a enviar: ");
Serial.println(cadena);
}
return cadena;
}
//////////////////// Obter Posição GPS ////////////////////
String GetGPSpositon() {
int messages_count = 0;
String pos;
if (debug) Serial.println("GPS LIGADO");
digitalWrite(GPS_PIN, HIGH); // Liga GPS
Wait(1, false);
while (messages_count < 5000) {
while (Serial1.available()) {
int GPS_info_char = Serial1.read();
if (GPS_info_char == '$') messages_count++;
if (debug) {
if (GPS_info_char == '$') {
message_started = true;
received_char = 0;
} else if (GPS_info_char == '*') {
for (i = 0; i < received_char; i++) {
Serial.write(GPS_info_buffer[i]);
}
Serial.println();
message_started = false;
} else if (message_started == true) {
if (received_char <= GPS_INFO_BUFFER_SIZE) {
GPS_info_buffer[received_char] = GPS_info_char;
received_char++;
} else {
message_started = false;
received_char = 0;
}
}
}
if (gps.encode(GPS_info_char)) {
gps.f_get_position(&latitude, &longitude);
altitud = gps.altitude() / 100;
gpscoord coords = {altitud, longitude, latitude};
gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths);
if (debug) {
Serial.println();
Serial.print("Lat/Long: ");
Serial.print(latitude, 5);
Serial.print(", ");
Serial.println(longitude, 5);
Serial.print("Data: ");
Serial.print(day, DEC); Serial.print("/");
Serial.print(month, DEC); Serial.print("/");
Serial.print(year);
Serial.print(" Hora: ");
Serial.print(hour, DEC); Serial.print(":");
Serial.print(minute, DEC); Serial.print(":");
Serial.print(second, DEC); Serial.print(".");
Serial.println(hundredths, DEC);
Serial.print("Altitude (m): ");
Serial.println(gps.f_altitude());
Serial.print("Rumo (graus): ");
Serial.println(gps.f_course());
Serial.print("Velocidade (km/h): ");
Serial.println(gps.f_speed_kmph());
Serial.print("Satélites: ");
Serial.println(gps.satellites());
Serial.println();
digitalWrite(backlights, HIGH);
delay(500);
digitalWrite(backlights, LOW);
delay(500);
}
gps.stats(&chars, &sentences, &failed_checksum);
if (debug) Serial.println("GPS desligado");
digitalWrite(GPS_PIN, LOW);
pos = ConvertGPSdata(&coords, sizeof(gpscoord));
return pos;
}
}
}
pos = "Sem Sinal";
return pos;
}
//////////////////// SETUP ////////////////////
void setup() {
pinMode(4, OUTPUT);
pinMode(backlights, OUTPUT);
pinMode(pulsador, INPUT);
pinMode(audio, OUTPUT);
if (debug) {
Serial.begin(9600);
while (!Serial) {}
Serial.println("Serial Conectado");
}
// Serial1 pinos 13-14 para conexão 3.3V ao GPS
Serial1.begin(9600);
while (!Serial1) {}
if (debug) Serial.println("GPS Conectado");
pinMode(GPS_PIN, OUTPUT);
if (!SigFox.begin()) {
Serial.println("Erro no shield ou não presente!");
return;
}
if (debug) {
SigFox.debug();
} else {
SigFox.end(); // Sono profundo
}
}
////////////////////// LOOP //////////////////////
void loop() {
String position_data;
position_data = GetGPSpositon();
SendSigfox(position_data);
Wait(WAITING_TIME, false);
}
Peças Personalizadas e Gabinetes
Cabe o MKR1200, bateria, botão, LEDs, GPS e buzzer.
Arquivo: nra_v_0_1_qCsc7I6QvO.zip
Esquemáticos
Nota: a foto do Arduino na imagem não é o MKR1200.
Diagrama disponível no projeto original.
Processo de manufatura
- Circuitos Integrados (CIs): Chips Compactos e Poderosos Impulsionando a Eletrônica Moderna
- Dominando a Instrução Switch em C#: Sintaxe, Exemplos e Boas Práticas
- Dados Digital com Arduino: Gere Números Aleatórios 1-6 em LCD 16x2
- Sistema Multi-Posição de Sensores de Temperatura para Integração em Casa Inteligente
- Controle USB para Jogos DIY com Arduino – Construa Seu Próprio Gamepad de Alto Desempenho
- Construa um Jogo Tetris com Arduino Nano em Matriz LED 16×8 DIY
- MotionSense: Detecção Inteligente de Intrusão com Arduino e ESP8266
- Kit MOSMusic: MOSFET, Arduino e Mais - Iluminação Sincronizada com Música
- Componentes Essenciais de uma Máquina de Furar: Visão Geral Completa
- Principais Componentes de um Motor de Combustão Interna