Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Manufacturing Technology >> Processo de manufatura

Rastreador GPS para carro com integração de mapa thinger.io

Componentes e suprimentos

Arduino Leonardo
Uso do Leonardo para obter serial de hardware dedicado.
× 1
Placa de desenvolvimento SIM900
× 1
módulo GPS u-blox NEO-6M
× 1
Antena, GPS
× 1
Resistor 220 ohm
× 2
LED (genérico)
× 2
Placa de solda 7 x 5 cm
Usei uma placa de solda que se encaixa no invólucro impresso em 3D para os LEDs de status "circuito". No entanto, você pode usar qualquer placa de ensaio genérica ou ignorá-la se não quiser LEDs de status
× 1
Módulo de redução de 12V para 5V
Para conectar a fonte de alimentação à bateria do carro (ou tomada de cigarro)
× 1
Leitor de cartão SD Adafruit
× 1
Cartão de memória Flash, cartão MicroSD
× 1

Ferramentas e máquinas necessárias

Ferro de soldar (genérico)

Aplicativos e serviços online

Plataforma Thinger.io
Um serviço IoT gratuito com painéis!

Sobre este projeto


Este projeto começou como uma simples “ideia de rastreador GPS” e acabou se tornando um “rastreador GPS multiuso”. Como meu primeiro projeto, a curva de aprendizado tem sido íngreme e, portanto, estou sempre aberto a contribuições, comentários e melhorias no design! :)

O rastreador deve ser colocado no meu carro e possui os seguintes recursos:
  • Rastreie as coordenadas do GPS e poste a última localização conhecida no painel da nuvem thinger.io IoT a cada 2 minutos (exibido em um mapa). Postagem em thinger.io com solicitações HTTP POST.
  • Respostas a comandos de SMS e retornar um link do mapa do Google para o local atual ou último local conhecido (último local conhecido se nenhum local atual estiver disponível).
  • Envie uma notificação por SMS a cada XX quilômetros (a ideia é que o rastreador me lembre de esvaziar meu tanque de coleta de óleo a cada 4000 km). Isso funciona como um "odômetro" de software personalizável.

Durante este projeto, percebi rapidamente o quão "limitado" o Arduino é em termos de memória disponível e tive que aprender técnicas para reduzir a sobrecarga e fazer um código eficiente (pelo menos tentei). Também usei bibliotecas leves para encaixar tudo no chip e na RAM disponível.

Os componentes usados ​​são os seguintes (como na lista de componentes):
  • Dispositivo GPS NEO-6M. Este parece ser um dispositivo GPS muito popular disponível barato no Ebay e similares. A comunicação com o GPS será via serial por hardware.
  • Antena GPS. Qualquer compatível servirá, no entanto, descobri que os mais baratos do Ebay não funcionaram muito bem, ou seja, má recepção / baixa contagem de satélites. Talvez eu só tenha tido azar com a primeira antena, mas tive que conseguir outra de melhor qualidade para uma recepção estável.
  • Placa de desenvolvimento SIM900 para conectividade GSM e GPRS. Este projeto também deve funcionar com SIM800- e módulos compatíveis, sem garantias no entanto. A comunicação com o SIM900 será por software serial.
  • Arduino Leonardo borda. Usei a placa Leonardo para ter uma linha serial de hardware dedicada, como precisamos de duas linhas seriais. Embora seja possível usar uma placa UNO comum, você deve desconectar o GPS para fazer o download do software e também não terá um monitor serial para depuração. Precisamos de duas linhas seriais (uma para GPS e outra para a placa SIM900); um serial de software e um serial de hardware.
  • Leitor de cartão SD (usei o leitor de cartão Adafruit, que é compatível com 5 V (facilitou a conexão ao conector SPI 5 V). Outros módulos mais baratos também podem funcionar. O cartão Micro SD será usado para armazenar a distância percorrida. Aviso: certifique-se de que seu leitor de cartão SD suporta alimentação de 5V se, seguindo meus esquemas, muitos leitores de cartão SD usam apenas 3,3V. Usar níveis de tensão incorretos provavelmente danificará os componentes eletrônicos. A comunicação com o leitor de cartão SD será a interface SPI.
  • LEDs e resistores para fazer circuitos indicadores de status (LED de energia e bloqueio de GPS).
  • cartão SIM com dados.
  • Eu também projetei um gabinete para impressão 3D com arquivos STL anexados que podem ser impressos diretamente em uma impressora 3D.

Primeiro, precisamos instalar as bibliotecas necessárias. Usei as seguintes bibliotecas para este projeto:
  • NeoGPS para rastreamento e decodificação GPS. Pode ser instalado diretamente do gerenciador de biblioteca no Arduino IDE. Mais informações:https://github.com/SlashDevin/NeoGPS
  • Tempo biblioteca (usada para conversão de fuso horário UTC):https://github.com/PaulStoffregen/Time
  • PetitFS para leitura / gravação no cartão SD:https://github.com/greiman/PetitFS Biblioteca Lightweight SD FAT.

Por que não usar a biblioteca disponível para Arduino por thinger.io?

Embora a biblioteca fornecida pelo thinger.io seja muito fácil de usar e simplificasse bastante as coisas, para não dizer já integrada no IDE, ela consome quase 80% do armazenamento no Arduino Leo, deixando pouco ou nenhum espaço para o código restante. Portanto, é muito grande para este projeto e teremos que fazê-lo da maneira mais difícil. Para comunicação com a nuvem thinger.io, usaremos solicitações HTTP POST.

SMS comandos

Os comandos disponíveis no SMS são os seguintes (todas as letras maiúsculas). Esses são os comandos com suporte no código fornecido; você pode adicionar / remover comandos para seu próprio projeto / requisitos:
  • "POS" retorna as coordenadas com o link do Google Maps, se houver coordenadas disponíveis. Caso contrário, o último local conhecido é retornado.
  • "GETKM" retorna a distância atual desde a última "reinicialização".
  • "RESETKM" define o contador de distância para 0 (redefinir hodômetro).
>





Configurando NeoGPS


Usamos a biblioteca NeoGPS para desempenho e uso de recursos em alternativas como TinyGPS ++. Ele consome muito pouca RAM, e isso é necessário; caso contrário, obteremos avisos de pouca memória e estabilidade.

Depois que a biblioteca for instalada, modifique o arquivo GPSPort.h no caminho de instalação da biblioteca (o exemplo dado é para OS X - para Windows, você encontrará a biblioteca em um local diferente)

Substitua todo o conteúdo em GPSPort.h pelo seguinte:
  #ifndef GPSport_h # define GPSport_h # define gpsPort Serial1 # define GPS_PORT_NAME "Serial1" #define DEBUG_PORT Serial # endif  

Este arquivo contém definições usadas pela biblioteca NeoGPS. Se você estiver usando uma placa Arduino diferente, é aqui que você define a linha serial para o receptor GPS, por exemplo, "Serial2", "Serial3" para Arduino MEGA.

Notas sobre precisão

Deve-se notar que o GPS não é a forma mais precisa de medir e acumular distâncias, já que a posição pode sofrer um ligeiro desvio mesmo quando está parado. Você pode testar isso parando no mesmo local e observar que as coordenadas do GPS serão diferentes para cada leitura. Para esta aplicação, a precisão é menos importante e, portanto, desvios menores estão OK.

No entanto, tentei contabilizar pequenos desvios nas coordenadas e o software apenas adiciona distâncias para movimentos acima de 10m (todos os movimentos abaixo de 10m são considerados estacionários) em 15 segundos.

Além disso, lembre-se de que a distância é calculada em linha reta, enquanto a distância real que o carro percorre depende da estrada, curvas, etc. Eu defini a taxa de amostragem para 15 segundos, mas você pode diminuí-la se quiser mais precisão.





Configurando PetitFS


Esta biblioteca é uma biblioteca superleve para leitura / gravação em cartões SD com formato FAT. Levei algum tempo para descobrir como isso funciona, já que a documentação é praticamente inexistente e alguns lugares até errados / desatualizados. O código de exemplo da biblioteca fornecido nem mesmo compila. Ele vem com um lote de restrições (em oposição a uma biblioteca "normal" como a biblioteca SD do Arduino ou SDFat):
  • Não é possível criar o arquivo. Apenas o arquivo existente pode ser gravado.
  • Não é possível expandir o tamanho do arquivo.
  • Não é possível atualizar o carimbo de data / hora do arquivo.
  • Não é possível anexar dados ao arquivo (sempre reescreve o arquivo).
  • Apenas um arquivo é aberto por vez.

Por que usar uma biblioteca pequena e limitada com muitas peculiaridades?

Tamanho, basicamente. Tentei algumas bibliotecas, incluindo a Arduino SD Library, SDFat e também fat16lib. Eles são todos grandes demais para fazer todo o código caber no chip, portanto, para não remover a funcionalidade, usei essa biblioteca (a biblioteca SD do Arduino padrão ocupa aproximadamente 12% a mais de espaço). Mesmo com todas as peculiaridades e limitações, ele ainda fornece o que precisamos para este aplicativo:leitura e gravação simples de um único valor para armazenamento.

Se você não usar todo o código e houver espaço suficiente para inserir um pouco mais, é muito mais fácil trabalhar com bibliotecas como a biblioteca SD padrão.

Abra o arquivo pffArduino.h da pasta da biblioteca PetitFS. Altere o SD_CS_PIN a 10. Este é o pino SS usado para se comunicar com o cartão SD com SPI.

Abra o arquivo pffconf.h da pasta da biblioteca. Desativar as seguintes opções, alterando o valor definido de 1 para 0:
  • _USE_DIR
  • _USE_LSEEK
  • _FS_FAT12
  • _FS_FAT16

Ao desabilitar essas opções, o programa compilado ocupa menos espaço - o que é necessário; O esboço final leva aprox. 96% de armazenamento.

Na primeira importação da biblioteca, você obterá um erro de compilação que * pode * ser ignorado (na segunda compilação, o erro não aparece - ainda não entendo o porquê). No entanto, se você deseja corrigir isso (ele reaparecerá toda vez que você iniciar o Arduino IDE -> compilar), adicione o parâmetro de retorno da função ausente "FRESULT", conforme mostrado na captura de tela acima. Isso está no arquivo pff.cpp na pasta da biblioteca.

Tentei o meu melhor para descobrir como essa biblioteca funciona e, embora tenha tudo para funcionar, tenho certeza de que as coisas também podem ser melhoradas. Se você encontrar erros ou melhorias nas rotinas que escrevi, sinta-se à vontade para compartilhar! Eu gostaria muito de aprender e adquirir mais experiência.

Prepare o cartão SD

Usei um cartão Micro SD para este projeto. Uma vez que a biblioteca não pode criar o (s) arquivo (s), é importante criar o arquivo "dist.txt" e "settings.txt" no cartão antes de usar. Eu recomendo copiar os arquivos "dist.txt" e "settings.txt" em anexo arquivo desta página do projeto, uma vez que esses arquivos já estão no formato correto e funcionam (a biblioteca é muito exigente quanto ao formato e conteúdo do texto).

Antes de colocar o arquivo no cartão Micro SD, certifique-se de formatar o cartão corretamente (como FAT32 ) Eu recomendo usar o "SD Card Formatter" oficial da SD Association:https://www.sdcard.org/downloads/formatter/.

Certificando-se de que o cartão SD funciona (ler / gravar no arquivo corretamente)

A biblioteca PetitFS é muito exigente com os arquivos de entrada. Se você inicializar o dispositivo e nenhuma saída for mostrada no monitor serial (apenas em branco), ele provavelmente está preso no "loop" onde tenta ler o arquivo do cartão, mas não consegue por algum motivo (função initializeSD ()). Tive inúmeros arquivos de texto em que, por algum motivo, não foi possível ler, portanto, incluí os arquivos de texto referenciados que usei e que funcionam. Coloque essas referências arquivos no cartão SD e deve ser capaz de ler e gravar corretamente nele.

Outra opção pode ser preencher o arquivo de texto com um número que seja maior do que a sua escrita. Eu não testei isso, mas como a biblioteca não pode expandir o tamanho do arquivo, presumo que isso seja um problema.

PetitFS gravará todo o comprimento do array de caracteres no arquivo, portanto, você verá espaços vazios na frente do número real (a menos que o número seja grande o suficiente para preencher o array - o comprimento do "array" é definido no código). Esses espaços devem ser mantidos ao fazer alterações no arquivo - como PetitFS não pode fazer alterações no tamanho do arquivo, ele pode causar problemas se o número de caracteres for alterado.

Defina o arquivo "dist.txt" como "0" se desejar que o odômetro comece em "0" ou qualquer outro número para facilitar a verificação de que funciona, por exemplo, enviando o comando "GETKM" para verificar a resposta do SMS.

Em "settings.txt" você define a distância de disparo da notificação, a distância onde o hodômetro dispara o SMS de notificação (em metros).





Prepare a placa SIM900


Algumas coisas devem ser configuradas na placa SIM900 antes de podermos usá-la. Para obter detalhes, há um ótimo recurso em https://lastminuteengineers.com/sim900-gsm-shield-arduino-tutorial/ para a configuração desta placa.

Fonte de energia

A placa Arduino não é capaz de fornecer energia suficiente, portanto, devemos usar uma fonte de alimentação externa. Como os picos podem consumir até 2A, certifique-se de usar uma fonte de alimentação que pode fornecer pelo menos 2A a 5V-9V DC; ele usa o conector barril de 5,5 mm.

Seletor de fonte de alimentação

Ao lado do conector DC está um seletor de fonte de alimentação . Para usar uma fonte de alimentação externa, mova o controle deslizante conforme mostrado na imagem acima.

Seletor serial

Configure a placa para usar o Software Serial alinhando os jumpers conforme mostrado acima.

Gatilho de software

Em vez de pressionar manualmente a tecla liga / desliga todas as vezes, você pode ligar / desligar o SIM900 no software. Para fazer isso, o jumper denominado R13 deve ser soldado. A placa é então ligada conectando o pino 9 do SIM900 ao pino 7 do Arduino (conforme mostrado nos esquemas).

Se mantiver a funcionalidade "ligação manual", a função "SIM900power ()" do código pode ser removida.

Remover bloqueio do PIN do cartão SIM

Certifique-se de remover o bloqueio do PIN no cartão SIM antes de usar. Isso pode ser feito inserindo-o em qualquer telefone comum e remova o bloqueio de pino do menu de configurações aplicável.

Observe também que o módulo SIM900 nos esquemas pode parecer diferente da placa real, no entanto, o layout dos pinos está correto, o que é a parte mais importante.

Versão do firmware SIM900 (Importante!)

É muito importante ter a versão correta do firmware carregado no chip. Isso ocorre porque um dos comandos para configurar corretamente o cabeçalho HTTP POST não é suportado até a versão B10 do firmware. Isso significa que você precisa ter pelo menos a versão B10 ou superior para que a comunicação http funcione. Especificamente, com uma versão de firmware inferior, não será possível definir "Content-type" no cabeçalho http. Se o tipo de conteúdo não for definido como "application / json" na solicitação de postagem, ele será rejeitado pelo servidor.

Para verificar a versão do firmware, use o seguinte comando AT:
  AT + CGMR  

O chip SIM900 fornecerá a versão atual do firmware no console de saída. Coloque o seguinte no final da seção de configuração () para imprimir a versão do firmware na inicialização:
  SIM900.println (F ("AT + CGMR"));  

No meu caso, mostraria isso (antes de atualizar):
  Revisão:1137B01SIM900M64_ST_AM  

Esta era a versão de firmware mais antiga possível para este chip ("B01"), então atualizei para a versão B10: 1137B10SIM900M64_ST . Firmwares mais novos também devem funcionar.

Não vou cobrir como atualizar o firmware neste guia, já existe um excelente guia como fazer isso:Atualização do firmware do SIM900 - ACOPTEX (embora seja um processo um tanto doloroso).

Não sei se esse será o caso de outros chips como o SIM800, no entanto, sendo um chip mais recente, eu diria que é mais provável que já esteja instalado lá.





Ajustes de código


Para adaptar o código para seu próprio projeto, alguns ajustes são necessários:
  • Altere as informações do APN (provedor de rede).
  • Modifique o URL thinger.io para corresponder ao seu (o URL vincula a solicitação de atualização ao seu próprio "depósito" com token de acesso). Isso é abordado no capítulo "integração de thinger.io".
  • Defina o fuso horário correto.
  • Definir distância de disparo para notificação por SMS
  • Defina (ou desative) o texto de notificação por SMS.
  • Defina um número de telefone padrão para notificação.

Provedor APN
  void connectGPRS () {... SIM900.println (F ("AT + SAPBR =3,1, \" APN \ ", \" TeleXXX \ "")); atraso (1000); updateSIM900 (); ...  

Sob o connectGPRS () você encontrará o nome APN fornecido por seu provedor de rede, mostrado acima como "TeleXXX". Substitua-o pelo seu próprio nome APN.
  ATOKAT + CMGF =1OKAT + CNMI =1,2,0,0,0OKAT + SAPBR =3,1, "CONTYPE", "GPRS" OKAT + SAPBR =3,1, "APN", " TeleXXX "OKAT + SAPBR =1,1OKAT + SAPBR =2,1 + SAPBR:1,1," 36.57.240.233 "OK  

Acima:saída da função connectGPRS () quando a conexão está funcionando. Todos os comandos devem retornar o status "OK".

Fuso Horário
  #define UTC_OFFSET 1 // definir deslocamento de fuso horário, ou seja, 1 =UTC + 1  

Na seção "definir", defina o fuso horário de acordo com seus requisitos. O código está definido para UTC + 1 .

Notificação por SMS

Eu configurei uma notificação a cada 4000 km para esvaziar meu tanque de coleta de óleo. Como eu percebi que a maioria das pessoas não tem um tanque de coleta de óleo, essa notificação deve ser alterada para o que você quiser (ou desativada por completo).
  void loop () {... // envia notificação por SMS se a distância total exceder 4000km if (totalDistance> triggerDistance) {char sms_msg [160]; char distanceTotalMsg [10]; itoa ((totalDistance / 1000), distanceTotalMsg, 10); sprintf (sms_msg, "Empty catchtank! Current distance:% skm", distanceTotalMsg); textMessage =""; totalDistance =0; // define o número de telefone padrão para acionar a notificação number =DEFAULT_NUMBER; sendSMS (sms_msg); } ...}  

Acima:seção de código que dispara a notificação (dentro do loop principal ()).

Comente / remova esta seção se você não quiser nenhuma notificação acionada. Alternativamente, altere o texto para algo útil.

A notificação é acionada assim que o "odômetro" (distância acumulada) atinge a distância configurada no arquivo "settings.txt".

Número de telefone padrão

Este é o número de telefone para o qual a notificação acionada é enviada (já que a notificação não tem um número de "remetente" para responder)
  // número de telefone para notificação acionada # define DEFAULT_NUMBER "+4712345678"  

Aguarde a conexão serial

Também é uma boa ideia remover o comentário da linha a seguir no código. Isso faz com que a placa Arduino espere até que a conexão serial se torne ativa, ou seja, monitor serial para depuração. Dessa forma, você não perderá nenhuma mensagem de depuração no início do código, antes que a linha serial se torne ativa.

Lembre-se de remover / comentar a linha antes de ligar o Arduino a partir de fontes de alimentação externas, caso contrário, ele irá parar em um loop infinito até se conectar a um PC.
  // while (! Serial); // aguarde a porta serial conectar - para ATmega32u4 (Leonardo)  





Integração Thinger.io


Não vou entrar em detalhes sobre como configurar o thinger.io como sendo bastante simples; você deve criar uma conta e um "balde" para receber os dados através de seu site, e um "dispositivo" ao qual nos conectaremos. Um "balde" é o banco de dados para receber dados. O "dispositivo" é o ponto de conexão para nosso código onde decidimos o que fazer com os dados (em nosso caso, preencher o banco de dados "balde").

Crie um "balde" conforme mostrado acima com seu próprio nome e descrição.

Agora, vá em frente e crie um "Dispositivo HTTP" conforme descrito na documentação oficial:https://docs.thinger.io/quick-sart/devices/http-devices.

Use um curto dispositivo nome . Como o nome do dispositivo faz parte do algoritmo que gera a chave de autorização, descobri que um nome de dispositivo mais longo também gera uma chave de autorização mais longa. O problema? A chave de autorização rapidamente ficou maior do que o buffer de 256 caracteres usado para enviar a string do Arduino. Provavelmente, existem maneiras melhores de consertar isso, mas descobri a abordagem mais fácil de manter o nome do dispositivo curto e evitar o problema.

No dispositivo ' chamada de retorno > configurações seção certifique-se de que a configuração "write bucket" aponta para o bucket criado anteriormente. Isso diz ao "dispositivo" para gravar os dados de entrada em nosso banco de dados.

No dispositivo ' chamada de retorno > visão geral seção anote o método URL e cabeçalho de autorização (string longa sem a palavra-chave "Portador").

Para enviar dados a um thinger.io, usamos uma "URL de autorização" na solicitação HTTP POST. Você deve então substituir o URL e a chave de autorização no código pelos seus.

No postDataThinger () função você encontrará a chamada (chave de autorização real embaralhada):
  SIM900.println (F ("AT + HTTPPARA =\" URL \ ", \" http://backend.thinger.io/v3/users/tom/devices/CT/callback/data?authorization =eyJhbGciOiJIUzI1NiIsInR5cdfkjowiuerdf.sdfsdf.wekrjciI6InRvcm1vZCJ9.AR1gWvIZB9KmtI-5Z12YXKuchPTGn58AkwBJSZQIoxQ \ ""));  

Você deve então substituir o URL e autorização chave no código com o seu próprio, gerado seguindo as instruções no link fornecido acima.
  http://backend.thinger.io / ...  

Por padrão, o URL de autorização gerado será https . O SIM900 não suporte SSL (pelo menos não consegui fazer funcionar), então certifique-se de alterar "http s :// "to" http:// ". A API thinger também suporta conexões não SSL. Isso é muito importante. Se você mantiver" https ", não funcionará. Quando tudo funcionar, o monitor serial deve dar um" 200 - OK "responda ao transmitir a solicitação de postagem de http.

Após o comando AT "AT + HTTPACTION =1" (enviar solicitação HTTP POST) você deve receber uma resposta como esta no monitor serial:
  + HTTPACTION:1.200,0  

Se você receber uma resposta "400 - pedido incorreto" ou semelhante ..
  + HTTPACTION:0,400,51  

.. provavelmente há algo errado com o URL, por exemplo "https" em vez de "http", sintaxe incorreta da "chave de autorização", etc. Quando você receber uma mensagem "200 - OK", os dados devem aparecer no balde do thinger como mostrado abaixo. Você também pode receber um 400 - "solicitação incorreta" se não tiver o firmware correto conforme mencionado anteriormente.

Acima está uma visão do balde assim que os dados chegam (embaralhados por motivos de privacidade). O conteúdo (colunas de dados) é definido pela sintaxe de solicitação HTTP POST no código, nenhuma configuração em thinger.io é necessária.

Abaixo está uma saída serial da solicitação HTTP POST como deve ser quando tudo funciona. + HTTPACTION:1, 200, 0 indica que a atualização foi bem-sucedida.
  AT + HTTPINITOKAT + HTTPPARA ="CID", 1OKAT + HTTPPARA ="URL", "OKAT + HTTPPARA =" CONTENT "," application / json "OKAT + HTTPDATA =84,10000DOWNLOADOKAT + HTTPACTION =1OK + HTTPACTION:1.200,0AT + HTTPTERMOK  

O painel pode então ser facilmente configurado com o widget de mapas usando o balde como fonte de dados.

Mais dados para ele?

Você quer enviar mais dados do que longitude, latitude e data / hora? Basta adicionar mais campos de dados à solicitação http, conforme mostrado abaixo.

O formato é {"field1 name":field1, "field2 name":field2, "field3 name":field3}
  sprintf (httpContent, "{\" longitude \ ":% s, \" latitude \ ":% s, \" date \ ":\"% s% s \ "}", tempstrLong, tempstrLat , data1, hora1);  

O comando sprintf acima compila a string de dados enviada a ele. A sintaxe é * muito * estrita e você deve adicionar novos campos de dados exatamente da mesma maneira. O exemplo é dado no código (seção de comentários). Uma boa ideia é anotar a impressão do monitor serial do comando que mostrará a string. Em seguida, você adiciona "field4" e assim por diante.





Gabinete


Anexei um gabinete para impressão 3D completo. Ele foi projetado para se ajustar aos PCBs exatos usados ​​neste projeto. Parafusos M3 são usados ​​para montagem.
>
Ele é projetado para uma placa de solda 7x5cm para o "circuito" de LED e não uma placa de ensaio. Se estiver usando uma placa de ensaio, use apenas um pouco de cola. O GPS e a placa de solda ("breadboard") são montados na caixa superior. Use espaçadores pequenos para melhor montagem de PCBs no revestimento superior.

Também mantive os pontos de montagem no revestimento superior sólidos (sem orifícios) para facilitar a impressão sem suportes. Abra-os com uma broca de 3 mm.

Imprime bem em 0,2 mm sem suportes.





Conexão à bateria / fonte de alimentação do carro


Provavelmente, existem centenas de maneiras de fazer isso, então não tenho a única resposta, ou a melhor resposta para esse assunto; como conectá-lo à bateria do carro. Tudo depende da sua aplicação, mas descreverei rapidamente minha solução.

I wanted the device to start with the car, hence not connected directly to the battery (and drawing power while the car is turned off). So I've connected it to the "cigarette socket" circuit that is already turning on/off with the car. If you want it to be online even when the car is off, you'll have to find a way to wire it to the battery. For most cars the cigarette socket turns off with the car, but you'll have to check this for your own. I will not show the exact wiring for mine as this will also be different for every car. You can also place a battery pack in between to keep the device going for hours after the car has been switched off (or stolen..).

You can of course also just use an adapter, like one of those USB phone chargers, but that defeats my purpose of hiding it (in case the car gets stolen). We also have two power sources, the Arduino board and the SIM900 module. I used a "China cheap-o matic" step-down module, that converts from 12V-5V (the actual input range was said to be 9V-20V). It's probably not good quality, but has been working ok so far :)

The step-down module transforms the 12V input to 5V output to two USB female connectors. I then connected the Arduino- and SIM900 module to each of these USB outputs to power them. There are probably other and more "professional" solutions, but this was cheap and worked well enough.

I have measured the power draw during GSM activity to around 110maH, so very little power consumption. It will probably draw more power in areas with poor GSM coverage.





Known issues


If an SMS command is received at the same time as the thinger.io http request is processed (while data is being pushed to thinger) the command will not be picked up by the software. In this case, you will not receive a SMS reply. Send a new command some seconds later and it will work again. I've not made a workaround for this, as its not a big problem. If someone should make a fix for this, please feel free to share.

Also, if the Arduino is started in an area without network coverage, it won't reconnect when the network is available again, as it only connects during startup. I might modify the code at some point to fix this, but at the moment it

Código

  • GPS_tracker_Leonardo_v2.ino
GPS_tracker_Leonardo_v2.inoArduino
#include #include #include #include #include "PF.h"#include "PetitSerial.h"#define UTC_OFFSET 1 // set time zone offset, i.e. 1 =UTC+1#define TXPin 8 // SIM900 Tx pin#define RXPin 9 // SIM900 Rx pin#define PWRPin 7 // SIM900 software power pin// phone number for triggered notification#define DEFAULT_NUMBER "+4712345678"FATFS fs; // file system object - for reading SD card// GSM variablesString textMessage; // holds the last received text messageString number =DEFAULT_NUMBER; // phone number from last text messagechar sms_msg[160]; // holds the SMS reply text// location variablesfloat Lat =0, Long =0;boolean valid_location =false; // initial valid location flaguint8_t num_sat;NeoGPS::Location_t prevFix; // holds previous location for distance calculationNMEAGPS gps; // parses the GPS charactersgps_fix fix; // holds on to the latest valuesconst char *googlePrefix ="http://maps.google.com/maps?q=";const char *filename ="DIST.TXT";const char *settings ="SETTINGS.TXT";// time variablesNeoGPS::time_t timeFix; // time object for current gps fixchar datePrint[13];char timePrint[10];// distance tracking variablesfloat totalDistance =0; // in meters// triggerdistance (odometer notification) is read from SD card on initfloat triggerDistance =4000000;SoftwareSerial SIM900( TXPin, RXPin ); // SIM900 Tx &Rx is connected to Arduino #8 	void setup() { pinMode(3, OUTPUT); pinMode (4, SAÍDA); digitalWrite(3, HIGH); // turn on power LED Serial.begin(9600); // serial monitor /* the "while (!serial)" construct below must only be enabled for debugging purposes when connected to a PC. If this is kept in the code the program will stop in a loop when connected to external power sources, as no serial connection will be established */ // while (!Serial); // wait for serial port to connect - for ATmega32u4 (Leonardo) SIM900.begin(9600); // SIM900 module on pins #8 and #9 gpsPort.begin(9600); // GPS receiver on Serial1 pins #0 and #1 - defined in GPSport.h // initialize the SD card and reads standard setting and accumulated distance initializeSD(); // power up SIM900 with software trigger SIM900power(); SIM900.println( F("AT") ); // Handshaking with SIM900 delay(500); SIM900.println( F("AT+CMGF=1") ); // Configuring TEXT mode delay(500); SIM900.println( F("AT+CNMI=1,2,0,0,0") ); // Decides how newly arrived SMS messages should be handled delay(500); connectGPRS();}void loop() { while (gps.available( gpsPort )) { fix =gps.read(); num_sat =fix.satellites; if (fix.valid.location) { digitalWrite(4, HIGH); // sets GPS lock LED Lat =fix.latitude(); Long =fix.longitude(); // saves the first "GPS lock" flag - we now have useful data if (Lat !=0 &&Long !=0 &&!valid_location) { valid_location =true; prevFix =fix.location; } } if (fix.valid.date &&fix.valid.time) { timeFix =fix.dateTime; updateTime(); } // update thinger.io and write values to SD card only for valid gps fix // typically at startup before gps has locked in coordinates first time if (valid_location) { // updates the distance travelled every 15 seconds static const unsigned long REFRESH_INTERVAL_UPD =15000; // 15 seconds static unsigned long lastRefreshTime =millis(); if (millis() - lastRefreshTime>=REFRESH_INTERVAL_UPD) { lastRefreshTime +=REFRESH_INTERVAL_UPD; // calculates distance between current and previous fix in meters float distanceDelta =prevFix.DistanceKm(fix.location) * 1000; // only update if distance is greater than 10 meters and less than 10km // 10km check is implemented to avoid erroneous data reading from GPS if (distanceDelta> 10 &&distanceDelta <10000) { totalDistance +=distanceDelta; } // reset the calculation point for next loop (set "previous" location) prevFix =fix.location; } // writes distance travelled to SD card every 2 minutes // uploads coordinates to thinger.io every 2 minutes static const unsigned long REFRESH_INTERVAL_WRITE_SD =120000UL; // 2 minutes static unsigned long lastRefreshTimeWriteSD =millis(); if (millis() - lastRefreshTimeWriteSD>=REFRESH_INTERVAL_WRITE_SD) { lastRefreshTimeWriteSD +=REFRESH_INTERVAL_WRITE_SD; // file write to SD card begin char buf[9]; dtostrf(totalDistance, 8, 0, buf); if (PF.open(filename)) Serial.println( F("error open file") ); while (1) { UINT nr; if (PF.writeFile(buf, sizeof(buf), &nr)) Serial.println( F("error write file") ); if (nr ==sizeof(buf)) { PF.writeFile( 0, 0, &nr); // finalize write operation by writing a null pointer break; } } // Petit FS has no "close" operation on file // next section transfers data to thinger.io IoT cloud with HTTP POST request. // only update thinger.io after first successful GPS lock char httpContent[60]; char tempstrLong[10]; char tempstrLat[10]; dtostrf(Lat, 2, 6, tempstrLat); dtostrf(Long, 2, 6, tempstrLong); // data fields to thinger.io bucket. Access to bucket is given through URL authorization in the post function. // format is { "field1 name" :field1 , "field2 name" :field2 , "field3 name" :field3 } with exact byte count. sprintf(httpContent, "{ \"longitude\":%s , \"latitude\":%s , \"date\":\"%s %s\" }", tempstrLong, tempstrLat, datePrint, timePrint); char httpdataLen[20]; // exact byte count for the content must be added to HTTPDATA // otherwise HTTP POST request is invalid, i.e. status 400 is retured. sprintf(httpdataLen, "AT+HTTPDATA=%i,10000", strlen(httpContent)); postDataThinger(httpdataLen, httpContent); } } } // send SMS notification if the total distance exceeds configured limit if (totalDistance> triggerDistance) { char distanceTotalMsg[10]; itoa( (totalDistance / 1000) , distanceTotalMsg, 10); sprintf(sms_msg, "Empty catchtank! Current distance:%skm", distanceTotalMsg); textMessage =""; number =DEFAULT_NUMBER; totalDistance =0; sendSMS(sms_msg); } updateSerial();}void updateSerial(){ // read incoming buffer. reads content of any text message if (SIM900.available()> 0) { textMessage =SIM900.readString(); } if (textMessage.indexOf("POS")>=0) { extractSenderNumber(); textMessage =""; char latPrint[10]; dtostrf(Lat, 5, 6, latPrint); char LonPrint[10]; dtostrf(Long, 5, 6, LonPrint); if (num_sat>=3 &&valid_location) { sprintf(sms_msg, "Current location:Lat:%s, Long:%s. %s%s,+%s\n", latPrint, LonPrint, googlePrefix, latPrint, LonPrint); } else if (num_sat <3 &&valid_location) { sprintf(sms_msg, "No gps fix. Last seen %s%sat:Lat:%s, Long:%s. %s%s,+%s\n", datePrint, timePrint, latPrint, LonPrint, googlePrefix, latPrint, LonPrint); } else if (!valid_location) { sprintf(sms_msg, "Tom not found. Maybe he is in North-Korea?"); } sendSMS(sms_msg); } // returns the current total accumulated distance if (textMessage.indexOf("GETKM")>=0 ) { char sms_msg[32]; char distanceTotalMsg[10]; itoa( (totalDistance / 1000) , distanceTotalMsg, 10); sprintf(sms_msg, "Current distance:%skm", distanceTotalMsg); textMessage =""; sendSMS(sms_msg); } // resets the distance counter to 0 if (textMessage.indexOf("RESETKM")>=0) { totalDistance =0; char sms_msg[] ="Acknowledge:distance reset"; textMessage =""; sendSMS(sms_msg); }}void SIM900power(){ // power up SIM900 board from pin #7 (default) -> 2sec. signal pinMode(PWRPin, OUTPUT); digitalWrite(PWRPin, LOW); atraso (1000); digitalWrite(PWRPin, HIGH); atraso (2000); digitalWrite(PWRPin, LOW); atraso (15000); // give module time to boot}void updateSIM900(){ // empty incoming buffer from SIM900 with read() delay(500); while (SIM900.available()) { // outputs buffer to serial monitor if connected Serial.write(SIM900.read()); }}void extractSenderNumber(){ uint8_t startPos =textMessage.indexOf("+", 6); uint8_t endPos =textMessage.indexOf(","); number =textMessage.substring(startPos, endPos - 1);}void sendSMS(char *content){ // really crappy string conversion since I was too lazy to do proper // char handling in the first place. // SMS is returned to the sender number. char numberChar[number.length() + 1]; number.toCharArray(numberChar, number.length() + 1); char cmd_sms[50]; sprintf(cmd_sms, "AT+CMGS=%c%s%c", 0x22, numberChar, 0x22); SIM900.println(cmd_sms); updateSIM900(); SIM900.print(content); updateSIM900(); SIM900.write(0x1A);}void connectGPRS(){ SIM900.println( F("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"") ); atraso (1000); updateSIM900(); SIM900.println( F("AT+SAPBR=3,1,\"APN\",\"TeleXXX\"") ); atraso (1000); updateSIM900(); SIM900.println( F("AT+SAPBR=1,1") ); atraso (1000); updateSIM900(); SIM900.println( F("AT+SAPBR=2,1") ); atraso (1000); updateSIM900();}void postDataThinger(char *httpDataLen, char* content){ SIM900.println( F("AT+HTTPINIT") ); atraso (1000); updateSIM900(); SIM900.println( F("AT+HTTPPARA=\"CID\",1") ); atraso (1000); updateSIM900(); SIM900.println( F("AT+HTTPPARA=\"URL\",\"http://backend.thinger.io/v3/users/tom/devices/CT/callback/data?authorization=eyJhbGciOiJIUzI1NiIsInR5cCI6lskjdflksjdfweruiowe19DVCIsInVzciI6InRvcm1vZCJ9.AR1gWvIZB9KmtI-5Z12YXKuchPTGn58AkwBJSZQIoxQ\"") ); atraso (1000); updateSIM900(); SIM900.println( F("AT+HTTPPARA=\"CONTENT\",\"application/json\"") ); atraso (1000); updateSIM900(); SIM900.println(httpDataLen); atraso (1000); updateSIM900(); SIM900.println(content); atraso (1000); updateSIM900(); SIM900.println( F("AT+HTTPACTION=1") ); atraso (10000); updateSIM900(); SIM900.println( F("AT+HTTPTERM") ); atraso (1000); updateSIM900();}// initialize SD card and retrieves stored distance valuevoid initializeSD(){ // first section read current distance from SD card char buf[10]; // buffer to hold retrieved distance value // Initialize SD card and file system. if (PF.begin(&fs)) Serial.println( F("error begin file") ); // Open file for read - saved accumulated total distance if (PF.open(filename)) Serial.println( F("error open file") ); while (1) { UINT nr; if (PF.readFile(buf, sizeof(buf), &nr)) Serial.println( F("error read file") ); if (nr ==sizeof(buf)) break; } // no close function for Petit FS. // retrieves stored distance value to program totalDistance =atof(buf); // second section read odometer notification trigger value char bufTrigger[10]; // buffer to hold trigger value if (PF.open(settings)) Serial.println( F("error open file") ); while (1) { UINT nr; if (PF.readFile(bufTrigger, sizeof(bufTrigger), &nr)) Serial.println( F("error read file") ); if (nr ==sizeof(bufTrigger)) break; } // retrieves odometer notification value triggerDistance =atof(bufTrigger);}// corrects time object with time zone offsetvoid updateTime(){ // set time from GPS data string setTime(timeFix.hours, timeFix.minutes, timeFix.seconds, timeFix.date, timeFix.month, timeFix.year); // calc current time zone time by offset value adjustTime(UTC_OFFSET * SECS_PER_HOUR); sprintf(datePrint, "%02d/%02d/%04d ", day(), month(), year()); sprintf(timePrint, "%02d:%02d:%02d ", hour(), minute(), second());}

Peças personalizadas e gabinetes

Top of casing for more space (taller). The mounting holes are closed and must be drilled after print (to make for easier printing)A compact version of the top casing (less space inside enclosure)Bottom part of casing - for SIM900 and Arduino board with cutouts for connectorsLocks SIM900 board in placeLocks SIM900 board in place (no mounting holes on SIM900 board)rename to "dist.txt" and place on SD card dist_1qOG9VMO2D.txtrename to "settings.txt" and place on SD card settings_iMpR6v81OB.txt

Esquemas


Processo de manufatura

  1. Tabua de passar
  2. Prancha de surf
  3. O que há com a tecnologia de rastreamento de ativos Outdoor (GPS)?
  4. Raspberry Pi projeta seu próprio MCU junto com a placa de $ 4
  5. A integração dos dados do sensor com o microprocessador Raspberry Pi
  6. Usando o PSoC 6 Pioneer Board com o Pioneer IoT Add-on Shield
  7. Repurpose Safe Drugs with BIOVIA Living Map
  8. Função Python map() com EXEMPLOS
  9. Trabalhando com sistemas internos de integração
  10. O que acontece se eu dirigir meu carro com pouco líquido de arrefecimento?