-
Notifications
You must be signed in to change notification settings - Fork 133
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unable to call the /set_parameter service on ROS2 server from the client running on micro-ROS #578
Comments
Parameter client is not available in micro-ROS, in any case, you can check the parameter server code to investigate on how to initialize the messages: https://github.com/ros2/rclc/blob/1c0ea5af6c1d5b3715af9a8029de2e5b03821b03/rclc_parameter/src/rclc_parameter/parameter_server.c#L412-L423 Maybe you need to init the sequences: rcl_interfaces__srv__SetParameters_Request__init(&req);
rcl_interfaces__srv__SetParameters_Response__init(&res);
rcl_interfaces__msg__Parameter__Sequence__init(
&req.parameters,
MAX_PARAMETERS);
req.parameters.size = 0;
rcl_interfaces__msg__SetParametersResult__Sequence__init(
&res.results,
MAX_PARAMETERS);
res.results.size = 0; |
I have used parameter client earlier to get the parameters and it seems to work fine. The only problem I am facing is in setting the parameters.
Parameter server does not handle arrays, I need to use it for arrays.
I will try this and update you about the progress. |
@pablogs9 where do you recommend to init the sequences? On the very top? Before adding to the executor? or somewhere else? |
Before |
OK, seems like
|
So if I comment these lines, the callback is getting called, maybe because the service response is empty:
But if I uncomment, the callback doesn't get called. |
Are you setting Are initializing strings in |
I have included those changes, but still doesn't work, any clue? Please see the code below: // memory allocation for fields in result
static bool bool_param = false;
static char res_message = '\0';
// Create executor
rcl_interfaces__srv__SetParameters_Response__init(&res);
rcl_interfaces__msg__SetParametersResult__Sequence__init(&res.results,10);
res.results.data[0].reason.capacity = 100;
res.results.data[0].reason.data = (char*) malloc(res.results.data[0].reason.capacity * sizeof(char));
res.results.data[0].reason.data = &res_message; // adding or removing this line doesn't make a difference
res.results.data[0].successful = &bool_param;
res.results.size=0;
rclc_executor_t executor;
RCCHECK(rclc_executor_init(&executor, &support.context,3, &allocator));
// Add the client to the executor
RCCHECK(rclc_executor_add_client(&executor, &client, &res, client_callback));
// populate the request message
rcl_interfaces__srv__SetParameters_Request__init(&req);
rcl_interfaces__msg__Parameter__Sequence__init(&req.parameters,10);
req.parameters.size = 0;
req.parameters.capacity = 100;
req.parameters.data = (rcl_interfaces__msg__Parameter*) malloc(req.parameters.capacity * sizeof(rcl_interfaces__msg__Parameter) );
req.parameters.data[0].name.capacity = 100;
req.parameters.data[0].name.data = (char*) malloc(req.parameters.data[0].name.capacity * sizeof(char));
strcpy(req.parameters.data[0].name.data,"left_marker_id");
req.parameters.data[0].name.size = strlen(req.parameters.data[0].name.data);
req.parameters.data[0].value.integer_value = (int64_t)5;
req.parameters.data[0].value.type = 2;
req.parameters.size++; |
@pablogs9 would you be able to reproduce and help? |
Rethink this:
you are allocating memory and setting the pointer to a single char. It seems that you were looking to do:
Please ensure that every sequence inside the Also, it can be a good idea to use I will check tomorrow if I have some time. |
@pablogs9, I meant to say that I used two different approaches for memory initialization and none of them worked. I thought this line of comment would indicate that :
I am not able to understand, if I initialize the memory for the parent structure then why do I need to initialize the memory for child structures?
Also, why do the caller needs to fill all this? Don't you think micro-ROS functions should do all this? I will try to use to
Did you figure something out? Also, I want to know if you are looking into supporting C++ soon? It is a real pain to work with C and deal with |
Working and tested code: #include <rcl/rcl.h>
#include <rcl/error_handling.h>
#include <rclc/rclc.h>
#include <rclc/executor.h>
#include <rcl_interfaces/srv/set_parameters.h>
#include <rcl_interfaces/srv/set_parameters.h>
#include <rcl_interfaces/msg/parameter_type.h>
#include <stdio.h>
#define RCCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){printf("Failed status on line %d: %d. Aborting.\n",__LINE__,(int)temp_rc); return 1;}}
#define RCSOFTCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){printf("Failed status on line %d: %d. Continuing.\n",__LINE__,(int)temp_rc);}}
// Define client object
rcl_client_t client;
// Service variables
rcl_interfaces__srv__SetParameters_Response res;
rcl_interfaces__srv__SetParameters_Request req;
void client_callback(const void * msg){
rcl_interfaces__srv__SetParameters_Response * msgin = (rcl_interfaces__srv__SetParameters_Response * ) msg;
printf("Response from server: %s. Reason: %s\n",msgin->results.data[0].successful ? "true" : "false", msgin->results.data[0].reason.data);
}
int main()
{
rcl_allocator_t allocator = rcl_get_default_allocator();
rclc_support_t support;
// create init_options
RCCHECK(rclc_support_init(&support, 0, NULL, &allocator));
// create node
rcl_node_t node;
RCCHECK(rclc_node_init_default(&node, "int32_subscriber_rclc", "", &support));
// create executor
rclc_executor_t executor = rclc_executor_get_zero_initialized_executor();
RCCHECK(rclc_executor_init(&executor, &support.context, 1, &allocator));
RCCHECK(rclc_client_init_default(&client, &node, ROSIDL_GET_SRV_TYPE_SUPPORT(rcl_interfaces, srv, SetParameters), "/parameter_node/set_parameters"));
// Init request memory
rcl_interfaces__srv__SetParameters_Request__init(&req);
rcl_interfaces__msg__Parameter__Sequence__init(&req.parameters, 1);
// Assing first parameter
rosidl_runtime_c__String__assign(&req.parameters.data[0].name, "int_param");
req.parameters.data[0].value.type = rcl_interfaces__msg__ParameterType__PARAMETER_INTEGER;
req.parameters.data[0].value.integer_value = 42;
// Init response memory
rcl_interfaces__srv__SetParameters_Response__init(&res);
rcl_interfaces__msg__SetParametersResult__Sequence__init(&res.results, 1);
rosidl_runtime_c__String__assign(&res.results.data[0].reason, " "); // Empty string for having enought memory
RCCHECK(rclc_executor_add_client(&executor, &client, &res, client_callback));
int64_t seq;
rcl_send_request(&client, &req, &seq);
rclc_executor_spin(&executor);
} I have check it against a RCLCPP node that is: #include <rclcpp/rclcpp.hpp>
#include <chrono>
#include <string>
#include <functional>
using namespace std::chrono_literals;
class ParametersClass: public rclcpp::Node
{
public:
ParametersClass()
: Node("parameter_node")
{
this->declare_parameter<int>("int_param", 1);
timer_ = this->create_wall_timer(
1000ms, std::bind(&ParametersClass::respond, this));
}
void respond()
{
this->get_parameter("int_param", int_param);
RCLCPP_INFO(this->get_logger(), "Hello %d", int_param);
}
private:
int int_param;
rclcpp::TimerBase::SharedPtr timer_;
};
int main(int argc, char** argv)
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<ParametersClass>());
rclcpp::shutdown();
return 0;
} Regarding your questions:
Please read: https://micro.ros.org/docs/tutorials/advanced/handling_type_memory/
Check ros2/rclc#126 |
@pablogs9, I tested your code, it works! Thanks for the help! |
I am running a parameter server on a
/state_machine
node on ROS2 computer. This parameter server gives access to several services such as:I am running a service client on micro-ros side to set-up the parameters. When I send a blank request message, the callback function is getting called. However, when I send a non-empty request message then callback is not getting called. Also,
RCCHEECK
function returns a failed status in that case.I had a similar issue in the past, when I was trying to get the parameters instead of setting them. I resolved that issue by doing memory allocation in the response message. However, that trick doesn't seem to work here.
Please see the code below and let me know if you can provide some guidance to debug.
The text was updated successfully, but these errors were encountered: