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

자동차 HUD - 속도 및 나침반을 위한 앞유리 디스플레이

구성품 및 소모품

Arduino Nano R3
× 1

이 프로젝트 정보

설명:

원했습니다! 나는 내 친구 Taggi의 큰 차가 앞 유리에 속도를 표시하는 것을 부러워했습니다. 가지고 있어야 했고, 당연히 직접 만들어야 했습니다!

소프트웨어 관점:

회로를 투영하는 가장 어렵고 혼란스러운 부분은 숫자가 "반전"되기 때문에 7개 세그먼트 디스플레이를 BCD 디코더에 연결하는 것입니다. (미러).

3개의 버튼이 있습니다. :+ 및 - 밝기를 높이거나 낮추고 S/H를 사용하여 km/h 단위의 속도와 도 단위 방향 사이를 전환합니다.; Heading의 경우에도 빨간색 LED가 켜져 있으면 움직일 때 나침반의 "도"(1-360°)를 의미합니다. 그것은 전자 나침반이 아니라 GPS이며 이동하는 방향에 대한 올바른 정보를 얻으려면 이동해야 합니다. 밝기는 EEPROM에 저장됩니다. 1분 후의 기억. PWM 핀을 통해 디스플레이와 LED 모두에서 밝기가 변경됩니다.

코드의 중요한 부분은 GPS에서 데이터, 주로 속도와 방향을 수집하여 모든 NMEA 문장에서 가져오는 것입니다. 주로 Serial NMEA 문장 조작을 위해 String 클래스를 사용하더라도 전체 정교화 흐름이 안정적이고 견고합니다. "serialEvent()"를 사용하여 GPS에서 초당 한 번 데이터 수신 , "nmeaExtractData()"를 호출하는 것보다 마지막으로 "nmea0183_checksum()을 사용하여 데이터 패킷을 검사하여 데이터 무결성을 확인합니다. 다른 제조사 및 모델 GPS를 사용하는 경우 문장이 동일한 구조인지 확인하거나 여기에서 일부 변경해야 합니다. 예를 들어 EM406A는 "$GPRMC" 패킷 ID를 사용하고 BT220은 "$GNRMC"를 사용합니다. 대신... 약간의 이름 변경... 유용한 링크가 체크섬 테스트에 도움이 될 수 있습니다. https://nmeachecksum.eqth.net - 다음은 완전한 NMEA 문장의 예입니다. 여기에는 id, time, validation, 위도, 경도, 속도, 실제 코스, 날짜, 변동 및 체크섬.

$GNRMC, 095836.000, A, 4551.9676, N, 01328.7118, E, 2.09, 341.84, 280519,, *08

스케치는 값이 변경될 때 모든 단일 디스플레이 BCD 디코더에 대한 래치를 한 번에 하나씩 활성화하고, 이진 4비트 버스에 코드 번호를 설정하고, 래치를 비활성화하는 등의 작업을 제공합니다. 중요하지 않은 왼쪽의 0은 공백입니다(표시되지 않음).

새 스케치를 로드하기 전 ~에 MCU 점퍼를 꺼내야 함 :아두이노의 Rx 핀에 연결되어 있으며 로딩시 GPS Tx와 충돌이 확실합니다. 소프트웨어 로딩 후 정상 기능을 복원하기 위해 점퍼를 다시 제자리에 놓습니다.

구성 요소 목록:

<울>
  • 1 x MCU Arduino Nano
  • <울>
  • 3 x 5161as 7세그먼트 디스플레이, 공통 음극, 빨간색
  • <울>
  • 1 x Beitian BN-220 직렬 TTL GPS(1Hz GNRMC 문장)
  • <울>
  • 1 x 점퍼
  • <울>
  • 3 x 버튼(일반적으로 열림) + 3 x 캡
  • <울>
  • 22 x 1/4W 220옴 저항기
  • <울>
  • 1 x 3mm LED, 빨간색
  • <울>
  • 2 x 100n 커패시터
  • <울>
  • 3 x 14511 BCD 디코더 + 래치
  • <울>
  • 1 x USB "B" 암
  • <울>
  • 1 x 스트립 라인 2x 수 핀(점퍼용)
  • <울>
  • 90°로 구부릴 수 있는 스트립 라인 4개(GPS용)
  • <울>
  • GPS를 온보드 4핀에 연결하는 피그테일 케이블 1개
  • <울>
  • 스택에 2개의 PCB를 결합하기 위한 22개의 스트립 라인 수 핀
  • <울>
  • GPS를 PCB에 붙이기 위한 양면 접착제 1개
  • <울>
  • 6 x 회전 스트립 라인 5x 암 핀(디스플레이용)
  • <울>
  • 50 x 구리 0.6mm 리벳
  • <울>
  • 8 x M3 나사
  • <울>
  • 20mm 높이의 M3 암 타워 4개
  • <울>
  • 플라스틱 상자 1개 + 덮개(아래에서 인쇄할 준비가 된 3D 파일 참조)
  • PCB(인쇄 회로 기판):

    두 개의 양면 PCB를 사용했습니다. 이러한 이유로 약 50개의 패스 스루 리벳 또는 핀이 전체 회로의 경로를 해결하는 데 사용됩니다. 5개의 정렬 구멍도 있습니다. 먼저 만들기. 나는 모든 PCB에 이 5개의 정렬 지점을 설계했습니다. 다운로드 섹션에는 레이저 프린터를 "노란색" 또는 "파란색" 시트에 다운로드하고 인쇄하기 위해 미러링된 모든 PCB 파일, 구성요소 및 솔더 면이 있습니다.; 이번에는 파란색을 사용했지만 노란색도 좋고 가격도 저렴합니다. 파란색 시트가 더 낫다고 말해야 합니다... 인쇄할 때 토너 절약 설정을 비활성화하는 것을 잊지 말고 대신 1200dpi 해상도를 사용하여 깊은 실제 검은색 결과를 얻으십시오. 매직 시트에서 PCB로의 토너 전사 과정은 뜨거운 다리미를 사용하여 이루어집니다. 인터넷에는 좋은 PCB를 생산하는 방법을 보여주는 튜토리얼이 있습니다. 그러나 다음 중요 사항을 기억하십시오. 구리를 완벽하게 청소하고 주방 루비드 스펀지로 살짝 닦기, 5분 다림질, 수열 충격, 5개의 구멍을 통한 양면 정렬(저는 큰 흰색 LED 표면에 5개의 핀을 사용하여 확인했습니다. 구멍), 부식 과정에서 다른 면을 보호합니다. 구성 요소면도 인쇄하면 프로젝트가 "전문적"이 됩니다 :-)

    참고: 사진은 가장 마지막 버전 이전에 촬영되었으며 몇 가지 세부 사항이 다를 수 있음을 의미합니다. 즉, 최종 버전에서 PCB 주변의 이상한 녹색 와이어가 사라지거나 점퍼가 PCB #1에서 PCB #2로 이동했습니다. GPS를 9600bps 속도, 1Hz GNRMC NMEA 문장에서만 설정해야 합니다. 이것은 자체 설정 소프트웨어를 사용하여 만들 수 있습니다. 마지막으로 USB 암 커넥터를 납땜하기 전에 바로 아래에 있는 구성 요소 쪽의 구리선과 원치 않는 접촉을 방지하기 위해 작은 절연 테이프를 그 아래에 붙입니다.

    처음으로 전원을 공급하면 앞 유리(거울)에 반사된 숫자를 보도록 만들어졌기 때문에 숫자가 "읽을 수 없음"이라는 것을 알게 될 것입니다. 자동차 운전석 앞부분에 설치 , 편안한 장소를 찾아 수리하십시오. USB 전원 케이블을 연결하는 것이 좋습니다. 점화 위치 후 엔진 on/off 시 on/off로 전환됩니다. 신사 숙녀 여러분!

    뉴스 및 개선 사항:

    <울>
  • 2021년 3월 25일:프로젝트를 완료하기 위해 두 개의 3D .STL 모델을 준비했습니다. 이 링크:https://grabcad.com/library/car-hud-1에서 3D 프린터를 통해 인쇄할 이 프로젝트의 모양 상자 및 표지 패널에 관한 파일을 다운로드할 수 있습니다.
  • <울>
  • 20.07.2021:V2(버전 2) 사용 가능 2개의 와이어와 1개의 저항과 함께 디스플레이에 고도 정보가 수천 미터(예:0.89 =890m)로 표시되는 소프트웨어의 경우 S/H 버튼을 다시 누르기만 하면 됩니다! 지침:1) 자체 소프트웨어를 통해 $GNGGA nmea 문장도 출력하도록 GPS를 설정합니다. 2) d5 Arduino pwm 핀과 나머지 회로 사이의 실제 연결을 끊고 220ohm 저항을 사용하여 중앙 디스플레이 10진수 점 핀에 연결합니다. 3) d13 Arduino 디지털 핀을 d5가 연결된 회로에 연결합니다. 여기에서 몇 장의 사진을 보십시오. 4) Arduino Nano에 V2 스케치를 설치합니다.
  • <울>
  • 2021년 11월 11일:버전 V2.2가 준비되었습니다. 당신을위한. 무슨 새로운? 고도(V2와 함께 이미 있음)에 대해 hud는 1000m부터 시작하여 1.24(1240m) 또는 2.02(2020m)와 같이 999m까지 전체 값을 표시합니다. LDR 포토레지스터 GL5539, 10kOhm 저항 및 2개의 와이어를 추가했습니다. V2.2 모드에 대한 아래 그림을보고 Arduino에 V2.2 스케치를 설치하십시오. LDR 센서는 조명 수준(낮, 흐림 또는 밤)에 따라 밝기(3단계)를 자동으로 수정합니다. 버튼 (+) 및 (-)는 밝기를 수동으로 수정하기 위해 여전히 작동하며 우선 순위가 있습니다. 자동으로 돌아가려면 (+) 및 (-) 버튼을 잠시 동안 함께 누르십시오. 밝기 수준을 저장하는 내부 EEPROM은 더 이상 사용되지 않습니다. 먼저 V2 모드를 시작하세요!
  • 운전할 때는 그냥 운전하세요. 안전 운전하세요!

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

    코드

    <울>
  • 자동차-HUD Arduino 스케치
  • Car-HUD Arduino 스케치Arduino
    /* 이 스케치는 자동차 앞유리 HUD(헤드업 디스플레이)로 작동합니다. Marco Zonca, 10/2020 Arduino Nano를 CPU로, GPS BT-220 nmea 매 1초, 3 x 버튼, 3 x 7 세그먼트 디스플레이 공통 음극 , 3 x 14511 BCD 래치 디코더, MPU EEPROM 메모리(1바이트) 및 많은 저항기, 경고:=======소프트웨어를 업데이트하기 전에 JUMPER*/#include #include String inputString =""을 통해 Arduino(GPS에서 TX)의 RX 핀을 분리합니다.;문자열 nm_time ="00:00:00";문자열 nm_validity ="V";문자열 nm_latitude ="dd°mm.mmmm'N";문자열 nm_longitude ="ddd°mm.mmmm'E";문자열 nm_knots ="0.0 kn";float nmf_knots =0.0;float nmf_kmh =0.0;int nmi_kmh =0;String nm_truecourse ="360";float nmf_truecourse =360;String nm_date ="dd/mm/yyyy"; int nmi_truecourse =0;byte kC;byte kDeci =0;byte kUnit =0;byte tCent =0;byte tDeci =0;byte tUnit =0;byte 밝기 =120;byte latch_off =HIGH;byte latch_on =LOW;int n=0;unsigned long lastmemcheck =0; 서명되지 않은 긴 memcheck =60000; // 60초마다 EEPROM에 "밝기" 값을 저장하는지 확인합니다.bool stringComplete =false;bool isKMH=true;bool ret =false;const int disp001 =2; // 단위는 래치콘스트를 표시합니다. int disp010 =8; // 10개를 표시합니다. latchconst int disp100 =12; // undreds 표시 래치 const int disp001dim =9; // 단위는 dimmer/off를 표시합니다. pinconst int disp010dim =10; // 10개의 디스플레이 디머/오프 pinconst int disp100dim =11; // undreds 디스플레이 dimmer/off pinconst int button_kt =14; // kmh/truecourse buttonconst int button_more =15; // 밝기 + buttonconst int button_less =16; // 밝기 - buttonconst int degreeLED =3; // 각도 LEDconst int bit_3 =7; // 비트 3const int bit_2 =6; // 비트 2const int bit_1 =5; // 비트 1const int bit_0 =4; // 비트 0const int dly =10; // 지연 래치 m/secconst 바이트 끄기 =0; // 밝기=0과 동일 const int addr =0; // 밝기 값에 대한 EEPROM 주소 const 바이트 수[10] [4] ={{0,0,0,0},{1,0,0,0},{0,1,0,0},{1, 1,0,0},{0,0,1,0}, {1,0,1,0},{0,1,1,0},{1,1,1,0},{0, 0,0,1},{1,0,0,1}}; // 비트 0,1,2,3void setup() { Serial.begin(9600); Wire.begin(); inputString.reserve(200); 밝기 =EEPROM.read(addr); if (밝기> 250 || 밝기 <10) { 밝기=120; } // 첫 번째 EEPROM에서 미친 값 피하기 read pinMode(disp001, OUTPUT); 핀모드(disp010, 출력); 핀모드(disp100, 출력); 핀모드(각도 LED, 출력); 핀모드(버튼_kt, INPUT_PULLUP); 핀모드(버튼리스, INPUT_PULLUP); 핀모드(버튼모어, INPUT_PULLUP); 핀모드(비트_3, 출력); 핀모드(비트_2, 출력); 핀모드(비트_1, 출력); 핀모드(비트_0, 출력); analogWrite(disp001dim, off); // off 및 0 표시 analogWrite(disp010dim, off); analogWrite(disp100dim, off); analogWrite(각도 LED, 꺼짐); 세트버스Nr(0); 디지털 쓰기(disp001, 래치_온); 디지털 쓰기(disp010, 래치_온); 디지털 쓰기(disp100, 래치_온); 지연(dly); 디지털 쓰기(disp001, 래치_오프); 디지털 쓰기(disp010, 래치_오프); 디지털 쓰기(disp100, 래치_오프); analogWrite(disp001dim, 밝기); // 디스플레이에 analogWrite(disp010dim, 밝기); analogWrite(disp100dim, 밝기);} // setup()void 루프() { // GPS NMEA ------------------ if (stringComplete ==true) { // 직렬 포트 RX로 nmea 문장을 수신함 ret =nmeaExtractData(); 입력 문자열 =""; 문자열 완성 =거짓; if (ret ==true) { kCent=nmi_kmh/100; n=nmi_kmh-(kCent*100); kDeci=n/10; n=nmi_kmh-(kCent*100)-(kDeci*10); kUnit=n; tCent=nmi_truecourse/100; n=nmi_truecourse-(tCent*100); tDeci=n/10; n=nmi_truecourse-(tCent*100)-(tDeci*10); t단위=n; 표시하다(); } } if (millis()> (lastmemcheck+memcheck)) { // 메모리에 밝기 값 입력(수정된 경우) EEPROM.update(addr,brightness); lastmemcheck=밀리(); } checkButtons();}void display() { if (isKMH ==true) { // km/h 단위의 속도(isKMH=true) analogWrite(degreesLED, off); setBusNr(kUnit); 디지털 쓰기(disp001, 래치_온); 지연(dly); 디지털 쓰기(disp001, 래치_오프); if (kDeci> 0 || kCent> 0) { // tens=0(그리고 undreds=0)이면 10을 끕니다. setBusNr(kDeci); 디지털 쓰기(disp010, 래치_온); 지연(dly); 디지털 쓰기(disp010, 래치_오프); analogWrite(disp010dim, 밝기); } else { analogWrite(disp010dim, off); } if (kCent> 0) { // undreds 끄기 if=0 setBusNr(kCent); 디지털 쓰기(disp100, 래치_온); 지연(dly); 디지털 쓰기(disp100, 래치_오프); analogWrite(disp100dim, 밝기); } else { analogWrite(disp100dim, off); } } else { // 실제 방위각(isKMH=false) analogWrite(degreesLED, 밝기); setBusNr(tUnit); 디지털 쓰기(disp001, 래치_온); 지연(dly); 디지털 쓰기(disp001, 래치_오프); if (tDeci> 0 || tCent> 0) { // 10이 0이면 10을 끕니다(또한 undreds=0) setBusNr(tDeci); 디지털 쓰기(disp010, 래치_온); 지연(dly); 디지털 쓰기(disp010, 래치_오프); analogWrite(disp010dim, 밝기); } else { analogWrite(disp010dim, off); } if (tCent> 0) { // undreds 끄기 if=0 setBusNr(tCent); 디지털 쓰기(disp100, 래치_온); 지연(dly); 디지털 쓰기(disp100, 래치_오프); analogWrite(disp100dim, 밝기); } else { analogWrite(disp100dim, off); } }} // display() 무효 checkButtons(){ if (digitalRead(button_kt) ==LOW) { if (isKMH ==true) { isKMH=false; } 그렇지 않으면 { isKMH=참; } 지연(250); } if (digitalRead(button_more) ==LOW) { if (밝기 <=240) { 밝기=밝기+10; } analogWrite(disp001dim, 밝기); analogWrite(disp010dim, 밝기); analogWrite(disp100dim, 밝기); 지연(100); } if (digitalRead(button_less) ==LOW) { if (밝기>=20) { 밝기=밝기-10; } analogWrite(disp001dim, 밝기); analogWrite(disp010dim, 밝기); analogWrite(disp100dim, 밝기); 지연(100); }} // checkButtons()void setBusNr(int number) { // 4비트 버스 설정 for (byte b=0; b<=3; b++) { if (numbers[number][b]==0) { if (b==0) {digitalWrite(bit_0, LOW);} if (b==1) {digitalWrite(bit_1, LOW);} if (b==2) {digitalWrite(bit_2, LOW);} if (b ==3) {digitalWrite(bit_3, LOW);} } else { if (b==0) {digitalWrite(bit_0, HIGH);} if (b==1) {digitalWrite(bit_1, HIGH);} if ( b==2) {digitalWrite(bit_2, HIGH);} if (b==3) {digitalWrite(bit_3, HIGH);} } }} // setBusNr()// nmea에서 데이터 추출 inputStringbool nmeaExtractData() { int d=0; 정수 s=0; 정수 y=0; 정수 z=0; 플로트 t=0; 부울 ret =거짓; //nmea 문장 =$GNRMC이고 유효한 CHKSUM인 경우 true if ((inputString.substring(0,6) =="$GNRMC") &&(inputString.substring(inputString.length()-4,inputString.length()- 2) ==nmea0183_checksum(inputString))) { y=0; (s =1; s <11; s ++) { y=inputString.indexOf(",",y); switch(s) { 사례 1://-----------------------time z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_time=inputString.substring(y+1,y+2+1)+":"+inputString.substring(y+1+2,y+4+1)+" :"+inputString.substring(y+1+4,y+6+1); } y=z; 부서지다; 사례 2://-----------------------유효성 z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_validity=inputString.substring(y+1,y+1+1); } y=z; 부서지다; 사례 3://----------------------- 위도 z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_latitude=inputString.substring(y+1,y+2+1)+"°"+inputString.substring(y+1+2,y+10+1)+" '"; } y=z; 부서지다; 사례 4://-----------------------북/남 z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_latitude=nm_latitude + inputString.substring(y+1,y+1+1); } y=z; 부서지다; 사례 5://-----------------------경도 z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_longitude=inputString.substring(y+1,y+3+1)+"°"+inputString.substring(y+1+3,y+11+1)+" '"; } y=z; 부서지다; 사례 6://-----------------------동/서 z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_longitude=nm_longitude + inputString.substring(y+1,y+1+1); } y=z; 부서지다; 사례 7://----------------------- 속도 매듭 z=inputString.indexOf(",",y+1); if (z>(y+1)) { nmf_knots=inputString.substring(y+1,z).toFloat(); t=roundOneDec(nmf_knots); nm_knots=문자열(t,1)+"kn"; nmf_kmh=roundTwoDec(nmf_knots * 1.852); nmi_kmh=roundZeroDec(nmf_knots * 1.852); } y=z; 부서지다; 사례 8://-----------------------참 과정 z=inputString.indexOf(",",y+1); if (z>(y+1)) { nmf_truecourse=inputString.substring(y+1,z).toFloat(); t=roundZeroDec(nmf_truecourse); nmi_truecourse=t; d=t; nm_truecourse=d; } y=z; 부서지다; 사례 9://-----------------------날짜 z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_date=inputString.substring(y+1,y+2+1)+"/"+inputString.substring(y+1+2,y+4+1)+" /20"+inputString.substring(y+1+4,y+6+1); } y=z; 부서지다; 사례 10:// 문 n.u. 부서지다; 기본값:// 문 n.u. 부서지다; } } 렛=참; } return ret;} // nmeaExtractData()/* 하드웨어 직렬 RX에 새 데이터가 들어올 때마다 SerialEvent가 발생합니다. 이 루틴은 loop()가 실행될 때마다 실행되므로 루프 내부에서 지연을 사용하면 응답이 지연될 수 있습니다. 여러 바이트의 데이터를 사용할 수 있습니다.*/void serialEvent() { while (Serial.available()) { char inChar =(char)Serial.read(); 입력 문자열 +=inChar; // 들어오는 문자가 개행 문자이면 기본 루프가 // 이에 대해 뭔가를 할 수 있도록 플래그를 설정합니다. if (inChar =='\n') { stringComplete =true; } }} // serialEvent()//nmea의 체크섬 계산 sentenceString nmea0183_checksum(String nmea_data) { int crc =0; 문자열 chSumString =""; 정수 나; // 첫 번째 $ 기호, 문장의 체크섬 무시 for (i =1; i <(nmea_data.length()-5); i ++) { // "*"가 없으면 - 5 제거 + cksum + cr + lf가 존재합니다. crc ^=nmea_data[i]; } chSumString =문자열(crc, 16진수); if (chSumString.length()==1) { chSumString="0"+chSumString.substring(0,1); } chSumString.toUpperCase(); return chSumString;} // nmea0183_checksum(String nmea_data)// 소수점 이하 자릿수 반올림float roundZeroDec(float f) { float y, d; y =f*1; d =y - (int)y; y =(float)(int)(f*1)/1; if (d>=0.5) { y +=1; } else { if (d <-0.5) { y -=1; } } return y;}// 10진수로 반올림float roundOneDec(float f) { float y, d; y =f*10; d =y - (int)y; y =(float)(int)(f*10)/10; if (d>=0.5) { y +=0.1; } else { if (d <-0.5) { y -=0.1; } } return y;}// 소수점 이하 두 자리 반올림float roundTwoDec(float f) { float y, d; y =f*100; d =y - (int)y; y =(float)(int)(f*100)/100; if (d>=0.5) { y +=0.01; } else { if (d <-0.5) { y -=0.01; } } 리턴 y;}

    회로도

    car-hud_m5RwPQqpxH.fzz ard-carhud-v2_3N5756haNI.ino ard-carhud-v2-2_XhXHFJu0T8.ino

    제조공정

    1. 장애인 운전자를 위한 반자율 자동차 해체
    2. Donkey Car Garbage Collector를 위한 자율 주행 AI
    3. 시뮬레이션된 도시 환경에서 여러 상황에서 자율 주행 자동차를 위한 실시간 모션 계획
    4. 5G는 커넥티드 카에 무엇을 제공할 수 있습니까?
    5. 안전:미래 자동차의 최우선 과제
    6. 가변 속도 드라이브용 모터 케이블
    7. 연마 및 디버링을 위한 향상된 선반
    8. 정밀성과 속도를 위해 설계된 선반
    9. 제품 데이터 교환:자동차 제조업체의 골칫거리
    10. 자동차용 터보차저를 선택하는 방법은 무엇입니까?