Différences entre les versions de « VOR-008 sous projet I2C »
Ligne 3 : | Ligne 3 : | ||
<center><big>Com I2C pour Odo souris</big></center> | <center><big>Com I2C pour Odo souris</big></center> | ||
[[Image:IIC.JPG|thumb|center]] | [[Image:IIC.JPG|thumb|400px|center]] | ||
= VoLAB = | = VoLAB = |
Version du 18 novembre 2015 à 19:55
← Accueil ← Nos Projets ← VOR-008
VoLAB
Association VoRoBoTics
Date : 27/10/2015
Auteur : J.Soranzo
Relecteur :
Thème: Communication IIC, odométrie, souris optique
Projet : VOR008 plate-forme odométrique
Problématique
Dans le cadre du projet VOR008 implémenter un canal de communication entre un module capteur odométrique constitué d'un composant ADNS-2610 (des souris optiques) et un ARDUINO UNO (dans un premier temps puis d'un microcontrôleur Atmega88PA) et le contrôleur du robot (Atmega2560).
A terme le module capteur odométrique devrait être constitué de 2 ADNS2610 et d'un microcontrôleur avec un bus IIC (cela pourrait être par exemple un ATmega88)
J'aurais pu choisir une trame de longueur fixe entre le maître et l’esclave (le module capteur) constituée de 21 octets (+1 pour l'adresse du composant). Cette trame pourrait être : dxd, dyd, dxg, dyg, status avec dxd déplacement mesuré suivant l'axe X de la roue droite en unsigned long + checksum soit 5 octets répété 4 fois et terminé par un octet d'état. Les 4 checksum sont là pour éviter que le maître utilise un donnée non à jour.
(4+1)+(4+1)+(4+1)+(4+1)+1
Pour palier au problème des données pas à jour, on pourrait également imaginer un mécanisme dans l'esclave avec un booléen qui permet de remplir le tableau juste après une lecture du maître économie alors de 3 octets. La trame devient alors Status + dxd +dyd + dxg +dyg + checksum globale de la trame soit 18 octets +1.
Pour élever un peu le niveau et augmenter la polyvalence de cette étude, j'ai décidé d'essayer d'implémenter un protocole similaire à celui rencontré dans les EEPROM IIC.
La trame est de longueur variable. Le maître fourni d'abord l'adresse du composant puis l'adresse dans le composant et enchaîne un certain nombre quelconque de lectures (à sa convenance). L'esclave, ici notre EEPROM, place sur le bus, ses données au fur et à mesure des coups d'horloge en incrémentant automatiquement son pointeur d'adresse interne. Arrivé au bout de sa zone mémoire, elle recommence à l'adresse 0 à moins que le maître ait recommencé une nouvelle trame en fournissant une nouvelle adresse interne.
Répertoire de travail
00-ProjetsPerso\009-asservDCMotor\06-userDoc\articleAnexI2C
00-ProjetsPerso\009-asservDCMotor\01-maquettageFaisabilite\VOR8_ODOSOURIS_I2C pour le code
Plate-forme de développement
Développement sous Codeblock for ARDUINO
2 Arduino UNO connectés cf. manip de mise au point
Librairie ADSN-2610 : utilisation de la librairie toute faite de Martijn Thé
Code suivi sous git
Manip de mise au point
Afin de mettre au point ce canal de communication et pour simplifier les manipulation, j'ai utilisé 2 ARDUINO UNO. Un en maître pour simuler la 2560 et un en escalve pour simuler le module capteur.
Le maître est directement programmé via USBASP depuis codeblocks quant à l'esclave, il est programmé via son port série usb de manière classique.
La programmation du maître via cette méthode permet de laisser connecté sur son port série USB une fenêtre de terminal puTTY
Communication IIC version EEPROM
Phase1
IIC master
La librairie Wire.h qui implémente un objet wire qui ciomprend un certain nombre de méthodes est faite pour sauf que, on a 2 possibilités pour constituer les trame IIC en tant que maître.
Soit beginTransmission(id), write(), endTransmission()
C'est au moment du endTransmission que le bus est réellement piloté.
Soit requestFrom(id, nbrOctet) suivi de read() qui prend tout en charge.
(devant toutes ces méthodes on mets wire.) évidement.
Questionnement:
Comment faire une trame: idcomposant – adresseDansleComposant – lectures répétées ?
Il faudrait pouvoir mélanger les 2 possibilités:
beginTransmission(id) – write( adresseInterne) – requestFrom(id, nbrOctets) – endTransmission.
La réponse est disponible dans le playground Arduino dans l'interface avec une EEPROM I2C. Exemple:
byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) { byte rdata = 0xFF; Wire.beginTransmission(deviceaddress); Wire.send((int)(eeaddress >> 8)); // MSB Wire.send((int)(eeaddress & 0xFF)); // LSB Wire.endTransmission(); Wire.requestFrom(deviceaddress,1); if (Wire.available()) rdata = Wire.receive(); return rdata; }
// maybe let's not read more than 30 or 32 bytes at a time! void i2c_eeprom_read_buffer( int deviceaddress, unsigned int eeaddress, byte *buffer, int length ) { Wire.beginTransmission(deviceaddress); Wire.send((int)(eeaddress >> 8)); // MSB Wire.send((int)(eeaddress & 0xFF)); // LSB Wire.endTransmission(); Wire.requestFrom(deviceaddress,length); int c = 0; for ( c = 0; c < length; c++ ) if (Wire.available()) buffer[c] = Wire.receive(); }
Donc on fait begin(id) write(adresse) end() requestFrom(nombre), suivi côté maître du nombre de read() qui vont bien...
Ce n'est pas tout à fait le comportement souhaité. En effet, le requestFrom répète l'adresse du composant.
Il pourrait être envisageable de faire :
begin(id) write(adresse) read() read().... end()
Oui mais non :
« Reads a byte that was transmitted from a slave device to a master after a call to requestFrom() or was transmitted from a master to a slave. read() inherits from the Stream utility class. »
Extrait du référentiel de la librairie Wire sur le site Arduino.cc. Après un requestFrom() côté maître donc impossible de metrre read() à l'intérieur d'une trame.
IIC Slave
Dans le setup, on "register" les 2 routine de traitement. Une pour les requête en écriture et une pour les requête en lecture:
Wire.onReceive(IIChandlerRec); Wire.onRequest(requestEvent);
Dans la boucle loop, on ne fait rien ! Ce sont les 2 routines de traitement qui font la majeur partie du traveille IIC.
void IIChandlerRec(int combien){ Serial.print(combien);Serial.println(" octet recue"); if (Wire.available()) regAdd = Wire.read(); }
et
void requestEvent(void){ Wire.write(registres, 3); //envoi de seulement 3 octets pour les premier tests }
Bug
Mode émulation d'une EEPROM, j'ai constaté un bug de fonctionnement.
L'escalve n'a pas le temps de retourner si les 2 trame sont trop rapporchées.
Delta entre les 2 trames 97us
Avec seulement onRequest cela fonctionne.
Avec 500us entre les 2 trames ça passe
Constat d'échec version EEPROM
Quand on comprend bien à la fois la mécanique de la librairie Wire et celle du bus I2C, on s’aperçoit que ce type d'implémentation (comportement d'une EEPROMI2C) est quasi impossible. Il faudrait pouvoir agir à un niveau très bas pour pouvoir injecter les octets sur le bus au fur et à mesure des coups d'horloge. Rappelons que l'esclave ne sait absolument pas combien d'octets vont être lu dans la trame et que le délais entre 2 octets et de seulement 10us à 20 us pas plus avec un bus à 100kHz.
Communication IIC version simplifiée
Phase 2
Dans cette version, la Trame est de longueur fixe avec 18 octets de données (16 + 1status + 1 checksum) et 19 octets pour la trame complète avec l'adresse du composant qui est transmise en premier.
Dans cette version, il n'y a qu'un trame onRequest de lecture des données de l'esclave vers le maître.
Durée de la trame : 19*10bits*10us= 1,9ms
LE premier octet de la trame est 5 (adresse du composant) puis 1C 34 20 en hexa |
Intégration avec la souris optique
ADSN2610 de chez AGILENT
Caractéristique Importante
83ms/image |
400dpi soit 400points pour 2,54cm soit pour 127 points (valeur maximum des 2 registres):
8mm !
Question : quelle est la vitesse maximum à ne pas dépasser si on fait une lecture toute les 10us
En lecture pleine vitesse: on est a 255us/ registre 1ms pour les 4
0,008m => 1x10-3s en théorie on peu mesurer du 8m/s (pour information VOR008 ne dépasse pas le 1,77ms
Ce calcul est erroné:
En effet pour lire un octet il faut constituer un trame de 2 octets (cf. Datasheet ADNS)
Il faut donc 2 fois plus de temps pour lire les 4 registres. Donc vitesse max 4m/s.
Trames du capteur avec le code ci-après. |
Code d'acquisition des données capteur
uint8_t OptiMouse::readRegister(uint8_t address) { int i = 7; uint8_t r = 0;
// Write the address of the register we want to read: pinMode (_sdioPin, OUTPUT); for (; i>=0; i--) { digitalWrite (_sclkPin, LOW); digitalWrite (_sdioPin, address & (1 << i)); digitalWrite (_sclkPin, HIGH); }
// Switch data line from OUTPUT to INPUT pinMode (_sdioPin, INPUT);
// Wait a bit... delayMicroseconds(100);
// Fetch the data! for (i=7; i>=0; i--) { digitalWrite (_sclkPin, LOW); digitalWrite (_sclkPin, HIGH); r |= (digitalRead (_sdioPin) << i); } delayMicroseconds(100);
return r; }
Extrait de la lib:
/*
OptiMouse.cpp - Part ofoptical mouse sensor library for Arduino
Copyright (c) 2008 Martijn The. All right reserved.
*/
Annexes
UNO pinout
Uno A4 (SDA), A5 (SCL)
328p27, 28
Wire.h
Begin() ou begin(address) : avec une adresse c'est côté slave
requestFrom(address, quantity) ou Wire.requestFrom(address, quantity, stop)
beginTransmission(address) Subsequently, queue bytes for transmission with the write()
endTransmission() ou Wire.endTransmission(stop)
stop : boolean. true envoie un stop, libérant le bus. false envoie un restart et garde le bus actif.
write(value), write(string) ou write(data, length)
data: an array of data to send as bytes
available()
read()
onReceive(handler) : permet d'avoir un handler côté slave.
onRequest()
ADNS2610 mouse
400DPI
soit 400points pour 2,54cm
soit 1pt pour 25,4mm/400
Relevés oscilloscope
Fichier:IMAG001.BMP | Fichier:IMAG002.BMP |
Trame IIC sans résiatance de rappel au 5V sur SCL et SDA | Les même Trame avec. |
Fichiers sources
Licence
Ce document est mise à disposition selon les termes de la Licence Creative Commons Attribution 4.0 International.
Paternité 'by' :L'œuvre peut être librement utilisée, à la condition de l'attribuer à l'auteur en citant son nom.
Note aux auteurs de documents du VoLAB, Vous avez la possibilité de changer de licence. Mais ce serait bien de rester libre et ouvert. Encore une fois ceci est une recommandation et pas une obligation.
Bibliographie
webographie
http://fr.wikipedia.org/wiki/Licence_Creative_Commons
http://www.martijnthe.nl/2009/07/interfacing-an-optical-mouse-sensor-to-your-arduino/
https://www.arduino.cc/en/Reference/Wire
Rédaction en langue française
Partant du constat de terrain qu'une énorme masse d'information concernant les sujets qui nous intéressent comme entre autres l'impression 3D n'étaient disponibles que dans la langue de Shakespeare et que de nombreuses personnes dans notre entourage ne maîtrisaient pas la dite langue et soucieux de diffuser encore plus l'information, nous avons pris le parti, au VoLAB, de rédiger nos documents de préférence en langue française.
VoLAB
Un mot sur le VoLAB. VoLAB est un fablab implanté à environ 30km au nord-ouest de Paris dans la commune de Vauréal dans l'agglomération de Cergy Pontoise. Il est animé par l'association VoRoBoTics.
Site internet www.vorobotics.com