# [ROS2][rclpy] how to set parameter hosted by another Node via service [closed]

I am looking for a solution to set the Parameter which is host by another node using rclpy.

I found there is a relavent post, but in rclcpp.

While, I tried below. But the error occurred. Any idea how I can fix it? Thank you very much!

import time

import rclpy
from rclpy.node import Node
import rclpy.qos as qos

from rclpy.parameter import Parameter
# from rcl_interfaces.msg import Parameter
from rcl_interfaces.msg import ParameterValue
from rcl_interfaces.srv import SetParameters, GetParameters, ListParameters
from rcl_interfaces.msg import ParameterDescriptor, ParameterValue

class MinimalClientAsync(Node):

def __init__(self):
super().__init__('my_node')

self.cli = self.create_client(SetParameters, '/another_node/set_parameters')
while not self.cli.wait_for_service(timeout_sec=1.0):
self.get_logger().info('service not available, waiting again...')
self.req = SetParameters.Request()

def send_request(self):
self.req.parameters = [Parameter(name='parameter_1', value=13)]
self.future = self.cli.call_async(self.req)

def main(args=None):
rclpy.init(args=args)

minimal_client = MinimalClientAsync()
minimal_client.send_request()

while rclpy.ok():
rclpy.spin_once(minimal_client)
if minimal_client.future.done():
try:
response = minimal_client.future.result()
except Exception as e:
minimal_client.get_logger().info(
'Service call failed %r' % (e,))
break

minimal_client.destroy_node()
rclpy.shutdown()

if __name__ == '__main__':
main()


The error is:

  File "/opt/ros/dashing/lib/python3.6/site-packages/rcl_interfaces/srv/_set_parameters.py", line 138, in parameters
"The 'parameters' field must be a set or sequence and each value of type 'Parameter'"
AssertionError: The 'parameters' field must be a set or sequence and each value of type 'Parameter'


I also tried to use rcl_interfaces.msg.Parameter instead of rclpy.parameter.Parameter so it won't failed at rcl_interfaces/srv/_set_parameters.py. However it failed at rcl_interfaces/msg/_parameter.py this time:

  File "/opt/ros/dashing/lib/python3.6/site-packages/rcl_interfaces/msg/_parameter.py", line 80, in __init__
self.value = kwargs.get('value', ParameterValue())
File "/opt/ros/dashing/lib/python3.6/site-packages/rcl_interfaces/msg/_parameter.py", line 149, in value
"The 'value' field must be a sub message of type 'ParameterValue'"
AssertionError: The 'value' field must be a sub message of type 'ParameterValue'


Then I kept trying, used ParameterValue, like this:

Parameter(name='parameter_1', value=ParameterValue(integer_value=3))


It did not cause any error, but when I check the param, it shows Parameter not set.. I am confused. The parameter parameter_1 seems to be undeclared.

edit retag reopen merge delete

### Closed for the following reason duplicate question by lin404 close date 2020-02-05 18:18:44.228658

Sort by » oldest newest most voted

You're very close. As there is currently no helper in rclpy, the "easier" might be to use only rcl_interfaces type for now to avoid confusion

The 'parameters' field must be a set or sequence and each value of type 'Parameter'

This means that you need to pass a rcl_interfaces.msg.Parameter to this function.

Then I kept trying, used ParameterValue, like this:

That's the way to go. On top of defining the value, the type of the parameter needs to be set, as it is not detected automatically

Parameter(name='parameter_1', value=ParameterValue(integer_value=3, type=ParameterType.PARAMETER_INTEGER))


The send_request function will look like this:

def send_request(self):
new_param_value = ParameterValue(type=ParameterType.PARAMETER_INTEGER, integer_value=13)
self.req.parameters = [Parameter(name='parameter_1', value=new_param_value)]
self.future = self.cli.call_async(self.req)


Note that you'll need to import ParameterType from rcl_interfaces.msg at the top of your file.

more

@marguedas Thank you very much! I have confirmed it, it works perfect!

( 2020-02-05 18:16:32 -0500 )edit

Does it work in foxy? I tried and get an error:

  File "/opt/ros/foxy/lib/python3.8/site-packages/rclpy/parameter.py", line 127, in __init__
type_ = Parameter.Type.from_parameter_value(value)
File "/opt/ros/foxy/lib/python3.8/site-packages/rclpy/parameter.py", line 70, in from_parameter_value
raise TypeError('The given value is not one of the allowed types.')
TypeError: The given value is not one of the allowed types.

( 2021-05-23 10:38:59 -0500 )edit

It effectively works on foxy. I encountered the same issue and the problem was that my Parameter class was not imported from rcl_interface.msg. It shouldn't come from rclpy.parameter like the code above.

( 2021-10-19 15:33:25 -0500 )edit

It's worth noting the rclpy Parameter object has a to_parameter_msg() method to it so you do not need to explicitly import rcl_interfaces.msg.Parameter or rcl_interfaces.msg.ParameterValue

Example usage:

from rclpy.parameter import Parameter

...

def send_request(self):
self.req.parameters = [Parameter(name='parameter_1', value=new_param_value).to_parameter_msg()]
self.future = self.cli.call_async(self.req)


This is also nice as it will handle the type for you automatically and put the value in the correct message field without you having to manually specify things such as "integer_value" or "string_value" etc.

( 2022-05-05 00:57:45 -0500 )edit