Aller au contenu


Information tutoriel

  • Ajouté le: janv. 05 2018 04:53
  • Date Updated: janv. 06 2018 07:30
  • Lectures: 1188
 


* * * * *
0 Notes

RobArchi 1.XX

Voici la suite de la version X.xx, avec la surveillance de la batterie.

Posté par Gyro49 on janv. 05 2018 04:53

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 joint  base_composants.pdf   121,37 Ko   225 téléchargement(s)

Fichier joint  base_stripboard.pdf   123,46 Ko   250 téléchargement(s)

Fichier joint  shield_composant.pdf   118,01 Ko   153 téléchargement(s)

Fichier joint  shield_stripboard.pdf   117,03 Ko   174 téléchargement(s)

Fichier joint  batterie.txt   4,19 Ko   153 téléchargement(s)