Aller au contenu


Photo
- - - - -

Vigibot Pi to multiple ESP32 WLAN Communications Example

esp32 arduino

6 réponses à ce sujet

#1 firened

firened

    Nouveau membre

  • Membres
  • 24 messages
  • Gender:Male

Posté 15 décembre 2020 - 11:11

Note:
• if you want to control a single ESP32 robot/gadget, use this guide instead:
https://www.robot-ma...ample/?p=111377
• if you want to control multiple ESP32 robots/gadgets, continue.

This code allows control of multiple ESP32 robots or gadgets over WLAN using vigibot.
A raspberry is still required for the camera and needs to be on the same network. the serial data usually sent and received to an Arduino over UART ( https://www.robot-ma...cation-example/ ), is being sent over WLAN instead, allowing control of small robots or gadgets.
usage example: a pi with a camera watches an arena where multiple small ESP32 robots can be driven, the ESP32 bots do not have an on-board camera.
second usage example: open or close a door or toy controlled fron an ESP32.

1) assign your pi a static IP address
https://thepihut.com...-address-update

2) the pi needs to create a virtual serial point that's accessible over WLAN from the ESP32. install socat and ncat on your raspberry:

sudo apt install socat ncat

3) create a new script:

sudo nano /usr/local/ncat_esp.sh

4) paste the following code:

#!/bin/bash

sudo socat pty,link=/dev/ttyVigi0,rawer,shut-none pty,link=/dev/ttySrv,rawer,shut-none &

while true
do
  sleep 1
  sudo ncat -l -k -4 --idle-timeout 15 7070 </dev/ttySrv >/dev/ttySrv
  date
  echo "restarting ncat"
done

5) add permissions

sudo chmod +x /usr/local/ncat_esp.sh

6) run the script

sudo /usr/local/ncat_esp.sh

7) insert your
- network info
- raspberry host IP
- vigibot NBpositions (if different from default)
into the following sketch and upload it to your ESP32 from the arduino IDE using a usb cable.
note: only one esp can send a reply, make sure `client.write();` is only being called on one ESP32, all others only listen without sending any data back. (i recommend that one ESP32 sends data back, this way the vigibot robot won't wake up if the ESP32 isn't connected properly, which makes it easier to notice that it isn't working.)

Spoiler


8) open the serial monitor to confirm a successful WLAN and TCP client connection.

9) test the pi <-> ESP connection by logging in as root in a new shell (needs root) :

su -

and sending a test text frame:

echo '$T  hello from cli       $n' > /dev/ttyVigi0

the arduino serial monitor now says "hello from cli "

10)if it works add it to start at boot:

sudo nano /etc/rc.local

and add

/usr/local/socat-esp.sh &

above the line "exit 0".

11) add an entry on the vigibot online remote control config -> SERIALPORTS -> 3 with value: "/dev/ttyVigi0"

12) set WRITEUSERDEVICE to "3"

13) if you set up an ESP32 to send data back:
set READUSERDEVICE to "3"

restart the client and wake your robot up, if it wakes up then everything works.


related notes:
you can add a dummy client from the command line, in case you want to check if the vigibot frames are made available:   

sudo socat tcp:localhost:7070 -
   

similarly it's theoretically also possible to fetch this data from another computer or custom script/application.

there's an outage happening every few weeks or so, from which it doesn't recover.   
it looks like ncat doesn't open the socat socket if there's too much data buffered. the workaround is to manually clear the socat socket using
sudo cat /dev/ttySrv
and then cancel with `ctrl-c`

 

#2 zavatha

zavatha

    Habitué

  • Membres
  • PipPip
  • 193 messages
  • Gender:Male

Posté 16 décembre 2020 - 10:59

Salut à tous,

 

J'avais dans l'idée de d'utiliser vigibot pour contrôler un projet à base d'ESPCam 32...

Le but étant de streamer non pas la video de la cam du pi mais celle de l'ESP cam... quitte à utiliser le PI comme passerelle et que ce soit lui qui s'ovvupe de commuter à video à consulter à la demande... un vigibot dans vigibot en somme :P

 

Je n'ai pas encore creusé... acr je n'ai le temps de rien, quasiment tous les projets sont en pause depuis 2 mois...

 

est-ce possible ?... en tout cas avec ce poste on s'en approche ;)

 

L'idée serait de contrôler plusieurs devices lowcost constitués sur la même base et de passer de l'un à l'autre...

 

allez je balance un screenshot de la modélisation du projet en question (le proto du premier device), l'électronique est en cours d'assemblage / tests et le dev (V1) est fait à 90% : 

 

image_2020-12-16_105220.png

 

pour le moment, le device heberge un serveur web et est donc contrôlé en direct avec un smartphone...

 

@+

 

Zav



#3 firened

firened

    Nouveau membre

  • Membres
  • 24 messages
  • Gender:Male

Posté 16 décembre 2020 - 11:12

Hi Zav
i thought about that too, it would be cool.
i doubt an esp32 will be able to send a low latency video stream. i don't know though, haven't used a cam32 board yet.

a different option could be using an analog fpv cam like a runcam used on multicopters and send that video to a usb capture device on a raspberry pi.
fpv cameras can have a very small footprint, which is great for tiny robots where a pi doesn't fit onto.

is your cam 32 webview test already working? I'd love to hear about its latency, resolution and fps rate.

good luck

#4 zavatha

zavatha

    Habitué

  • Membres
  • PipPip
  • 193 messages
  • Gender:Male

Posté 16 décembre 2020 - 11:31

hi firened,

 

i don't have analog runcam because of low costs constraints... so i turned back to espcam 32 (6$ only)

i agree : low latency streaming is a little bit deception with espcam 32 so for the moment i only make one POOC and i will see the effectivity of the system...

i didnt made serious mesures but i think i have 5fps, perhaps 10fps with correct resolution (not 320p)

it is not very good but sufficient for my usage...

 

but, in an other hand, i observed stability issues (freeze) while connected to my computer with a ftdi module... wait to see with dedicated power supply system.

 

i totaly agree with you and think a realist way is to use some fpv cams, associated to esp in order pilot the devices from the PI... like Pascal conception for vigibot... but don't have the funds :(

 

have a good day

 

@+

Zav



#5 Gamepigeek

Gamepigeek

    Nouveau membre

  • Membres
  • 58 messages
  • Gender:Male
  • Location:Auxerre
  • Interests:Robots, Electronique, Informatique.

Posté 06 avril 2021 - 09:30

Bonjour a toutes et tous,

 

Je cherche a connecter un NodeMCU a base d'ESP8266 pour "vigiboter" un train lego.

 

J'ai utilisé l'exemple de @Mike118 modifié par @Firened sans succès car j'obtiens l'erreur : 

void writePiSerial()':
sketch_apr06a:237:34: error: 'struct TrameRx' has no member named 'choixCameras'
   trameTx.choixCameras = trameRx.choixCameras;
                                  ^
exit status 1
'struct TrameRx' has no member named 'choixCameras'

le code est : 

#include <WiFi.h>
#include <ESP8266WiFi.h>
 
//ici c'est simplement en tant que serveur :P
const char* ssid = "your_ssid";
const char* pass = "your_pass";
// Set your Static IP address
IPAddress local_IP(192, 168, 1, 61);
// Set your Gateway IP address
IPAddress gateway(192, 168, 1, 1);
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);
  Serial.println();
 
  WiFi.begin("SSID", "PASS");
 
  Serial.print("Connecting");
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println();
 
  Serial.print("Connected, IP address: ");
  Serial.println(WiFi.localIP());
}
 
void loop() {
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
 
  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
    
  } 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];
  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;
  }
}

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 Mike118

Mike118

    Staff Robot Maker

  • Administrateur
  • PipPipPipPipPip
  • 9 048 messages
  • Gender:Male
  • Location:Anglet
  • Interests:Robotique, Entrepreneuriat, Innovation, Programmation, Résolution de problème, Recherche de solutions, Mécanique, Electronique, Créer, Concevoir

Posté 06 avril 2021 - 09:36

tu as pas su copier coller la structure correctement ... 

 

#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;

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 ! 

 

Les réalisations de Mike118  

 

 

 


#7 firened

firened

    Nouveau membre

  • Membres
  • 24 messages
  • Gender:Male

Posté 07 avril 2021 - 11:19

I recommend using a ESP 32 because the esp8266 only has one core, which means the the codes and the Wi-Fi stack will shared time on the processor, causing delays from time to time. also this code might need some adjustments to work on the esp8266



Répondre à ce sujet



  



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

0 members, 0 guests, 0 anonymous users