Aller au contenu


Photo
- - - - -

Vigibot Pi arduino Serial Communication Example


6 réponses à ce sujet

#1 Mike118

Mike118

    Staff Robot Maker

  • Administrateur
  • PipPipPipPipPip
  • 9 968 messages
  • Gender:Male
  • Location:Anglet

Posté 03 décembre 2019 - 03:30

This is a simple code example for serial communication between pi and arduino or other board with vigibot protocole with default remote configuration : 

/*
 * Vigibot Pi to Arduino Uart default remote configuration example by Mike118
 */


// Meta Type : 

typedef struct {
 union {
  struct {
   int16_t x;
   int16_t y;
  };
  int16_t coordonnees[2];
  uint8_t bytes[4];
 };
} Point;

typedef struct {
 union {
  struct {
   int8_t x;
   int8_t y;
   int8_t z;
  };
  uint8_t bytes[3];
 };
} Vitesses;


// CONFIG 

#define PISERIAL Serial
#define NBPOSITIONS 2
#define FAILSAFE 250 // ms


// TTS 

#define TTSBUFFERSIZE 255  
uint8_t ttsBuffer[TTSBUFFERSIZE];
uint8_t ttsCurseur = 0;


// TX

#define TXFRAMESIZE (NBPOSITIONS * 4 + 17)

typedef struct {
 union {
  struct {
   uint8_t sync[4];               // 4
   Point positions[NBPOSITIONS];  // NBPOSITIONS * 4
   uint16_t val16[2];             // 2 * 2
   uint8_t choixCameras;          // 1
   Vitesses vitesses;             // 3
   uint8_t interrupteurs;         // 1
   uint8_t val8[4];               // 4
  };

  uint8_t bytes[TXFRAMESIZE];
 };
} TrameTx;


// RX

#define RXFRAMESIZE (NBPOSITIONS * 4 + 9)

typedef struct {
 union {
  struct {                       // Sizes
   uint8_t sync[4];              // 4
   Point positions[NBPOSITIONS]; // NBPOSITIONS * 4
   uint8_t choixCameras;         // 1
   Vitesses vitesses;            // 3
   uint8_t interrupteurs;        // 1
  };

  uint8_t bytes[RXFRAMESIZE];
 };
} TrameRx;


TrameTx trameTx;
TrameRx trameRx;

uint32_t lastTrameTimestamp = millis();

void setup() {
  PISERIAL.begin(115200);
  // add all your init here
}


void loop() {
  
  if(readPiSerial()) {
    // each time we receive a full trame run repeatedly:
    // use values inside trameRx to tell your robot how to move ...
    // trameRx.vitesses.x , trameRx.vitesses.y, trameRx.vitesses.z 
    // trameRx.positions[i].x trameRx.positions[i].y  etc.... 
    
    writePiSerial();
    lastTrameTimestamp = millis();
  }

  if( millis() - lastTrameTimestamp > FAILSAFE ) {
    // Stop the robot in case the robot lost connection with the Pi
  } else {
    // put your main code here, to run repeatedly:
    // avoid abstacle, run speed ...
  }
}


bool readPiSerial() {
 uint8_t current;
 static uint8_t lastType = 0;
 static uint8_t n = 0;
 static uint8_t frame[RXFRAMESIZE];

 while(PISERIAL.available()) {
  current = PISERIAL.read();

  switch(n) {

   case 0:
    if(current == '$')
     n = 1;
    break;

   case 1:
    if(current != 'T' && lastType == 'T')
     writeTtsBuffer('\0');

    if(current == 'S' || current == 'T') {
     lastType = current;
     n = 2;
    } else
     n = 0;
    break;

    default:
    frame[n++] = current;

    if(n == RXFRAMESIZE) {

     if(lastType == 'T') {

      for(uint8_t i = 4; i < RXFRAMESIZE; i++) // Do not send the 4 sync data in tts
       writeTtsBuffer(frame[i]);

     } else if(lastType == 'S') {

      for(uint8_t p = 0; p < RXFRAMESIZE; p++)
       trameRx.bytes[p] = frame[p];

     }
     n = 0;
     return true;
    }

  }
 }

 return false;
}

void writePiSerial() {
 // Header, do not modify
 trameTx.sync[0] = '$';
 trameTx.sync[1] = 'R';
 trameTx.sync[2] = ' '; 
 trameTx.sync[3] = ' ';

 // modify the feedback according your need. By default we copy the trameRx content ... 
 for(uint8_t i = 0; i < NBPOSITIONS; i++) {
  trameTx.positions[i].x = trameRx.positions[i].x;
  trameTx.positions[i].y = trameRx.positions[i].y;
 }
 trameTx.val16[0] = 0;   // Voltage (will be updated by Raspberry pi)
 trameTx.val16[1] = 0;   // Percent (will be updated by Raspberry pi)
 trameTx.choixCameras = trameRx.choixCameras;
 trameTx.vitesses.x = trameRx.vitesses.x;
 trameTx.vitesses.y = trameRx.vitesses.y;
 trameTx.vitesses.z = trameRx.vitesses.z;
 trameTx.interrupteurs = trameRx.interrupteurs;
 trameTx.val8[0] = 0;   // CPU load (will be updated by Raspberry pi)
 trameTx.val8[1] = 0;   // Soc temp (will be updated by Raspberry pi)
 trameTx.val8[2] = 0;   // link (will be updated by Raspberry pi)
 trameTx.val8[3] = 0;   // RSSI (will be updated by Raspberry pi)

 for( uint8_t i = 0; i < TXFRAMESIZE; i++)
  PISERIAL.write(trameTx.bytes[i]);
}

void displayTtsBuffer (uint8_t * ttsBuffer, uint8_t bufferSize) {
// you should modify this function to display text on a screen depending on your hardware...
/* if using an arduino with a second Serial different from the PISERIAL example SERIAL1 you can do this :
  for( uint8_t i = 0; i < bufferSize; i++)
    Serial1.write(ttsBuffer[i]);
  Serial1.println("");
*/
}

void writeTtsBuffer( uint8_t ttsChar) {
  static uint8_t ttsCurseur = 0;
  if( ttsCurseur < TTSBUFFERSIZE && ttsChar != '\0') {
    ttsBuffer[ttsCurseur] = ttsChar;
    ttsCurseur ++;
  }
  if( ttsCurseur == TTSBUFFERSIZE || ttsChar == '\0') {
    displayTtsBuffer (ttsBuffer, ttsCurseur);
    ttsCurseur = 0;
  }
}
   

Note : 

 

EN

You will need change the -1 WRITEUSERDEVICE value  and replace it by the serial connection number you want use ( by default use 0 ) to tell the raspberryPi to send data to the arduino and same for READUSERDEVICE if you want the Pi to read information sent by the arduino on Vigibot. ( To do this open the management tab, open the hardware config and enable them in the effective configuration tab)

To connect your arduino to the Pi, you need to connect Arduino TX pin on Pi RX pin and Arduino Rx pin on TX Pi pin. 
Plus, you need to connect ground between Arduino and Pi .

 

Warning: 
Pi is working with a 3.3V logic level. If using a 5V arduino board ( like uno, nano or mega) you should use a logic level converter 

 

 

FR

Vous devrez changer le WRITEUSERDEVICE -1 et mettre le numero du serial que vous souhaiter utiliser pour dire à la Raspberry pi d'envoyer des données à l'arduino ( en général par défaut le numéro à mettre est 0 ) et Idem avec READUSERDEVICE pour dire à la Raspberry pi de lire les informations envoyée par l'arduino sur Vigibot. ( pour le faire ouvrez la fenêtre de Gestion, puis la fenêtre de configuration matériel et activez les options souhaitées dans " configuration effective " )

Pour relier une arduino à un pi en Serial il faut connecter le TX de l'arduino au RX de la raspberry pi et inversement le RX de l'arduino au TX de la raspberry pi. 
De plus, la masse de l'arduino et de la raspberry pi doit être commune...

 

Attention rappel : 
La raspberry pi est en niveau logique 3.3V. 
Si vous utilisez une arduino en 5V (arduino uno, mega, nano ) il faudra utiliser un convertisseur de niveau logique


 


  • Melmet aime ceci

Si mon commentaire vous a plus laissez nous un avis  !  :thank_you:

Nouveau sur Robot Maker ? 

Jetez un oeil aux blogs, aux tutoriels, aux ouvrages, au robotscope  aux articles,  à la boutique  et aux différents services disponible !
En attendant qu'une bibliothèque de fichiers 3D soit mise en place n'hésitez pas à demander si vous avez besoin du fichier 3D d'un des produits de la boutique... On l'a peut être ! 
Si vous souhaitez un robot pilotable par internet n'hésitez pas à visiter www.vigibot.com et à lire le sous forum dédié à vigibot!

 

Les réalisations de Mike118  

 

 

 


#2 Marmont

Marmont

    Nouveau membre

  • Membres
  • 2 messages

Posté 04 décembre 2019 - 03:02

Hello here,

I have tested the code with a pololu zumo, work like a charm!

 

The advantage here is if you have a robot wich is already driven by arduino, it can be easily modified to work with vigibot:

 

1) Connect the UART :

  • Ardu.pin0 RX <-> PI GPIO14 TX
  • Ardu.pin1 TX <-> PI GPIO15 RX
  • GND <-> GND

2) Modify the code above to work with your bot, in the main loop you can get the most importants variables:

trameRx.vitesses.y -> Speed in main axis of the robot send by the server

trameRx.vitesses.z - Rotation around the vertical axis send by the server

 

With theses moves requests you can program your motors to feet the particularity of the robot. Here the exemple with a classical differential driven robot, the Zumo.

    // mixage pour obtenir les vitesses moteurs
    left_speed = (trameRx.vitesses.y * MAX_SPEED / SPEED_RANGE) - (trameRx.vitesses.z * MAX_SPEED / SPEED_RANGE);
    right_speed = (trameRx.vitesses.y * MAX_SPEED / SPEED_RANGE) + (trameRx.vitesses.z * MAX_SPEED / SPEED_RANGE);

    // Saturation des vitesses
    left_speed = min(max(left_speed, -MAX_SPEED), MAX_SPEED);
    right_speed = min(max(right_speed, -MAX_SPEED), MAX_SPEED);

Then you can send the right speed to your motors, in my case: (I use a library to drive the zumo)

    ZumoMotors::setSpeeds(left_speed, right_speed);

Here the complete code :

/*
 * Vigibot Pi to Arduino Uart default remote configuration example by Mike118
 * Completed by Marmont to work with a Zumo
 */

#include <ZumoShield.h>

// Meta Type :

typedef struct {
 union {
  struct {
   uint16_t x;
   uint16_t y;
  };
  uint16_t coordonnees[2];
  uint8_t bytes[4];
 };
} Point;

typedef struct {
 union {
  struct {
   int8_t x;
   int8_t y;
   int8_t z;
  };
  uint8_t bytes[3];
 };
} Vitesses;


// CONFIG

#define PISERIAL Serial
#define NBPOSITIONS 2
#define FAILSAFE 250 // ms

#define MAX_SPEED              400 // max motor speed
#define SPEED_RANGE            128 //

// TTS

#define TTSBUFFERSIZE 255  
uint8_t ttsBuffer[TTSBUFFERSIZE];
uint8_t ttsCurseur = 0;


// TX

#define TXFRAMESIZE (NBPOSITIONS * 4 + 17)

typedef struct {
 union {
  struct {
   uint8_t sync[4];               // 4
   Point positions[NBPOSITIONS];  // NBPOSITIONS * 4
   uint16_t val16[2];             // 2 * 2
   uint8_t choixCameras;          // 1
   Vitesses vitesses;             // 3
   uint8_t interrupteurs;         // 1
   uint8_t val8[4];               // 4
  };

  uint8_t bytes[TXFRAMESIZE];
 };
} TrameTx;


// RX

#define RXFRAMESIZE (NBPOSITIONS * 4 + 9)

typedef struct {
 union {
  struct {                       // Sizes
   uint8_t sync[4];              // 4
   Point positions[NBPOSITION];  // NBPOSITIONS * 4
   uint8_t choixCameras;         // 1
   Vitesses vitesses;            // 3
   uint8_t interrupteurs;        // 1
  };

  uint8_t bytes[RXFRAMESIZE];
 };
} TrameRx;


TrameTx trameTx;
TrameRx trameRx;

uint32_t lastTrameTimestamp = millis();

void setup() {
  PISERIAL.begin(115200);
 
 
  // add all your init here
}


void loop() {
 
  if(readPiSerial()) {
    // each time we receive a full trame run repeatedly:
    // use values inside TrameRx to tell your robot how to move ...
    // trameRx.vitesses.x , trameRx.vitesses.y, trameRx.vitesses.z
    // trameRx.positions[i].x trameRx.positions[i].y  etc....
    
    writePiSerial();
    lastTrameTimestamp = millis();
  }

  if( millis() - lastTrameTimestamp > FAILSAFE ) {
    // Stop the robot in case the robot lost connection with the Pi
  } else {

    int left_speed, right_speed;
    
    // mixage pour obtenir les vitesses moteurs
    left_speed = (trameRx.vitesses.y * MAX_SPEED / SPEED_RANGE) - (trameRx.vitesses.z * MAX_SPEED / SPEED_RANGE);
    right_speed = (trameRx.vitesses.y * MAX_SPEED / SPEED_RANGE) + (trameRx.vitesses.z * MAX_SPEED / SPEED_RANGE);

    // Saturation des vitesse
    left_speed = min(max(left_speed, -MAX_SPEED), MAX_SPEED);
    right_speed = min(max(right_speed, -MAX_SPEED), MAX_SPEED);

    ZumoMotors::setSpeeds(left_speed, right_speed);
  }
}

bool readPiSerial() {
 uint8_t current;
 static uint8_t lastType = 0;
 static uint8_t n = 0;
 static uint8_t frame[RXFRAMESIZE];

 while(PISERIAL.available()) {
  current = PISERIAL.read();

  switch(n) {

   case 0:
    if(current == '$')
     n = 1;
    break;

   case 1:
    if(current != 'T' && lastType == 'T')
     writeTtsBuffer('\0');

    if(current == 'S' || current == 'T') {
     lastType = current;
     n = 2;
    } else
     n = 0;
    break;

    default:
    frame[n++] = current;

    if(n == RXFRAMESIZE) {

     if(lastType == 'T') {

      for(uint8_t i = 4; i < RXFRAMESIZE; i++) // 4 to not send the sync data into tts
       writeTtsBuffer(frame[i]);

     } else if(lastType == 'S') {

      for(uint8_t p = 0; p < RXFRAMESIZE; p++)
       trameRx.bytes[p] = frame[p];

     }
     n = 0;
     return true;
    }

  }
 }

 return false;
}

void writePiSerial() {
 // Header, do not modify
 trameTx.sync[0] = '$';
 trameTx.sync[1] = 'R';  
 trameTx.sync[2] = ' ';
 trameTx.sync[3] = ' ';

 // modify the feedback according your need. By default we copy the trameRx content ...
 for(uint8_t i = 0; i < NBPOSITIONS; i++) {
  trameTx.positions[i].x = trameRx.positions[i].x;
  trameTx.positions[i].y = trameRx.positions[i].y;
 }
 trameTx.val16[0] = 0;   // Voltage
 trameTx.val16[1] = 0;   // Percent
 trameTx.choixCameras = trameRx.choixCameras;
 trameTx.vitesses.x = trameRx.vitesses.x;
 trameTx.vitesses.y = trameRx.vitesses.y;
 trameTx.vitesses.z = trameRx.vitesses.z;
 trameTx.interrupteurs = trameRx.interrupteurs;
 trameTx.val8[0] = 0;   // CPU load
 trameTx.val8[1] = 0;   // Soc temp 
 trameTx.val8[2] = 0;   // link
 trameTx.val8[3] = 0;   // RSSI

 for( uint8_t i = 0; i < TXFRAMESIZE; i++)
  PISERIAL.write(trameTx.bytes[i]);
}

void displayTtsBuffer (uint8_t * ttsBuffer, uint8_t bufferSize) {
  // you should modify this function to display text on a screen depending on your hardware...
  /* if using an arduino with a second Serial different from the PISERIAL example SERIAL1 you can do this :
  for( uint8_t i = 0; i < bufferSize; i++)
    Serial1.write(ttsBuffer[i]);
  Serial1.println("");
  */
}

void writeTtsBuffer( uint8_t ttsChar) {
  static uint8_t ttsCurseur = 0;
  if( ttsCurseur < TTSBUFFERSIZE && ttsChar != '\0') {
    ttsBuffer[ttsCurseur] = ttsChar;
    ttsCurseur ++;
  }
  if( ttsCurseur == TTSBUFFERSIZE || ttsChar == '\0') {
    displayTtsBuffer (ttsBuffer, ttsCurseur);
    ttsCurseur = 0;
  }
}

Very easy, very fonctionnal, a lot more functionnality to investigate!

Thk to mikes118 for the great work.

Marmont


  • Mike118 et Path aiment ceci

#3 Snyp54

Snyp54

    Membre

  • Membres
  • 32 messages

Posté 10 janvier 2020 - 10:14

Hi all,

With Mike118 ( and only Mike118 ^^ ), we have make a code for use FEETECH SCS15 servo to work with Vigibot.

 

The full code

/*
 * Vigibot Pi to Arduino Uart default remote configuration example by Mike118
 */

#include <SCServo.h>
SCSCL sc;

int uint16toSCS15( uint16_t value ) {
  return (value - 32768)* 512 * 180 / (100 * 32768) + 512;
}

uint8_t servoId[4] {2, 3 , 4, 5};

// Meta Type : 

struct Point {
 union {
  struct {
   uint16_t x;
   uint16_t y;
  };
  uint16_t coordonnees[2];
  uint8_t bytes[4];
 };
} ;

struct  Vitesses{
 union {
  struct {
   int8_t x;
   int8_t y;
   int8_t z;
  };
  uint8_t bytes[3];
 };
};


// CONFIG 

#define PISERIAL Serial2
#define NBPOSITIONS 2
#define FAILSAFE 200 // ms


// TTS 

#define TTSBUFFERSIZE 255  
uint8_t ttsBuffer[TTSBUFFERSIZE];
uint8_t ttsCurseur = 0;


// TX

#define TXFRAMESIZE (NBPOSITIONS * 4 + 17)

struct TrameTx {
 union {
  struct {
   uint8_t sync[4];               // 4
   Point positions[NBPOSITIONS];  // NBPOSITIONS * 4
   uint16_t val16[2];             // 2 * 2
   uint8_t choixCameras;          // 1
   Vitesses vitesses;             // 3
   uint8_t interrupteurs;         // 1
   uint8_t val8[4];               // 4
  };

  uint8_t bytes[TXFRAMESIZE];
 };
};


// RX

#define RXFRAMESIZE (NBPOSITIONS* 4 + 9)

struct TrameRx{
 union {
  struct {                        // Sizes
   uint8_t sync[2];               // 4
   Point positions[NBPOSITIONS];  // NBPOSITIONS * 4
   uint8_t choixCameras;          // 1
   Vitesses vitesses;             // 3
   uint8_t interrupteurs;         // 1
  };

  uint8_t bytes[RXFRAMESIZE];
 };
} ;


TrameTx trameTx;
TrameRx trameRx;

uint32_t lastTrameTimestamp = millis();
Point oldPositions[NBPOSITIONS];        // NBPOSITIONS * 4

void setup() {
  PISERIAL.begin(115200);
  // add all your init here
  Serial1.begin(1000000);
  sc.pSerial = &Serial1;
}


void loop() {
  
  if(readPiSerial()) {    
    writePiSerial();
    lastTrameTimestamp = millis();
  }
  
  if( millis() - lastTrameTimestamp > FAILSAFE ) {
    // Stop the robot in case the robot lost connection with the Pi
  } else {
    // put your main code here, to run repeatedly:
    updateServo();
  }
}

void updateServo() {
  for(uint8_t i = 0; i < NBPOSITIONS; i++) {
    for(uint8_t j = 0; j < 2 ; j++) {
      if(oldPositions[i].coordonnees[j] != trameRx.positions[i].coordonnees[j]) {
        sc.WritePos(servoId[i + j], uint16toSCS15(trameRx.positions[i].coordonnees[j]), 200);
        oldPositions[i].coordonnees[j] = trameRx.positions[i].coordonnees[j];
      }
    }
  }
}

bool readPiSerial() {
 uint8_t current;
 static uint8_t lastType = 0;
 static uint8_t n = 0;
 static uint8_t frame[RXFRAMESIZE];

 while(PISERIAL.available()) {
  current = PISERIAL.read();

  switch(n) {

   case 0:
    if(current == '$')
     n = 1;
    break;

   case 1:
    if(current != 'T' && lastType == 'T')
     writeTtsBuffer('\0');

    if(current == 'S' || current == 'T') {
     lastType = current;
     n = 2;
    } else
     n = 0;
    break;

    default:
    frame[n++] = current;

    if(n == RXFRAMESIZE) {

     if(lastType == 'T') {

      for(uint8_t i = 2; i < RXFRAMESIZE; i++)
       writeTtsBuffer(frame[i]);

     } else if(lastType == 'S') {

      for(uint8_t p = 0; p < RXFRAMESIZE; p++)
       trameRx.bytes[p] = frame[p];

     }
     n = 0;
     return true;
    }

  }
 }

 return false;
}

void writePiSerial() {
 // Header, do not modify
 trameTx.sync[0] = '$';
 trameTx.sync[1] = 'R';
 trameTx.sync[2] = ' ';
 trameTx.sync[3] = ' ';  

 // modify the feedback according your need. By default we copy the trameRx content ... 
 for(uint8_t i = 0; i < NBPOSITIONS; i++) {
  trameTx.positions[i].x = trameRx.positions[i].x;
  trameTx.positions[i].y = trameRx.positions[i].y;
 }
 trameTx.val16[0] = 0;   // Voltage
 trameTx.val16[1] = 0;   // Percent
 trameTx.choixCameras = trameRx.choixCameras;
 trameTx.vitesses.x = trameRx.vitesses.x;
 trameTx.vitesses.y = trameRx.vitesses.y;
 trameTx.vitesses.z = trameRx.vitesses.z;
 trameTx.interrupteurs = trameRx.interrupteurs;
 trameTx.val8[0] = 0;   // CPU load
 trameTx.val8[1] = 0;   // Soc temp
 trameTx.val8[2] = 0;   // link
 trameTx.val8[3] = 0;   // RSSI

 for( uint8_t i = 0; i < TXFRAMESIZE; i++)
  PISERIAL.write(trameTx.bytes[i]);
}

void displayTtsBuffer (uint8_t * ttsBuffer, uint8_t bufferSize) {
  // you can modify this function to display text on a screen depending on your hardware...
  for( uint8_t i = 0; i < bufferSize; i++)
    Serial.write(ttsBuffer[i]);
  Serial.println("");
}

void writeTtsBuffer( uint8_t ttsChar) {
  static uint8_t ttsCurseur = 0;
  if( ttsCurseur < TTSBUFFERSIZE && ttsChar != '\0') {
    ttsBuffer[ttsCurseur] = ttsChar;
    ttsCurseur ++;
  }
  if( ttsCurseur == TTSBUFFERSIZE || ttsChar == '\0') {
    displayTtsBuffer (ttsBuffer, ttsCurseur);
    ttsCurseur = 0;
  }
}

 

Add SCS Library and convert 0 65535 -> -180° à 180° to 0 1023 -> -100° à 100°:

#include <SCServo.h>
SCSCL sc;

int uint16toSCS15( uint16_t value ) {
  return (value - 32768)* 512 * 180 / (100 * 32768) + 512;
}

Configure ID servo with POSITIONS: ( sc.WritePos(IDSERVO, uint16toSCS15(trameRx.positions[0].y), 200);

 
uint8_t servoId[4] {2, 3 , 4, 5};

void updateServo() {
  for(uint8_t i = 0; i < NBPOSITIONS; i++) {
    for(uint8_t j = 0; j < 2 ; j++) {
      if(oldPositions[i].coordonnees[j] != trameRx.positions[i].coordonnees[j]) {
        sc.WritePos(servoId[i + j], uint16toSCS15(trameRx.positions[i].coordonnees[j]), 200);
        oldPositions[i].coordonnees[j] = trameRx.positions[i].coordonnees[j];
      }
    }
  }
}

And voila!



#4 Mike118

Mike118

    Staff Robot Maker

  • Administrateur
  • PipPipPipPipPip
  • 9 968 messages
  • Gender:Male
  • Location:Anglet

Posté 13 février 2020 - 09:29

How to add your custom return value ? 

Chose if you want return a val8  ( 8bits value ) or a val16 ( 16bits value ) 

For example I want add a voltage value as val8. 

 

=> I will need to configure vigibot to activate devCommande and devTelemetrie  and add a val8 in RX config 

=> I will need to modify the arduino code to add my val8 in the trameTx structure and update TXFRAMESIZE. 

#define TXFRAMESIZE (NBPOSITIONS * 4 + 18)   // NBPOSITIONS * 4 + 17 by default + 1 for the val8 added ( we would add 2 for  val16)

struct TrameTx {
 union {
  struct {
   uint8_t sync[4];               // 4
   Point positions[NBPOSITIONS];  // NBPOSITIONS * 4
   uint16_t val16[2];             // 2 * 2
   uint8_t choixCameras;          // 1
   Vitesses vitesses;             // 3
   uint8_t interrupteurs;         // 1
   uint8_t val8[5];               // 4 by default => Now set to 5 = 4 +1
  };

  uint8_t bytes[TXFRAMESIZE];
 };
};

Then I will be able to make the line somewhere in the code : ( can be done in writePiSerial() but can be done elsewhere... )

trameTx.val8[4] = yourCustomValue;  // change yourCustomValue according your need.

See a full code example here : https://www.robot-ma...gibot/?p=107522

 


Si mon commentaire vous a plus laissez nous un avis  !  :thank_you:

Nouveau sur Robot Maker ? 

Jetez un oeil aux blogs, aux tutoriels, aux ouvrages, au robotscope  aux articles,  à la boutique  et aux différents services disponible !
En attendant qu'une bibliothèque de fichiers 3D soit mise en place n'hésitez pas à demander si vous avez besoin du fichier 3D d'un des produits de la boutique... On l'a peut être ! 
Si vous souhaitez un robot pilotable par internet n'hésitez pas à visiter www.vigibot.com et à lire le sous forum dédié à vigibot!

 

Les réalisations de Mike118  

 

 

 


#5 Gamepigeek

Gamepigeek

    Membre

  • Membres
  • 61 messages
  • Gender:Male
  • Location:Auxerre

Posté 05 mai 2021 - 01:15

Hello everyone ! 

 

Je vais Vigiboter mon train légo. Pour ce faire, j'utilise un ESP32. 

 

J'ai donc repris le code d'exemple de @Mike118 que j'ai adapté :


#include <WiFi.h>
#include <ESPmDNS.h>
#include "esp32-hal-ledc.h"

const char* ssid = "ssid";
const char* pass = "mdp";
// Set your Static IP address
IPAddress local_IP(192, 168, 0, 61);
// Set your Gateway IP address
IPAddress gateway(192, 168, 0, 254);
IPAddress subnet(255, 255, 255, 0);


// Meta Type :

typedef struct {
  union {
    struct {
      int16_t x;
      int16_t y;
    };
    int16_t coordonnees[2];
    uint8_t bytes[4];
  };
} Point;

typedef struct {
  union {
    struct {
      int8_t x;
      int8_t y;
      int8_t z;
    };
    uint8_t bytes[3];
  };
} Vitesses;


// CONFIG

//#define PISERIAL Serial
#define NBPOSITIONS 2
#define FAILSAFE 250 // ms

#define MAX_SPEED              1275 // max motor speed
#define SPEED_RANGE            256 //


// TTS

#define TTSBUFFERSIZE 255
uint8_t ttsBuffer[TTSBUFFERSIZE];
uint8_t ttsCurseur = 0;


// TX

#define TXFRAMESIZE (NBPOSITIONS * 4 + 17)

typedef struct {
  union {
    struct {
      uint8_t sync[4];               // 4
      Point positions[NBPOSITIONS];  // NBPOSITIONS * 4
      uint16_t val16[2];             // 2 * 2
      uint8_t choixCameras;          // 1
      Vitesses vitesses;             // 3
      uint8_t interrupteurs;         // 1
      uint8_t val8[4];               // 4
    };

    uint8_t bytes[TXFRAMESIZE];
  };
} TrameTx;

// RX

#define RXFRAMESIZE (NBPOSITIONS * 4 + 9)

typedef struct {
  union {
    struct {                       // Sizes
      uint8_t sync[4];              // 4
      Point positions[NBPOSITIONS]; // NBPOSITIONS * 4      
      uint8_t choixCameras;         // 1
      Vitesses vitesses;            // 3
      uint8_t interrupteurs;        // 1
    };

    uint8_t bytes[RXFRAMESIZE];
  };
} TrameRx;


TrameTx trameTx;
TrameRx trameRx;

uint32_t lastTrameTimestamp = millis();
uint32_t lastSleepBeacon;

WiFiServer server(7070);  //ESP server port
WiFiClient client;

void setup()
{
  Serial.begin(115200);
  ledcSetup(1, 50, 16); // channel 1, 50 Hz, 16-bit width
  ledcAttachPin(13, 1);   // GPIO 13 assigned to channel 1


  // We start by connecting to a WiFi network

  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.config(local_IP, gateway, subnet);
  WiFi.setHostname("Vigibot_ESP_0");
  WiFi.begin(ssid, pass);
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("Connection Failed! Rebooting...");    delay(5000);
    ESP.restart();
  }

  server.begin();

  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());


  // add all your init here
}

void loop() {
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("WLAN Connection Failed! reconnecting...");
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, pass);
    delay(10000);
  }

  if (readPiSerial()) {
    // each time we receive a full trame run repeatedly:
    // use values inside trameRx to tell your robot how to move ...
    // trameRx.vitesses.x , trameRx.vitesses.y, trameRx.vitesses.z
    // trameRx.positions[i].x trameRx.positions[i].y  etc....

    

    writePiSerial();
    lastTrameTimestamp = millis();
  }
  if ( millis() - lastTrameTimestamp > FAILSAFE ) {
    if ((millis() - lastSleepBeacon > 10000) ) { // every 10 seconds
      writePiSerial();                        // Beacon to say that the robot is alive
      lastSleepBeacon = millis();
    }
    // Stop the robot in case the robot lost connection with the Pi
    ledcWrite(1, 0); //stop the train

  } else {
    // put your main code here, to run repeatedly:
    // avoid abstacle, run speed ...
    
    int speed;
    
    // mixage pour obtenir les vitesses moteurs
    speed = (trameRx.vitesses.y * MAX_SPEED / SPEED_RANGE) - (trameRx.vitesses.z * MAX_SPEED / SPEED_RANGE);


    // Saturation des vitesse
    speed = min(max(speed, -MAX_SPEED), MAX_SPEED);

    ledcWrite(1, speed);
    
  }
  
}


bool readPiSerial() {
  uint8_t current;
  static uint8_t lastType = 0;
  static uint8_t n = 0;
  static uint8_t frame[RXFRAMESIZE];
  static byte lastClientState = 0;
  if (client.connected()) {
    if (!lastClientState) {
      lastClientState = 1;
      Serial.println("New Client.");
    }
    while (client.available()) {
      current = client.read();
      //Serial.write(current); //debug

      switch (n) {

        case 0:
          if (current == '$')
            n = 1;
          break;

        case 1:
          if (current != 'T' && lastType == 'T')
            writeTtsBuffer('\n');

          if (current == 'S' || current == 'T') {
            lastType = current;
            n = 2;
          } else
            n = 0;
          break;

        default:
          frame[n++] = current;

          if (n == RXFRAMESIZE) {

            if (lastType == 'T') {

              for (uint8_t i = 4; i < RXFRAMESIZE; i++) // Do not send the 4 sync data in tts
                writeTtsBuffer(frame[i]);

            } else if (lastType == 'S') {

              for (uint8_t p = 0; p < RXFRAMESIZE; p++)
                trameRx.bytes[p] = frame[p];

            }
            n = 0;
            return true;
          }
          //break;
      }
    }
  } else { //if current client is not actively connected anymore, disconnect and wait for new client
    if (lastClientState) {
      lastClientState = 0;
      // close the connection:
      client.stop();
      Serial.println("Client Disconnected.");
    }
    client = server.available();   // listen for incoming clients
  }
  return false;
}

void writePiSerial() {
  // Header, do not modify
  trameTx.sync[0] = '$';
  trameTx.sync[1] = 'R';
  trameTx.sync[2] = ' ';
  trameTx.sync[3] = ' ';

  // modify the feedback according your need. By default we copy the trameRx content ...
  for (uint8_t i = 0; i < NBPOSITIONS; i++) {
    trameTx.positions[i].x = trameRx.positions[i].x;
    trameTx.positions[i].y = trameRx.positions[i].y;
  }
  trameTx.val16[0] = 0;   // Voltage (will be updated by Raspberry pi)
  trameTx.val16[1] = 0;   // Percent (will be updated by Raspberry pi)
  trameTx.choixCameras = trameRx.choixCameras;
  trameTx.vitesses.x = trameRx.vitesses.x;
  trameTx.vitesses.y = trameRx.vitesses.y;
  trameTx.vitesses.z = trameRx.vitesses.z;
  trameTx.interrupteurs = trameRx.interrupteurs;
  trameTx.val8[0] = 0;   // CPU load (will be updated by Raspberry pi)
  trameTx.val8[1] = 0;   // Soc temp (will be updated by Raspberry pi)
  trameTx.val8[2] = 0;   // link (will be updated by Raspberry pi)
  trameTx.val8[3] = 0;   // RSSI (will be updated by Raspberry pi)

  for ( uint8_t i = 0; i < TXFRAMESIZE; i++)
    client.write(trameTx.bytes[i]);
}

void displayTtsBuffer (uint8_t * ttsBuffer, uint8_t bufferSize) {
  // you can modify this function to display text on a screen depending on your hardware...
  for ( uint8_t i = 0; i < bufferSize; i++) {
    Serial.write(ttsBuffer[i]);
  }
  Serial.println("");
}

void writeTtsBuffer( uint8_t ttsChar) {
  static uint8_t ttsCurseur = 0;
  if ( ttsCurseur < TTSBUFFERSIZE && ttsChar != '\n') {
    ttsBuffer[ttsCurseur] = ttsChar;
    ttsCurseur ++;
  }
  if ( ttsCurseur == TTSBUFFERSIZE || ttsChar == '\n') {
    displayTtsBuffer (ttsBuffer, ttsCurseur);
    ttsCurseur = 0;
  }
}

Ca fonctionne parfaitement sauf que quand j'accélère sur Vigibot ca n'avance pas comme je veux vu que les math n'ont pas été faites.

 

Je parle de :

#define MAX_SPEED              1275 // max motor speed
#define SPEED_RANGE            256 //

ou/et de :

ledcSetup(1, 50, 16); // channel 1, 50 Hz, 16-bit width

en sachant que vigibot envoi les consignes moteurs en 8 bit .. 

 

Je n'ai pas encore le niveau pour améliorer comme je veux ce genre de réglage PWM Hertz etc..

 

Le calcul reste le meme que pour Zumo.

 

Merci de votre aide !

 

Pierre


Pierre

 

Pour visiter mon site perso auto hébergé, cliquez sur ce : Lien.

Je possède des robots sur Vigibot, n'hésitez pas a y faire un tour et demander l'accès au pilotage x).


#6 firened

firened

    Membre

  • Membres
  • 44 messages
  • Gender:Male

Posté 05 mai 2021 - 07:07

Hi Pierre
Good job with the ledc functions, it's not easy to learn that!

i only found this, could be a problem:

int speed;
    
    // mixage pour obtenir les vitesses moteurs
    speed = (trameRx.vitesses.y * MAX_SPEED / SPEED_RANGE) - (trameRx.vitesses.z * MAX_SPEED / SPEED_RANGE);
integer is only -32'xxx to + 32'xxx, your calculation with maximum values (127 * 1275) will exceed that value. consider using a single factor like this to get somewhere close (only natural numbers, no 10.1 or so) :
int speed;
    
    // mixage pour obtenir les vitesses moteurs
    speed = (trameRx.vitesses.y * 10) - (trameRx.vitesses.z * 10);

and also make sure `IPAddress gateway(192, 168, 0, 254);` is the IP of your Router.

let me know if it helps. if not: is the motor speed random or always the same when not stopped?

#7 Gamepigeek

Gamepigeek

    Membre

  • Membres
  • 61 messages
  • Gender:Male
  • Location:Auxerre

Posté 07 mai 2021 - 10:25

Hello,

 

I finished my code with the help of Mike118 and Firened ! Thank you so much


#include <WiFi.h>
#include <ESPmDNS.h>

int pwmChannel = 0; //Choisit le canal 0
int frequence = 50; //Fréquence PWM de 5 KHz
int resolution = 16; //Résolution de 16 bits, 65535 valeurs possibles
int pwmPin = 13;
int MaxRev = 8192;// duty cycle pour avancer fond
int MaxFor = 1638;// duty cycle pour reculer a fond



const char* ssid = "My Wifi";
const char* pass = "My Pass";
// Set your Static IP address
IPAddress local_IP(192, 168, 0, 61);
// Set your Gateway IP address
IPAddress gateway(192, 168, 0, 254);
IPAddress subnet(255, 255, 255, 0);


// Meta Type :

typedef struct {
  union {
    struct {
      int16_t x;
      int16_t y;
    };
    int16_t coordonnees[2];
    uint8_t bytes[4];
  };
} Point;

typedef struct {
  union {
    struct {
      int8_t x;
      int8_t y;
      int8_t z;
    };
    uint8_t bytes[3];
  };
} Vitesses;


// CONFIG

//#define PISERIAL Serial
#define NBPOSITIONS 2
#define FAILSAFE 250 // ms

// TTS

#define TTSBUFFERSIZE 255
uint8_t ttsBuffer[TTSBUFFERSIZE];
uint8_t ttsCurseur = 0;


// TX

#define TXFRAMESIZE (NBPOSITIONS * 4 + 17)

typedef struct {
  union {
    struct {
      uint8_t sync[4];               // 4
      Point positions[NBPOSITIONS];  // NBPOSITIONS * 4
      uint16_t val16[2];             // 2 * 2
      uint8_t choixCameras;          // 1
      Vitesses vitesses;             // 3
      uint8_t interrupteurs;         // 1
      uint8_t val8[4];               // 4
    };

    uint8_t bytes[TXFRAMESIZE];
  };
} TrameTx;

// RX

#define RXFRAMESIZE (NBPOSITIONS * 4 + 9)

typedef struct {
  union {
    struct {                       // Sizes
      uint8_t sync[4];              // 4
      Point positions[NBPOSITIONS]; // NBPOSITIONS * 4      
      uint8_t choixCameras;         // 1
      Vitesses vitesses;            // 3
      uint8_t interrupteurs;        // 1
    };

    uint8_t bytes[RXFRAMESIZE];
  };
} TrameRx;


TrameTx trameTx;
TrameRx trameRx;

uint32_t lastTrameTimestamp = millis();
uint32_t lastSleepBeacon;

WiFiServer server(7070);  //ESP server port
WiFiClient client;

void setup()
{
  Serial.begin(115200);
  
  ledcSetup(pwmChannel, frequence, resolution);
  ledcAttachPin(pwmPin, pwmChannel);
  // We start by connecting to a WiFi network

  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.config(local_IP, gateway, subnet);
  WiFi.setHostname("Vigibot_ESP_0");
  WiFi.begin(ssid, pass);
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("Connection Failed! Rebooting...");    delay(5000);
    ESP.restart();
  }

  server.begin();

  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());


  // add all your init here
}

void loop() {
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("WLAN Connection Failed! reconnecting...");
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, pass);
    delay(10000);
  }

  if (readPiSerial()) {
    // each time we receive a full trame run repeatedly:
    // use values inside trameRx to tell your robot how to move ...
    // trameRx.vitesses.x , trameRx.vitesses.y, trameRx.vitesses.z
    // trameRx.positions[i].x trameRx.positions[i].y  etc....

    

    writePiSerial();
    lastTrameTimestamp = millis();
  }
  if ( millis() - lastTrameTimestamp > FAILSAFE ) {
    if ((millis() - lastSleepBeacon > 10000) ) { // every 10 seconds
      writePiSerial();                        // Beacon to say that the robot is alive
      lastSleepBeacon = millis();
    }
    // Stop the robot in case the robot lost connection with the Pi
    ledcWrite(pwmChannel, 0); //stop the train

  } else {
    // put your main code here, to run repeatedly:
    // avoid abstacle, run speed ...
    
    // mixage pour obtenir les vitesses moteurs
    int speed = map(trameRx.vitesses.y, -128, 128, MaxFor, MaxRev); // 128 recu par vigibot
    
    ledcWrite(pwmChannel, speed); //envoyer la consigne vitesse au moteur via la lib
    
  }
  
}


bool readPiSerial() {
  uint8_t current;
  static uint8_t lastType = 0;
  static uint8_t n = 0;
  static uint8_t frame[RXFRAMESIZE];
  static byte lastClientState = 0;
  if (client.connected()) {
    if (!lastClientState) {
      lastClientState = 1;
      Serial.println("New Client.");
    }
    while (client.available()) {
      current = client.read();
      //Serial.write(current); //debug

      switch (n) {

        case 0:
          if (current == '$')
            n = 1;
          break;

        case 1:
          if (current != 'T' && lastType == 'T')
            writeTtsBuffer('\n');

          if (current == 'S' || current == 'T') {
            lastType = current;
            n = 2;
          } else
            n = 0;
          break;

        default:
          frame[n++] = current;

          if (n == RXFRAMESIZE) {

            if (lastType == 'T') {

              for (uint8_t i = 4; i < RXFRAMESIZE; i++) // Do not send the 4 sync data in tts
                writeTtsBuffer(frame[i]);

            } else if (lastType == 'S') {

              for (uint8_t p = 0; p < RXFRAMESIZE; p++)
                trameRx.bytes[p] = frame[p];

            }
            n = 0;
            return true;
          }
          //break;
      }
    }
  } else { //if current client is not actively connected anymore, disconnect and wait for new client
    if (lastClientState) {
      lastClientState = 0;
      // close the connection:
      client.stop();
      Serial.println("Client Disconnected.");
    }
    client = server.available();   // listen for incoming clients
  }
  return false;
}

void writePiSerial() {
  // Header, do not modify
  trameTx.sync[0] = '$';
  trameTx.sync[1] = 'R';
  trameTx.sync[2] = ' ';
  trameTx.sync[3] = ' ';

  // modify the feedback according your need. By default we copy the trameRx content ...
  for (uint8_t i = 0; i < NBPOSITIONS; i++) {
    trameTx.positions[i].x = trameRx.positions[i].x;
    trameTx.positions[i].y = trameRx.positions[i].y;
  }
  trameTx.val16[0] = 0;   // Voltage (will be updated by Raspberry pi)
  trameTx.val16[1] = 0;   // Percent (will be updated by Raspberry pi)
  trameTx.choixCameras = trameRx.choixCameras;
  trameTx.vitesses.x = trameRx.vitesses.x;
  trameTx.vitesses.y = trameRx.vitesses.y;
  trameTx.vitesses.z = trameRx.vitesses.z;
  trameTx.interrupteurs = trameRx.interrupteurs;
  trameTx.val8[0] = 0;   // CPU load (will be updated by Raspberry pi)
  trameTx.val8[1] = 0;   // Soc temp (will be updated by Raspberry pi)
  trameTx.val8[2] = 0;   // link (will be updated by Raspberry pi)
  trameTx.val8[3] = 0;   // RSSI (will be updated by Raspberry pi)

  for ( uint8_t i = 0; i < TXFRAMESIZE; i++)
    client.write(trameTx.bytes[i]);
}

void displayTtsBuffer (uint8_t * ttsBuffer, uint8_t bufferSize) {
  // you can modify this function to display text on a screen depending on your hardware...
  for ( uint8_t i = 0; i < bufferSize; i++) {
    Serial.write(ttsBuffer[i]);
  }
  Serial.println("");
}

void writeTtsBuffer( uint8_t ttsChar) {
  static uint8_t ttsCurseur = 0;
  if ( ttsCurseur < TTSBUFFERSIZE && ttsChar != '\n') {
    ttsBuffer[ttsCurseur] = ttsChar;
    ttsCurseur ++;
  }
  if ( ttsCurseur == TTSBUFFERSIZE || ttsChar == '\n') {
    displayTtsBuffer (ttsBuffer, ttsCurseur);
    ttsCurseur = 0;
  }
}

Pierre

 

Pour visiter mon site perso auto hébergé, cliquez sur ce : Lien.

Je possède des robots sur Vigibot, n'hésitez pas a y faire un tour et demander l'accès au pilotage x).




Répondre à ce sujet



  


0 utilisateur(s) li(sen)t ce sujet

0 members, 0 guests, 0 anonymous users