Closed Vicidel closed 2 years ago
If i remember correctly some APs can skip sending some params for disabled blocks. Unsure if that is the case.
Normally after PARAM_REQUEST_LIST AP should send all existing PARAM_VALUE's. But sometimes it possible to miss some, so plugin uses first PV count to estimate all indexes, then run re-request loop of absent PVs by index.
Could you please enable debug logging for the param plugin logger and then force pull? Need to check param_index
vs param_count
.
While trying to debug I had things working more or less nicely except for the force param pull, not sure how related it is. In any case the first issue did not arrive in this case, will continue debugging to reproduce.
I could not find how to switch only the param plugin to debug, so I switched all of MAVROS and grep-ed the PR lines only. The output is in my gist here.
We can see that at connection of PX4 (ts=1652337616) I get a few params already. Then 10s after connection (as defined by BOOTUP_TIME) I get the full 831 params (ts=1652337626->1652337631).
At this moment triggering a non-forced pull gave me the full param list:
root@victor-ThinkPad-E595:/home/workspace# ros2 service call /mavros/param/pull mavros_msgs/srv/ParamPull
requester: making request: mavros_msgs.srv.ParamPull_Request(force_pull=False)
response:
mavros_msgs.srv.ParamPull_Response(success=True, param_received=832)
However, after this if I forced pull (at ts=1652337667) I received only 485 params at first (up to ts=1652337669), then the service call timed out and returned me this:
root@victor-ThinkPad-E595:/home/workspace# ros2 service call /mavros/param/pull mavros_msgs/srv/ParamPull force_pull:\ true\
waiting for service to become available...
requester: making request: mavros_msgs.srv.ParamPull_Request(force_pull=True)
response:
mavros_msgs.srv.ParamPull_Response(success=False, param_received=485)
And after 30s (LIST_TIMEOUT) the param plugin got the rest (ts=1652337697).
I found my issue!
Basically I had another ROS2 node that was sending some param pull requests with force=true
and I think it messed up the params sent in the param topic.
I'll mark as complete
@Vicidel, I am trying to set parameters, but the response I get from the service is always success=False
. Can you share with me the command you are using in the terminal (or the snippet of code) were you are able to successfully set a PX4 param?
I've tried using set
and set_params
. Neither work (although my get
commands do work). I am using PX4 Gazebo with a px4_sitl_rtps
vehicle. I am using ROS2 foxy.
Examples below:
# Set
ros2 service call /mavros/param/set mavros_msgs/srv/ParamSetV2 "{'force_set': True, 'param_id': 'BAT_CRIT_THR', 'value': {'double_value': 0.90}}"
requester: making request: mavros_msgs.srv.ParamSetV2_Request(force_set=True, param_id='BAT_CRIT_THR', value=rcl_interfaces.msg.ParameterValue(type=0, bool_value=False, integer_value=0, double_value=0.9, string_value='', byte_array_value=[], bool_array_value=[], integer_array_value=[], double_array_value=[], string_array_value=[]))
response:
mavros_msgs.srv.ParamSetV2_Response(success=False, value=rcl_interfaces.msg.ParameterValue(type=0, bool_value=False, integer_value=0, double_value=0.9, string_value='', byte_array_value=[], bool_array_value=[], integer_array_value=[], double_array_value=[], string_array_value=[]))
# SetParameters
ros2 service call /mavros/param/set_parameters rcl_interfaces/srv/SetParameters "{parameters: [{name: BAT_CRIT_THR, value: {double_value: 0.09}}]}"
requester: making request: rcl_interfaces.srv.SetParameters_Request(parameters=[rcl_interfaces.msg.Parameter(name='BAT_CRIT_THR', value=rcl_interfaces.msg.ParameterValue(type=0, bool_value=False, integer_value=0, double_value=0.09, string_value='', byte_array_value=[], bool_array_value=[], integer_array_value=[], double_array_value=[], string_array_value=[]))])
response:
rcl_interfaces.srv.SetParameters_Response(results=[rcl_interfaces.msg.SetParametersResult(successful=False, reason='')])
Hey @jaredsjohansen, indeed when I run your commands they both fails too. I have a print in MAVROS [WARN] PR: Unsupported ParameterValue type: not set
Trying with standard ROS2 CLI works:
root@d9d0b0d6bd2b:/home/workspace# ros2 param get /mavros/param BAT_CRIT_THR
Double value is: 0.05000000074505806
root@d9d0b0d6bd2b:/home/workspace# ros2 param set /mavros/param BAT_CRIT_THR 0.06
Set parameter successful
root@d9d0b0d6bd2b:/home/workspace# ros2 param get /mavros/param BAT_CRIT_THR
Double value is: 0.05999999865889549
If I change it from my code it also works, but I changed my method to set them to a third method as the two other mentioned above: AsyncParametersClient. You have some example on how to use them in demo nodes, but here is my code. It might be overcomplicated in this form because I'm converting it from my class structure to simplify things
// define client
rclcpp::AsyncParametersClient::SharedPtr paramClientMavros = std::make_shared<rclcpp::AsyncParametersClient>(this, "/mavros/param");
// wait for param client
if (!paramClientMavros->wait_for_service(2s))
{
std::cout << "Param server not available" << std::endl;
return false;
}
// create request
std::vector<rclcpp::Parameter> parameters_to_change;
parameters_to_change.emplace_back("BAT_CRIT_THR", rclcpp::ParameterValue(0.06));
// set the params (answer type is https://github.com/ros2/rcl_interfaces/blob/foxy/rcl_interfaces/msg/SetParametersResult.msg)
auto set_param_result = paramClientMavros->set_parameters(parameters_to_change);
if (set_param_result.wait_for(2s) == std::future_status::ready)
{
// failed
auto future_response = set_param_result.get();
if (!future_response.front().successful)
{[
std::cout << "Param set failed" << std::endl;
return false;
}
}
// timeout
else
{
std::cout << "Param set timed out" << std::endl;
return false;
}
// all good
return true;
Hope it helps, but no clue why the CLI service call fails...
Thanks, @Vicidel, for the guidance!
I've spent some time investigating everything you've shared. I'll share some of my takeaways (about mavros in general; and this problem in specific) for anyone who comes this way:
namespace=namespace,
as one of the Node parameters (in a python launch file).
/mavros/
. AsyncParametersClient
only has a cpp implementation; the python version doesn't exist until ros2-rolling. Based on @Vicidel shared, it is possible to use this mechanism to set
parameters. I haven't developed a cpp ros2node to use this mechanism yet, but I appreciate @Vicidel's support in sharing what he's done to get it to work!For my preflight check, I ended up using the limited capabilities of mavros to get
certain PX4 parameters. I compare the results against expected values and inform the operator of the results. Most relevant code is below:
from rcl_interfaces.srv import GetParameters
def get_px4_params(self, px4_params_to_get): # px4_params_to_get is a list of strings
# Get PX4 params
self.get_logger().info('Getting PX4 params')
self.px4_client = self.create_client(GetParameters, '/mavros/param/get_parameters', callback_group=self.client_callback_group)
while not self.px4_client.wait_for_service(timeout_sec=2.0):
self.get_logger().info('/mavros/param/get_parameters service not available, waiting again...')
request = GetParameters.Request()
request.names = px4_params_to_get
result = self.perform_service(self.px4_client, request)
result_dict = {}
for i in range(len(result.values)):
param = px4_params_to_get[i]
v = result.values[i]
value = None
if v.type == 1: value = v.bool_value
elif v.type == 2: value = v.integer_value
elif v.type == 3: value = v.double_value
elif v.type == 4: value = v.string_value
elif v.type == 5: value = v.byte_array_value
elif v.type == 6: value = v.bool_array_value
elif v.type == 7: value = v.integer_array_value
elif v.type == 8: value = v.double_array_value
elif v.type == 9: value = v.string_array_value
result_dict[param] = value
return result_dict
def perform_service(self, client, request):
self.service_done_event.clear()
event=Event()
def done_callback(future):
nonlocal event
event.set()
future = client.call_async(request)
future.add_done_callback(done_callback)
event.wait()
return future.result()
If anyone finds a nice solution to this problem in the future, please share! I'd be interested in it!
Issue details
In some cases MAVROS2 cannot change some parameters. I'm using the service
/mavros/param/set_parameters
which returns a failure with reasonUndeclared parameter
. I know the parameter in question exists in the connected SITL autopilot, and if I restart the system sometimes it's other parameters that fails, sometimes not any.I think the issue is linked to this warning I have in my logs.
In addition if I request the param list with one of the two lines below, I get 580 params in the response (including
_HASH_CHECK
).I know that my autopilot has 831 params (including
_HASH_CHECK
). Which approximately matches the 254 missing. So I'm wondering where those 254 parameters went... Subscribing to the/mavros/param/param_value
topic, I see all of them published when MAVROS pulls them from autopilot 10s after boot (I created a small Python script to receive them withmavutil
).I tried to pull params with MAVROS service. If I don't force I get the 580 I had previously (as expected), and if I force pull I get usually more
MAVROS version and platform
Mavros: 2.1.1 ROS: ROS2 Galactic Ubuntu: 20.04
Autopilot type and version
[ ] ArduPilot [x] PX4
Node logs