Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Manufacturing Technology >> Processus de fabrication

HUD de voiture - Affichage du pare-brise pour la vitesse et la boussole

Composants et fournitures

Arduino Nano R3
× 1

À propos de ce projet

Descriptif :

Je le voulais ! J'ai été indigne de la grosse voiture de mon ami Taggi qui affichait la vitesse sur le pare-brise. Je devais l'avoir, je devais le faire moi-même bien sûr !

Point de vue logiciel :

Pour projeter le circuit, la partie la plus difficile et la plus déroutante a été la connexion des affichages à 7 segments aux décodeurs BCD car les nombres sont "inversés" (en miroir).

Il y a 3 boutons :+ et - pour augmenter/diminuer la luminosité et S/H pour basculer entre Vitesse en km/h et Cap en degrés; en cas de cap, la LED rouge est également allumée, cela signifie "degrés" de la boussole (1-360°) lors du déplacement. Ce n'est pas une boussole électronique, c'est un GPS et vous devez vous déplacer pour avoir la bonne information sur la direction vers laquelle vous vous dirigez. La luminosité est enregistrée dans l'EEPROM mémoire après une minute. La luminosité est modifiée à la fois sur les écrans et sur les LED via les broches PWM.

Une partie importante du code sert à collecter les données du GPS, principalement la vitesse et la direction, en les retirant de chaque phrase NMEA. Même en utilisant la classe String, principalement pour la manipulation de phrases Serial NMEA, l'ensemble du flux d'élaboration est stable et solide ; il utilise "serialEvent()" pour recevoir les données du GPS une fois par seconde , puis appelle "nmeaExtractData()" et enfin, il vérifie le paquet de données avec "nmea0183_checksum() pour être sûr de l'intégrité des données. Si vous utilisez une autre marque et un autre modèle de GPS, assurez-vous que les phrases ont la même structure ou vous devez apporter des modifications ici . Par exemple, EM406A utilise l'identifiant de paquet "$GPRMC", BT220 utilise "$GNRMC" à la place... juste un petit changement de nom... Un lien utile peut vous aider avec le test de la somme de contrôle :https://nmeachecksum.eqth.net - Voici un exemple de phrase NMEA complète, elle contient :id, time, validity, latitude, longitude, vitesse, cap vrai, date, variation et somme de contrôle.

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

L'esquisse prévoit d'activer le verrou pour chaque décodeur BCD d'affichage un par un, de définir le numéro de code sur le bus binaire 4 bits, de désactiver le verrou, et ainsi de suite lorsque la valeur change. Les zéros non significatifs du côté gauche sont masqués (non affichés).

Avant de charger une nouvelle esquisse à le MCU n'oubliez pas de sortir le Jumper :il est connecté à la broche Rx d'Arduino et lors du chargement, il est à coup sûr en conflit avec le GPS Tx. Après le chargement du logiciel, remettez en place le cavalier pour restaurer la fonctionnalité normale.

Liste des composants :

  • 1 x MCU Arduino Nano
  • 3 x 5161en tant qu'écrans à sept segments, cathode commune, rouge
  • 1 x GPS TTL série Beitian BN-220 (phrases GNRMC 1 Hz)
  • 1 x Cavalier
  • 3 x boutons (normalement ouverts) + 3 x capuchons
  • 22 résistances 1/4 W 220 ohms
  • 1 LED 3 mm, rouge
  • 2 condensateurs de 100 n
  • 3 décodeurs BCD 14511 + loquet
  • 1 x USB "B" femelle
  • 1 x strip line 2x broches mâles (pour Jumper)
  • 1 x strip line 4x broches mâles à plier à 90° (pour GPS)
  • 1 câble en queue de cochon reliant le GPS à 4 broches à bord
  • 22 broches mâles de ligne à ruban pour joindre deux circuits imprimés dans une pile
  • 1 x morceau d'adhésif double face pour coller le GPS sur le PCB
  • 6 x lignes à ruban tournées 5x broches femelles (pour les écrans)
  • 50 rivets en cuivre 0,6 mm
  • 8 vis M3
  • 4 tours femelles M3 de 20 mm de haut
  • 1 x boîte en plastique + couvercle (regardez mes fichiers 3D prêts pour l'impression, ci-dessous)

PCB (circuits imprimés) :

J'ai utilisé deux PCB double face pour cette raison, une cinquantaine de rivets ou de goupilles traversants sont utilisés pour résoudre des itinéraires pour des circuits entiers. Il y a aussi 5 trous d'alignement faire en premier. J'ai conçu sur chaque PCB ces 5 points d'alignement. Dans la section de téléchargement, vous avez tous les fichiers PCB, composants et faces de soudure, en miroir, à télécharger et à imprimer au moyen d'une imprimante laser sur des feuilles "jaunes" ou "bleues"; cette fois j'ai utilisé les bleus mais aussi les jaunes sont bons et le prix est plus bas. Je dois dire que les feuilles bleues sont meilleures... Lors de l'impression, n'oubliez pas de désactiver les paramètres d'économie de toner, utilisez plutôt une résolution de 1200 dpi pour obtenir un résultat noir profond et réel. Le processus de transfert de toner des feuilles magiques au PCB se fait à l'aide d'un fer chaud... Autour du Net il y a quelques tutoriels montrant comment produire un bon PCB mais n'oubliez pas ces points importants :nettoyer parfaitement et brosser légèrement le cuivre avec une éponge ruvid de cuisine, 5 minutes de repassage, choc thermique à l'eau, alignement des deux faces en passant par 5 trous (j'ai utilisé 5 broches sur une grande surface LED blanche pour voir trous), protégez l'autre face pendant le processus de corrosion. L'impression aussi des composants face rend le projet "professionnel" :-)

REMARQUES : les photos sont prises avant la toute dernière version, cela signifie que quelques détails peuvent être différents :par exemple, l'étrange fil vert autour des PCB dans la version finale disparaît, ou le Jumper est passé du PCB #1 au PCB #2. Vous devez configurer le GPS à une vitesse de 9600 bps, phrase GNRMC NMEA de 1 Hz uniquement ; cela peut être fait en utilisant son propre logiciel de configuration. Enfin, avant de souder le connecteur USB femelle, collez un petit morceau de ruban isolant en dessous pour éviter tout contact indésirable avec une ligne en cuivre, côté composant, juste en dessous.

En donnant le pouvoir pour la première fois, vous découvrirez que les chiffres sont "illisibles", car il est fait pour les regarder se refléter sur le pare-brise (miroir). Installez-le dans la voiture à l'avant du siège conducteur , trouvez un endroit confortable et réparez-le. Je suggère de connecter le câble d'alimentation USB après la position d'allumage afin qu'il s'allume / s'éteigne lorsque le moteur s'allume / s'éteint. C'est tout mesdames et messieurs !

Nouveautés et améliorations :

  • 25.03.2021 :pour terminer le projet j'ai préparé deux modèles 3D .STL à ce lien :https://grabcad.com/library/car-hud-1 où vous pouvez télécharger des fichiers concernant une boîte en forme et son panneau de couverture pour ce projet à imprimer à l'aide d'une imprimante 3D.
  • 20.07.2021 :il est disponible une V2 (version deux) du logiciel qui, avec deux fils et une résistance, vous aurez des informations d'altitude sur l'écran en milliers de mètres (c'est-à-dire 0,89 =890 m), appuyez simplement une autre fois sur le bouton S/H ! Instructions :1) configurer le GPS pour qu'il génère également la phrase nmea $GNGGA via son propre logiciel ; 2) coupez la connexion réelle entre la broche pwm d5 Arduino et le reste du circuit, connectez-la à la broche à point décimal de l'affichage central avec une résistance de 220 ohms; 3) connectez la broche numérique d13 Arduino au circuit où d5 était connecté ; regardez quelques images ci-dessous; 4) installez V2 sketch sur votre Arduino Nano.
  • 01.11.2021 :la version V2.2 est prête pour vous. Quoi de neuf? Concernant l'altitude (déjà présente avec V2), le hud affiche une valeur complète jusqu'à 999 m, à partir de 1000 m, il affiche des valeurs en milliers, c'est-à-dire 1,24 (1240 m) ou 2,02 (2020 m). J'ai ajouté une photorésistance LDR GL5539, une résistance de 10kOhm et 2 fils. Regardez les images ci-dessous pour les mods V2.2 et installez le sketch V2.2 sur votre Arduino. Le capteur LDR modifiera automatiquement la luminosité (3 niveaux) en fonction du niveau de luminosité (jour, nuageux ou nuit). Les boutons (+) et (-) fonctionnent toujours pour modifier manuellement la luminosité, ils sont prioritaires; pour revenir en mode automatique, appuyez simultanément sur les boutons (+) et (-) pendant un moment. L'EEPROM interne pour stocker le niveau de luminosité n'est plus utilisée. Faisons d'abord les mods V2 !

Lorsque vous conduisez, conduisez simplement. Conduisez prudemment !

Code

  • Croquis Arduino Car-HUD
Croquis Arduino Car-HUDArduino
/* Ce croquis agit comme HUD de pare-brise de voiture (affichage tête haute), par Marco Zonca, 10/2020 Arduino Nano comme CPU, GPS BT-220 nmea toutes les 1 seconde, 3 x boutons, 3 x sept segments affiche cathode commune , décodeur de verrouillage BCD 3 x 14511, mémoire EEPROM MPU (1 octet) et de nombreuses résistances ; AVERTISSEMENT : =======Avant de mettre à jour le logiciel, déconnectez la broche RX sur Arduino (TX du GPS) via le 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/yyyy";int nmi_truecourse =0;byte kCent =0;octet kDeci =0;octet kUnit =0;octet tCent =0;octet tDeci =0;octet tUnit =0;octet luminosité =120;octet latch_off =HIGH;octet latch_on =LOW;int n=0;unsigned long lastmemcheck =0 ; long non signé memcheck =60000 ; // vérifier pour enregistrer la valeur "luminosité" dans l'EEPROM toutes les 60 secondesbool stringComplete =false;bool isKMH=true;bool ret =false;const int disp001 =2; // les unités affichent latchconst int disp010 =8; // affichage des dizaines latchconst int disp100 =12; // undreds affiche latchconst int disp001dim =9; // les unités affichent le gradateur/désactivé pinconst int disp010dim =10; // affichage des dizaines dimmer/off pinconst int disp100dim =11; // undreds display dimmer/off pinconst int button_kt =14; // kmh/truecourse buttonconst int button_more =15; // luminosité + buttonconst int button_less =16; // luminosité - buttonconst int degrésLED =3; // degrés 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; // délai de verrouillage m/secconst octet off =0; // identique à luminosité=0const int addr =0; // Adresse EEPROM pour les nombres d'octets de la valeur de luminosité [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); Fil.begin(); inputString.reserve(200); luminosité =EEPROM.read(addr); if (luminosité> 250 || luminosité <10) { luminosité=120; } // évite les valeurs folles de la 1ère lecture EEPROM pinMode(disp001, OUTPUT); pinMode(disp010, SORTIE); pinMode(disp100, SORTIE); pinMode(degrésLED, SORTIE); pinMode(button_kt, INPUT_PULLUP); pinMode(button_less, INPUT_PULLUP); pinMode(button_more, INPUT_PULLUP); pinMode(bit_3, SORTIE); pinMode(bit_2, SORTIE); pinMode(bit_1, SORTIE); pinMode(bit_0, SORTIE); analogWrite(disp001dim, off); // off et zéro affiche analogWrite(disp010dim, off); analogWrite(disp100dim, off); analogWrite (degrésLED, éteint); setBusNr(0) ; digitalWrite(disp001, latch_on); digitalWrite(disp010, latch_on); digitalWrite(disp100, latch_on); retarder (dly); digitalWrite(disp001, latch_off); digitalWrite(disp010, latch_off); digitalWrite(disp100, latch_off); analogWrite(disp001dim, luminosité); // sur l'affichage analogWrite(disp010dim, luminosité); analogWrite(disp100dim, luminosité);} // setup()void loop() { // GPS NMEA ------------------ if (stringComplete ==true) { // phrase nmea reçue par le port série RX ret =nmeaExtractData(); chaîne d'entrée ="" ; stringComplete =false; if (ret ==vrai) { 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); tDéci=n/10 ; n=nmi_truecourse-(tCent*100)-(tDeci*10) ; tUnité=n; affichage(); } } if (millis()> (lastmemcheck+memcheck)) { // mettre en mémoire la valeur de luminosité (si modifiée) EEPROM.update(addr,brightness); lastmemcheck=millis(); } checkButtons();}void display() { if (isKMH ==true) { // vitesse en km/h (isKMH=true) analogWrite(degreesLED, off); setBusNr(kUnit); digitalWrite(disp001, latch_on); retarder (dly); digitalWrite(disp001, latch_off); if (kDeci> 0 || kCent> 0) { // désactiver les dizaines if tens=0 (et aussi undreds=0) setBusNr(kDeci); digitalWrite(disp010, latch_on); retarder (dly); digitalWrite(disp010, latch_off); analogWrite (disp010dim, luminosité); } else { analogWrite(disp010dim, off); } if (kCent> 0) { // désactive les désactivations if=0 setBusNr(kCent); digitalWrite(disp100, latch_on); retarder (dly); digitalWrite(disp100, latch_off); analogWrite (disp100dim, luminosité); } else { analogWrite(disp100dim, off); } } else { // relèvement vrai en degrés (isKMH=false) analogWrite(degreesLED, luminosité); setBusNr(tUnit); digitalWrite(disp001, latch_on); retarder (dly); digitalWrite(disp001, latch_off); if (tDeci> 0 || tCent> 0) { // désactiver les dizaines if tens=0 (et aussi undreds=0) setBusNr(tDeci); digitalWrite(disp010, latch_on); retarder (dly); digitalWrite(disp010, latch_off); analogWrite (disp010dim, luminosité); } else { analogWrite(disp010dim, off); } if (tCent> 0) { // désactive les désactivations if=0 setBusNr(tCent); digitalWrite(disp100, latch_on); retarder (dly); digitalWrite(disp100, latch_off); analogWrite (disp100dim, luminosité); } else { analogWrite(disp100dim, off); } }} // display() void checkButtons(){ if (digitalRead(button_kt) ==LOW) { if (isKMH ==true) { isKMH=false; } else { isKMH=true; } délai (250); } if (digitalRead(button_more) ==LOW) { if (luminosité <=240) { luminosité=luminosité+10; } analogWrite(disp001dim, luminosité); analogWrite (disp010dim, luminosité); analogWrite (disp100dim, luminosité); retard (100); } if (digitalRead(button_less) ==LOW) { if (luminosité>=20) { luminosité=luminosité-10; } analogWrite(disp001dim, luminosité); analogWrite (disp010dim, luminosité); analogWrite (disp100dim, luminosité); retard (100); }} // checkButtons()void setBusNr(int number) { // définit un bus de 4 bits pour (byte b=0; b<=3; b++) { if (numbers[number][b]==0) { if (b==0) {digitalWrite(bit_0, LOW);} si (b==1) {digitalWrite(bit_1, LOW);} if (b==2) {digitalWrite(bit_2, LOW);} si (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()// extrait les données de nmea inputStringbool nmeaExtractData() { int d=0 ; entier s=0; entier y=0; entier z=0; flottant t=0; bool ret =faux ; //true if nmea phrase =$GNRMC et CHKSUM valide if ((inputString.substring(0,6) =="$GNRMC") &&(inputString.substring(inputString.length()-4,inputString.length()- 2) ==nmea0183_checksum(inputString))) { y=0; for (s =1; s <11; s ++) { y=inputString.indexOf(",",y); switch (s) { cas 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; Pause; cas 2 ://-----------------------validité z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_validity=inputString.substring(y+1,y+1+1); } y=z; Pause; cas 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; Pause; cas 4://-----------------------nord/sud z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_latitude=nm_latitude + inputString.substring(y+1,y+1+1); } y=z; Pause; cas 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; Pause; cas 6 ://----------------------- est/ouest z=inputString.indexOf(",",y+1); if (z>(y+1)) { nm_longitude=nm_longitude + inputString.substring(y+1,y+1+1); } y=z; Pause; cas 7 ://----------------------- nœuds de vitesse z=inputString.indexOf(",",y+1); if (z>(y+1)) { nmf_knots=inputString.substring(y+1,z).toFloat(); t=roundOneDec(nmf_knots); nm_knots=Chaîne(t,1)+"kn" ; nmf_kmh=roundTwoDec(nmf_knots * 1.852); nmi_kmh=roundZeroDec(nmf_knots * 1.852); } y=z; Pause; cas 8 ://-------------bien sûr 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; Pause; cas 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; Pause; cas 10 :// déclarations n.u. Pause; par défaut :// instructions n.u. Pause; } } ret=vrai; } return ret;} // nmeaExtractData()/* SerialEvent se produit chaque fois qu'une nouvelle donnée arrive dans le RX série matériel. Cette routine est exécutée entre chaque exécution de loop(), donc l'utilisation du délai dans la boucle peut retarder la réponse. Plusieurs octets de données peuvent être disponibles.*/void serialEvent() { while (Serial.available()) { char inChar =(char)Serial.read(); chaîne d'entrée +=inChar; // si le caractère entrant est une nouvelle ligne, définissez un indicateur pour que la boucle principale puisse // faire quelque chose à ce sujet if (inChar =='\n') { stringComplete =true; } }} // serialEvent()//calculer la somme de contrôle de nmea phraseString nmea0183_checksum(String nmea_data) { int crc =0; Chaîne chSumString =""; int je; // ignore le premier signe $, somme de contrôle dans la phrase pour (i =1; i <(nmea_data.length()-5); i ++) { // supprime le - 5 si non "*" + cksum + cr + Si sont présents 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)// round zero decimalsfloat roundZeroDec(float f) { float y, d; y =f*1 ; d =y - (int) y ; y =(float)(int)(f*1)/1 ; si (d>=0,5) { y +=1; } else { if (d <-0,5) { y -=1; } } return y;}// arrondir un décimalfloat roundOneDec(float f) { float y, d; y =f*10 ; d =y - (int) y ; y =(float)(int)(f*10)/10 ; si (d>=0,5) { y +=0,1 ; } else { if (d <-0,5) { y -=0,1; } } return y;}// arrondir deux décimalesfloat roundTwoDec(float f) { float y, d; y =f*100 ; d =y - (int) y ; y =(float)(int)(f*100)/100 ; si (d>=0,5) { y +=0,01 ; } else { si (d <-0,5) { y -=0,01 ; } } retourne y;}

Schémas

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

Processus de fabrication

  1. Démolition d'une voiture semi-autonome pour conducteurs handicapés
  2. Autonomous Driving AI for Donkey Car Garbage Collector
  3. Planification de mouvement en temps réel pour une voiture autonome dans plusieurs situations, dans un environnement urbain simulé
  4. Que peut apporter la 5G pour la voiture connectée ?
  5. Sécurité :une priorité absolue pour les voitures du futur
  6. Câbles moteur pour variateurs de vitesse
  7. Tours améliorés pour le polissage et l'ébavurage
  8. Tour conçu pour la précision et la vitesse
  9. L'échange de données produit :un problème pour les constructeurs automobiles