Ein robustes Robot Car mit Fernsteuerung

Dans l'introduction de notre série de blogs sur les voitures robot, nous avons déjà mentionné qu'en termes d'alimentation et d'adéquation pour les débutants, notre carte microcontrôleur avec ATmega328P, ATmega16U2, compatible avec Arduino UNO R3, est le premier choix. Avec elle, nous voulons construire aujourd'hui notre premier Robot Car. Ensuite, à l'aide d'une seconde carte MC, nous voulons développer une télécommande simple avec un émetteur/récepteur de 433 MHz. Allons-y.

Matériel nécessaire dans la première partie

Nombre Composantes
1 Carte de microcontrôleur avec atmega328p, atmega16u2, compatible avec arduino uno R3
1 4 canaux L293D Shield Motor Driver
1 Châssis de véhicule robotique à deux ou quatre roues
Batterie / batterie, par exemple 2 x 18650 batterie lipo


Matériel nécessaire dans la deuxième partie

Nombre Composantes
1 Carte de microcontrôleur avec atmega328p, atmega16u2, compatible avec arduino uno R3
1 Le clavier LCD protège uno R3 et d'autres.
2 Module émetteur / récepteur HC - 12 433 MHz (malheureusement plus dans la plage)
Piles / batteries, p.ex. 2 x 18650 piles lipo ou 9V


En plus des instructions de construction fournies avec les kits, voici quelques conseils pour le montage du microcontrôleur et du compartiment de la batterie :

Le bouclier du conducteur est livré avec une petite plaque de mousse pour protéger les nombreux contacts. Je l'ai enregistré sous le microcontrôleur avec du ruban adhésif double face (moquette) puis sur le châssis. Cela m'évite de percer de nouveaux trous et de visser des entretoises.

J'ai utilisé du ruban velcro autocollant pour fixer le compartiment des piles, afin de pouvoir le retirer rapidement si nécessaire.

Bibliothèque de programmes pour les moteurs :

Comme souvent, Lady Ada (Limor Fried), avec l'équipe d'Adafruit, a développé une très bonne bibliothèque, que nous pouvons facilement intégrer dans l'environnement de développement avec le responsable de la bibliothèque. En raison du IC 74HC595 (registre à décalage), la programmation du bouclier du conducteur est relativement complexe, mais Adafruit nous a débarrassé de ce travail. L'utilisation des méthodes (fonctions) de la bibliothèque AFMotor.h nous permet d'envoyer facilement des commandes de mouvement à la voiture robot. Veuillez noter : Adafruit a aujourd'hui le Motor Shield V2 dans sa gamme de produits. Nous utilisons l'"ancienne" bibliothèque, pour ainsi dire, et non la V2. Voir l'image suivante "Gestionnaire de la bibliothèque", entrée supérieure.


Le fragment de code pour instancier les quatre moteurs est :


« 35; comprend < afmotor.h >
Moteur AF / DC 1 (4);
Moteur AF / DC 2 (3);
Moteur AF / DC 3 (1);
Moteur AF / DC 4 (2);

Vous vous interrogez sur les écarts entre les chiffres ? Je ne voulais pas changer les connexions des moteurs dans ma configuration dans la bibliothèque de programmes, mais je voulais également conserver ma systématique pour la numérotation des moteurs (gauche impair, droite pair, de l'avant à l'arrière). Pour deux moteurs, vous pouvez commenter ou supprimer les lignes dont vous n'avez pas besoin.

Dans le code du programme suivant, les quatre objets motor1 à motor4 peuvent ensuite être modifiés avec les méthodes run() et setSpeed(), par exemple


motor1.run(FORWARD);
motor1.setSpeed(200);;

La méthode run() connaît les paramètres FORWARD, BACKWARD et RELEASE.

La méthode setSpeed() accepte un nombre entier entre 0 et 255, également comme variable pouvant prendre ces valeurs. À ce stade, cependant, je voudrais lancer un avertissement, dont nous aborderons les implications plus tard : La valeur 255 signifie que le voltage complet est fourni par la source de tension externe, donc environ 8V pour mes deux batteries LiPo. Cependant, les moteurs sont conçus pour une tension de 5V. Ma valeur la plus élevée n'est donc peut-être que d'environ 150 !


Dans un premier temps, je recommande un test fonctionnel avec l'exemple de croquis MotorTest installé avec la bibliothèque de programmes. Essayez les chiffres de 1 à 4 de la ligne


AF_DCMotor motor(4);


pour déterminer le brochage et se souvenir de la valeur maximale de setSpeed() dans les boucles pour si on utilise une tension supérieure à 5V.


Je suis sûr que vous êtes d'accord pour dire qu'il est ennuyeux d'utiliser un profil de conduite préprogrammé. D'une manière ou d'une autre, vous voulez contrôler le véhicule. Avec le Raspberry Pi, je pouvais connecter un clavier sans fil ou utiliser une connexion WLAN comme avec les microcontrôleurs ESP. Malheureusement, cela n'est pas possible avec notre simple carte microcontrôleur avec ATmega328P, ATmega16U2, compatible avec Arduino UNO R3. Mais j'avais testé le module émetteur/récepteur 433MHz HC-12 il y a quelques mois et j'ai écrit un blogpost en trois parties (lien vers la partie 1, partie 2, partie 3) à ce sujet. Je peux peut-être utiliser ces connaissances à nouveau.

Considérations préliminaires :

  1. Si je veux envoyer un code pour la télécommande, il doit être clairement résoluble, mais aussi pas trop long. Lors de précédentes tentatives avec le HC-12, j'avais réussi à utiliser un code à quatre chiffres pour allumer et éteindre une LED.
  2. Lorsque je connecte un joystick analogique au Micro Controller, j'obtiens des valeurs entre 0 et 1023 avec des valeurs pour les axes x et y de 511 chacun en position centrale pour une entrée analogique de 10 bits.

Pour la direction y (plus tard en avant et en arrière), je divise cette valeur par 100 et j'obtiens 11 pas de vitesse de 0 à 10 avec un arrêt à 5. L'idée des pas de vitesse peut être transférée à d'autres contrôleurs et offre d'autres avantages (voir ci-dessous).

  1. Le contrôle de la vitesse se fait par modulation de largeur d'impulsion (PWM), de sorte que les pas de vitesse doivent être convertis en valeurs de cycle d'utilisation pour la PWM dans le croquis pour le contrôleur de moteur du Robot Car. Seuls les pas de vitesse sont utilisés dans le croquis pour la télécommande.
  2. Faire tourner la voiture robot signifie qu'un moteur tourne plus vite et l'autre plus lentement. Ici, je décide de quatre pas chacun, qui provoquent l'augmentation ou la diminution respective des valeurs du moteur gauche ou droit.
  3. Pour pouvoir réaliser plusieurs possibilités de saisie (joystick, clavier à touches ou saisie au clavier) je me décide pour le code 505 pour la position de repos. Le numéro arrière (entre 1 et 9) correspond aux virages, le numéro avant (entre 0 et 10) au niveau de conduite. Ainsi, par exemple, le code 1005 pour la ligne droite la plus rapide, 505 pour l'arrêt, 707 pour l'avance à droite.

Axe Y 0 X X X

1

2

3

4

5

6

7

8

9

10

9

8

7

6

5

0

4

3

2

1

0


Pour l'instant, je vais opter pour le blindage du clavier LCD car il comporte cinq boutons pour ma télécommande et un écran LCD intégré pour afficher le code que j'envoie.

  1. Dans le code, le plus grand nombre possible de numéros est limité par des "if-queries".
  2. Les codes supérieurs à 1010 sont disponibles pour d'autres fonctions (par exemple, les servos).


Le LCD-Keypad-Shield :

Les cinq boutons de l'écran du clavier LCD sont connectés à l'entrée A0 avec des diviseurs de tension. Andreas Wolter a bien expliqué comment cela fonctionne dans son blog Arduino : Multi-IO et EEPROM - [Partie 1].

À côté, il y a les broches A1 à A5, que je veux utiliser pour l'émetteur HC-12 à 433 MHz. Pour cela, j'y soude un connecteur femelle. Je fais la même chose pour le bouclier du conducteur du moteur ; ici aussi, les entrées analogiques sont facilement accessibles.


Attribution des broches :

A1=GPIO15 pour l'alimentation électrique 5V

A2=GPIO16 pour GND

A3=GPIO17 et A4=GPIO18 pour RX/TX via SoftwareSerial

Deux autres notes sur le bouclier du moteur :

1. Si les câbles aux bornes du moteur (à gauche sur la photo, à droite cachés par le HC-12) sont interchangeables, la polarité de l'alimentation électrique externe doit être strictement respectée.

2. Le jumper (fiche de court-circuit) PWRJMP au milieu de l'image relie le microcontrôleur à l'alimentation électrique externe. Ne connectez le MCU à l'ordinateur via USB que lorsque la broche est ouverte. Cependant, même dans ce cas, l'isolation galvanique n'est pas assurée par l'ensemble du circuit.


Schéma de la télécommande:

/*
LCD-Keypad-Shield as MotorController, stand still = 505
je 5 Stufen vor/zurück, je 3 Stufen rechts/links
*/

#include <SoftwareSerial.h>

//Pin assignment for HC-12 Transceiver
SoftwareSerial mySerial(18, 17); //RX, TX
int HC12PWR = 15;
int HC12GND = 16;
//int HC12SET = 19;

// LCD without I2C-Adapter
// Die Daten werden über die Pins D4 bis D7 übertragen
#include <LiquidCrystal.h>
//LCD pin to Arduino
const int pin_EN = 9;
const int pin_RS = 8;
const int pin_D4 = 4;
const int pin_D5 = 5;
const int pin_D6 = 6;
const int pin_D7 = 7;
LiquidCrystal lcd( pin_RS, pin_EN, pin_D4, pin_D5, pin_D6, pin_D7);

int x = 5;
int y = 5;
int delay4bounce = 250;

void setup() {
  pinMode(HC12PWR,OUTPUT);
  digitalWrite(HC12PWR,HIGH);
  pinMode(HC12GND,OUTPUT);
  digitalWrite(HC12GND,LOW);
  // pinMode(HC12SET,OUTPUT);
  // digitalWrite(HC12SET,LOW);
  mySerial.begin(9600);
  // Initialisierung des eingebauten LCD
  lcd.begin(16, 2); //LCD1602 mit 16 Zeichen und 2 Zeilen
  lcd.setCursor(0,0); //Zählung beginnt bei Null, erst Zeichen, dann Zeile
  lcd.print("AZ-Delivery.com");
  lcd.setCursor(0,1); // 0=Erstes Zeichen, 1=zweite Zeile
  lcd.print("Press Key:");
}

void sendcode() {
  mySerial.println(100*y + x);  //send code for motor
  delay(200); // little delay for next button press
}

void loop() {
  int A0;
  // alle Taster liegen über einen Spannungsteiler an A0
  // mit 3,9 kOhm Widerstand liegen die Spannungen zwischen 0 und 3,3 V
  // Werte des ADC liegen zwischen 0 und 1023
  // ggf. müssen die Werte angepasst werden
  A0 = analogRead (0); //
  lcd.setCursor(10,1); // Cursor beginnt hinter "Press Key"

  if (A0 < 60) {
    x = x+1;
    if (x>9) {x=9;}
    delay(delay4bounce);
    lcd.print (" ");
    lcd.setCursor(10,1);
    lcd.print (100*y + x);
    sendcode();
  }
  else if (A0 < 250) {
    y = y+1;
    if (y>10) {y=10;}
    delay(delay4bounce);
    lcd.print (" ");
    lcd.setCursor(10,1);
    lcd.print (100*y + x);
    sendcode();
  }
  else if (A0 < 400){
    y = y-1;
    if (y<0) {y=0;}
    delay(delay4bounce);
    lcd.print (" ");
    lcd.setCursor(10,1);
    lcd.print (100*y + x);
    sendcode();
  }
  else if (A0 < 700){
    x = x-1;
    if (x<1) {x=1;}
    delay(delay4bounce);
    lcd.print (" ");
    lcd.setCursor(10,1);
    lcd.print (100*y + x);
    sendcode();
  }
  else if (A0 < 900){
    x = 5;
    y = 5;
    delay(delay4bounce);
    lcd.print (" ");
    lcd.setCursor(10,1);
    lcd.print (100*y + x);
    sendcode();
  }
  else {
    lcd.setCursor(10,1);
    lcd.print (100*y + x);
    sendcode();
  }
}




Maintenant, avant de présenter un éventuel croquis pour la voiture-robot ci-dessus, j'aimerais revenir sur l'idée qui se cache derrière les marches de conduite :

L'hypothèse selon laquelle la vitesse du moteur est proportionnelle à la tension n'est que partiellement correcte. En raison de leur conception, les moteurs ne tournent pas à basse tension. Vous entendez un bourdonnement, mais le couple ne suffit pas pour démarrer. La première étape de vitesse est donc à un cycle d'utilisation d'au moins 30-40%. Et nous avions vu que selon la source de tension utilisée, nous devons baisser la tension pour l'étage le plus élevé, environ 66% dans mon cas. Mes cinq niveaux de conduite par direction ont donc un cycle d'utilisation compris entre 30 et 66. Je les mets dans une liste et j'accède à la valeur correspondante à l'aide de l'index. J'ai utilisé les valeurs suivantes pour le sketch Arduino avec la motothèque ci-dessus.

Int speedlevel [11] = {65, - 57, - 49, - 41, - 33,0,33,41,49,57,65};


Attention : Il existe également des différences dans les microcontrôleurs : avec le PWM 8 bits, les valeurs sont comprises entre 0 et 255, avec le PWM 10 bits entre 0 et 1023, avec le Raspberry Pi et le module gpiozero entre -1 et +1. 

Avec le facteur multiplicateur, j'ajuste ensuite les valeurs pour le système respectif. Mais les valeurs de la liste peuvent bien sûr être ajustées en fonction de la situation.

Et il se peut que vous deviez aussi jouer un peu avec les valeurs du détournement. Avec les quatre niveaux par direction que j'utilise, j'augmente ou je diminue les valeurs pour le "speedLevel" respectif des deux côtés.


Par ici. Robot car sketch Utilisation de la télécommande:


// Adafruit Motor shield library
// copyright Adafruit Industries LLC, 2009
// this code is public domain, enjoy!
// modified for AZ-Delivery

#include <AFMotor.h>
AF_DCMotor motor1(4);
AF_DCMotor motor2(3);
AF_DCMotor motor3(1);
AF_DCMotor motor4(2);
#include <SoftwareSerial.h>

// initialize HC-12
SoftwareSerial mySerial(18, 17); // RX, TX
int HC12PWR = 15;
int HC12GND = 16;
//int HC12SET = 19;

int x = 0;
int y = 0;
int left = 0;
int right = 0;
int code = 505;
int codeRead = 505;
int speedL = 0;
float faktor = 2.2; // Korrektur für Fahrtstufe

void setup() {
  Serial.begin(9600); // set up Serial Monitor at 9600 bps
  Serial.println("Motor test!");
  mySerial.begin(9600); // set up transmission speed for HC-12
  // initialize HC-12 power supply
  pinMode(HC12PWR,OUTPUT);
  digitalWrite(HC12PWR,HIGH);
  pinMode(HC12GND,OUTPUT);
  digitalWrite(HC12GND,LOW);
  // pinMode(HC12SET,OUTPUT);
  // digitalWrite(HC12SET,LOW);

  // turn on motor
  // motor4.setSpeed(200);
  // motor4.run(RELEASE);
}

void loop() {
  if (mySerial.available() > 1) {
    //read serial input and convert to integer (-32,768 to 32,767)
    codeRead = mySerial.parseInt();
    Serial.print("code received: ");
    Serial.println(codeRead);
    if (codeRead<=1010) {
      if (code != codeRead) {
        code = codeRead;
      }
    }
    else {
      Serial.print("wrong code received: ");
      code = 505;
    }
  }
  else {
    code = 505;
  }
  motor();

  mySerial.flush();//clear the serial buffer for unwanted inputs

  delay(20); //little delay for better serial communication
}

void motor(){
  int speedLevel[11]={-65,-57,-49,-41,-33,0,33,41,49,57,65};
  y = int(code /100);
  x = code - 100*y;
  speedL = speedLevel[y];
  Serial.print("code = ");
  Serial.print(code);
  Serial.print(" y = ");
  Serial.print(y);
  Serial.print(" x = ");
  Serial.print(x);
  Serial.print(" speedL = ");
  Serial.println(speedL);

  //Korrektur der Fahrtstufen für Kurvenfahrt
  if (x==0){
    right = speedL+16;
    left = speedL-16;
  }
  else if (x==1){
    right = speedL+16;
    left = speedL-16;
  }
  else if (x==2){
    right = speedL+13;
    left = speedL-13;
  }
  else if (x==3) {
    right = speedL+10;
    left = speedL-10;
  }
  else if (x==4) {
    right = speedL+7;
    left = speedL-7;
  }
  else if (x==6) {
    right = speedL -7;
    left = speedL+7;
  }
  else if (x==7) {
    right = speedL-10;
    left = speedL+10;
  }
  else if (x==8) {
    right = speedL-13;
    left = speedL+13;
  }
  else if (x==9) {
    right = speedL-16;
    left = speedL+16;
  }
  else if (x==10) {
    right = speedL-16;
    left = speedL+16;
  }
  else {
    right = speedL;
    left = speedL;
  }

  //Eingabe der Fahrtstufen für "left" und "right"
  Serial.print("left = ");
  Serial.print(left);
  Serial.print(" right = ");
  Serial.println(right);

  if (left < 25 & left > -25) {
    motor1.run(RELEASE);
    motor3.run(RELEASE);
  }

  if (right < 25 & right > -25) {
    motor2.run(RELEASE);
    motor4.run(RELEASE);
  }
  if (left>=25) {
    if (left>65) left=65;
      motor1.run(FORWARD);
      motor3.run(FORWARD);
      motor1.setSpeed(left * faktor);
      motor3.setSpeed(left * faktor);
  }
  if (right>=25) {
    if (right>65) right=65;
      motor2.run(FORWARD);
      motor4.run(FORWARD);
      motor2.setSpeed(right * faktor);
      motor4.setSpeed(right * faktor);
  }
  if (left<= -25) {
    if (left<-65) left=-65;
      motor1.run(BACKWARD);
      motor3.run(BACKWARD);
      motor1.setSpeed(-left * faktor);
      motor3.setSpeed(-left * faktor);
  }
  if (right<= -25) {
    if (right<-65) right=-65;
      motor2.run(BACKWARD);
      motor4.run(BACKWARD);
      motor2.setSpeed(-right * faktor);
      motor4.setSpeed(-right * faktor);
  }
}

 


Avec la carte microcontrôleur avec ATmega328P, ATmega16U2, compatible avec Arduino UNO R3, nous avons un MCU robuste, facile à programmer avec l'IDE Arduino. Convient parfaitement non seulement pour entrer dans le monde de la programmation (nouvel allemand : pensée informatique), mais aussi pour accéder aux circuits électroniques (nouvel allemand : informatique physique).

Le moteur L293D à 4 canaux Shield permet de démarrer facilement avec la robotique en utilisant les bibliothèques de programmes existantes telles que la bibliothèque Adafruit <AFMotor.h>.

Dans d'autres articles du blog, nous présenterons des solutions alternatives avec d'autres microcontrôleurs et d'autres options de contrôle à distance.

Télécharger le pdf


Amateurfunk (amateurfunk)Pour arduino

Laisser un commentaire

Tous les commentaires sont modérés avant d'être publiés

Messages de blogs recommandés

  1. Installez maintenant ESP32 via l'administrateur de la carte
  2. Lüftersteuerung Raspberry Pi
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1
  4. ESP32 - das Multitalent
  5. OTA-Over the Air-ESP Programmation par WiFi

Produits recommandés