Aller au contenu


Gyro49

Inscrit(e) (le) 06 sept. 2012
Déconnecté Dernière activité sept. 14 2023 06:32
-----

RobArchi 1.XX

Publié Gyro49 le 05 janvier 2018 - 04:53 in Robot complet

RobArchi 1.XX

 

 

Ce tutoriel vient en complément du RobArchi X.xx qui était la base de départ.

Cette nouvelle version a pour objectif de proposer une surveillance du niveau de charge de la batterie.

Mots clefs :
Atmega 328p, Raspberry,  I2C, batterie, NPN 2N2222, eeprom, 24LCXXX

Avertissements :
Comme pour la version X.xx, vous ne devez pas chercher, dans RobArchi, la solution à vos problèmes mais plus une approche de laboratoire de test et d'apprentissage.
En effet, multiplier les Atmegas comme je l'ai fait, n'ai pas la solution ultime. En terme de coût, ce n'est pas exorbitant, mais il serait difficile de tous les loger dans un gabarit de robot plus petit.

Objectifs :
Comme présenté ci-dessus la version 1.XX va apporter un contrôle régulier du niveau de charge de la batterie et cela à la demande de la carte Raspberry.

Il me semble qu’un robot d’exploration qui ne surveille pas la décharge de sa batterie prend beaucoup de risque.

Histoire de pousser le vice au maximum, j’ai décidé de jouer également avec une eeprom en I2C.

La carte du X.xx a donc subi une petite modification par l’implantation de l’eeprom 24LC128 juste au-dessus de la carte Pi mais toujours sur la ligne I2C coté 3V (annexe1 et 2 en bas de page).

Préambule :
Lors de mes tests sur la version X.xx je passais mon temps à monter et démonter mon Atméga à chaque modification du code… l’horreur.

Pour cette nouvelle étape je suis passé par un banc de tests : une plaque de test 840 points et Arduino Nano à la place d’un simple Atméga. Et une carte Raspberry avec un connecteur GPIO.

Déroulement du tuto :
Chapitre 1.1 : Création du shield accueillant la gestion de la batterie
Chapitre 1.2 : Mesure de la tension de la batterie arduino uniquement
Chapitre 1.3 : Mesure de la tension de la batterie à la demande du Raspberry
Chapitre 1.4 : Utilisation d’une eeprom entre l’Atmega et la Raspberry
Chapitre 1.5 : Mesure de la tension toutes les deux minutes via un job CRON

Annexes :
Annexe 1 - Mise à jour de la carte Version X.XX - Composants
Annexe 2 - Mise à jour de la carte Version X.XX - Stripboard
Annexe 3 – Création du shield batterie - Composants
Annexe 4 – Création du shield batterie - Stripboard

Chapitre 1.1 - Création du shield accueillant la gestion de la batterie
Je suis donc parti sur un deuxième shield fait maison qui sera ajusté à la carte de la version X.xx.

Les deux plaques sont mises en communication via un groupe de 2x6 « long header » pour envoyer sur le shield batterie l’alimentation et la connexion I2C.
La tension arrive directement sur la plaque 1.xx. Etant du genre distrait, j’ai mis un pont de diode afin de garantir la bonne polarité dans le circuit.
P1040585.JPG
P1040584.JPG

En regardant sur le web il y a beaucoup de référence sur le sujet.
J’ai choisi de suivre le blog suivant :
http://www.chicoree.fr/w/Mesurer_une_tension_avec_un_ATmega328P

Histoire d’éviter une consommation d’énergie trop important, j’ai associé un transistor 2N2222 dans mon circuit afin d’envoyer du 12V dans le pont diviseur uniquement au moment de la mesure.

Voici mon schéma de principe sans le pont de diode.
 
batterie.png

 

Chapitre 1.2 - Mesure de la tension de la batterie
La première étape sera la mesure de la batterie par « l’Atméga batterie ».

Le code arduino de l’Atmega

#include <stdlib.h>

// Constants
const int analogInPin = A0; // Analog pin the voltage divider is attached to
const float Vcc = 5; // µC Vcc (V)
const float R1 = 27000; // Voltage divider R1 (Ohm)
const float R2 = 10000; // Voltage divider R2 (Ohm)

const int pause = 60*1000; // delay between samples (ms)

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);
}

void loop() {
  // read the analog in value:
  int sensorValue = analogRead(analogInPin);

  // Serial.println(sensorValue); // for debug / calibration
  float v_pin = Vcc*sensorValue/1023.;
  float v_bat = v_pin/(R2/(R1+R2));

  // Convert to string using the format ddd.dd
  char buffer[21];
  dtostrf(v_bat, 6, 2, buffer);
  buffer[6] = 0;
 
  // Display result
  Serial.println(buffer);
 
  // wait before the next loop
  delay(pause);
}

Chapitre 1.3 - Mesure de la tension de la batterie à la demande du Raspberry
En reprenant une bonne partie du code de la version X.xx, c’est déjà plus facile.
Les tests ont été effectué sur une carte Arduino Uno puis une Arduino Nano et à mon grand bonheur, pas de difficulté.
Maintenant une fois le code transféré sur Ateméga « baterrie » grosse déception, au lieu de 11.56 V (mesure multimètre) je n’avais que 3.49V. Après trois jours de recherche j’ai capitulé en multipliant par 3.4 la mesure en entrée A0.

int sensorValue = analogRead(analogInPin)*3.4;

Je hercherais un autre jour la solution avec AREF certainement.

Le code arduino de l’Atmega

#include <Wire.h>
#include <stdlib.h>

#define SLAVE_ADDRESS 0x14

String dataReceived;
char dataSend[6] ;
int index = 0;

// Constants
const int analogInPin = A0; 
const int T2N = 9;
const float Vcc = 5;
const float R1 = 26500; // Voltage divider R1 (Ohm)
const float R2 = 9910; // Voltage divider R2 (Ohm)

void setup() {   
  Wire.begin(SLAVE_ADDRESS);
  Wire.onReceive(receiveData);
  Wire.onRequest(sendData);
  
  pinMode(T2N, OUTPUT);  
}
 
void loop() {
	/* Il n'y a rien dans la boucle infinie */
}

void receiveData(int byteCount){
  dataReceived = NULL;
  int numOfBytes = Wire.available();
  
  byte b = Wire.read();  //cmd
  
  for(int i=0; i<numOfBytes-1; i++){
    char c = (char) Wire.read(); 
    dataReceived += (char) c; 
  }
  
  digitalWrite(T2N, HIGH);
  int sensorValue = analogRead(analogInPin)*3.4;

  float v_pin = Vcc*sensorValue/1023;

  float v_bat = v_pin/(R2/(R1+R2));
  
  dtostrf(v_bat, 6, 2, dataSend);
  dataSend[6] = 0;
  digitalWrite(T2N, LOW);  
  }

void sendData(){
  Wire.write(dataSend[index]);
    ++index;
    if (index >= 6) {
         index = 0;
    }
  }

Coté Raspberry

#!/usr/bin/env python

import smbus
import time
import os

bus = smbus.SMBus(1)

# I2C address of Arduino Slave
i2c_add_batterie = 0x14
i2c_cmd = 0x01

def ConvertStringToBytes(src):
  converted = []
  for b in src:
    converted.append(ord(b))
  return converted

data = ""
# loop to send message
exit = False
while not exit:
  r = raw_input('Enter something, "q" to quit"')
  print(r)

  bytesToSend = ConvertStringToBytes(r)
  bus.write_i2c_block_data(i2c_add_batterie, i2c_cmd, bytesToSend)

  time.sleep(0.1)

  for i in range(0, 5):
    data += chr(bus.read_byte(i2c_add_batterie));
  print data
  time.sleep(1);
  data = ""

  if r=='q':
    exit=True

Après connexion au raspberry en SSH, il suffit de taper une lettre pour recevoir de l’atmega la tension de la batterie.

Chapitre 1.4 - Utilisation d’une eeprom entre l’Atmega et la Raspberry

 

Ne fondez pas de grand espoir dans cette partie car si cela fonctionne presque sur la plaque d'essai, c'est une véritable perte de temps après mise en place sur le robot.

Je vous mets les codes pour info ou tout simplement si vous voulez tenter le coup.

Histoire de préparer la version 2.xx j’ai décidé de jouer avec une eeprom en I2C forcément.

Pour la mise en place il y a beaucoup de tuto sur le net, il suffit de taper dans un navigateur :
arduino eeprom I2C

L’eeprom doit être du côté 5v du réseau I2C. En mettant les pins 1 à 4 à la masse, l’eeprom aura l’adresse 0x50.
Contrairement au Raspberry, l’Atmega (ou simplement l’Arduino) peut accepter d’être aussi bien esclave que maître mais forcément pas en même temps.

La démarche et simple, au démarrage, l’Atmega est en esclave jusqu’au moment de recevoir la commande du Raspberry. A ce moment-là, il ouvre une connexion I2C en qualité de maître vers l’eeprom pour y déposer la valeur de la tension de batterie puis revient à l’écoute du Raspberry.

Le raspberry attend 5 secondes puis va voir sur l’eeprom ce qu’a déposé l’atméga.

Dans le pays à Oui-Oui c’est comme ça que ça marche. Maintenant, il y a toujours un problème qui vient contredire la théorie. Dans la pratique, lorsque la Rpi affiche une erreu de connexion avec l’eeprom pour une histoire de délai dépassé. A première vue, l’Atméga semble garder un lien avec l’eeprom même lorsque la connexion est terminée avec :

 

Wire.endTransmission(deviceaddress);

Une solution c’est de rebooter l’Atméga. Coté informatique je n’ai pas trouvé, j’ai donc choisi la méthode électronique. Un 2222 en parallèle du bouton RESET avec une commande depuis le PIN 5. C’est un peu brutal mais ça marche (Sur la plaque d'essai).
 
Le code arduino de l’Atmega

#include <Wire.h>
#include <stdlib.h>

#define SLAVE_ADDRESS 0x14
#define I2C_add_eeprom 0x50

String dataReceived;
char dataSend[6] ;
unsigned int address = 0;

// Constants
const int analogInPin = A0; 
const int T2N = 9;
const int RESET = 13;
const float Vcc = 5;
const float R1 = 26500; // Voltage divider R1 (Ohm)
const float R2 = 9910; // Voltage divider R2 (Ohm)

void setup() {   
  Wire.begin(SLAVE_ADDRESS);
  Wire.onReceive(receiveData); 
  
  pinMode(T2N, OUTPUT);  
  pinMode(RESET, OUTPUT); 
}
 
void loop() {
	/* Il n'y a rien dans la boucle infinie */
}

void receiveData(int byteCount){
  dataReceived = NULL;
  
  int numOfBytes = Wire.available();
  
  byte b = Wire.read();  //cmd
  
  for(int i=0; i<numOfBytes-1; i++){
    char c = (char) Wire.read();
    dataReceived += (char) c; 
  }
  
  digitalWrite(T2N, HIGH);
  
  int sensorValue = analogRead(analogInPin)*3.4;

  float v_pin = Vcc*sensorValue/1023;

  float v_bat = v_pin/(R2/(R1+R2));
  
  dtostrf(v_bat, 6, 2, dataSend);
  dataSend[6] = 0;
  digitalWrite(T2N, LOW);
  	
  writeEEPROM(I2C_add_eeprom, address);
  
  delay(1);
  
  digitalWrite(RESET, HIGH);  
  }

void writeEEPROM(int deviceaddress, unsigned int eeaddress) 
{
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8));   // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  for(int i=0; i<strlen(dataSend); i++){
    Wire.write(dataSend[i]);
    }  
  Wire.endTransmission(deviceaddress);
 
  delay(1);
} 

Coté Raspberry

#!/usr/bin/env python

import smbus
import time
import os

bus = smbus.SMBus(1)

# I2C address of Arduino Slave
i2c_add_batterie = 0x14
i2c_add_eeprom = 0x50
i2c_cmd = 0x01

def ConvertStringToBytes(src):
  converted = []
  for b in src:
    converted.append(ord(b))
  return converted

level = ""
# loop to send message
exit = False
while not exit:
  r = raw_input('Enter something, "q" to quit"')
  print(r)

  bytesToSend = ConvertStringToBytes(r)
  bus.write_i2c_block_data(i2c_add_batterie, i2c_cmd, bytesToSend)

  time.sleep(5)
  memory_address = 0
  data=""
  bus.write_byte(i2c_add_eeprom, memory_address >> 8)
  bus.write_byte(i2c_add_eeprom, memory_address & 0xff)
  for i in range(0,10):
    data =bus.read_byte(i2c_add_eeprom)
    if data>45 and data<58:
      level +=chr(data)
  print level
  time.sleep(1)
  data = ""
  level = „“
  if r=='q':
    exit=True
} 

Chapitre 1.5 - Mesure de la tension toutes les deux minutes via un job CRON
Pour terminer cette version 1.xx je voudrais connaître le temps de décharge de la batterie sans surveillance de ma part.
Je vais donc créer un nouveau fichier Python au nom de « batterie.py » qui sera dans le répertoire : /home/pi/batterie.py

 

Je suis reparti sur la base du chapitre 1.3

Ne pas oublier de créer le répertoire data

 

Code Raspberry : fichier batterie.py

#!/usr/bin/env python

import smbus
import time
import os
import datetime

bus = smbus.SMBus(1)

# I2C address of Arduino Slave
i2c_add_batterie = 0x14
i2c_cmd = 0x01

def ConvertStringToBytes(src):
  converted = []
  for b in src:
    converted.append(ord(b))
  return converted

data = ""

bytesToSend = ConvertStringToBytes("m")
bus.write_i2c_block_data(i2c_add_batterie, i2c_cmd, bytesToSend)

time.sleep(0.1)

for i in range(0, 5):
  data += chr(bus.read_byte(i2c_add_batterie));
print data
time.sleep(1);

fichier = open("/home/pi/data/batterie.txt", "w")
fichier.write("\n" + datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + " " + data)
fichier.close()

Avec la commande « crontab –e » dans le terminal SSH, nous avons accès à la liste des Job CRON.
Il faut mettre cette ligne à la fin du fichier

*/1  *  *  *  *   sudo python /home/pi/batterie.py

Lorsque le fichier batterie.txt ne sera plus rempli, nous pourrons en déduire la tension minimale à la batterie pour que le système fonctionne.

 

Histoire de compléter le système vous pouvez créer un serveur Samba pour accéder facilement au fichier batterie.txt

 

En annexe 5 le fichier batterie.txt avec comme unique consommation électrique le PI et les Atmegas. les moteurs étant débranchés.

Annexes

Fichier attaché  base_composants.pdf   121,37 Ko   714 Nombre de téléchargements

Fichier attaché  base_stripboard.pdf   123,46 Ko   901 Nombre de téléchargements

Fichier attaché  shield_composant.pdf   118,01 Ko   719 Nombre de téléchargements

Fichier attaché  shield_stripboard.pdf   117,03 Ko   768 Nombre de téléchargements

Fichier attaché  batterie.txt   4,19 Ko   703 Nombre de téléchargements

 

 




RobArchi X.XX

Publié Gyro49 le 28 janvier 2017 - 03:09 in Robot complet

Si comme moi vous avez interdiction de faire rouler vos créations dans la maison sous peine d'entendre "Qu'est-ce que c'est que ce truc qui fait du bruit" ou encore "J'ai encore faillit marcher dessus va dehors".
 
Seule solution, en effet, faire rouler mes projets dehors.
 
Problématique d'un robot d'extérieur
 
La garde au sol doit être plus grande que les herbes du jardin.
J'ai bien réalisé un premier projet, mais avec sa garde au sol inférieur à 2 cm, il est juste bon à rouler sur la terrasse.
 
Mots-clés
 
Raspberry, atmega328, ardiuno, batterie 12v, L298N, motoréducteur, I2C
 
Objectifs principaux
 
Disposer d'une base évolutive et pouvant se déplacer en extérieur.
 

 
RobArchi X.XX
 
P1040221.JPG
 
La liste des courses
 
C'est une liste très réduite, il faudra forcément des vis, un clou, des résistance et des condensateurs, sinon principalement il faut :

raspberry pi                                                     50€00 amazon
atmega328P                                                      6€00 amazon
plaque stripboard de 50 x 12cm                      21€00 (chez mon fournisseur local)
deux roues de diam 25cm                               38€00 bricodepot
connecteur à souder                                         2€60 hobbytronics
deux moteurs à engrenage                             35€00  sud-import-express.com
deux engrennages                                            6€00  amazon
deux motoréducteurs                                       14€50 amazon
un L298N                                                          3€52 amazon
une plaque de médium prédécoupé                 5€00 leroymerlin
une batterie 12v 7Ah                                       20€00 amazon
i2c level shifter                                                   4€00 hobbytronics
 
La partie bois
 
Dans la plaque de bois de 80 x 60 cm il faut placer:
- un cercle de 50 cm de diamètre;
- deux rectangles de 13 x 28,2 cm;
- un rectangle de 19 x 12,4 cm
plaque.png
 
Puis dans les rectangles de 13 x 28,2cm. Cette plaque accueillera le moteur.
coté.png
 
Pour finir, afin que les cotés restent perpendiculaire avec le fond du robot il y a une plaque au centre. Les trois gros trous sont là uniquement des passes câbles, donc d'un diamètre libre. 
Attention dans le bas de cette plaque il faudra casser les angles (non dessiné) avec une râpe à bois.
milieu.png
 
Les moteurs + roues
 
De base, le bloc tourne en sortie de réduction à 400 tr/min ce qui est trop important pour le projet.
Le moteur est alimenté en 12V et il a un diamètre de 38mm (3,8cm).
 
P1040222.JPG
 
J'ai donc choisi de mettre à la place un motoréducteur avec 150tr/min en sortie d'arbre ce qui fera à la roue environ 4tr/min.
Je pense qu'un 250 tr/min aurait été plus judicieux.
 
Nouveau moteur et nouveau pignon prennent un axe différent par rapport à l'original. Avec un foret de 10mm il faudra faire un deuxième axe dans la coque plastique.
P1040224.JPG
 
Il faudra également ouvrir le capot du dessus pour laisser passer le pignon qui est trop gros. Ce n'est pas très joli mais il n'y a pas le choix.
P1040227.JPG
 
Pour le raccordement des moteurs, j'ai placé un condensateur 100 micro non polarisé entre les deux bornes d'alimentation.
 
Les roues font donc 25 cm de diamètre avec un axe de 20mm sur roulement à bille.
 
Pour le raccordement au moteur j'ai été au plus simple -> deux bouts de tuyau en PVC de diamètres 50mm et de longueur 5 cm et 4cm.
le tube 1: Le 5 cm sera relié à la roue après avoir fait des encoches.
le tube 2; Le 4cm il faut lui enlever sur la longueur une bande de 2cm environ puis le serrer pour le faire rentrer dans le tube 1 puis lui faire les encoches coté moteur.
P1040230.JPG
 
 
Comme vous pouvez le remarquer, l'axe de la roue c'est du 20mm et celui du groupe-moteur c'est du 12mm.
Donc acheter un tube de 12mm, une plaque de fixation métallique et faire un peu de soudure.
La plaque ne servant qu'au maintien du tube de 12 lors des démontages réguliers.
 
P1040234.JPG
 
A chaque extrémité du tube de 12mm j'ai insérer 8cm de tige filetée en laissant dépasser 15mm. Par la suite il faut percer le tube de par en par avec un foret le plus petit possible, en prenant la tige filetée. Un morceau de clou dans le trou fera office de clavette.
 
Il faut trouver de quoi combler l'espace entre le tube de 12mm et l'intérieur de l'axe de roue.
J'ai donc découpé 10cm d'un tube d'acier diamètre 20 et récupérer une cheville plastique de montage de mes WC suspendu. Il est possible d'utiliser un bout de tube PER d'alimentation en eau récupérer chez un ami qui fait de l'auto construction. Le reste du jeu pourra être comblé par du scotch renforcé.
 
L'électronique
 
Pour l'électronique, j'ai choisi d'utiliser une plaque à bande car tout le monde n'a pas forcément accès à une graveuse.
Donc une plaque stripboard de 17,5 x 12cm.
P1040212.JPG
 
Il faut faire quelques modifications en suivant les croix
stripboard.png
 
composants.png
 
Pour les vérifications j'ai suivi le tuto paperduino.
 
Attention, il ne faut pas oublier le strap sous le support de l'Atmega et les condensateur entourant le quartz sont de 22pf et non 22nf
 
Pour charger le code arduino j'ai suivi le tuto de chez Arduino
 
J'ai placé entre l'Atmega et le Raspberry un i2c level shifter car il travail respectivement en 5V et en 3,3V.
 
J'ai écarté légèrement les pattes du connecteur du raspberry car j'avais peur de faire de mauvaise soudure.
P1040216.JPG
 
Avec des straps, vous avez juste à relier les SDA et les SCL ensemble au travers du I2C level.
De plus la partie de droite sur la photo correspond aussi à la partie de droite sur le plan de grattage de la face cuivré.
J'ai placé à la suite un 7812,7809,7805 et un LD1086v33
P1040235.JPG
 
 
Les codes informatique
J'ai fait l'impasse sur le formatage de la Raspberry et sur l'installation de l'I2C.
 
il y a plusieurs version du code informatique.
Version X.01 -> Test de l'atmega pour le contrôle des moteurs
 
Avec le code suivant les roues vont dans un sens puis dans l'autre.
// moteur droit
int MD = 11;
int in1 =10;
int in2 = 9;
// moteur gauche
int MG =  6;
int in3 = 7;
int in4 = 8;
void setup()
{
  pinMode(MD, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(MG, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);
}
void demoOne()
{ digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);//AVANCE
  digitalWrite(in3, LOW);
  digitalWrite(in4, HIGH);//AVANCE
  analogWrite(MD, 250);
  analogWrite(MG, 250);
 
  delay(8000);
  //ARRET TOTAL
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);
 
}
void demoTwo()
{ 
  digitalWrite(in1, HIGH); //RECUL
  digitalWrite(in2, LOW);
  digitalWrite(in3, HIGH); //RECUL
  digitalWrite(in4, LOW);
  analogWrite(MD, 250);
  analogWrite(MG, 250);
  delay(8000);
 
  //ARRET TOTAL
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);
}
void loop()
{
  demoOne();
  delay(1000);
  demoTwo();
  delay(1000);
}
Version X.02 -> Test de la connexion I2C entre la Raspberry et d'Atmega
 
Rien de bien compliqué, je tout copier/coller sur le net
 
Code Atmega
#include <Wire.h>

#define SLAVE_ADDRESS 0x12
int dataReceived = 0;

void setup() {
    Serial.begin(9600);
    Wire.begin(SLAVE_ADDRESS);
    Wire.onReceive(receiveData);
    Wire.onRequest(sendData);
}

void loop() {
    delay(100);
}

void receiveData(int byteCount){
    while(Wire.available()) {
        dataReceived = Wire.read();
        Serial.print("Donnee recue : ");
        Serial.println(dataReceived);
    }
}

void sendData(){
    int envoi = dataReceived + 1;
    Wire.write(envoi);
}
Code Raspberry
#!/usr/bin/env python
# coding: utf-8

import smbus
import time

# Remplacer 0 par 1 si nouveau Raspberry
bus = smbus.SMBus(0)
address = 0x12

print "Envoi de la valeur 3"
bus.write_byte(address, 3)
# Pause de 1 seconde pour laisser le temps au traitement de se faire
time.sleep(1)
reponse = bus.read_byte(address)
print "La reponse de l'arduino : ", reponse
Version X.03 -> Commande de RobArchi par ssh
Code Atmega
#include <Wire.h>

#define SLAVE_ADDRESS 0x12
String dataReceived;
String sens;
String angle;

// moteur droit
int MD = 11;
int in1 =10;
int in2 = 9;
// moteur gauche
int MG =  6;
int in3 = 7;
int in4 = 8;

void setup() {
    pinMode(MD, OUTPUT);
    pinMode(in1, OUTPUT);
    pinMode(in2, OUTPUT);
    pinMode(MG, OUTPUT);
    pinMode(in3, OUTPUT);
    pinMode(in4, OUTPUT);
    
    Serial.begin(9600);
    Wire.begin(SLAVE_ADDRESS);
    Wire.onReceive(receiveData);
    Wire.onRequest(sendData);
}

void loop() {
    delay(100);
}

void receiveData(int byteCount){
  dataReceived = NULL;
  int numOfBytes = Wire.available();
  Serial.print("len:");
  Serial.print(numOfBytes);

  byte b = Wire.read();  //cmd
  Serial.print("cmd:");
  Serial.print(b);
  Serial.print(" ");
   // Read serial input:
   for(int i=0; i<numOfBytes-1; i++){
     char c = (char) Wire.read(); // Recevoir un caractere
    dataReceived += (char) c; //Concateneer les caractères reçus
  }
  Serial.print("Donnee recue : ");
  Serial.println(dataReceived);
 
  int str_len = dataReceived.length() + 1;

  // Préparation d'un tableau à la longueur des données reçues
  char char_array[str_len];

  // Copie des données reçues dans le tableau
  dataReceived.toCharArray(char_array, str_len);
 
  // Recupération de la première données
  sens =strtok(char_array,",");
  Serial.println(sens);
 
  // Recupération de la deuxième données
  angle =strtok(char_array,",");
  Serial.println(angle);
 
  if(sens == "g") // G COMM GO DONC AVANCE
    {
    digitalWrite(in1, LOW);
    digitalWrite(in2, LOW);
    digitalWrite(in3, LOW);
    digitalWrite(in4, LOW);
    digitalWrite(in1, LOW);
    
    digitalWrite(in1, LOW);
    digitalWrite(in2, HIGH);//AVANCE
    digitalWrite(in3, LOW);
    digitalWrite(in4, HIGH);//AVANCE
    
    analogWrite(MD, 250);
    analogWrite(MG, 250);    
    }
  else if(sens == "b") // B COMME BACK DONC RECUL
    {
    digitalWrite(in1, LOW);
    digitalWrite(in2, LOW);
    digitalWrite(in3, LOW);
    digitalWrite(in4, LOW);
    
    digitalWrite(in1, HIGH); //RECUL
    digitalWrite(in2, LOW);
    digitalWrite(in3, HIGH); //RECUL
    digitalWrite(in4, LOW);
    
    analogWrite(MD, 250);
    analogWrite(MG, 250);    
    }
  else if(sens == "l") // L COMME LEFT DONC GAUCHE
    {
    digitalWrite(in1, LOW);
    digitalWrite(in2, LOW);
    digitalWrite(in3, LOW);
    digitalWrite(in4, LOW);
        
    digitalWrite(in1, LOW);
    digitalWrite(in2, HIGH);//AVANCE
    digitalWrite(in3, HIGH); //RECUL
    digitalWrite(in4, LOW);
    analogWrite(MD, 250);
    analogWrite(MG, 250);    
    }
  else if(sens == "r") // R COMME RIGHT DONC DROITE
    {
    digitalWrite(in1, LOW);
    digitalWrite(in2, LOW);
    digitalWrite(in3, LOW);
    digitalWrite(in4, LOW);
    
    digitalWrite(in1, HIGH); //RECUL
    digitalWrite(in2, LOW);
    digitalWrite(in3, LOW);
    digitalWrite(in4, HIGH);//AVANCE
    
    analogWrite(MD, 250);
    analogWrite(MG, 250);    
    }
  else
    {
    //ARRET TOTAL
    digitalWrite(in1, LOW);
    digitalWrite(in2, LOW);
    digitalWrite(in3, LOW);
    digitalWrite(in4, LOW);
    }  
}

void sendData(){
  int str_len = dataReceived.length() + 1;

  // Préparation d'un tableau à la longueur des données reçues
  char char_array[str_len];

  // Copie des données reçues dans le tableau
  dataReceived.toCharArray(char_array, str_len);
 
  // Recupération de la première données
  char *envoi =strtok(char_array,",");
  Wire.write(envoi);
}
 
Code Raspberry
#!/usr/bin/env python
# coding: utf-8

import smbus
import time
import os

# display system info
print os.uname()

bus = smbus.SMBus(1)

# I2C address of Arduino Slave
i2c_address = 0x12
i2c_cmd = 0x01

def ConvertStringToBytes(src):
    converted = []
    for b in src:
        converted.append(ord(b))
    return converted

# send welcome message at start-up
bytesToSend = ConvertStringToBytes("S")
bus.write_i2c_block_data(i2c_address, i2c_cmd, bytesToSend)

# loop to send message
exit = False
while not exit:
    r = raw_input('Enter something, "q" to quit"')
    print(r)
    
    bytesToSend = ConvertStringToBytes(r)
    bus.write_i2c_block_data(i2c_address, i2c_cmd, bytesToSend)
    
    if r=='q':
        exit=True
Ca marche, se connecter au raspberry en SSH via le WIFI forcément.
Les commandes sont:
g-> avance
b-> recul
l-> gauche
r-> droite
 
A bientôt pour la version 1.XX qui aura une autonomie avec un capteur ultrason.