ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
0

How to pass argument to callback in rclc?

asked 2022-10-22 18:48:43 -0500

Dben gravatar image

I have a subscription:

rclc_executor_add_subscription(&executor, &data_subscription, &data_msg, &data_callback, ON_NEW_DATA);

But I would like to pass a variable to it. I know in rclcpp, you can use std::bind and rclpy you can you functools.partials but I don't know how to do it in pure C. I tried looking for dynamic variable allocation, and also pass a void* in the callback parameters, but without success.

Can you point me to some example?

Thanks

edit retag flag offensive close merge delete

1 Answer

Sort by ยป oldest newest most voted
0

answered 2022-10-23 01:56:22 -0500

PointCloud gravatar image

Hi there, I'm working on a rclc implementation myself on teensy with micro-ROS and the below has worked for me.

I have submitted a pull request on this github repository (still waiting to get merged). https://github.com/micro-ROS/micro_ro...

this as a new example This might provide some guidance into the right direction. Note it is loading the address of msg_sub to the pointer that is then used in the callback routine. (I think that's what it does)

Here is the source code:

#include <Arduino.h>
#include <Wire.h>
#include <micro_ros_platformio.h>
#include <rcl/rcl.h>
#include <rclc/rclc.h>
#include <rclc/executor.h>
#include <std_msgs/msg/int32.h>

#if !defined(MICRO_ROS_TRANSPORT_ARDUINO_SERIAL)
#error This example is only avaliable for Arduino framework with serial transport.
#endif

//publisher
rcl_publisher_t publisher;
std_msgs__msg__Int32 msg_pub;

// subscriber
rcl_subscription_t subscriber;
std_msgs__msg__Int32 msg_sub;

// publisher and subscriber common
rcl_node_t node;
rclc_support_t support;
rcl_allocator_t allocator;
rclc_executor_t executor;
rcl_timer_t timer;
unsigned int num_handles = 2;   // 1 subscriber, 1 publisher

#define LED_PIN 13

#define RCCHECK(fn){rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){error_loop();}}
#define RCSOFTCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){}}

// Error handle loop
void error_loop() {
  while(1) {
    digitalWrite(LED_PIN, !digitalRead(LED_PIN));
    delay(500);
  }
}

void timer_callback(rcl_timer_t * timer, int64_t last_call_time) {
  RCLC_UNUSED(last_call_time);
  if (timer != NULL) {
    RCSOFTCHECK(rcl_publish(&publisher, &msg_pub, NULL));
    msg_pub.data++;
  }
}

void subscription_callback(const void * msgin)
{  
  const std_msgs__msg__Int32 * msg = (const std_msgs__msg__Int32 *)msgin;
  digitalWrite(LED_PIN, (msg->data == 0) ? LOW : HIGH);  
}

void setup() {
  // Configure serial transport
  Serial.begin(115200);
  set_microros_serial_transports(Serial);

  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH); 

  delay(2000);

  allocator = rcl_get_default_allocator();

  //create init_options
  RCCHECK(rclc_support_init(&support, 0, NULL, &allocator));

  // create node
  RCCHECK(rclc_node_init_default(&node, "uros_platformio_node", "", &support));

  // create publisher
  RCCHECK(rclc_publisher_init_default(
    &publisher,
    &node,
    ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int32),
    "micro_ros_platformio_node_publisher"));

  // create subscriber
  RCCHECK(rclc_subscription_init_default(
    &subscriber,
    &node,
    ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int32),
    "micro_ros_platformio_node_subscriber"));

  // create timer,
  const unsigned int timer_timeout = 1000;
  RCCHECK(rclc_timer_init_default(
    &timer,
    &support,
    RCL_MS_TO_NS(timer_timeout),
    timer_callback));

  // create executor
  RCCHECK(rclc_executor_init(&executor, &support.context, num_handles, &allocator));  
  RCCHECK(rclc_executor_add_timer(&executor, &timer));
  RCCHECK(rclc_executor_add_subscription(&executor, &subscriber, &msg_sub, &subscription_callback, ON_NEW_DATA));   

  msg_pub.data = 0;
}

void loop() {
  delay(100);
  RCSOFTCHECK(rclc_executor_spin_some(&executor, RCL_MS_TO_NS(100)));
}
edit flag offensive delete link more

Comments

Thanks! My question was more, how do I pass the message type + another variable. Here I can only see the message type being passed. To be clear, let's say an int is published, I want to access this one + my own variable. PS: all maintainers are at roscon, probably not checking PRs right now

Dben gravatar image Dben  ( 2022-10-23 03:46:23 -0500 )edit

Is the other "own" variable withing the computer running the subscriber node, and maybe even within that same program? So i understand the int is published, but we don't know yet where the other variable comes from. Same host, and even same program, or external?

If, so, I can maybe see two different ways this could work. 1. global variable (yuck :-) ) 2. create a pointer and pass address reference to the variable, similar to what the subscriber callback uses?

PointCloud gravatar image PointCloud  ( 2022-10-23 11:40:06 -0500 )edit

Yes, same program, and I think the pointer should work and what I wanted to get, but don't know how

Dben gravatar image Dben  ( 2022-10-23 12:54:00 -0500 )edit

Question Tools

1 follower

Stats

Asked: 2022-10-22 18:48:43 -0500

Seen: 82 times

Last updated: Oct 23 '22