Robot sur Chassis Chenille et Bras Robotique avec Arduino et Raspberry Version 2

Plan et Schéma pour réaliser RaspCurioDuino from scratch, le principal avantage sur cette version et que on peut alimenter le drone via un powerbank disposant de 2 ports USB, l’arduino sera alimenté via son port serie en USB et le raspberry sera alimenté sur l’autre pose USB. La communication entre Raspberry et Arduino serra effectuée via les PIN GPIO RX/TX des deux péripéhriques.

Carte contrôleur pour deux moteurs courant continu compatible arduino L9110S H-pont

Un lot de cables dupont permettant de connecter les composants sur la breadboard du shield de prototypage

Le chassis type tank avec chenille avec les deux moteurs courant continu

Un Raspberry Pi Modèle 3 et sa coque permettant de les superposer avec l’arduino et facilite la ventilation dans le boitier.

Une clef Wifi compatible Raspberry permettant un accès réseau sans fils au raspberry

La caméra infrarouge pour la vision, compatible Raspberry et « Motion » sous Raspbian Stretch

Un servo moteur afin de permettre la rotation de la caméra

Un arduino UNO classique sur lequel on positionnera un shield de prototypage. Le Shield de prototypage permet d’avoir plus de PIN 5V et GND disponible pour les branchements de tout les modules.(Indispensable car l’arduino uno seul ne délivre pas assez de courant pour tout gérer correctement )

Afin de permettre des mouvements au robot j’ai ajouté ce bras robotique bon marché.

Montage Finale,

L’ensemble des sources de l’interface Web de contrôle hébergé sur Raspberry est disponible

Code à déployer dans l’Arduino, veillez à bien faire correspondre les PIN de chaque modules, pour l’expliquer brievement, l’arduino reste en écoute sur son port serie. Lorsqu’il recoit une chaine il va déclencher la fonction correspondante.

#include <Servo.h>

//string pour data from serial
String readString;


const int A1A = 10;//define pin 2 for A1A
const int A1B = 11;//define pin 3 for A1B

const int B1A = 8;//define pin 8 for B1A
const int B1B = 9;//define pin 9 for B1B

Servo monservosocle;  
Servo monservopincehautbas;
Servo monservopince;  
Servo monservoaxehautbas;
Servo monservocamera;


void setup(){
  Serial.begin(9600);

  pinMode(B1A,OUTPUT);// define pin as output
  pinMode(B1B,OUTPUT);
 
  pinMode(A1A,OUTPUT);
  pinMode(A1B,OUTPUT);  

 
  pinMode(LED_BUILTIN, OUTPUT);



 
  monservosocle.attach(6);  
  monservopince.attach(7);  
  monservoaxehautbas.attach(5);
  monservopincehautbas.attach(3);
  monservocamera.attach(12);

/*reinitialisation a la mise sous tansion*/
  PivotRaz();
  TeteMilieu();
  monservoaxehautbas.write(0);
  monservopincehautbas.write(180);
 /*
  delay(1000);
  Lever();
*/  
}
void loop(){
 
  while (Serial.available()) {
    delay(3);  
    char c = Serial.read();
    readString += c;
  }
  readString.trim();
    if (readString.length() >0) {
     
      Serial.println(readString);
      if (readString == "on"){
        BlinkLed();
      }
      if (readString == "leverpince"){
        ControlePince(readString);
      }
      if (readString == "baisserpince"){
        ControlePince(readString);
      }
      if (readString == "replierpince"){
        ControlePince(readString);
      }
      if (readString == "droitepince"){
        ControlePince(readString);
      }
      if (readString == "gauchepince"){
        ControlePince(readString);
      }
      if (readString == "lever"){
        Lever();
      }
      if (readString == "saisir"){
        Saisir();
      }
      if (readString == "lacher"){
        Lacher();
      }
      if (readString == "pivotdroite"){
        PivotDroite();
      }
      if (readString == "pivotgauche"){
        PivotGauche();
      }
      if (readString == "pivotraz"){
        PivotRaz();
      }
      if (readString == "avancerdrone"){
        AvancerDrone();
      }
      if (readString == "reculerdrone"){
        ReculerDrone();
      }
      if (readString == "stoperdrone"){
        StoperDrone();
      }
      if (readString == "droitedrone"){
        DroiteDrone();
      }
      if (readString == "gauchedrone"){
        GaucheDrone();
      }
      if (readString == "debloquerdrone"){
        DebloquerDrone();
      }
      if (readString == "tetedroite"){
        TeteDroite();
      }
      if (readString == "tetegauche"){
        TeteGauche();
      }
      if (readString == "tetemilieu"){
        TeteMilieu();
      }
      if (readString == "balayagetete"){
        BalayageTete();
      }
    }
  readString ="";
}
void Lever()
{
  Serial.println("Lever");
  monservopincehautbas.write(5);
  delay(700);
  monservoaxehautbas.write(30);
  delay(700);
  Saisir();
  Serial.println("Saisir durant 1sec5");
  delay(1500);
  Lacher();
  delay(1500);
  Serial.println("Dessendre");

  monservoaxehautbas.write(0);
      delay(700);
  monservopincehautbas.write(180);
}



void ControlePince(String action)
{
  int val;
  Serial.println(action);
 
  int CurrentPositionpincehautbas = monservopincehautbas.read();
  int CurrentPositionaxehautbas = monservoaxehautbas.read();
  int CurrentPositionsocle = monservosocle.read();

  int MAXpincehautbas = 178;
  int MINpincehautbas = 10;

  int MAXaxehautbas = 120;
  int MINaxehautbas = 2;

  int MAXsocle = 180;//position  initiale
  int MINsocle = 0;

  if (action == "droitepince"){
    if(CurrentPositionsocle-5 > MINsocle){
      CurrentPositionsocle=CurrentPositionsocle-5;
      monservosocle.write(CurrentPositionsocle);
    }
  }
  if (action == "gauchepince"){
    if(CurrentPositionsocle+5 < MAXsocle){
      CurrentPositionsocle=CurrentPositionsocle+5;
      monservosocle.write(CurrentPositionsocle);
    }
  }
 
  if (action == "leverpince"){
    if(CurrentPositionaxehautbas+4 < MAXaxehautbas){
      CurrentPositionaxehautbas=CurrentPositionaxehautbas+4;
      monservoaxehautbas.write(CurrentPositionaxehautbas);
    }
    if(CurrentPositionpincehautbas-10 > MINpincehautbas){
      CurrentPositionpincehautbas=CurrentPositionpincehautbas-10;
      monservopincehautbas.write(CurrentPositionpincehautbas);
    }
  }
  if (action == "baisserpince"){
    if(CurrentPositionaxehautbas-10 > MINaxehautbas){
      CurrentPositionaxehautbas=CurrentPositionaxehautbas-10;
      monservoaxehautbas.write(CurrentPositionaxehautbas);
    }
    if(CurrentPositionpincehautbas+10 < MAXpincehautbas){
      CurrentPositionpincehautbas=CurrentPositionpincehautbas+10;
      monservopincehautbas.write(CurrentPositionpincehautbas);
    }
  }
  if (action == "replierpince"){
        for (int position = CurrentPositionaxehautbas; position > MINaxehautbas; position--) {
            monservoaxehautbas.write(position);
            Serial.println(position);
            delay(10);
        }
        for (int position = CurrentPositionpincehautbas; position < MAXpincehautbas; position++) {
            monservopincehautbas.write(position);
            Serial.println(position);
            delay(10);
        }
        for (int position = CurrentPositionsocle; position <= 90; position++) {
            monservosocle.write(position);
            Serial.println(position);
            delay(10);
        }
       
   }
}
void Saisir()
{
  Serial.println("Saisir");
  monservopince.write(180);


}
void Lacher()
{
  Serial.println("Lacher");
  monservopince.write(150);
}
void PivotGauche()
{
   int CurrentPositionmonservosocle = monservosocle.read();
   int Maxmonservosocle = 179;

   if(CurrentPositionmonservosocle+5 <= Maxmonservosocle){
     int NewPosition = CurrentPositionmonservosocle+5;
     monservosocle.write(NewPosition);
      Serial.println("PivotGauche"+NewPosition);
   }
 
}
void PivotDroite()
{

   int CurrentPositionmonservosocle = monservosocle.read();
   int Minmonservosocle = 1;

   if(CurrentPositionmonservosocle-5 >= Minmonservosocle){
     int NewPosition = CurrentPositionmonservosocle-5;
     monservosocle.write(NewPosition);
      Serial.println("PivotDroite" + NewPosition);
   }
 
}
void PivotRaz()
{
  Serial.println("PivotRaz -> 90");
  monservosocle.write(90);
}
void AvancerDrone()
{
   Serial.println("Avancer");
   motorA('R');// Turn motor A to RIGHT
   motorB('R'); // Turn motor A to RIGHT
}
void ReculerDrone()
{
   Serial.println("Reculer");
   motorA('L');// Turn motor A to RIGHT
   motorB('L'); // Turn motor A to RIGHT
}
void StoperDrone()
{
   Serial.println("Stoper");
    motorA('O');// Turn motor A OFF
    motorB('O');// Turn motor B OFF
}
void DroiteDrone()
{
   Serial.println("Debloquer");
   motorB('R');// Turn motor B to RIGHT
   motorA('L');// Turn motor B to LEFT

}
void GaucheDrone()
{
   Serial.println("Debloquer");
   motorB('L');// Turn motor B to RIGHT
   motorA('R');// Turn motor B to LEFT

}
void DebloquerDrone()
{
   Serial.println("Debloquer");
   motorB('L');// Turn motor B to RIGHT
   motorA('R');// Turn motor B to LEFT
   delay(1500) ;
   StoperDrone();
}
void TeteGauche()
{

   int CurrentPositionmonservocamera = monservocamera.read();
   int Minmonservocamera = 60;

   if(CurrentPositionmonservocamera-5 >= Minmonservocamera){
     int NewPosition = CurrentPositionmonservocamera-5;
     monservocamera.write(NewPosition);
      Serial.println("TeteGauche ");
      Serial.println(NewPosition);
   }
}
void TeteDroite()
{
   int CurrentPositionmonservocamera = monservocamera.read();
   int Maxmonservocamera = 120;

   if(CurrentPositionmonservocamera+5 <= Maxmonservocamera){
     int NewPosition = CurrentPositionmonservocamera+5;
     monservocamera.write(NewPosition);
      Serial.println("TeteDroite ");
      Serial.println(NewPosition);
   }
}
void TeteMilieu()
{
   Serial.println("TeteMilieu");
   monservocamera.write(90);
   Serial.println(monservocamera.read());
}

void BalayageTete(){
  int CurrentPositionmonservocamera = monservocamera.read();
  for (int position = CurrentPositionmonservocamera; position <= 110; position++) {
      monservocamera.write(position);
      Serial.println(position);
      delay(60);
  }
  CurrentPositionmonservocamera = monservocamera.read();
  for (int position = 110; position >= 65; position--) {
    monservocamera.write(position);
    Serial.println(position);
    delay(60);
  }
  monservocamera.write(90);
}

void BlinkLed()
{
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);    
}

/*
 * @motorA
 * activation rotation of motor A
 * d is the direction
 * R = Right
 * L = Left
 */
void motorA(char d)
{
  if(d =='R'){
    digitalWrite(A1A,LOW);
    digitalWrite(A1B,HIGH);
  }else if (d =='L'){
    digitalWrite(A1A,HIGH);
    digitalWrite(A1B,LOW);    
  }else{
    //Robojax.com L9110 Motor Tutorial
    // Turn motor OFF
    digitalWrite(A1A,LOW);
    digitalWrite(A1B,LOW);    
  }
}// motorA end


/*
 * @motorB
 * activation rotation of motor B
 * d is the direction
 * R = Right
 * L = Left
 */
void motorB(char d)
{

    if(d =='R'){
      digitalWrite(B1A,LOW);
      digitalWrite(B1B,HIGH);
    }else if(d =='L'){
      digitalWrite(B1A,HIGH);
      digitalWrite(B1B,LOW);    
    }else{
    //Robojax.com L9110 Motor Tutorial
    // Turn motor OFF      
      digitalWrite(B1A,LOW);
      digitalWrite(B1B,LOW);    
    }

}// motorB end

Configuration du Raspberry avec le dongle Wifi

Branchez la clef Wifi sur le Raspberry, démarrez le puis consulter la liste des périphériques afin de déterminer si il est correctement détecte.

pi@ninive:~ $ lsusb
Bus 001 Device 006: ID 2341:0043 Arduino SA Uno R3 (CDC ACM)
Bus 001 Device 005: ID 0bda:8179 Realtek Semiconductor Corp. RTL8188EUS 802.11n Wireless Network Adapter
Bus 001 Device 004: ID 05e3:0610 Genesys Logic, Inc. 4-port hub
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp. SMC9514 Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

La clef est detectée sur : Bus 001 Device 005 Realtek Semiconductor Corp. RTL8188EUS 802.11n Wireless Network Adapter

On va récupérer le nom de la clef wifi avec ip addr, ici pour moi il s’agit de wlan0

pi@ninive:~ $ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000
    link/ether 41-03-20-49-54-E0 brd ff:ff:ff:ff:ff:ff
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 41-03-20-49-54-E0 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.31/24 brd 192.168.1.255 scope global wlan0
       valid_lft forever preferred_lft forever
    inet6 fe80::123e:aaee:fe3b:2875/64 scope link
       valid_lft forever preferred_lft forever
4: wlan1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 41-03-20-49-54-E0 brd ff:ff:ff:ff:ff:ff

Avec le nom de la clee wlan0 je vais indiquer au raspberry de connecter directement au boot la clef USB sur ma freebox

sudo nano /etc/network/interfaces
# interfaces(5) file used by ifup(8) and ifdown(8)

# Please note that this file is written to be used with dhcpcd
# For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'

# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d

auto lo

iface lo inet loopback

auto eth0
iface eth0 inet dhcp

allow-hotplug wlan0
auto wlan0

iface wlan0 inet dhcp
wpa-ssid "Lessiddevotrereseauwifi"
wpa-psk "masuperclefpourprotegermonwifi"

Redémarrez le raspberry et déconnectez votre câble réseau pour vérifier, votre dhcp doit vous délivrer une nouvelle adresse, reprenez la main via ssh sur le raspberry via cette adresse.

Configuration de la Camera avec Motion

Éteignez le raspberry, puis connectez la camera sur la board et reprenez la main via ssh.

Il faut activer la camera dans la configuration de raspbian avec

sudo raspi-config

Dans le Menu, Onglet 5 : « Interfacing Options », le P1 désigne la camera, faite enable puis valider les modifications et rebootez le raspberry.

Après re-démarrage on vérifie que la camera fonctionne avec la commande raspistill qui vous génère dans le dossier courant une image appelé test.jpg

raspistill -v -o test.jpg

On install le paquet Motion qui va permettre de stream la vue de la camera

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install motion
sudo modprobe bcm2835-v4l2

A la fin du fichier ajouter la ligne :

sudo nano /etc/modules
#
#
bcm2835-v4l2

On active le daemon Motion

sudo nano /etc/default/motion
#
start_motion_daemon=yes

On fait une copie du fichier de configuration initiale et on édite le notre

sudo cp /etc/motion/motion.conf /etc/motion/motion.conf.bak
sudo nano /etc/motion/motion.conf

#Autoriser le daemon motion
daemon on
# Emplacement du fichier de log de motion
logfile /tmp/motion.log
# on autorise de consulter le steam video depuis le lan
stream_localhost off
# desactive enregistrement photo video
output_pictures off
ffmpeg_output_movies off
# definis le framerate du stream
framerate 50
# largeur et hauteur de la video
width 640
height 480
# port de controle admin pour motion
webcontrol_port 8081

on démarre le service avec

sudo service motion start

A présent le flux de votre camera doit être disponible sur http://ip.du.rasp.berry:8080, sur http://ip.du.rasp.berry:8081 est disponible l’administration

Connection Serie Raspberry vers Arduino

Notre objectif étant de pouvoir piloter notre arduino via le raspberry celui-ci va dialoguer avec le port serie.
Je liste l’ensemble avec ls -la /dev, je dois trouver

lrwxrwxrwx   1 root root           5 Jan  1 19:59 serial0 -> ttyS0

Il s’agit du port serie raspberry/arduino par défaut, on peut tester si il s’agit du bon port avec un script python

sudo nano /var/www/html/sendstringtoserial.py
#!/usr/bin/env python
# coding: utf-8
import sys     # pour la gestion des parametres
import serial  # bibliothèque permettant la communication série
#print str(sys.argv[1])
ser = serial.Serial('/dev/serial0', 9600)
print str(sys.argv[1])
ser.write(str(sys.argv[1]))

Puis on essaye d’envoyer une commande a l’arduino, il s’agit ici d’un des mots clefs que doit reconnaitre l’arduino, dans mon exemple je ferai. Ce qui déclencherai la fonction « lever » sur l’arduino

sudo python /var/www/html/sendstringtoserial.py lever

Le bras robotique sur contrôlé par l’arduino doit alors effectuer le mouvement demandé.

Serveur Web pour commander Arduino

L’interface WEB va simplement faire exécuter les commandes python testé ci-dessus.

sudo apt-get install apache2 git
cd /var/www/html/
sudo git clone https://github.com/VeilleurTrytoFix/RaspCurioDuino
sudo chown -R www-data:www-data /var/www/html/
#deplacement du fichier server pour le websocket
mv ./server.js /home/monuser/

Modifier l’adresse ip dans index.php pour faire correspondre avec celle du raspberry pour le retour camera.

On va autoriser l’utilisateur www-data de apache2 à executer des scripts avec sudo, car sinon www-data n’a pas les droits pour accéder au port serie /dev/serial0

Le fichier complet avec la modification donne :

sudo nano /etc/sudoers
#
# This file MUST be edited with the 'visudo' command as root.
#
# Please consider adding local content in /etc/sudoers.d/ instead of
# directly modifying this file.
#
# See the man page for details on how to write a sudoers file.
#
Defaults        env_reset
Defaults        mail_badpass
Defaults        secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

# Host alias specification

# User alias specification

# Cmnd alias specification

# User privilege specification
root    ALL=(ALL:ALL) ALL
www-data ALL=(ALL) NOPASSWD:ALL
# Allow members of group sudo to execute any command
%sudo   ALL=(ALL:ALL) ALL

# See sudoers(5) for more information on "#include" directives:

#includedir /etc/sudoers.d

Lancement du Server websocket

node server.js
#retourne
Wed Jan 16 2019 17:28:13 GMT+0000 (Coordinated Universal Time) Server is listening on port 1337
open serial communication
Wed Jan 16 2019 17:30:33 GMT+0000 (Coordinated Universal Time) Connection accepted.

Résolution d’incidents :

npm ERR! Error: Method Not Allowed
npm ERR!     at errorResponse (/usr/share/npm/lib/cache/add-named.js:260:10)
npm ERR!     at /usr/share/npm/lib/cache/add-named.js:203:12
npm ERR!     at saved (/usr/share/npm/node_modules/npm-registry-client/lib/get.js:167:7)
npm ERR!     at FSReqWrap.oncomplete (fs.js:135:15)
npm ERR! If you need help, you may report this *entire* log,
npm ERR! including the npm and node versions, at:
npm ERR!     <http://github.com/npm/npm/issues>
#Résolu avec un upgrade de nodejs vers la last lts version (11 actu)
curl -sL https://deb.nodesource.com/setup_11.x | sudo -E bash -

Laisser un commentaire