산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

thinger.io 지도 통합 기능이 있는 자동차 GPS 추적기

구성품 및 소모품

Arduino Leonardo
Leonardo를 사용하여 전용 하드웨어 시리얼 얻기
× 1
SIM900 개발 보드
× 1
u-blox NEO-6M GPS 모듈
× 1
안테나, GPS
× 1
저항 220옴
× 2
LED(일반)
× 2
솔더 보드 7 x 5cm
상태 LED "회로"용 3D 인쇄 인클로저에 맞는 납땜 보드를 사용했습니다. 그러나 일반 브레드보드를 ​​사용하거나 상태 LED를 원하지 않는 경우 건너뛸 수 있습니다.
× 1
12V ~ 5V 스텝 다운 모듈
자동차 배터리(또는 담배 소켓)에 전원 공급 장치 연결용
× 1
Adafruit SD 카드 리더기
× 1
플래시 메모리 카드, MicroSD 카드
× 1

필요한 도구 및 기계

납땜 인두(일반)

앱 및 온라인 서비스

Thinger.io 플랫폼
대시보드가 ​​포함된 무료 IoT 서비스!

이 프로젝트 정보

이 프로젝트는 단순한 "GPS 추적기 아이디어"로 시작하여 "다목적 GPS 추적기"로 밝혀졌습니다. 첫 번째 프로젝트인 만큼 학습 곡선이 가파르기 때문에 디자인에 대한 의견, 피드백 및 개선 사항에 대해 항상 열려 있습니다! :)

트래커는 내 차에 장착해야 하며 다음과 같은 기능이 있습니다.

<울>
  • GPS 좌표를 추적하고 마지막으로 알려진 위치를 2분마다 thinger.io IoT 클라우드 대시보드에 게시합니다(지도에 표시됨). HTTP POST 요청으로 thinger.io에 게시.
  • <울>
  • SMS 명령에 응답하고 현재 또는 마지막으로 알려진 위치에 대한 Google 지도 링크를 반환합니다(현재 위치를 사용할 수 없는 경우 마지막으로 알려진 위치).
  • <울>
  • XX 킬로미터마다 SMS 알림을 보냅니다(4000km마다 오일 캐치 탱크를 비우도록 트래커가 나에게 상기시키도록 하는 것입니다). 이것은 맞춤형 소프트웨어 "주행 거리계"로 작동합니다.
  • 이 프로젝트를 하는 동안 나는 Arduino가 사용 가능한 메모리 측면에서 얼마나 "제한적"인지 빨리 깨달았고 오버헤드를 줄이고 효율적인 코드를 만드는 기술을 배워야 했습니다(최소한 시도했습니다). 또한 칩과 사용 가능한 RAM에 모든 것을 맞추기 위해 경량 라이브러리를 사용했습니다.

    사용된 구성 요소는 다음과 같습니다(구성 요소 목록에 있음).

    <울>
  • NEO-6M GPS 장치. 이것은 Ebay 및 이와 유사한 곳에서 저렴하게 구할 수 있는 매우 인기 있는 GPS 장치인 것 같습니다. GPS와의 통신은 하드웨어 직렬입니다.
  • <울>
  • GPS 안테나. 호환되는 모든 것이 가능하지만 Ebay의 가장 저렴한 제품은 잘 작동하지 않는다는 것을 알았습니다. 즉, 수신 불량/위성 수가 적습니다. 첫 번째 안테나가 운이 없었을 수도 있지만 안정적인 수신을 위해 더 나은 품질의 다른 안테나를 구입해야 했습니다.
  • <울>
  • GSM 및 GPRS 연결을 위한 SIM900 개발 보드. 이 프로젝트는 SIM800 및 호환 모듈에서도 작동해야 하지만 보장되지는 않습니다. SIM900과의 통신은 소프트웨어 직렬입니다.
  • <울>
  • Arduino 레오나르도 판자. 저는 Leonardo 보드를 사용하여 전용 하드웨어 직렬 회선을 보유하고 있습니다. 두 개의 직렬 라인이 필요하기 때문입니다. 일반 UNO 보드도 사용할 수 있지만 소프트웨어를 다운로드하려면 GPS를 분리해야 하며 디버깅을 위한 직렬 모니터도 없습니다. 두 개의 직렬 라인이 필요합니다(GPS용 하나와 SIM900 보드용 하나). 소프트웨어 시리얼 1개와 하드웨어 시리얼 1개.
  • <울>
  • SD 카드 리더기(5V와 호환되는 Adafruit 카드 리더기를 사용했습니다(5V SPI 헤더에 쉽게 연결할 수 있음). 다른 저렴한 모듈도 마찬가지로 작동할 수 있습니다. Micro SD 카드는 이동 거리를 저장하는 데 사용됩니다. 경고: 내 회로도를 따르면 많은 SD 카드 리더가 3.3V만 사용하는 경우 SD 카드 리더가 5V 전원을 지원하는지 확인하십시오. 잘못된 전압 레벨을 사용하면 전자 장치가 손상될 가능성이 큽니다. SD 카드 리더와의 통신은 SPI 인터페이스가 됩니다.
  • <울>
  • 상태 표시기 회로를 만들기 위한 LED 및 저항기(전원 및 GPS 잠금 LED)
  • <울>
  • 데이터가 있는 SIM 카드.
  • <울>
  • 또한 3D 프린터에서 직접 인쇄할 수 있는 STL 파일이 첨부된 3D 인쇄 가능한 인클로저를 설계했습니다.
  • 먼저 필요한 라이브러리를 설치해야 합니다. 이 프로젝트에 다음 라이브러리를 사용했습니다.

    <울>
  • NeoGPS GPS 추적 및 디코딩용. Arduino IDE의 라이브러리 관리자에서 직접 설치할 수 있습니다. 추가 정보:https://github.com/SlashDevin/NeoGPS
  • <울>
  • 시간 라이브러리(UTC 시간대 변환에 ​​사용):https://github.com/PaulStoffregen/Time
  • <울>
  • PetitFS SD 카드 읽기/쓰기:https://github.com/greiman/PetitFS Lightweight SD FAT 라이브러리
  • Arduino용으로 사용 가능한 라이브러리를 사용하지 않는 이유 thinger.io?

    thinger.io에서 제공하는 라이브러리는 사용하기가 매우 쉽고 작업을 크게 단순화하지만 이미 IDE에 통합되어 있지는 않지만 Arduino Leo에서 저장소의 거의 80%를 사용하여 나머지 코드를 위한 공간을 거의 또는 전혀 남기지 않습니다. 그래서 이 프로젝트에는 너무 크고 우리는 그것을 어려운 방법으로 해야 할 것입니다. thinger.io 클라우드와 통신하기 위해 HTTP POST 요청을 사용합니다.

    SMS 명령

    SMS에서 사용 가능한 명령은 다음과 같습니다(모두 대문자). 다음은 제공된 코드에서 지원되는 명령입니다. 자신의 프로젝트/요구사항에 대한 명령을 추가/제거할 수 있습니다.

    <울>
  • "POS" 좌표를 사용할 수 있는 경우 Google 지도 링크가 있는 좌표를 반환합니다. 그렇지 않으면 마지막으로 알려진 위치가 반환됩니다.
  • <울>
  • "GETKM" 마지막 "재설정" 이후의 현재 거리를 반환합니다.
  • <울>
  • "RESETKM" 거리 카운터를 0으로 설정합니다(주행 거리계 재설정).
  • NeoGPS 설정

    TinyGPS++와 같은 대안보다 성능 및 리소스 사용을 위해 NeoGPS 라이브러리를 사용합니다. RAM을 거의 소모하지 않으며 이것이 필요합니다. 그렇지 않으면 메모리 부족 및 안정성에 대한 경고가 표시됩니다.

    라이브러리를 설치한 후 GPSPort.h 파일을 수정합니다. 라이브러리 설치 경로에서(제공된 예는 OS X용입니다. Windows의 경우 다른 위치에서 라이브러리를 찾을 수 있습니다.)

    GPSPort.h의 모든 콘텐츠를 다음으로 교체합니다.

    #ifndef GPSport_h#define GPSport_h#define gpsPort Serial1#define GPS_PORT_NAME "Serial1#define DEBUG_PORT Serial#endif 

    이 파일에는 NeoGPS 라이브러리에서 사용하는 정의가 포함되어 있습니다. 다른 Arduino 보드를 사용하는 경우 여기에서 GPS 수신기에 대한 직렬 라인을 정의합니다. Arduino MEGA용 "Serial2", "Serial3".

    정확성에 대한 참고 사항

    GPS는 정지 상태에서도 위치가 약간 이동하므로 거리를 측정하고 누적하는 가장 정확한 방법이 아니라는 점에 유의해야 합니다. 같은 지점에 가만히 서서 이것을 테스트하고 GPS 좌표가 모든 판독값에 대해 다른지 관찰할 수 있습니다. 이 응용 프로그램의 경우 정확도가 덜 중요하므로 편차가 작아도 괜찮습니다.

    그러나 나는 좌표의 작은 드리프트를 설명하려고 시도했으며 소프트웨어는 15초 동안 10m(10m 미만의 모든 움직임은 정지된 것으로 가정) 이상의 움직임에 대해서만 거리를 추가합니다.

    또한 거리는 직선으로 계산되지만 자동차가 이동하는 실제 거리는 도로, 커브 등에 따라 다릅니다. 샘플링 속도를 15초로 설정했지만 더 높이려면 이 값을 낮출 수 있습니다. 정확도.

    PetitFS 설정

    이 라이브러리는 FAT 형식의 SD 카드에 읽기/쓰기를 위한 초경량 라이브러리입니다. 문서가 거의 존재하지 않고 일부 장소는 심지어 잘못되거나 구식이기 때문에 이것이 어떻게 작동하는지 알아내는 데 시간이 걸렸습니다. 제공된 라이브러리 예제 코드는 컴파일조차 되지 않습니다. 많은 과 함께 제공됩니다. 제한 사항(Arduino의 SD 라이브러리 또는 SDFat과 같은 "일반" 라이브러리와 반대):

    <울>
  • 파일을 생성할 수 없습니다. 기존 파일에만 쓸 수 있습니다.
  • <울>
  • 파일 크기를 확장할 수 없습니다.
  • <울>
  • 파일의 타임스탬프를 업데이트할 수 없습니다.
  • <울>
  • 파일에 데이터를 추가할 수 없습니다(매번 파일 재작성).
  • <울>
  • 한 번에 하나의 파일만 열 수 있습니다.
  • 특이점이 많은 작고 제한된 라이브러리를 사용하는 이유는 무엇입니까?

    크기는 기본적으로. Arduino SD 라이브러리, SDFat 및 fat16lib를 포함한 몇 가지 라이브러리를 시도했습니다. 모든 코드를 칩에 맞추기에는 너무 커서 기능을 제거하지 않기 위해 이 라이브러리를 사용했습니다(표준 Arduino SD 라이브러리는 약 12% 더 많은 공간을 차지함). 모든 단점과 한계가 있음에도 불구하고 이 애플리케이션에 필요한 것은 여전히 ​​제공합니다. 즉, 단일 값의 스토리지를 읽고 쓸 수 있습니다.

    모든 코드를 사용하지 않고 추가 코드를 넣을 수 있는 충분한 공간이 있다면 표준 SD 라이브러리와 같은 라이브러리로 작업하는 것이 훨씬 쉽습니다.

    pffArduino.h 파일을 엽니다. PetitFS 라이브러리 폴더에서. SD_CS_PIN 변경 10.까지 SPI가 있는 SD 카드와 통신하는 데 사용되는 SS 핀입니다.

    pffconf.h 파일을 엽니다. 라이브러리 폴더에서. 비활성화 설정 값을 1에서 0으로 전환하여 다음 옵션:

    <울>
  • _USE_DIR
  • <울>
  • _USE_LSEEK
  • <울>
  • _FS_FAT12
  • <울>
  • _FS_FAT16
  • 이 옵션을 비활성화하면 컴파일된 프로그램이 필요한 공간을 덜 차지합니다. 최종 스케치는 대략적으로 소요됩니다. 스토리지의 96%.

    라이브러리를 처음 가져올 때 무시할 수 있는* 컴파일 오류가 발생합니다(두 번째 컴파일 오류는 표시되지 않음 - 여전히 이유를 이해하지 못함). 그러나 이것을 수정하려면(Arduino IDE -> 컴파일을 시작할 때마다 다시 나타납니다) 위의 스크린샷과 같이 누락된 함수 반환 매개변수 "FRESULT"를 추가합니다. 이것은 pff.cpp 파일에 있습니다. 라이브러리 폴더에 있습니다.

    나는 이 라이브러리가 어떻게 작동하는지 알아내기 위해 최선을 다했고 모든 것이 작동했지만 개선될 수 있다고 확신합니다. 내가 작성한 루틴에서 실수나 개선 사항을 발견하면 자유롭게 공유하십시오! 더 많이 배우고 경험을 쌓고 싶습니다.

    SD 카드 준비

    이 프로젝트에 Micro SD 카드를 사용했습니다. 라이브러리는 파일 자체를 생성할 수 없으므로 사용하기 전에 카드에 "dist.txt" 및 "settings.txt" 파일을 생성하는 것이 중요합니다. 첨부된 "dist.txt" 및 "settings.txt"를 복사하는 것이 좋습니다. 이 프로젝트 페이지의 파일은 이미 올바른 형식과 작동을 하고 있기 때문입니다(라이브러리는 매우 텍스트 형식과 내용에 까다로움).

    파일을 Micro SD 카드에 넣기 전에 카드를 올바르게 포맷해야 합니다(FAT32 ). SD Association:https://www.sdcard.org/downloads/formatter/의 공식 "SD 카드 포맷터"를 사용하는 것이 좋습니다.

    SD 카드가 작동하는지 확인(올바른 파일 읽기/쓰기)

    PetitFS 라이브러리는 매우 입력 파일에 대해 까다롭습니다. 장치를 부팅하고 직렬 모니터에 출력이 표시되지 않으면(비어 있음) 카드에서 파일을 읽으려고 시도하지만 어떤 이유로(initializeSD() 기능) 읽을 수 없는 "루프"에 멈췄을 가능성이 큽니다. 어떤 이유에서인지 읽을 수 없는 텍스트 파일이 셀 수 없이 많았으므로 작동하는 데 사용한 참조 텍스트 파일을 포함했습니다. 참조 배치 SD 카드에 파일이 있고 올바르게 읽고 쓸 수 있어야 합니다.

    또 다른 옵션은 텍스트 파일을 더 큰 숫자로 채우는 것입니다. 그 글보다. 나는 이것을 테스트하지 않았지만 라이브러리는 파일 크기 자체를 확장 할 수 없기 때문에 이것이 문제가 될 수 있다고 가정합니다.

    PetitFS는 문자 배열의 전체 길이를 파일에 기록하므로 실제 숫자 앞에 빈 공간이 표시됩니다(숫자가 배열을 채울 만큼 충분히 크지 않은 경우 - "배열" 길이는 코드에 정의되어 있음). 이 공백은 파일을 변경할 때 유지되어야 합니다 - PetitFS는 파일 크기를 변경할 수 없으므로 문자 수가 변경되면 문제가 발생할 수 있습니다.

    주행 거리계를 "0"에서 시작하려면 "dist.txt" 파일을 "0"으로 설정하고, 작동 여부를 쉽게 확인할 수 있도록 다른 숫자를 설정합니다. SMS 응답을 확인하기 위해 "GETKM" 명령을 보냅니다.

    "settings.txt"에서 알림 트리거 거리, 주행 거리계가 알림 SMS를 트리거하는 거리(미터 단위)를 설정합니다.

    SIM900 보드 준비

    SIM900 보드를 사용하기 전에 몇 가지 설정을 해야 합니다. 자세한 내용은 이 보드 설정에 대한 훌륭한 리소스가 https://lastminuteengineers.com/sim900-gsm-shield-arduino-tutorial/에 있습니다.

    전원

    Arduino 보드는 충분한 전원을 공급할 수 없으므로 외부 전원 공급 장치를 사용해야 합니다. 스파이크는 최대 2A를 소모할 수 있으므로 5V-9V DC에서 최소 2A를 전달할 수 있는 전원 공급 장치를 사용해야 합니다. 배럴 5.5mm 커넥터를 사용합니다.

    전원 선택기

    DC 잭 옆에는 전원 선택기가 있습니다. . 외부 전원을 사용하려면 위 그림과 같이 슬라이더를 이동하세요.

    직렬 선택기

    소프트웨어 직렬 을 사용하도록 보드 설정 위와 같이 점퍼를 정렬하여.

    소프트웨어 트리거

    매번 전원 키를 수동으로 누르는 대신 소프트웨어에서 SIM900을 켜고 끌 수 있습니다. 이렇게 하려면 R13이라는 이름의 점퍼를 납땜해야 합니다. 그런 다음 SIM900 핀 #9를 Arduino 핀 #7에 연결하여 보드의 전원을 켭니다(회로도 참조).

    "수동 전원 켜기" 기능을 유지하는 경우 코드에서 "SIM900power()" 기능을 제거할 수 있습니다.

    SIM 카드 PIN 잠금 해제

    PIN 잠금을 제거해야 합니다. 사용하기 전에 SIM 카드에 일반 휴대폰에 삽입하고 해당 설정 메뉴에서 핀 잠금을 제거하면 됩니다.

    또한 회로도의 SIM900 모듈은 실제 보드와 다르게 보일 수 있지만 가장 중요한 부분인 핀 레이아웃이 정확합니다.

    SIM900 펌웨어 버전 (중요!)

    칩에 올바른 버전의 펌웨어를 로드하는 것이 매우 중요합니다. HTTP POST 헤더를 올바르게 설정하는 명령 중 하나가 펌웨어 버전 B10까지 지원되지 않기 때문입니다. 즉, http 통신이 작동하려면 버전 B10 이상이 필요합니다. 특히, 낮은 펌웨어 버전에서는 http 헤더에 "Content-type"을 설정할 수 없습니다. post 요청에서 content-type이 "application/json"으로 설정되어 있지 않으면 서버에서 거부됩니다.

    펌웨어 버전을 확인하려면 다음 AT 명령을 사용하십시오.

    AT+CGMR 

    그러면 SIM900 칩이 출력 콘솔에 현재 펌웨어 버전을 제공합니다. setup() 섹션 끝에 다음을 입력하여 시작 시 펌웨어 버전을 인쇄합니다.

    SIM900.println( F("AT+CGMR") );  

    제 경우에는 다음과 같이 표시됩니다(업데이트 전).

    개정:1137B01SIM900M64_ST_AM 

    이것은 이 칩("B01")에 대해 가능한 가장 오래된 펌웨어 버전이므로 버전 B10:1137B10SIM900M64_ST로 업데이트했습니다. . 최신 펌웨어도 작동해야 합니다.

    이 가이드에서 펌웨어를 업데이트하는 방법은 다루지 않겠습니다. 이 작업을 수행하는 방법에 대한 훌륭한 가이드가 이미 있습니다. SIM900 펌웨어 업데이트 - ACOPTEX(다소 고통스러운 과정이지만)

    이것이 SIM800과 같은 다른 칩의 경우인지는 모르겠습니다. 그러나 이것은 최신 칩이므로 이미 거기에 있을 가능성이 더 큽니다.

    코드 조정

    자신의 프로젝트에 코드를 적용하려면 몇 가지 조정이 필요합니다.

    <울>
  • APN(네트워크 공급자) 정보를 변경합니다.
  • <울>
  • thinger.io URL을 수정하여 자신의 URL과 일치시킵니다(URL은 업데이트 요청을 액세스 토큰이 있는 자신의 "버킷"에 연결합니다). 이것은 "thinger.io 통합" 장에서 다룹니다.
  • <울>
  • 정확한 시간대를 설정합니다.
  • <울>
  • SMS 알림을 위한 트리거 거리 설정
  • <울>
  • SMS 알림 텍스트를 설정(또는 비활성화)합니다.
  • <울>
  • 알림을 위한 기본 전화번호를 설정합니다.
  • APN 제공업체

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

    connectGPRS() 아래 기능을 사용하면 위에 "TeleXXX"로 표시된 네트워크 공급자가 제공한 APN 이름을 찾을 수 있습니다. 이것을 자신의 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"확인

    위:연결이 작동 중일 때 connectGPRS() 함수의 출력. 모든 명령은 "OK" 상태를 반환해야 합니다.

    시간대

    #define UTC_OFFSET 1 // 시간대 오프셋 설정, 즉 1 =UTC+1 

    "정의" 섹션에서 요구 사항에 따라 표준 시간대를 설정합니다. 코드가 UTC+1로 설정됩니다. .

    SMS 알림

    4000km마다 오일 캐치 탱크를 비우도록 알림을 설정했습니다. 대부분의 사람들이 오일 캐치 탱크를 가지고 있지 않다는 것을 알고 있기 때문에 이 알림은 원하는 대로 변경되어야 합니다(또는 완전히 비활성화되어야 함).

    void loop() {... // 총 거리가 4000km를 초과하면 SMS로 알림을 보냅니다. if (totalDistance> triggerDistance) { char sms_msg[160]; 문자 거리TotalMsg[10]; itoa((총 거리 / 1000) , 총 거리 메시지, 10); sprintf(sms_msg, "빈 집수조! 현재 거리:%skm", distanceTotalMsg); 텍스트 메시지 =""; 총 거리 =0; // 알림 번호를 트리거하도록 기본 전화 번호를 설정합니다. =DEFAULT_NUMBER; sendSMS(sms_msg); } ...} 

    위:알림을 트리거하는 코드 섹션(메인 루프() 내부).

    트리거된 알림을 원하지 않으면 이 섹션을 주석 처리/제거하십시오. 또는 텍스트를 유용한 것으로 변경하십시오.

    "주행 거리계"(누적 거리)가 "settings.txt" 파일에 설정된 구성된 거리에 도달하면 알림이 트리거됩니다.

    기본 전화번호

    이것은 트리거된 알림이 전송되는 전화번호입니다(알림에는 회신할 "발신인" 번호가 없기 때문에)

    // 트리거된 알림의 전화번호#define DEFAULT_NUMBER "+4712345678"  

    직렬 연결 대기

    코드에서 다음 줄의 주석 처리를 제거하는 것도 좋은 생각입니다. 이것은 Arduino 보드가 직렬 연결, 즉 디버깅을 위한 직렬 모니터가 활성화될 때까지 기다리게 합니다. 이렇게 하면 직렬 라인이 활성화되기 전에 코드 시작 부분에 있는 디버깅 메시지를 놓치지 않습니다.

    외부 전원에서 Arduino에 전원을 공급하기 전에 라인을 제거/주석하는 것을 잊지 마십시오. 그렇지 않으면 PC에 연결될 때까지 무한 루프에서 중지됩니다.

     // while (!Serial); // 직렬 포트가 연결될 때까지 대기 - ATmega32u4(Leonardo)용 

    Thinger.io 통합

    thinger.io를 매우 간단하게 설정하는 방법에 대해서는 자세히 설명하지 않겠습니다. 웹사이트를 통해 데이터를 수신하려면 계정과 "버킷"을 생성해야 하며, 우리가 연결할 "장치"를 생성해야 합니다. "버킷"은 데이터를 수신하기 위한 데이터베이스입니다. "장치"는 데이터로 무엇을 할지 결정하는 코드의 연결 지점입니다(이 경우 "버킷" 데이터베이스를 채움).

    위와 같이 자신의 이름과 설명으로 "버킷"을 만듭니다.

    이제 공식 문서(https://docs.thinger.io/quick-sart/devices/http-devices)에 설명된 대로 "HTTP 장치"를 만듭니다.

    짧은 사용 기기 이름 . 장치 이름은 인증 키를 생성하는 알고리즘의 일부이므로 더 긴 장치 이름도 더 긴 인증 키를 생성한다는 것을 알았습니다. 문제? 인증 키가 Arduino에서 문자열을 보내는 데 사용되는 256자 버퍼보다 ​​빠르게 길어졌습니다. 이 문제를 해결하는 더 좋은 방법이 있을 수 있지만 기기 이름을 짧게 유지하고 문제를 방지하는 가장 쉬운 방법을 찾았습니다.

    기기의 콜백에서 > 설정 섹션에서 "버킷 쓰기" 설정이 이전에 생성된 버킷을 가리키는지 확인하십시오. 이것은 "장치"가 수신 데이터를 우리 데이터베이스에 쓰도록 지시합니다.

    기기의 콜백에서 > 개요 섹션에서 메서드를 기록해 둡니다. URL승인 헤더 (키워드 "Bearer"가 없는 긴 문자열).

    thinger.io에 데이터를 보내기 위해 HTTP POST 요청에서 "인증 URL"을 사용합니다. 그런 다음 코드의 URL과 인증 키를 자신의 것으로 바꿔야 합니다.

    postDataThinger() 호출을 찾을 수 있는 기능(실제 인증 키 스크램블):

    SIM900.println( F("AT+HTTPPARA=\"URL\",\"http://backend.thinger.io/v3/users/tom/devices/CT/callback/data?authorization =eyJhbGciOiJIUzI1NiIsInR5cdfkjowiuerdf.sdfsdf.wekrjciI6InRvcm1vZCJ9.AR1gWvIZB9KmtI-5Z12YXKuchPTGn58AkwBJSZQIoxQ\">) ) 

    그런 다음 URL을 교체해야 합니다. 및 승인 위에 제공된 링크의 지침에 따라 생성된 코드에서.

    http://backend.thinger.io/... 

    기본적으로 생성된 승인 URL은 https입니다. . SIM900은 그렇지 않습니다. 지원 SSL (적어도 작동하지 않음) "http //" ~ "http://". thinger API는 비 SSL 연결도 지원합니다. 이것은 매우 중요합니다. "https"를 유지하면 작동하지 않습니다. 모든 것이 작동하면 직렬 모니터는 "200 - http 게시 요청 전송 시 "OK" 응답

    AT 명령 "AT+HTTPACTION=1" 뒤에 (HTTP POST 요청 보내기) 직렬 모니터에서 다음과 같은 응답을 받아야 합니다.

    +HTTPACTION:1,200,0 

    "400 - 잘못된 요청"이라는 답장을 받은 경우 등..

    +HTTPACTION:0,400,51  

    ..URL에 문제가 있을 가능성이 높습니다. 예:"http" 대신 "https", "인증 키"의 잘못된 구문 등. "200 - OK" 메시지를 수신하면 데이터가 아래와 같이 싱거 버킷에 표시되어야 합니다. 앞서 언급한 올바른 펌웨어가 없으면 400 - "잘못된 요청"을 받을 수도 있습니다.

    위는 데이터가 도착한 후 버킷의 보기입니다(개인 정보 보호를 위해 스크램블됨). 콘텐츠(데이터 열)는 코드의 HTTP POST 요청 구문에 의해 설정되며, thinger.io에서 설정할 필요가 없습니다.

    다음은 모든 것이 작동할 때 표시되어야 하는 HTTP POST 요청의 직렬 출력입니다. +HTTPACTION:1, 200, 0은 업데이트가 성공했음을 나타냅니다.

    AT+HTTPINITOKAT+HTTPPARA="CID",1OKAT+HTTPPARA="URL","OKAT+HTTPPARA="CONTENT","application/json"OKAT+HTTPDATA=84,10000DOWNLOADOKAT+HTTPACTION=1OK+ HTTPACTION:1,200,0AT+HTTPTERMOK  

    대시보드 그러면 버킷을 데이터 소스로 사용하여 지도 위젯으로 쉽게 설정할 수 있습니다.

    더 많은 데이터를 처리하시겠습니까?

    경도, 위도, 날짜/시간보다 더 많은 데이터를 푸시하시겠습니까? 아래와 같이 http 요청에 더 많은 데이터 필드를 추가하기만 하면 됩니다.

    형식은 { "field1 name":field1, "field2 name":field2, "field3 name":field3 }

    입니다.
    sprintf(httpContent, "{ \"경도\" :%s , \"위도\" :%s , \"날짜\" :\"%s %s\" }", tempstrLong, tempstrLat , 날짜1, 시간1); 

    위의 sprintf 명령은 thinger로 보낸 데이터 문자열을 컴파일합니다. 구문은 *매우* 엄격하며 정확히 동일한 방식으로 새 데이터 필드를 추가해야 합니다. 예제는 코드(주석 섹션)에 나와 있습니다. 문자열을 표시할 명령의 직렬 모니터 인쇄를 기록해 두는 것이 좋습니다. 그런 다음 "field4" 등을 추가합니다.

    인클로저

    나는 완전한 3D 인쇄 가능한 인클로저를 부착했습니다. 이 프로젝트에 사용된 정확한 PCB에 맞게 설계되었습니다. M3 나사를 사용하여 장착합니다.

    브레드보드가 아닌 LED "회로"용 7x5cm 솔더 보드용으로 설계되었습니다. 브레드 보드를 사용하는 경우 대신 접착제를 사용하십시오. GPS 및 솔더 보드("브레드보드")는 상단 케이스에 장착됩니다. 상단 케이싱에 PCB를 가장 잘 장착하려면 작은 스페이서를 사용하십시오.

    또한 지지대 없이 더 쉽게 인쇄할 수 있도록 상단 케이싱의 장착 지점을 견고하게 유지했습니다(구멍 없음). 3mm 드릴 비트로 여십시오.

    지지대 없이 0.2mm에서도 잘 인쇄됩니다.

    자동차 배터리/전원 연결

    There are probably hundreds of ways of doing this, so I don't have the only answer, or best answer for that matter; how to wire it up to the car battery. It all depends on your application, but I'll quickly describe my solution.

    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

    <섹션 클래스="섹션 컨테이너 섹션 축소 가능" id="코드">

    코드

    <울>
  • 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, OUTPUT); 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); 지연(1000); digitalWrite(PWRPin, HIGH); 지연(2000); digitalWrite(PWRPin, LOW); delay(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\"") ); 지연(1000); updateSIM900(); SIM900.println( F("AT+SAPBR=3,1,\"APN\",\"TeleXXX\"") ); 지연(1000); updateSIM900(); SIM900.println( F("AT+SAPBR=1,1") ); 지연(1000); updateSIM900(); SIM900.println( F("AT+SAPBR=2,1") ); 지연(1000); updateSIM900();}void postDataThinger(char *httpDataLen, char* content){ SIM900.println( F("AT+HTTPINIT") ); 지연(1000); updateSIM900(); SIM900.println( F("AT+HTTPPARA=\"CID\",1") ); 지연(1000); updateSIM900(); SIM900.println( F("AT+HTTPPARA=\"URL\",\"http://backend.thinger.io/v3/users/tom/devices/CT/callback/data?authorization=eyJhbGciOiJIUzI1NiIsInR5cCI6lskjdflksjdfweruiowe19DVCIsInVzciI6InRvcm1vZCJ9.AR1gWvIZB9KmtI-5Z12YXKuchPTGn58AkwBJSZQIoxQ\"") ); 지연(1000); updateSIM900(); SIM900.println( F("AT+HTTPPARA=\"CONTENT\",\"application/json\"") ); 지연(1000); updateSIM900(); SIM900.println(httpDataLen); 지연(1000); updateSIM900(); SIM900.println(content); 지연(1000); updateSIM900(); SIM900.println( F("AT+HTTPACTION=1") ); 지연(10000); updateSIM900(); SIM900.println( F("AT+HTTPTERM") ); 지연(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());}

    맞춤형 부품 및 인클로저

    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

    회로도


    제조공정

    1. 다리미판
    2. 서프보드
    3. 야외(GPS) 자산 추적 기술은 어떻습니까?
    4. Raspberry Pi는 $4 보드와 함께 자체 MCU를 설계합니다.
    5. 센서 데이터와 Raspberry Pi 마이크로프로세서의 통합
    6. Pioneer IoT 애드온 실드와 함께 PSoC 6 파이오니어 보드 사용
    7. BIOVIA Living Map으로 안전한 의약품 재활용
    8. 예제가 있는 Python map() 함수
    9. 사내 통합 시스템 작업
    10. 냉각수가 부족한 상태에서 차를 운전하면 어떻게 됩니까?