Advanced stuf for robot Junior

Avertissement

Pour fonctionner la maquette à besoin de la station sol à cause du NRF24 bloquant (sauf si la ligne est commentée).

Bilan hardware

La liste des broches utilisées dans la version de base se trouve dans les fiches pédagogiques 1 sous Github

La dessus, on ajoute 6 broches pour le capteur du Suiveur de ligne (6,8,10,14,16,18)

Le module NRF24 pour la télémétrie utilise les broches SPI cf Télémètrie / RF transmissions ainsi que 48 et 49

La mesure de la tension batterie est sur A0

Suiveur de ligne

Projet très ressemblant sur Hackster.io 2

3 capteurs IR de chaque côté

Ajout d’un connecteur 8 points.

Pin

Signal

Arduino pin

1

GND

2

D EXT

6

3

D MID

8

4

D INT

10

5

G INT

14

6

G MID

16

7

G EXT

18

8

P5V

Résultats

Enregistrement avec station sol NRF24L01

Station sol

Station sol NRF24

Test du 23/11/2019 à 18:52
  • VBAT 6.9V à 7.4V

  • vitesse : 90

  • Durée du test : 072725 au chrono manuel 1:11:53

  • les 4 points; 08:80, 24:68, 47:97, 1:03:21 (En ms 8800, 24680, 47970, 63210, 71530).

Essais de vitesse : 7.0V 120 ok putty_tx_191123_2131

Remplacement des batterie 7.8V(ie 8.4V à vide) KO pour 120 7.7 90 OK putty_tx_191123_2316.log en 57s 7.7V vitesse 110 ok 46s putty_tx_191124_0000.log

Temps de cycle à 10ms putty_tx_191124_0008.log TC 10ms V 110 BAT 7.7V putty_tx_191124_0017.log US actif refresh every 10ms

Mesure de vitesse

Sur une ligne droite de 3m parcours en 7s (vitesse dans le code : 110, tension bat-moyenne: 7.45V) 3/7 m/s soit 42.85cm/s = 1.54km/h Diam roue = 65mm Périmètre = 204mm on tourne à 2.1 tr/s soit environ 126tr/min Mesure au tachymetre à vide : 171 RPM

Même essai à 90 (7.42V pour 7.87V à vide) : 3m en 9.4s à 70 : 3m en 16.7s

Avec batterie full : 13.5s avec 90 8.43s fichier non conservé avec 110 6.5s Vbat_moy : 7.65V - en charge - mesurées à 8.18V à vide fichier : putty_tx_191126_2317_3m_110_full.log

V=200 4.6s, VBAT 7.5V

Le reste des résultats est consigné dans le fichier Excel : speeds.xlsx

En conclusion on est à environ 110tr/min

Calcul du demi tour

Diametre de roue 65mm, soit un périmètre de 204mm.

Vitesse 120tr/min (Vbat 7.2V consigne 115) soit 2tr/s soit encore 0.02tr/cycle de 10ms.

Ce qui nous donne un déplacement de’environ 4mm/cycle (204*0.02).

Pour faire un demi tour en bloquant une roue, il faut parcourir un demi périmètre du cercle décrit par une roue (entraxe des roues 110mm).

Distance à parcourir pixD/2 soit encore pi*R soit 346mm à raison de 4mm/cycle, il faut 86.5 cycles.

Résultat expérimental : avec 90 cycles on a seulement un bon tiers de tour.

Explication : au démarrage de la rotation la roue en rotation « broute ».

Par expérimentation (branche cpUnTour) on arrive à environ 120 cycles pour un demi-tour.

En activant les 2 roues une en avant et l’autre en arrière la valeur serait de 55, le mouvement est alors plus agréable.

Maitrise des déplacements

A VBAT = 7.5V, V = 110, on fait du 4mm/cycle de 10ms A VBAT = 7.5V, V = 70, on fait du 2mm/cycle

Fin des travaux suivenur de ligne décembre 2019

Resterait à faire:
  • évaluation du sens du virage avant la perte de ligne

  • ralentir dans les virages

  • plusieurs canaux de télémétrie (BLE4.0 et LORA cartes reçues)

  • adapter la vitesse en fonction de la tension batterie

  • ajouter l’odomètrie

Télémètrie / RF transmissions

Besoin débit

Exemple:

On part sur 32 octets soit 320bits en moins de 1ms à transmettre

1 bits (1/320)ms = 3.215 10-6 environ 312kbits/s

Trame: (séparateur ,)

Sensor gauche (1c),Sensor droit (1c),Vbat(3c),reserve (3c) soit 11 octets

Exemple:

4,0,3.2,0.0

11 octets trasmis en 1ms (max)

10-3/110 = 9us/bits soit 110kbits/s

Choix du module RF

Très bonne vidéo youtube: Electronoobs 3

433MHz low cost modules

Utilisation de module 433MHz solution rapidement abandonnée porté insufisante au travers des murs.

Modules RF 433MHz

Modules RF 433MHz

Deux fils de 173mm de long pour les antennes des modules radio.

Communiquer sans fil en 433MHz avec la bibliothèque VirtualWire et une carte Arduino / Genuino sur les carnets du maker 4

Très bon article sur DroneBot Workshop 6

Radiohead library 5

ACP220 modules

On a pas réussi à les faire fonctionner

Nous avons réussi à les faire communiquer avec le logiciel prévu pour les paramètrer: RF-Magic

A condition de lancer le logiciel en mode admi (sous W7) et de changer le nom du port COM pour un nom ne comportant qu’un seul digit de COM37 vers COM2 par exemple.

Essais à 433MHz, 470, 434 avec les même id node et des id différents. sans aucun succès.

Module récupérer il y a quelques année impossible de dire s’ils étaient fonctionnels.

NF24

Utilisation de la librairie : RF24 from TMRh20 7 disponible sur github mais aussi directement dans le gestionnaire de librairie ARDUINO. Librairie très bien renseignée avec une documentation très complète sous Doxygen.

Les modules NRF24RL01 8 utilsés proviennent de chez Amazon.

NRF24L01 modules

NRF24L01 modules

Réussite. Transfert de 4 puis 8 octets à 2Mbps.

Le temps total d’aller et retour est d’environ 1.4ms. Utilisation du sketch exemple GettingStarted.ino Léèrement modifié.

/*
* Getting Started example sketch for nRF24L01+ radios
* This is a very basic example of how to send data from one node to another
* Updated: Dec 2014 by TMRh20
*/

#include <SPI.h>
#include "RF24.h"

/****************** User Config ***************************/
/***      Set this radio as radio number 0 or 1         ***/
bool radioNumber = 1;

/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */
RF24 radio(7,8);
/**********************************************************/

byte addresses[][6] = {"Node1","Node2"};

// Used to control whether this node is sending or receiving
bool role = 0;
unsigned long cpt = 0;
void setup() {
  Serial.begin(115200);
  Serial.println(F("RF24/examples/GettingStarted"));
  Serial.println(F("*** PRESS 'T' to begin transmitting to the other node"));

  radio.begin();

  // Set the PA Level low to prevent power supply related issues since this is a
 // getting_started sketch, and the likelihood of close proximity of the devices. RF24_PA_MAX is default.
  radio.setPALevel(RF24_PA_MAX);
  if( radio.setDataRate( RF24_2MBPS ) ) Serial.println("speed is now 2Mbps");


  // Open a writing and reading pipe on each radio, with opposite addresses
  if(radioNumber){
    radio.openWritingPipe(addresses[1]);
    radio.openReadingPipe(1,addresses[0]);
    Serial.print("Je suis le node : ");Serial.println( (char *)addresses[1] );
  }else{
    radio.openWritingPipe(addresses[0]);
    radio.openReadingPipe(1,addresses[1]);
    Serial.print("Je suis le node : ");Serial.println( (char *)addresses[0] );
  }
  if ( !radio.isChipConnected() ){
      Serial.println(" Pb connection ! Aborted.");
      for(;;);
  } else {
      Serial.println( "appreil bien connecte.");
      // for(;;);
  }
  Serial.print("pa level : "); Serial.println( radio.getPALevel() );
  Serial.print("Payloadsize : ");Serial.println( radio.getPayloadSize() );

  // Start the radio listening for data
  radio.startListening();
}

void loop() {


/****************** Ping Out Role ***************************/
if (role == 1)  {
    Serial.println("TX role");
    radio.stopListening();                                    // First, stop listening so we can talk.


    Serial.println(F("Now sending"));

    // unsigned long start_time = micros();                             // Take the time, and send it.  This will block until complete
    unsigned long start_time[2];
    start_time[0]= micros();                             // Take the time, and send it.  This will block until complete
    start_time[1]= millis();
     if (!radio.write( start_time, 2*sizeof(unsigned long) )){
       Serial.println(F("failed"));
     }

    radio.startListening();                                    // Now, continue listening

    unsigned long started_waiting_at = micros();               // Set up a timeout period, get the current microseconds
    boolean timeout = false;                                   // Set up a variable to indicate if a response was received or not

    while ( ! radio.available() ){                             // While nothing is received
      if (micros() - started_waiting_at > 200000 ){            // If waited longer than 200ms, indicate timeout and exit while loop
          timeout = true;
          break;
      }
    }

    if ( timeout ){                                             // Describe the results
        Serial.println(F("Failed, response timed out."));
    }else{
        unsigned long got_time[2];                                 // Grab the response, compare, and send to debugging spew
        radio.read( got_time, 2*sizeof(unsigned long) );
        unsigned long end_time = micros();

        // Spew it
        Serial.print(F("Sent "));
        Serial.print(start_time[0]);
        Serial.print(start_time[1]);
        Serial.print(F(", Got response "));
        Serial.print(got_time[0]);
        Serial.print(got_time[1]);
        Serial.print(F(", Round-trip delay "));
        Serial.print(end_time-start_time[0]);
        Serial.println(F(" microseconds"));
    }

    // Try again 1s later
    delay(1000);
  }



/****************** Pong Back Role ***************************/

if ( role == 0 ){
    // unsigned long got_time;
    unsigned long got_time[2];
    // Serial.print("Role peroquet.");
    // Serial.println( cpt++);
    if( radio.available()){
        // Variable for the received timestamp
        while (radio.available()) {                                   // While there is data ready
            radio.read( got_time, 2*sizeof(unsigned long) );             // Get the payload
        }

        radio.stopListening();                                        // First, stop listening so we can talk
        radio.write( got_time, 2*sizeof(unsigned long) );              // Send the final one back.
        radio.startListening();                                       // Now, resume listening so we catch the next packets.
        // Serial.print(F("Sent response "));
        // Serial.println(got_time);
    }
}




/****************** Change Roles via Serial Commands ***************************/

  if ( Serial.available() )
  {
    char c = toupper(Serial.read());
    if ( c == 'T' && role == 0 ){
      Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK"));
      role = 1;                  // Become the primary transmitter (ping out)

   }else
    if ( c == 'R' && role == 1 ){
      Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK"));
       role = 0;                // Become the primary receiver (pong back)
       radio.startListening();

    }
  }


} // Loop

La doc de la méthode write, nous apprend que c’est une méthode bloquante et que la pyload est fixe.

La méthode getPayloadSize() renvoi 32. donc que nous transmettion 8 ou 32 octets le temps sera identique !

On atteind facilement les extrémité du lab en conservant 1.5ms.

Avertissement

Les broche 7 et 8 étaient inversée.

 /**
* Arduino Constructor
*
* Creates a new instance of this driver.  Before using, you create an instance
* and send in the unique pins that this chip is connected to.
*
* @param _cepin The pin attached to Chip Enable on the RF module
* @param _cspin The pin attached to Chip Select
*/
 RF24(uint16_t _cepin, uint16_t _cspin);

Temps d’émission mesuré avec la technique de micros : 700us entre mon poste et l’autre extrêmité du lab.

Mise en place du module NRF24 sur le robot

Sur la maquette ainsi que sur la version PCB, nous n’avons que peu de lattitude pour ajouter des modules. Chance, la 2560pro fourni un petit connecteur de 6 IO que nous n’avons pas utilisé.

Connecteur 2560pro 6 io

Connecteur 2560pro 6 io

En réalité, ces 6 broches ne sont pas vraiment disponibles si on veut utiliser le bus SPI. En effet, sur l’ATMega2560 le bus SPI est sur ces broches… seules 48 et 49 sont vraiment disponibles.

Connecteur 2560pro partage SPI

Connecteur 2560pro 6 Connecteur 2560pro partage SPI

Réalisation d’un adaptateur :

adatateur NRF24 cablage

Adatateur NRF24 plan de cablage

NRF24L01 modules

NRD24L01 pinout

texte

Autres solutions à explorer

XBEE : product line sur protocole ZigBee

Diffcile à approvisionner sur le marcher chinois et relativement honéreux.

Dispo XBEE chez MOUSER 9 à 18€ sans antenne sachant qu’il en faut au moins 2

Préférer les modules en 2.4GHz à mon avis (pifométrique)

LORA un bon exemple sur Hacksterio 10

BLE4.0

Modules BLE sur AMAZON 11 à 9.99€ pièce

Modules BLE sur aliExpress 12 à 2.33€ basé sur un CC2541 de TI

Exemple ARDUINO 13

BLE5.0 sur AMAZON 14 9.99€ basé sur un CC2640R2F de TI

DSD Tech 15 official website

RPM Mesure

140 à vide pouvant descendre jusqu’à 50 en charge mais une valeur raisonnable semble être 130 rpm. Pour un PWM à 100

260 RPM full batterie et PWM à 250

109 RMP full batterie et pour PWM 70

109 rpm avec des roues de 66mm Soit 1 tour 66x2xpimm = 415mm x 109 / 60 soit 753mm/s ou encore 0.753mm/ms 3.77mm / cycle de 5ms

Mesure de temps de cycle

Mesure du temps nécessaire pour exécuter la mise à jour des pwm moteur

méthode : void CRobotJunior::update()

Branche devJojo_sans_OptiVersionAvecTlmNRF24, commit : 53488c

Temps mesuré à l’oscilloscope 69us (y compris les 2 digitalWrite qui prennet chacun environ 9us)

Plus grâve est le temps de répétition qui vaut une vingtaine de ms très instable. Cause identifiée : les capteurs ultrason et leur timeout à 30ms utilisant la fonction pulse bloquante.

une solution élégante serait de fixer le timeout à 2900us soit 50cm.

En désactivant tout, le temps de cyle est à 5ms/+1.4ms : ce jitter de 1.4ms est inexplicable et persiste même en aillant désactivé tous les update de la méthode robot.update(). Un début d’explication serait dans l’implémentation de la foinction millis elle-même voir sur le forum ARDUINO 16

Batterie pack

16850 batterie

Chargeur de batteries

LED bar : Seedstudio 17

ou