micro_ros_arduino
micro_ros_arduino copied to clipboard
The session has been established, but the nodes are not functioning correctly.
rpi4master@rpi4master:~$ sudo micro-xrce-dds-agent serial --dev /dev/ttyACM0 -b 115200 [1698546806.114685] info | TermiosAgentLinux.cpp | init | running... | fd: 3 [1698546806.115410] info | Root.cpp | set_verbose_level | logger setup | verbose_level: 4 [1698546806.554954] info | Root.cpp | create_client | create | client_key: 0x25E30594, session_id: 0x81 [1698546806.555178] info | SessionManager.hpp | establish_session | session established | client_key: 0x635635092, address: 0
-Im using a raspberry pi pico rp2040, a raspberry pi 4 4gb and a computer to access via ssh to the raspberry pi
- RTOS: FREERTOS
- Installation type: I use a docker to acces micro ros: https://hub.docker.com/r/microros/micro-ros-agent (Humble) Also install the micro-xrce-dds-agent following the steps right here: https://snapcraft.io/micro-xrce-dds-agent
- Im using micro ros to connect with ROS2 Humble.
Steps to reproduce the issue
Install ROS2 humble using the debian packages. Follow the instructions that is shown in this pages: https://hub.docker.com/r/microros/micro-ros-agent (humble) https://snapcraft.io/micro-xrce-dds-agent
Expected behavior
[1698548607.973741] info | TermiosAgentLinux.cpp | init | running... | fd: 3 [1698548608.521272] info | Root.cpp | delete_client | delete | client_key: 0x14642262 [1698548608.521385] info | SessionManager.hpp | destroy_session | session closed | client_key: 0x14642262, address: 0 [1698548608.521434] info | Root.cpp | create_client | create | client_key: 0x4F4067EA, session_id: 0x81 [1698548608.521459] info | SessionManager.hpp | establish_session | session established | client_key: 0x4F4067EA, address: 0 [1698548608.533004] info | ProxyClient.cpp | create_participant | participant created | client_key: 0x4F4067EA, participant_id: 0x000(1) [1698548608.536969] info | ProxyClient.cpp | create_topic | topic created | client_key: 0x4F4067EA, topic_id: 0x000(2), participant_id: 0x000(1) [1698548608.539250] info | ProxyClient.cpp | create_publisher | publisher created | client_key: 0x4F4067EA, publisher_id: 0x000(3), participant_id: 0x000(1) [1698548608.542347] info | ProxyClient.cpp | create_datawriter | datawriter created | client_key: 0x4F4067EA, datawriter_id: 0x000(5), publisher_id: 0x000(3) [1698548608.545870] info | ProxyClient.cpp | create_topic | topic created | client_key: 0x4F4067EA, topic_id: 0x001(2), participant_id: 0x000(1) [1698548608.548010] info | ProxyClient.cpp | create_subscriber | subscriber created | client_key: 0x4F4067EA, subscriber_id: 0x000(4), participant_id: 0x000(1) [1698548608.552643] info | ProxyClient.cpp | create_datareader | datareader created | client_key: 0x4F4067EA, datareader_id: 0x000(6), subscriber_id: 0x000(4)
Actual behavior
[1698546806.114685] info | TermiosAgentLinux.cpp | init | running... | fd: 3 [1698546806.115410] info | Root.cpp | set_verbose_level | logger setup | verbose_level: 4 [1698546806.554954] info | Root.cpp | create_client | create | client_key: 0x25E30594, session_id: 0x81 [1698546806.555178] info | SessionManager.hpp | establish_session | session established | client_key: 0x635635092, address: 0
The expected behavior was obtained by the computer that has the "micro-ros-agent." When you plug in the Raspberry Pi Pico, everything works fine. However, in the case where we are using a Raspberry Pi 4, we can't install the "micro-ros-agent" because the terminal says that it only works on AMD64 systems, not on ARM64. Therefore, we searched for information and found an alternative called "micro-xrce-dds-agent."
With this latter agent, the connection is initialized, but the nodes don't work
Feel free if you want to answer me in spanish, I'm from Colombia. Your work is amazing.
This is the code we are using:
#include <iostream>
#include <rcl/rcl.h>
#include <rcl/error_handling.h>
#include <rclc/rclc.h>
#include <rclc/executor.h>
#include <std_msgs/msg/int32.h>
#include <rmw_microros/rmw_microros.h>
#include "FreeRTOS.h"
#include "task.h"
#include "pico/stdlib.h"
#include "hardware/pwm.h"
#include "hardware/adc.h"
#include "hardware/gpio.h"
extern "C" {
#include "pico_uart_transports.h" // Archivo de encabezado correspondiente
}
#include <std_msgs/msg/float32.h>
#include <geometry_msgs/msg/vector3.h>
volatile long encoder_count = 0;
volatil
e long encoder_count2 = 0;
//Definicion global pin Led deafultc
#define LED_PIN PICO_DEFAULT_LED_PIN
//Defino pi para posterior uso
#define PI 3.14159265358979323846
float w_motor1=0;
float w_motor2=0;
float U1=0;
float U2=0;
float e[2]={0,0};
int led_value=0;
float Wi[2] = {13,13};
//--------------------------------------------------------------------- Clase Motor ----------------------------------------------------------------------------------------
class Motor {
private : //atributos
int pin_num_pwm, pin_num_in1, pin_num_in2,sensorA_pin, sensorB_pin, freq=1000 , FC1 , FC2;
//parametros
int ppr;
int decoder_number;
int gear_ratio;
absolute_time_t prevT = get_absolute_time();
double posPrev;
int slice_num;
int CH;
public://metodos
//Metodo constructor
Motor(int _pin_num_pwm, int _pin_num_in1, int _pin_num_in2, int _sensorA_pin, int _sensorB_pin, int _freq){
this-> pin_num_pwm = _pin_num_pwm;
this-> pin_num_in1 = _pin_num_in1;
this-> pin_num_in2 = _pin_num_in2;
this-> sensorA_pin = _sensorA_pin;
this-> sensorB_pin = _sensorB_pin;
this-> freq = _freq;
gpio_init(this->pin_num_pwm);
gpio_init(this->pin_num_in1);
gpio_init(this->pin_num_in2);
gpio_init(this->sensorA_pin);
gpio_init(this->sensorB_pin);
gpio_set_function(this->pin_num_pwm, GPIO_FUNC_PWM);
gpio_set_dir(this->pin_num_in1, GPIO_OUT);
gpio_set_dir(this->pin_num_in2, GPIO_OUT);
gpio_set_dir(this->sensorA_pin, GPIO_IN);
gpio_set_dir(this->sensorB_pin, GPIO_IN);
gpio_pull_down(this->sensorA_pin);
gpio_pull_down(this->sensorB_pin);
this->slice_num = pwm_gpio_to_slice_num(this->pin_num_pwm);
this->CH = pwm_gpio_to_channel(this->pin_num_pwm);
pwm_set_clkdiv(slice_num,10.0);
pwm_set_wrap(slice_num, 65535);
pwm_set_enabled(slice_num,true);
// Encoder and motor parameters
this-> ppr = 12;
this-> decoder_number = 2;
this-> gear_ratio = 30;
// Speed time variables
this-> posPrev = 0;
}
// Metodo get para obtener pin Sensor B
int getsensorB_pin() {
return this->sensorB_pin;
}
int getsensorA_pin() {
return this->sensorA_pin;
}
int getEncoderatio() {
return (this->ppr * this->gear_ratio* this->decoder_number)/360;
}
//Funcion para asignar direccion y ciclo de dureza
void set_motor(int dir,int speed){
if (dir==1){
gpio_put(this->pin_num_in1,0);
gpio_put(this->pin_num_in2,1);
}
else if (dir==-1){
gpio_put(this->pin_num_in1,1);
gpio_put(this->pin_num_in2,0);
}
else{
gpio_put(this->pin_num_in1,0);
gpio_put(this->pin_num_in2,0);
}
pwm_set_chan_level(this->slice_num,this->CH, speedToU16(speed));
}
//Metodo conversor de porcentaje 0-100 a 16 bits
int speedToU16(int speed){
int speed_u16=speed*65535.0/100;
return speed_u16;
}
//Metodo para obtener la velocidad del motor
double encoder2speed(int encoder_count_){
absolute_time_t currT =get_absolute_time();
int64_t deltaT = absolute_time_diff_us(this-> prevT, currT);
this -> prevT=currT;
double resta=encoder_count_-this->posPrev;
double vel = ((resta*1000000)/deltaT);
this-> posPrev =encoder_count_;
double vel_rad_raw = ((vel*2*PI)/(180));
return vel_rad_raw;
}
};
Motor motor_1(16, 18, 17, 21,22, 1000);
Motor motor_2(15, 13, 12, 9,8, 1000);
int sensorB_M1=motor_1.getsensorB_pin();
int sensorA_M1= motor_1.getsensorA_pin();
int sensorB_M2=motor_2.getsensorB_pin();
int sensorA_M2= motor_2.getsensorA_pin();
int estado=0;
//---------------------------------------------------------------------- Definicion funciones Callback Interrupciones --------------------------------------------------
static void encoderInterruptHandler(uint gpio, uint32_t events) {
if(gpio==sensorA_M1){
if(gpio_get(sensorB_M1)==1){
encoder_count--;
}
else{
encoder_count++;
}
}
else if (gpio==sensorB_M1){
if(gpio_get(sensorA_M1)==1){
encoder_count++;
}
else{
encoder_count--;
}
}
else if (gpio==sensorA_M2){
if(gpio_get(sensorB_M2)==1){
encoder_count2--;
}
else{
encoder_count2++;
}
}
else if(gpio==sensorB_M2){
if(gpio_get(sensorA_M2)==1){
encoder_count2++;
}
else{
encoder_count2--;
}
}
}
int ms_to_ticks(int ms){
int ticks= (ms*100)/1000;
return ticks;
}
//----------------------------------------------------------------------------------- Definicion de Publicadores , Mensajes etc ----------------------------------------------------------------------
rcl_publisher_t publisher_1;
geometry_msgs_msg_Vector3 msg_1;
rcl_subscription_t subscriber;
geometry_msgs_msg_Vector3 msg;
rcl_node_t node;
rcl_allocator_t allocator; //Distribuidor de memoria
rclc_support_t support;
rclc_executor_t executor; //Distribuidor de Tareas_uROS
//----------------------------------------------------------------------------------- Tareas de FREERTOS ---------------------------------------------------------------------------------------------------
void stateMachine(void *pvParameters)
{
//Variables
//Estados
int Estado=0; //unconfigured
float Uprev[2]={0,0};
float eprev[2]={0,0};
float eprev2[2]={0,0};
float inicial_2=0;
float inicial=0;
float q0[2]={0.8,0.8};
float q1[2]={-0.7,-0.7};
float q2[2]={0,0};
while (true) {
switch (Estado) {
case 0: //unconfigured
//Variables
led_value=0;
vTaskDelay(ms_to_ticks(5000));
Estado=1;
break;
case 1: //active
w_motor1=motor_1.encoder2speed(encoder_count);
w_motor2=motor_2.encoder2speed(encoder_count2);
e[0]=Wi[0]-w_motor1;
e[1]=Wi[1]-w_motor2;
U1=Uprev[0]+ q0[0]e[0] + q1[0] eprev[0] + q2[0]*eprev2[0];
U2=Uprev[1]+ q0[1]e[1] + q1[1] eprev[1] + q2[1]*eprev2[1];
float U1_abs=std::abs(U1);
float U2_abs=std::abs(U2);
if (U1>0){
motor_1.set_motor(1, U1_abs);
gpio_put(LED_PIN, 1);
} else{
motor_1.set_motor(-1,U1_abs);
gpio_put(LED_PIN, 0);
}
if (U2>0){
motor_2.set_motor(1, U2_abs);
} else{
motor_2.set_motor(-1, U2_abs);
}
Uprev[0]=U1;
Uprev[1]=U2;
eprev2[0]=eprev[0];
eprev2[1]=eprev[1];
eprev[0]=e[0];
eprev[1]=e[1];
vTaskDelay(ms_to_ticks(20));
break;
}
}
}
void Print_Task(void *pvParameters) {
while (1) {
msg_1.x=w_motor1;
msg_1.y=w_motor2;
rcl_publish(&publisher_1, &msg_1, NULL);
vTaskDelay(ms_to_ticks(100));
}
}
void Spin_Task(void *pvParameters) {
while (true)
{
rclc_executor_spin_some(&executor, RCL_MS_TO_NS(100));
vTaskDelay(ms_to_ticks(50));
}
}
void subscription_callback(const void * msgin)
{
// Cast received message to used type
const geometry_msgs_msgVector3 *msg_vector3 = (const geometry_msgsmsg_Vector3 *)msgin;
Wi[0] = msg_vector3->x;
Wi[1]= msg_vector3->y;
}
//-------------------------------------------------------------------------- Main ---------------------------------------------------------------------------------------------
int main()
{
gpio_set_irq_enabled_with_callback(sensorA_M1, GPIO_IRQ_EDGE_RISE, 1, &encoderInterruptHandler);
gpio_set_irq_enabled_with_callback(sensorA_M2, GPIO_IRQ_EDGE_RISE, 1, &encoderInterruptHandler);
gpio_set_irq_enabled_with_callback(sensorB_M1, GPIO_IRQ_EDGE_RISE, 1, &encoderInterruptHandler);
gpio_set_irq_enabled_with_callback(sensorB_M2, GPIO_IRQ_EDGE_RISE, 1, &encoderInterruptHandler);
rmw_uros_set_custom_transport(
true,
NULL,
pico_serial_transport_open,
pico_serial_transport_close,
pico_serial_transport_write,
pico_serial_transport_read
); // DEFINIR TIPO DE TRANSPORTE USB
gpio_init(LED_PIN);
gpio_set_dir(LED_PIN, GPIO_OUT);
allocator = rcl_get_default_allocator(); //inicializar el allocator
// Wait for agent successful ping for 2 minutes.
const int timeout_ms = 1000;
const uint8_t attempts = 120;
rcl_ret_t ret = rmw_uros_ping_agent(timeout_ms, attempts);
if (ret != RCL_RET_OK)
{
// Unreachable agent, exiting program.
return ret;
}
rclc_support_init(&support, 0, NULL, &allocator);
rclc_node_init_default(&node, "pico_node", "", &support);
rclc_publisher_init_default(
&publisher_1,
&node,
ROSIDL_GET_MSG_TYPE_SUPPORT(geometry_msgs,msg,Vector3),
"/reptil321");
rcl_ret_t rc = rclc_subscription_init_default(
&subscriber,
&node,
ROSIDL_GET_MSG_TYPE_SUPPORT(geometry_msgs, msg, Vector3)
, "/rex123");
rclc_executor_init(&executor, &support.context, 2, &allocator);
gpio_put(LED_PIN, 1);
rclc_executor_add_subscription(
&executor, &subscriber, &msg,
&subscription_callback, ON_NEW_DATA);
xTaskCreate(Print_Task, "Imprimir", 512, NULL, 1, NULL);
xTaskCreate(stateMachine, "Maquina de estados", 1024, NULL, 2, NULL);
xTaskCreate(Spin_Task, "Spin", 512, NULL, 4, NULL);
vTaskStartScheduler();
return 0;
}
Does the provided example works as expected?