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

HUD do carro - Tela do pára-brisa para velocidade e bússola

Componentes e suprimentos

Arduino Nano R3
× 1

Sobre este projeto





Descrição:


Eu queria! Tenho sido invejoso do grande carro do meu amigo Taggi mostrando no para-brisa a velocidade. Eu tinha que ter isso, eu tinha que fazer isso sozinho, é claro!





Ponto de vista do software:


Projetar o circuito, a parte mais difícil e confusa tem sido a conexão dos monitores de 7 segmentos aos decodificadores BCD porque os números são "invertidos" (espelhado).

Existem 3 botões :+ e - para aumentar / diminuir o brilho e S / H para alternar entre Velocidade em km / he Direção em graus ; no caso do rumo, o LED vermelho também está aceso, significa "graus" da bússola (1-360 °) ao se mover. Não é uma bússola eletrônica, é um GPS e você precisa se mover para ter as informações corretas da direção para a qual está se movendo. O brilho é salvo em EEPROM memória depois de um minuto. O brilho é alterado nos visores e no LED por meio dos pinos PWM.

Uma parte importante do código é a coleta de dados do GPS, principalmente velocidade e direção, retirando-os de cada frase NMEA. Mesmo usando a classe String, principalmente para manipulação de sentenças Serial NMEA, todo o fluxo de elaboração é estável e sólido; ele usa "serialEvent ()" para receber dados do GPS uma vez por segundo , então chama "nmeaExtractData ()" e finalmente verifica o pacote de dados com "nmea0183_checksum () para ter certeza da integridade dos dados. Se você usar outra marca e modelo de GPS, certifique-se de que as frases tenham a mesma estrutura ou você terá que fazer algumas alterações aqui . Por exemplo, EM406A usa ID de pacote "$ GPRMC", BT220 usa "$ GNRMC" em vez disso ... apenas uma pequena mudança de nome ... Um link útil pode ajudá-lo com o teste de checksum:https://nmeachecksum.eqth.net - aqui um exemplo de uma frase NMEA completa, que contém:id, tempo, validade, latitude, longitude, velocidade, curso verdadeiro, data, variação e soma de verificação.

$ GNRMC, 095836.000, A, 4551,9676, N, 01328.7118, E, 2.09, 341,84, 280519 ,, * 08

O esboço permite habilitar a trava para cada decodificador BCD de exibição individual, um de cada vez, definir o número do código no barramento binário de 4 bits, desabilitar a trava e assim por diante quando o valor mudar. Os zeros não significativos do lado esquerdo ficam em branco (não são exibidos).

Antes de carregar um novo esboço para o MCU lembre-se de tirar o Jumper :está conectado ao pino Rx do Arduino e durante o carregamento com certeza está em conflito com o GPS Tx. Após o carregamento do software, coloque novamente o Jumper para restaurar a funcionalidade normal.





Lista de componentes:

  • 1 x MCU Arduino Nano
  • 3 x 5161 como monitores de sete segmentos, cátodo comum, vermelho
  • 1 x Beitian BN-220 serial TTL GPS (frases GNRMC de 1 Hz)
  • 1 x Jumper
  • 3 botões x (normalmente aberto) + 3 x maiúsculas
  • resistores 22 x 1 / 4W 220 ohm
  • 1 LED de 3 mm, vermelho
  • 2 condensadores de 100n
  • 3 x 14511 decodificadores BCD + trava
  • 1 x USB "B" feminino
  • 1 linha de tira 2x pinos machos (para Jumper)
  • 1 linha de tira 4x pinos machos para dobrar em 90 ° (para GPS)
  • 1 cabo pigtail conectando GPS a 4 pinos a bordo
  • 22 pinos machos de linha de tira para unir dois PCB em uma pilha
  • 1 x pedaço de adesivo dupla-face para colar o GPS no PCB
  • 6 x linha de tira torneada 5x pinos fêmea (para monitores)
  • 50 x rebites de cobre de 0,6 mm
  • 8 parafusos M3
  • 4 torres femininas M3 com 20 mm de altura
  • 1 x caixa de plástico + tampa (veja meus arquivos 3D prontos para impressão, abaixo)





PCB (placas de circuito impresso):


Usei dois PCBs de dupla face por isso cerca de 50 rebites ou pinos passantes são usados ​​para resolver rotas de circuitos inteiros. Existem também 5 orifícios de alinhamento para fazer primeiro. Eu projetei em cada PCB esses 5 pontos de alinhamento. Na seção de download você tem todos os arquivos PCB, componentes e faces de solda, espelhados, para download e impressão por meio de uma impressora a laser em folhas "amarelas" ou "azuis" ; desta vez usei os azuis mas também os amarelos são bons e o preço é mais baixo. Devo dizer que as folhas azuis são melhores ... Ao imprimir, lembre-se de desativar as configurações de economia de toner, use a resolução de 1200 dpi para obter um resultado de preto real profundo. O processo de transferência de toner das folhas mágicas para o PCB é feito com o uso de um ferro quente ... Na rede existem alguns tutoriais que mostram como produzir um bom PCB mas lembre-se destes pontos importantes:limpe perfeitamente e escove levemente o cobre com uma esponja ruvid de cozinha, 5 minutos de engomar, choque térmico de água, alinhamento de duas faces por meio de 5 orifícios (usei 5 pinos em uma grande superfície de LED branco para ver orifícios), proteja a outra face durante o processo de corrosão. Imprimir também a face dos componentes torna o projeto "profissional" :-)

NOTAS: as fotos foram tiradas antes da última versão, isso significa que alguns detalhes podem ser diferentes:ou seja, o estranho fio verde ao redor dos PCBs na versão final desaparece ou o Jumper mudou do PCB # 1 para o PCB # 2. Você deve configurar o GPS na velocidade de 9600 bps, apenas frase GNRMC NMEA de 1 Hz; isso pode ser feito usando seu próprio software de configuração. Finalmente, antes de soldar o conector USB fêmea, cole um pequeno pedaço de fita isolante sob ele para evitar o contato indesejado com uma linha de cobre, no lado do componente, logo abaixo.



Dando força pela primeira vez você descobrirá que os números são "ilegíveis", pois é feito para olhar para eles refletidos no pára-brisa (espelho). Instale-o no carro na frente do banco do motorista , encontre um local confortável e arrume-o. Sugiro que conecte o cabo de alimentação USB após a posição de ignição para ligar / desligar quando o motor é ligado / desligado. Isso é tudo senhoras e senhores!





Notícias e melhorias:

  • 25.03.2021:para concluir o projeto preparei dois modelos 3D .STL neste link:https://grabcad.com/library/car-hud-1 onde você pode baixar os arquivos relativos a uma caixa em forma e seu painel de capa para este projeto para imprimir por meio de uma impressora 3D.
  • 20.07.2021:está disponível uma V2 (versão dois) do software que junto com dois fios e um resistor você terá informações de altitude no display como milhares de metros (ou seja, 0,89 =890m), basta pressionar mais uma vez o botão S / H! Instruções:1) configure o GPS para emitir também uma sentença $ GNGGA nmea por meio de seu próprio software; 2) corte a conexão real entre o pino pwm do d5 Arduino e o resto do circuito, conecte-o ao pino do ponto decimal do display central com um resistor de 220 ohms; 3) conecte o pino digital do Arduino d13 ao circuito onde o d5 foi conectado; veja algumas fotos aqui abaixo; 4) instale o esboço V2 em seu Arduino Nano.
  • 01.11.2021:a versão V2.2 está pronta para você. Quais são as novidades? Sobre a altitude (já presente com V2) o hud mostra valor total até 999m, a partir de 1000m mostra valores em mil, ou seja, 1,24 (1240m) ou 2,02 (2020m). Eu adicionei um fotoresistor LDR GL5539, um resistor de 10kOhm e 2 fios. Veja as imagens abaixo para mods V2.2 e instale o esboço V2.2 em seu Arduino. O sensor LDR irá modificar o brilho automaticamente (3 níveis) dependendo do nível de luz (dia, nublado ou noite). Os botões (+) e (-) ainda funcionam para modificar manualmente o brilho, eles têm prioridade; para voltar ao automático, basta pressionar os botões (+) e (-) juntos por um momento. A EEPROM interna para armazenar o nível de brilho não é mais usada. Vamos fazer os mods V2 primeiro!





Ao dirigir, basta dirigir. Dirija com segurança!

Código

  • Esboço Car-HUD Arduino
Esboço do Arduino do Car-HUD Arduino
 / * Este esboço atua como HUD do pára-brisa do carro (head up display), de Marco Zonca, 10/2020 Arduino Nano como CPU, GPS BT-220 nmea a cada 1 segundo, 3 x botões, 3 x 7 segmentos exibe catodo comum , Decodificador de trava 3 x 14511 BCD, memória MPU EEPROM (1 byte) e muitos resistores; AVISO:=======Antes de atualizar o software, desconecte o pino RX do Arduino (TX do GPS) por meio do JUMPER * / # include  #include  String inputString =""; String nm_time ="00:00:00"; String nm_validity ="V"; String nm_latitude ="dd ° mm.mmmm'N"; String nm_longitude ="ddd ° mm.mmmm'E"; String 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 / aaaa "; int nmi_truecourse =0; byte kCent =0; byte kDeci =0; byte kUnit =0; byte tCent =0; byte tDeci =0; byte tUnit =0; byte brilho =120; byte latch_off =HIGH; byte latch_on =LOW; int n =0; sem sinal longo lastmemcheck =0; verificação de memória longa sem sinal =60000; // marque para salvar o valor de "brilho" na EEPROM a cada 60 segundos bool stringComplete =false; bool isKMH =true; bool ret =false; const int disp001 =2; // unidades exibem latchconst int disp010 =8; // dezenas de exibição latchconst int disp100 =12; // undreds exibe latchconst int disp001dim =9; // unidades exibem dimmer / off pinconst int disp010dim =10; // dezenas exibir dimmer / off pinconst int disp100dim =11; // undreds display dimmer / off pinconst int button_kt =14; // kmh / truecourse buttonconst int button_more =15; // brilho + botãoconst int button_less =16; // brilho - buttonconst int degreesLED =3; // graus LEDconst int bit_3 =7; // bit 3const int bit_2 =6; // bit 2const int bit_1 =5; // bit 1const int bit_0 =4; // bit 0const int dly =10; // retarda a trava m / secconst byte off =0; // igual a brilho =0const int addr =0; // Endereço EEPROM para valores de brilho - números de byte [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}}; // bits 0,1,2,3void setup () {Serial.begin (9600); Wire.begin (); inputString.reserve (200); brilho =EEPROM.read (addr); if (brilho> 250 || brilho <10) {brilho =120; } // evita valores malucos da primeira leitura de EEPROM pinMode (disp001, OUTPUT); pinMode (disp010, OUTPUT); pinMode (disp100, OUTPUT); pinMode (degreesLED, OUTPUT); pinMode (button_kt, INPUT_PULLUP); pinMode (button_less, INPUT_PULLUP); pinMode (button_more, INPUT_PULLUP); pinMode (bit_3, SAÍDA); pinMode (bit_2, OUTPUT); pinMode (bit_1, OUTPUT); pinMode (bit_0, OUTPUT); analogWrite (disp001dim, desligado); // off e zero exibe analogWrite (disp010dim, off); analogWrite (disp100dim, desligado); analogWrite (degreesLED, off); setBusNr (0); digitalWrite (disp001, latch_on); digitalWrite (disp010, latch_on); digitalWrite (disp100, latch_on); atraso (dly); digitalWrite (disp001, latch_off); digitalWrite (disp010, latch_off); digitalWrite (disp100, latch_off); analogWrite (disp001dim, brilho); // no display analogWrite (disp010dim, brilho); analogWrite (disp100dim, brilho);} // setup () void loop () {// GPS NMEA ------------------ if (stringComplete ==true) {// recebeu nmea sentença pela porta serial RX ret =nmeaExtractData (); inputString =""; stringComplete =false; if (ret ==verdadeiro) {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); tUnit =n; exibição(); }} if (millis ()> (lastmemcheck + memcheck)) {// colocar o valor de brilho da memória (se modificado) EEPROM.update (addr, brilho); lastmemcheck =millis (); } checkButtons ();} void display () {if (isKMH ==true) {// velocidade em km / h (isKMH =true) analogWrite (degreesLED, off); setBusNr (kUnit); digitalWrite (disp001, latch_on); atraso (dly); digitalWrite (disp001, latch_off); if (kDeci> 0 || kCent> 0) {// definir dezenas se dezenas =0 (e também undreds =0) setBusNr (kDeci); digitalWrite (disp010, latch_on); atraso (dly); digitalWrite (disp010, latch_off); analogWrite (disp010dim, brilho); } else {analogWrite (disp010dim, off); } if (kCent> 0) {// definir undreds off if =0 setBusNr (kCent); digitalWrite (disp100, latch_on); atraso (dly); digitalWrite (disp100, latch_off); analogWrite (disp100dim, brilho); } else {analogWrite (disp100dim, off); }} else {// rolamento verdadeiro em graus (isKMH =false) analogWrite (degreesLED, brilho); setBusNr (tUnit); digitalWrite (disp001, latch_on); atraso (dly); digitalWrite (disp001, latch_off); if (tDeci> 0 || tCent> 0) {// definir dezenas se dezenas =0 (e também undreds =0) setBusNr (tDeci); digitalWrite (disp010, latch_on); atraso (dly); digitalWrite (disp010, latch_off); analogWrite (disp010dim, brilho); } else {analogWrite (disp010dim, off); } if (tCent> 0) {// definir undreds off if =0 setBusNr (tCent); digitalWrite (disp100, latch_on); atraso (dly); digitalWrite (disp100, latch_off); analogWrite (disp100dim, brilho); } else {analogWrite (disp100dim, off); }}} // display () void checkButtons () {if (digitalRead (button_kt) ==LOW) {if (isKMH ==true) {isKMH =false; } else {isKMH =true; } atraso (250); } if (digitalRead (button_more) ==LOW) {if (brilho <=240) {brilho =brilho + 10; } analogWrite (disp001dim, brilho); analogWrite (disp010dim, brilho); analogWrite (disp100dim, brilho); atraso (100); } if (digitalRead (button_less) ==LOW) {if (brilho> =20) {brilho =brilho-10; } analogWrite (disp001dim, brilho); analogWrite (disp010dim, brilho); analogWrite (disp100dim, brilho); atraso (100); }} // checkButtons () void setBusNr (número int) {// define barramento de 4 bits para (byte b =0; b <=3; b ++) {if (números [número] [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 () // extrair dados de nmea inputStringbool nmeaExtractData () {int d =0; int s =0; int y =0; int z =0; float t =0; bool ret =falso; // verdadeiro se nmea frase =$ GNRMC e CHKSUM válido if ((inputString.substring (0,6) =="$ GNRMC") &&(inputString.substring (inputString.length () - 4, inputString.length () - 2) ==nmea0183_checksum (inputString))) {y =0; para (s =1; s <11; s ++) {y =inputString.indexOf (",", y); switch (s) {case 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; pausa; caso 2:// ----------------------- validade z =inputString.indexOf (",", y + 1); if (z> (y + 1)) {nm_validity =inputString.substring (y + 1, y + 1 + 1); } y =z; pausa; caso 3:// ----------------------- latitude 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; pausa; caso 4:// ----------------------- norte / sul z =inputString.indexOf (",", y + 1); if (z> (y + 1)) {nm_latitude =nm_latitude + inputString.substring (y + 1, y + 1 + 1); } y =z; pausa; case 5:// ----------------------- longitude 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; pausa; case 6:// ----------------------- east / west z =inputString.indexOf (",", y + 1); if (z> (y + 1)) {nm_longitude =nm_longitude + inputString.substring (y + 1, y + 1 + 1); } y =z; pausa; caso 7:// ----------------------- nós de velocidade z =inputString.indexOf (",", y + 1); if (z> (y + 1)) {nmf_knots =inputString.substring (y + 1, z) .toFloat (); t =roundOneDec (nmf_knots); nm_knots =String (t, 1) + "kn"; nmf_kmh =roundTwoDec (nmf_knots * 1.852); nmi_kmh =roundZeroDec (nmf_knots * 1.852); } y =z; pausa; case 8:// ----------------------- true course 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; pausa; case 9:// ----------------------- date 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; pausa; caso 10:// declarações n.u. pausa; default:// instruções n.u. pausa; }} ret =verdadeiro; } return ret;} // nmeaExtractData () / * SerialEvent ocorre sempre que um novo dado chega no RX serial do hardware. Essa rotina é executada entre cada execução do loop de tempo (), portanto, usar o atraso dentro do loop pode atrasar a resposta. Vários bytes de dados podem estar disponíveis. * / Void serialEvent () {while (Serial.available ()) {char inChar =(char) Serial.read (); inputString + =inChar; // se o caractere de entrada for uma nova linha, defina um sinalizador para que o loop principal // faça algo a respeito if (inChar =='\ n') {stringComplete =true; }}} // serialEvent () // calcula a soma de verificação de nmea fraseString nmea0183_checksum (String nmea_data) {int crc =0; String chSumString =""; int i; // ignorar o primeiro sinal $, checksum na frase para (i =1; i <(nmea_data.length () - 5); i ++) {// remover o - 5 se não "*" + cksum + cr + Se estiverem presentes crc ^ =nmea_data [i]; } chSumString =String (crc, HEX); if (chSumString.length () ==1) {chSumString ="0" + chSumString.substring (0,1); } chSumString.toUpperCase (); return chSumString;} // nmea0183_checksum (String nmea_data) // arredondar zero decimaisfloat roundZeroDec (float f) {float y, d; y =f * 1; d =y - (int) y; y =(flutuante) (int) (f * 1) / 1; se (d> =0,5) {y + =1; } else {if (d <-0,5) {y - =1; }} return y;} // arredondar uma casa decimal roundOneDec (float f) {float y, d; y =f * 10; d =y - (int) y; y =(flutuante) (int) (f * 10) / 10; se (d> =0,5) {y + =0,1; } else {if (d <-0,5) {y - =0,1; }} return y;} // arredondar dois decimaisfloat roundTwoDec (float f) {float y, d; y =f * 100; d =y - (int) y; y =(flutuante) (int) (f * 100) / 100; se (d> =0,5) {y + =0,01; } else {if (d <-0,5) {y - =0,01; }} return y;} 

Esquemas

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

Processo de manufatura

  1. Derrubando um automóvel semi-autônomo para motoristas com deficiência
  2. Autonomous Driving AI para Donkey Car Garbage Collector
  3. Planejamento de movimento em tempo real para carro autônomo em várias situações , sob ambiente urbano simulado
  4. O que o 5G pode oferecer para o carro conectado?
  5. Segurança:Uma das principais prioridades para os carros do futuro
  6. Cabos de motor para inversores de velocidade variável
  7. Tornos aprimorados para polimento e rebarbação
  8. Torno projetado para precisão e velocidade
  9. Intercâmbio de dados de produtos:um ponto problemático para os fabricantes de automóveis
  10. Como escolher um turbocompressor para o seu carro?