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



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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
#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);


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

  PivotRaz();
  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 PivotDroite()
{
  Serial.println("PivotDroite");
   int CurrentPositionmonservosocle = monservosocle.read();
   int Maxmonservosocle = 120;

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

   if(CurrentPositionmonservosocle-5 >= Minmonservosocle){
     int NewPosition = CurrentPositionmonservosocle-5;
     monservosocle.write(NewPosition);
      Serial.println(NewPosition);
   }
 
}
void PivotRaz()
{
  Serial.println("PivotRaz");
  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()
{
    Serial.println("TeteDroite");
   int CurrentPositionmonservocamera = monservocamera.read();
   int Minmonservocamera = 60;

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

   if(CurrentPositionmonservocamera+5 <= Maxmonservocamera){
     int NewPosition = CurrentPositionmonservocamera+5;
     monservocamera.write(NewPosition);
      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.

1
2
3
4
5
6
7
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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

1
sudo nano /etc/network/interfaces
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 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

1
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

1
raspistill -v -o test.jpg

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

1
2
3
4
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 :

1
2
3
4
sudo nano /etc/modules
#
#
bcm2835-v4l2

On active le daemon Motion

1
2
3
sudo nano /etc/default/motion
#
start_motion_daemon=yes

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

1
sudo cp /etc/motion/motion.conf /etc/motion/motion.conf.bak
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

1
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

1
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

1
sudo nano /var/www/html/sendstringtoserial.py
1
2
3
4
5
6
7
8
#!/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

1
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.

1
2
3
4
5
6
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 :

1
sudo nano /etc/sudoers
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#
# 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

1
2
3
4
5
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.

Laisser un commentaire