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

IoT4Car

구성품 및 소모품

Arduino MKR1000
× 1
SparkFun 로직 레벨 변환기 - 양방향
× 1
SparkFun OBD-II UART
× 1
SparkFun OBD-II-DB9 케이블
× 1

앱 및 온라인 서비스

Arduino IDE
자유 게시판
트윗

이 프로젝트 정보

배경

차량을 운전할 때 대시보드를 보고 미터 판독값을 수집하고 일부 분석을 수행할 생각을 해본 적이 있습니까? 이러한 데이터에는 숨겨진 보물이 포함될 수 있습니다. 개인의 경우 운전 습관을 반영하고 속도, 평균 mpg, 신호등 수, 각 교차로에서의 대기 시간을 알려줍니다. 기업의 경우 이러한 데이터는 차량 관리의 실시간 모니터링에 매우 중요합니다. 차량 상태, 작업 부하 분포, 휘발유 효율, 심지어 차량 위치까지 모두 클라우드를 통해 중앙 제어 시스템에 피드백할 수 있습니다. 회사는 기계 학습을 사용하여 데이터를 교육 모델에 입력하여 비용을 예측하고 운전자의 특성을 분석할 수도 있습니다. IoT가 널리 보급됨에 따라 위의 응용 프로그램은 멀리 있지 않을 것입니다. IoT 애플리케이션을 대상으로 하는 Arduino MKR 보드를 사용하면 자동차와 통신하고 원격 측정 데이터를 클라우드에 업로드하는 장치를 직접 구축할 수 있습니다. 멋지지 않나요?

차량과 대화

차량 시스템에 액세스하려면 인터페이스가 필요합니다. 어디에서 차를 해킹할 수 있습니까? 정답은 OBD-II 인터페이스입니다.

OBD-II란 무엇입니까?

OBD(On-Board Diagnostics)는 차량에 내장된 자가 진단 시스템으로 이를 통해 차량과 통신할 수 있습니다. 1994년에 미국에서 처음 도입되었으며 1996년 및 최신 미국 차량에 대한 요구 사항이 되었습니다. 캐나다, 유럽 연합의 일부, 일본, 호주, 브라질을 포함한 다른 국가들도 유사한 법안을 채택했습니다. OBD-II(2세대)에는 5가지 신호 프로토콜이 있으며 CAN 버스(Controller Area Network)가 그 중 하나입니다. CAN 버스는 2008년부터 모든 미국 자동차에 구현되어야 합니다. 유투브에 CSS Electronics에서 제공하는 OBDII에 대한 훌륭한 소개가 있습니다. 이 프로젝트에서는 16핀 OBD-II 인터페이스를 통해 데이터에 액세스합니다.

내 컨트롤러

Arduino는 애호가, 제작자 및 전문가를 위한 훌륭한 플랫폼입니다. 다양한 애플리케이션을 대상으로 하는 다양한 보드가 있습니다. 여기에서는 WiFi 기능으로 인해 Arduino MKR WiFi 1000 보드를 사용합니다. 당신은 또한 당신이 좋아하는 다른 보드를 사용할 수 있습니다. GSM이 WiFi보다 훨씬 더 넓은 영역을 커버하기 때문에 Arduino MKR GSM 1400을 추천합니다. 하지만 걱정하지 마세요. WiFi가 있어도 도로를 따라 인터넷에 접속할 수 있습니다. 해결 방법을 알려 드리겠습니다.

통역 게시판

Arduino 자체에는 많은 I/O와 수많은 라이브러리가 있지만 여전히 OBD 프로토콜을 Arduino가 인식할 수 있는 언어로 변환할 수 있는 보드가 필요합니다. 제가 사용하는 보드는 SparkFun OBD-II UART 보드입니다.

이 보드를 사용하면 자동차의 OBD-II 버스와 인터페이스할 수 있습니다. ELM327 명령 세트를 사용하여 직렬 인터페이스를 제공하고 CAN과 같은 모든 주요 OBD-II 표준을 지원합니다. 보드에는 현재 사용 중인 OBD-II 프로토콜과 UART 간에 메시지를 변환하는 데 사용할 수 있는 OBD-UART 인터프리터인 STN1110 칩이 포함되어 있습니다.

그러나 인터프리트 보드의 I/O 전압은 5V이므로 직접 연결하면 Arduino MKR 보드 I/O가 손상될 수 있습니다. Arduino MKR WiFI 1000은 더 낮은 전압에서 실행되고 I/O 전압은 3.3V입니다. 따라서 신호를 5V에서 3.3V로 또는 그 반대로 변환하려면 레벨 시프터가 필요합니다. 아래는 제가 사용하는 레벨 시프트 이미지입니다.

연결

회로를 연결하는 것은 매우 쉽습니다. 레벨 시프터를 통해 Arduino MRK 핀 13 Rx 및 핀 14 Tx를 OBD-II UART 보드 Tx 및 Rx 핀에 연결하기만 하면 됩니다. 물론 두 보드의 접지를 함께 연결해야 합니다.

디버깅 및 데모를 쉽게 하기 위해 LCD 1602 화면도 Arduino에 연결하여 데이터를 실시간으로 표시했습니다. LCD에서 Arduino로의 배선은 이 자습서에서 찾을 수 있으므로 여기에서 자세히 설명하지 않습니다.

아래는 브레드보드 연결 이미지입니다. 초록색 선은 아두이노와 OBD-II UART 보드를 연결하는 선이고 노란색 선은 아두이노와 LCD를 연결하는 선입니다. 도식은 첨부 파일에서도 볼 수 있습니다.

실제 연결은 제한된 브레드 보드 영역으로 인해 약간 지저분하지만 위의 회로도를 따릅니다. 사진에 마이크로 USB와 ODB-II to DB9 케이블이 포함되어 있습니다.

직렬1이 직렬이 아님

자, 이제 Arduino MKR 보드를 프로그래밍할 시간입니다. 내 Arduino MKR 보드는 UART를 통해 인터프리트 보드와 통신하므로 타사 라이브러리를 설치할 필요가 없습니다. 해석 보드에 명령을 보내는 것은 단순히 직렬 모니터와 통신하는 것과 같습니다. 내가 강조하고 싶은 유일한 것은 핀 13 및 핀 14와 연결된 직렬 포트가 직렬 1이라는 것입니다. ! Arduino MKR 보드 직렬 포트 컴퓨터와 통신하는 데 사용되는 USB 포트를 나타냅니다. 직렬 1 초기화를 잊지 마세요. setup() 함수의 포트입니다.

 Serial1.begin(9600); 

직렬 1을 사용합니다. 통역 게시판에 명령을 푸시합니다.

 Serial1.println(메시지); 

메시지

보시다시피 "message" 변수를 사용하여 명령을 저장합니다. OBD 명령은 ASCII 문자로 작성된 16진수 코드로 구성됩니다. 처음 두 개의 16진수 숫자는 사용할 서비스 모드를 나타냅니다. 최신 OBD-II 표준 SAE J1979에 설명된 10가지 진단 서비스가 있습니다. 실시간 모니터링에 관심이 있으므로 01만 사용합니다. 이 프로젝트의 현재 데이터를 표시하는 코드입니다.

서비스 모드 뒤의 모든 16진수는 특수 기능을 달성하기 위한 매개변수 ID(PID)를 나타냅니다. 아래는 01 서비스 모드에서 PID의 스크린샷입니다. 자세한 내용은 Wikipedia에서 찾을 수 있습니다.

이 프로젝트에서는 자동차 속도, 엔진 RPM, 연료 수준 및 엔진 냉각수 온도를 구하는 방법을 보여줍니다. 이 네 가지 기능에 대한 OBD 명령은 다음과 같습니다.

<울>
  • 010D // 자동차 속도
  • <울>
  • 010C // 엔진 RPM
  • <울>
  • 012F // 연료량
  • <울>
  • 0105 // 냉각수 온도.
  • 데이터 디코딩

    명령이 전송되면 Arduino MKR 보드는 직렬 1 포트에서 응답을 수신합니다. 명령을 보낸 후 200ms의 지연을 두는 것이 좋습니다. 다음 코드를 사용하여 응답을 받습니다.

    void getResponse(void){ while(Serial1.available()> 0) { // 메시지 끝 문자('\r')를 받았는지 확인하는 것으로 시작합니다. if(Serial1.peek() =='\r'){ // 메시지 끝에 도달하면 직렬 버퍼를 지웁니다. inChar =Serial1.read(); rxData[rxIndex] ='\0'; // 다음 문자가 문자열의 시작 부분으로 돌아가도록 버퍼 인덱스를 재설정합니다. rxIndex =0; } // 메시지 문자의 끝을 얻지 못한 경우 문자열에 새 문자를 추가합니다. else{ // 직렬 포트에서 새 문자를 가져옵니다. inChar =Serial1.read(); // 문자열에 새 문자를 추가하고 인덱스 변수를 늘립니다. rxData[rxIndex++] =inChar; } }} 

    통역 게시판의 응답은 다음 형식을 따릅니다.

    ">1 반복 PID 데이터"

    예를 들어 위의 스크린샷에서는 "010D"를 전송하여 자동차 속도를 가져옵니다. 응답은 ">1 0D 00"입니다. 처음 5개의 문자는 자동차가 명령을 수신하고 PID 0x0D를 다시 반복한다는 것을 보여줍니다. 마지막 두 자리는 속도 데이터 0x00을 반환합니다.

    그런 다음 엔진 RPM을 얻기 위해 "010C"를 보내고, 응답 ">1 0C"는 명령 승인을 보여주고, 데이터 0x098C는 16진수로 엔진 RPM 값의 4배입니다. 0x098C / 4 =611 dec이므로 엔진 RPM은 611 rpm입니다.

    그 후 연료 레벨을 얻기 위해 명령 "012F"를 보내고 데이터 0x1D를 얻습니다. 연료 레벨은 0x1D / 255 * 100 =11% dec로 계산됩니다.

    최종 명령은 "0105"이며 냉각수 온도는 0x79입니다. 실제 온도는 0x79 - 40 =81℃ dec입니다. 그런 다음 명령 시퀀스가 ​​반복됩니다.

    보시다시피 응답 줄에는 두 개의 16진수 숫자 사이에 공백이 있으며 처음 5자리는 단순히 명령을 반복하는 것입니다. 따라서 실제 데이터는 6번째 문자부터 시작합니다(첫 번째 문자는 0 인덱스부터 시작).

    프로그래밍 및 디버깅에서는 직렬 모니터가 유용하지만 실제 응용 프로그램에서는 LCD 화면이 더 휴대하기 쉽고 IoT 전원 요구 사항을 충족합니다. 직렬 모니터를 LCD 화면으로 교체하기만 하면 차량 데이터를 실시간으로 모니터링할 수 있습니다. 아래는 내 차에서 프로젝트를 사용하는 사진입니다.

    데이터 클라우드

    UNO에 비해 Arduino MKR의 장점은 인터넷 접근성입니다. IoT 애플리케이션을 대상으로 하는 Arduino MKR은 산업을 보다 지능적이고 연결적으로 만들 것입니다. 자동차 애플리케이션에서는 MKR WiFi 1000이 실외 환경에서 WiFi 신호가 거의 없기 때문에 최고의 보드가 아닐 수 있지만, 저는 휴대폰을 개인용 핫스팟으로 사용하기 때문에 문제가 되지 않습니다.

    데이터를 저장, 확인 및 사후 처리할 수 있는 다른 클라우드 플랫폼이 많이 있습니다. 당신은 당신이 좋아하는 무엇이든 선택할 수 있습니다. dweet.io와 freeboard.io를 예로 사용하겠습니다. Dweet.io는 데이터를 보낼 수 있는 API를 제공합니다. Freeboard.io에는 dweet.io 데이터를 가져와 시각화하는 핸들이 있습니다. dweet.io와 freebboard.io를 설정하는 몇 가지 튜토리얼이 있으므로 다시 설명하지 않겠습니다. 관심이 있는 경우 예 1, 예 2와 같은 몇 가지 예가 있습니다.

    데이터 푸시 코드는 dweet 명령을 만드는 방법을 예시로 보여줍니다.

    무효 httpRequest() { client.stop(); // 프리보드에 보낼 데이터 문자열 생성 if (client.connect(server, 80)){ Serial.println("Connected"); 문자열 데이터 ="POST /dweet/for/mkr1000?RPM="; data.concat(vRPM); // 엔진 RPM 업로드 data.concat("&Speed="); data.concat(vSpeed); // 자동차 속도 업로드 data.concat("&Fuel="); data.concat(vFuel); // 연료량 업로드 data.concat("&Temp="); data.concat(vTemp); // 냉각수 온도 업로드 client.println(data); client.println("호스트:https://www.dweet.io"); client.println("연결:닫기"); // 연결 종료 client.println(); } else { lcd.clear(); lcd.setCursor(0,0); lcd.println("연결 실패"); }} 

    freeboard.io에서 새 대시보드를 만들고 이 대시보드 내부에 새 데이터 소스를 만들어야 합니다. 이 데이터 소스를 코드에서 정의한 dweet.io 항목에 연결합니다. 제 경우에는 mkr1000입니다. 데이터를 표시하는 데 사용할 새 게이지 위젯을 만듭니다. 이름을 지정하고 변수 중 하나에 연결합니다. 아래는 내 대시보드의 스크린샷입니다. SPEED, RPM, FUEL LEVEL 및 COOLANT TEMPERATURE를 보여줍니다.

    결론

    나는 내 차에서 보드를 시험해 보았고 잘 작동합니다. 저는 집적 회로의 모든 기능을 포함하는 PCB를 설계하는 일을 하고 있습니다. 바라건대, 나는 앞으로 더 많은 튜토리얼을 작성할 것입니다. 비디오 데모도 포함할 수 있습니다. 이번에는 차를 몰고 동영상을 찍지 못해서 죄송합니다. 또한 거리에서 운전하는 동안 코드를 디버깅할 때도 주의해야 합니다!

    Arduino MKR WiFi 보드는 이 애플리케이션에 충분합니다. 더 많은 보드가 있다면 MKR GSM 1400 보드를 사용해 볼 수 있을 것 같습니다. 이 튜토리얼에서 다른 IoT 보드를 자유롭게 사용하고 피드백을 알려주십시오.

    프로젝트 작업은 재미있고 교육적입니다. 나는 문제를 디버깅하는 느낌을 즐긴다. 제가 알고 있는 것을 웹상에서 공유하는 것 또한 저의 기쁨입니다. 읽어 주셔서 감사합니다. 질문이나 의견이 있으면 알려주세요.

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

    코드

    <울>
  • IoT4Car_code
  • IoT4Car_codeC/C++
    이 프로그램은 OBDII-UART 보드를 사용하여 차량과 대화하고 LCD에 결과를 표시하고 freeboard IoT 플랫폼에 업로드합니다.
    /** OBDII-UART-Serial 버전 9* 이 프로그램은 OBDII를 사용하여 차량과 대화합니다. -UART 보드, * 및 결과를 LCD에 표시하고, freeboard IoT 플랫폼에 업로드* * 작성자:zhaoshentech* 업데이트:2018-08-27* * 업데이트:* v3:버퍼가 수신하도록 getResponse() 함수 수정 정확한 응답.* getRPM()을 추가하여 차량에서 엔진 RPM을 가져옵니다.* v4:차량의 속도를 가져오기 위해 getSpeed() 함수를 추가* v5:LCD 모듈을 추가하고 속도와 RPM을 표시합니다. LCD* v6:Wi-Fi 버전* v7:Wi-Fi가 아닌, 직렬이 아닌 버전입니다. 보드가 컴퓨터 없이 작동할 수 있도록 직렬 초기화*를 제거하십시오.* v8:은 비-wifi, 비-직렬 버전입니다. 연료량과 냉각수 온도를 추가합니다.* 디스플레이 위치를 재정렬합니다.* v9:Wi-Fi, 비직렬 버전입니다. Upolad 속도, RPM, 연료 수준 및 냉각수 온도* * LCD 회로 연결:* LCD RS 핀에서 디지털 핀 12* LCD 활성화 핀에서 디지털 핀 11* LCD D4 핀에서 디지털 핀 5* LCD D5 핀에서 디지털 핀 4* LCD D6 핀 대 디지털 핀 3 * LCD D7 핀 대 디지털 핀 2* LCD R/W 핀 대 접지* 10K 전위계:* +5V로 끝남 및 접지* 와이퍼 대 LCD VO 핀(핀 3)*///// ////////////////////////////////////////////////////// ////// 와이파이 관련 //////////////////////////////////////////// ///////////////#include#includechar ssid[] ="당신의 와이파이 SSID"; // 와이파이 IDchar pass[] ="당신의 와이파이 PSWD"; // 와이파이 passwordchar 서버[] ="www.dweet.io"; // 프리보드 및 dweet Settingsunsigned long lastConnectionTime =0; // 마지막 연결 시간 추적 const unsigned long postingInterval =10L * 1000L; // 10초마다 데이터 게시WiFiClient 클라이언트; //와이파이 초기화 clientint status =WL_IDLE_STATUS; // WiFi 라디오 상태 // LDC 라이브러리 포함#include const int rs =12, en =11, d4 =5, d5 =4, d6 =3, d7 =2;LiquidCrystal lcd(rs, en, d4, d5, d6, d7);// 직렬 포트의 데이터를 저장할 문자 버퍼입니다.char rxData[20];char rxIndex =0;char inChar =0;String message;// 변수 속도와 RPM 데이터 유지:int vSpeed ​​=0;int vRPM =0;int vFuel =0;int vTemp =0;void setup() { // LCD의 열과 행 수 설정:lcd.begin( 16,2); lcd.clear(); // 쉴드가 있는지 확인:if (WiFi.status() ==WL_NO_SHIELD) { lcd.println("WiFi not ready"); 동안(참); } // WiFi 네트워크 연결 시도:while (status !=WL_CONNECTED) { lcd.clear(); lcd.setCursor(0, 0); lcd.println("와이파이 연결 중..."); 상태 =WiFi.begin(ssid, 통과); // 연결을 위해 5초간 대기:delay(5000); } lcd.setCursor(0, 1); lcd.println("연결되었습니다!"); // Serial1은 차량과 통신하기 위한 acutal 포트입니다. Serial1.begin(9600); resetBuffer();} 무효 루프() { 동안 ( 상태 !=WL_CONNECTED) { lcd.clear(); lcd.setCursor(0,0); // WPA/WPA2 Wi-Fi 네트워크에 연결 Serial.println("Wifi에 연결 중"); lcd.println("와이파이 연결..."); 상태 =WiFi.begin(ssid, 통과); // 연결 딜레이(5000)를 위해 10초 기다림; } getSpeed(); getRPM(); getFuel(); getCoolTemp(); if (millis() - lastConnectionTime> postingInterval) { httpRequest(); 마지막 연결 시간 =밀리(); }}// getRPM 데이터는 "010C" 명령을 Serial1 포트에 보내고// getResponse()를 호출하여 데이터를 수집합니다. 그런 다음 // 직렬 모니터에 RPM 데이터를 인쇄합니다.void getRPM(void){ message ="010C"; Serial1.println(메시지); 지연(200); //현재 줄 지우기 for (int i =8; i <16; ++i) { lcd.setCursor(i, 0); // 0행, i열 lcd.write(' '); } lcd.setCursor(8,0); // LCD 화면의 첫 번째 행 후반 // 응답 대기 getResponse(); // RPM 응답을 4로 나눈 값은 올바른 값입니다. vRPM =((strtol(&rxData[6],0,16)*256) + strtol(&rxData[9],0,16))/4; lcd.print(vRPM); lcd.print(" rpm");} 무효 getSpeed(무효){ 메시지 ="010D"; Serial1.println(메시지); 지연(200); //현재 줄 지우기:for (int i =0; i <8; ++i) { lcd.setCursor(i, 0); // 0행, i열 lcd.write(' '); } lcd.setCursor(0,0);// LCD 화면의 첫 번째 행 전반부 // 자동차의 응답을 기다립니다. getResponse(); vSpeed ​​=strtol(&rxData[6], 0, 16); // km/h 단위 vSpeed ​​=vSpeed ​​* 0.621371; // mph 단위로 lcd.print(vSpeed); lcd.print("mph");}무효 getFuel(무효){ 메시지 ="012F"; Serial1.println(메시지); 지연(200); // 현재 줄 지우기:for (int i =0; i <8; i++){ lcd.setCursor(i, 1); // 첫 번째 행, i 열 lcd.write(' '); } lcd.setCursor(0, 1); // LCD 화면의 두 번째 행 전반부 //자동차의 응답을 기다립니다. getResponse(); vFuel =strtol(&rxData[6], 0, 16); // 255 스케일에서 //vFuel =244; // 디버그 사용법 vFuel =1.0* vFuel / 255 *100; // 100 스케일 lcd.print(vFuel); lcd.print(" %"); //Serial.println(vFuel); // 디버그 사용법}void getCoolTemp(void){ message ="0105"; Serial1.println(메시지); 지연(200); // 현재 줄 지우기:for (int i =8; i <16; i++){ lcd.setCursor(i, 1); // 첫 번째 행, i 열 lcd.write(' '); } lcd.setCursor(8, 1); // LCD 화면의 두 번째 행 후반 // 자동차의 응답을 기다립니다. getResponse(); vTemp =strtol(&rxData[6], 0, 16); // C 단위이지만 40도 오프셋 vTemp =vTemp - 40; // 0만큼 오프셋 lcd.print(vTemp); // C도 출력 lcd.write(0xDF); lcd.print("C");}// getResponse 함수는 UART에서 rxData 버퍼로 들어오는 데이터를 수집하고// 응답이 전송되면 종료됩니다. 캐리지 리턴 문자열//이 감지되면 rxData 버퍼는 null로 종료되고(문자열로 취급할 수 있도록)// rxData 인덱스는 다음 문자열을 복사할 수 있도록 0으로 재설정됩니다.void getResponse(void ){ while(Serial1.available()> 0) { // 메시지 끝 문자('\r')를 받았는지 확인하는 것으로 시작합니다. if(Serial1.peek() =='\r'){ // 메시지 끝에 도달하면 직렬 버퍼를 지웁니다. inChar =Serial1.read(); rxData[rxIndex] ='\0'; // 다음 문자가 문자열의 시작 부분으로 돌아가도록 버퍼 인덱스를 재설정합니다. rxIndex =0; } // 메시지 문자의 끝을 얻지 못한 경우 문자열에 새 문자를 추가합니다. else{ // 직렬 포트에서 새 문자를 가져옵니다. inChar =Serial1.read(); // 문자열에 새 문자를 추가하고 인덱스 변수를 늘립니다. rxData[rxIndex++] =inChar; } }} 무효 resetBuffer(void){ for (int i =0; i <20; i++){ rxData[i] =0; }} 무효 httpRequest() { client.stop(); // 프리보드에 보낼 데이터 문자열 생성 if (client.connect(server, 80)){ Serial.println("Connected"); 문자열 데이터 ="POST /dweet/for/mkr1000?RPM="; data.concat(vRPM); // 엔진 RPM 업로드 data.concat("&Speed="); data.concat(vSpeed); // 자동차 속도 업로드 data.concat("&Fuel="); data.concat(vFuel); // 연료량 업로드 data.concat("&Temp="); data.concat(vTemp); // 냉각수 온도 업로드 client.println(data); client.println("호스트:https://www.dweet.io"); client.println("연결:닫기"); // 연결 종료 client.println(); } else { lcd.clear(); lcd.setCursor(0,0); lcd.println("연결 실패"); }}

    회로도

    Arduino MKR WiFi 1000, SparkFun OBD-II UART 보드, SparkFun 로직 레벨 시프터 및 LCD 1602 연결 frizling_schematics_M8kF26dafQ.fzz

    제조공정

    1. 번호판
    2. 안티록 브레이크 시스템
    3. 파워트레인이란 무엇입니까?
    4. 발전기란 무엇입니까?
    5. 인공 지능을 사용한 장애물 회피
    6. Arduino 게임 컨트롤러
    7. 구름 의상
    8. 섀시 접지란 무엇입니까?
    9. 차량의 섀시 레이아웃
    10. 차량 배선 이해