esimonsite

Guia ESP32 rosserial sin WiFi

Guia para la instalación de rosserial con ESP32 sin WiFi

Pasos previos - Permisos del USB

Te puedes saltar este paso si ya tienes configurado los permisos del usb para ubuntu.

Para comprobar la dirección el usb podemos ejecutar los siguientes comandos:

Comando Resultado info
ls /dev/ttyA* ls: cannot access ‘/dev/ttyA*': No such file or directory La dirección el esp32 no empieza por ttyA
ls /dev/ttyU* /dev/ttyUSB0 La dirección del esp32 es /dev/ttyUSB0

Como se puede ver en la tabla, el primer comando no produjo ningún resultado, ya que no hay ningún dispositivo en el directorio /dev que comience con ttyA. Por otro lado, el segundo comando produjo el resultado /dev/ttyUSB0, lo que indica que hay un dispositivo en el directorio /dev que se llama /dev/ttyUSB0.

Que pasa si tengo varios dispositivos?

Si tienes varias placas de desarrollo conectadas a tu computadora, es posible que tengas problemas para determinar cuál es la que quieres utilizar.Por lo tanto, es recomendable tener solo una placa de desarrollo conectada a tu computadora en cualquier momento. De esta manera, puedes asegurarte de que estás utilizando la placa correcta y evitar posibles problemas. Si necesitas utilizar varias placas de desarrollo, puedes conectarlas y desconectarlas según sea necesario.

Si quieres tener varios dispositivos conectados y necesitas diferenciarlos puedes cambiar el nombre de cada dispositivo

Añadir los permisos

sudo usermod -a -G dialout $USER

Que versión de ROS estamos usando?

Para saber qué versión de ROS (Robot Operating System) estás utilizando, puedes utilizar siguiente comando

rosversion -d

Este comando mostrará el número de versión de ROS que estás utilizando, así como la fecha de lanzamiento y otra información relevante.

# output
noetic

Si tienes una versión distinta de ROS, asegúrate de utilizar los comandos correspondientes a tu versión.

Instalar ROSserial

Instala ROSserial utilizando el siguiente comando:

sudo apt-get install ros-noetic-rosserial

Reemplaza noetic con la versión de ROS que estás utilizando (por ejemplo, kinetic, melodic, etc.).

Proyecto de ESP32 con PlatformIO

Para usar PlatformIO desde Visual Studio Code (VSC), primero necesitarás tener instalado VSC en tu sistema. Luego, necesitarás instalar el complemento de PlatformIO en VSC. Esto puedes hacer desde la página de extensiones de VSC. Una vez instalado el complemento, deberás configurar tu entorno de desarrollo para utilizar PlatformIO.

Si no sabes de que estamos hablando te recomiendo buscar información en otra página.

Platformio.ini

Platformio.ini es el archivo de configuración principal de PlatformIO. Este archivo contiene información sobre el entorno de desarrollo, las opciones de compilación y las dependencias de bibliotecas necesarias para un proyecto determinado.

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
lib_deps = frankjoshua/Rosserial Arduino Library@^0.9.1

El ESP32 puede tener problemas con una parte de su librería. Cuando intentes compilar tu código si el ESP32 se reinicia constantemente, es posible que tengas que buscar y reemplazar las siguientes líneas de código para solucionar los fallos:

Antes

#if defined(ESP8266) or defined(ESP32) or defined(ROSSERIAL_ARDUINO_TCP)
  #include "ArduinoTcpHardware.h"
#else
  #include "ArduinoHardware.h"
#endif

Después

#if defined(ROSSERIAL_ARDUINO_TCP)
  #include "ArduinoTcpHardware.h"
#else
  #include "ArduinoHardware.h"
#endif

Consultar Fuentes

Código de ejemplo con muchos comentarios


/*
 * rosserial Publisher Example
 * Prints "hello world!"
 */

// Incluye la biblioteca ros.h, que proporciona las funciones y
// clases necesarias para trabajar con ROS (Robot Operating System).
#include <ros.h>

// Incluye la biblioteca std_msgs/String.h, que define el tipo de
// mensaje std_msgs::String utilizado en este ejemplo.
#include <std_msgs/String.h>

ros::NodeHandle nh; // Crea una instancia de la clase ros::NodeHandle, que se utiliza para inicializar el nodo ROS y establecer la comunicación con el resto de la red ROS.

std_msgs::String str_msg; // Crea una instancia de la clase std_msgs::String, que representa un mensaje ROS de tipo cadena de texto.
ros::Publisher chatter("chatter", & str_msg); // Crea una instancia de la clase ros::Publisher, que se utiliza para publicar mensajes en un tópico ROS específico. En este caso, se crea un publicador llamado "chatter" que utilizará el mensaje std_msgs::String definido anteriormente.

char hello[13] = "hello world!"; // Define una variable char hello[13] que contiene la cadena de texto "hello world!" que se publicará en el tópico "chatter".

void setup() // La función setup() se llama una vez al iniciar el programa y se utiliza para inicializar el nodo ROS y publicar en el tópico "chatter".
{
  nh.initNode(); // Inicializa el nodo ROS.
  nh.advertise(chatter); // Publica en el tópico "chatter".
}

void loop() // La función loop() se ejecuta en un bucle y se utiliza para publicar el mensaje std_msgs::String en el tópico "chatter" y esperar a que se complete la comunicación con otros nodos ROS. Después de publicar el mensaje, se utiliza la función delay() para detener temporalmente la ejecución del programa durante un segundo.
{
  str_msg.data = hello; // Asigna el valor de la variable char hello a la propiedad data del mensaje std_msgs::String.
  chatter.publish( & str_msg); // Publica el mensaje std_msgs::String en el tópico "chatter".
  nh.spinOnce(); // Espera a que se complete la comunicación con otros nodos ROS.
  delay(1000); // Detiene temporalmente la ejecución del programa durante un segundo.
}

Código de ejemplo con sin comentarios

/*
 * rosserial Publisher Example
 * Prints "hello world!"
 */

#include <ros.h>
#include <std_msgs/String.h>


ros::NodeHandle  nh;

std_msgs::String str_msg;
ros::Publisher chatter("chatter", &str_msg);

char hello[13] = "hello world!";

void setup()
{
  nh.initNode();
  nh.advertise(chatter);
}

void loop()
{
  str_msg.data = hello;
  chatter.publish( &str_msg );
  nh.spinOnce();
  delay(1000);
}

Para ejecutar ROSserial

En el Terminal 1

roscore

En el Terminal 2

rosrun rosserial_python serial_node.py _port:=/dev/ttyUSB0

Output

[INFO] [1670670363.958689]: ROS Serial Python Node
[INFO] [1670670363.962023]: Connecting to /dev/ttyUSB0 at 57600 baud
[INFO] [1670670366.072302]: Requesting topics...

Para ver que funciona

En el Terminal 3

rostopic list
rostopic echo /chatter

Código más complejo

El código inicia un nodo ROS y publica un mensaje periódicamente en un tópico denominado “mensaje”. También se suscribe a un tópico llamado “ledValue” y configura un LED conectado al pin 26 para encenderse apagarse o parpadear en función del valor del mensaje recibido. Además, el código mantiene una variable entera llamada “a” y la incrementa en uno cada segundo, y publica su valor en el tópico “mensaje”.


/*
| Mensaje recibido | Valor del LED |
|------------------|---------------|
| 0                | Apagado       |
| 1                | Encendido     |
| Cualquier otro   | Parpadeando   |
*/

#include <Arduino.h>

#include <ros.h>

#include <std_msgs/String.h>
#include <std_msgs/Int16.h>

ros::NodeHandle nh;
std_msgs::String str_msg;
ros::Publisher pub("mensaje", &str_msg);

const int ledPin = 26;
int ledValue = 0;
bool isblinkMode = false;

// subscriptor

void ledValueCb(const std_msgs::Int16 &ledMsg)
{
  if (ledMsg.data == 0)
  {
    isblinkMode = false;
    digitalWrite(ledPin, LOW);
  }
  else if (ledMsg.data == 1)
  {
    isblinkMode = false;
    digitalWrite(ledPin, HIGH);
  }
  else
  {
    isblinkMode = true;
  }
}

ros::Subscriber<std_msgs::Int16> sub("ledValue", &ledValueCb);

void setup()
{
  // put your setup code here, to run once:
  nh.initNode();
  nh.advertise(pub);
  nh.subscribe(sub);

  pinMode(ledPin, OUTPUT);
}

unsigned long startTime = millis();
unsigned long delayTime = 250; // ms

unsigned long startTime1 = millis();
unsigned long delayTime1 = 1000; // ms

int a = 0;

char msg[22];

void loop()
{
  if (millis() - startTime >= delayTime)
  {
    // ocurre esto cada segundo
    startTime = millis();
    a = a + 1;

    sprintf(msg, "El valor de a es: %d", a);
    str_msg.data = msg;
    pub.publish(&str_msg);

    if (isblinkMode)
    {
      if (ledValue)
        ledValue = 0;
      else
        ledValue = 1;

      digitalWrite(ledPin, ledValue);
    }
  }

  if (millis() - startTime1 >= delayTime1)
  {
    startTime1 = millis();
  }

  nh.spinOnce();
}