제조공정
![]() |
| × | 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와 충돌이 확실합니다. 소프트웨어 로딩 후 정상 기능을 복원하기 위해 점퍼를 다시 제자리에 놓습니다.
구성 요소 목록: <울>
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로 전환됩니다. 신사 숙녀 여러분!
뉴스 및 개선 사항: <울>
운전할 때는 그냥 운전하세요. 안전 운전하세요!
섹션> <섹션 클래스="섹션 컨테이너 섹션 축소 가능" id="코드">/* 이 스케치는 자동차 앞유리 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;}
제조공정
알루미늄은 현대 생산에서 가장 널리 사용되는 합금 중 하나이며 알루미늄이 최고의 재료인 것 같습니다. 가볍고 강하며 내구성이 있으며 부식에 강합니다. 이것이 새로운 밀링 알루미늄 전략이 빠르게 개발된 이유입니다. 현대의 성공적인 CNC 알루미늄 밀링 방법 중 하나는 고속 가공입니다. 기존 밀링과 비교하여 가장 큰 차이점은 고속 밀링 속도가 훨씬 빠르고 기계공이 이를 사용하여 절삭 이송을 높일 수 있다는 것입니다. 고속 밀링은 기존 밀링과 다릅니다. 이것은 소량의 부품과 프로토타입을 생산하는 보다 생산적이고 혁신적인 방법입니다. 진
정밀 CNC 생산 연삭은 부품에 엄격한 기하학적 공차와 고품질 표면 마감이 필요할 때 빛을 발합니다. 일반적으로 표면 마감은 32마이크로인치 Ra에서 4.0마이크로인치 Ra까지의 범위에서 달성해야 하는 숫자가 더 많습니다. 이에 비해 전통적인 밀링 또는 터닝 작업은 약 125마이크로인치에서 32마이크로인치 Ra의 마감을 달성할 수 있습니다. 목표가 현재 표면 조도를 20마이크로인치 Ra에서 17마이크로인치 Ra로 개선하는 것이라면 단순히 휠 속도를 높이거나 이송 속도를 약간 줄이는 것으로 충분할 수 있습니다. 그러나 더 미세한 표