1.现象
当我在我的独立Qt程序中试图调用
setApproximateJointValueTarget(target_pose)
时,会返回false,并且出现错误提示:
No kinematics solver instantiated for group ‘my_group’
2.查找资料
东找西找,这找那找。找到了一个有用的资料
该问题在MoveIt2的issues上也有人提问过,而且开发人员也回答了:
【 hello_moveit does not work when demo.launch.py is modified to include use of occupancy map monitor plugin #1843 】
3.分析
3.1.参数的传递
根据henningkayser关于这个问题的回答,主要的原因是需要将moveit的配置传递给MGI(moveit::planning_interface::MoveGroupInterface)节点,让MGI能够通过节点使用参数。
而moveit相关的参数是通过 from launch_ros.actions import Node里面的Node节点的parameters来传递给启动的节点的:【move_group_interface_tutorial.launch.py】
launch_ros.actions.Node节点传递参数的方式是保存参数文件放在/tmp目录下,然后将文件路径作为argv传递给我们的程序,而 rclcpp::init(argc, argv); 则通过argc、argv来初始化好参数。
3.2.参数传递的测试
这一点可以通过自己写一个节点来验证:
代码参考:【2.参数之RCLCPP实现】
先创建一个包example_parameters_rclcpp,里面有一个parameters_basic节点,在其main函数中,将argc、argv给打印出来
然后再创建一个包param_startup,这个不用创建节点,但是要搞个launch文件。这个launch文件使用launch_ros.actions.Node来启动前面的parameters_basic,并传递了parameters给它
代码参考:【2.1 三种编写launch文件的方法】
执行一下看看有什么结果:
可以看到,传递了很多参数进来,主要看–params-file。但是我们打印一个/tmp/launch_params_jzq3dg9_来看看:
可以看到,里面就是我们试图通过launch_ros.actions.Node传递进来的参数中的一个。那么,此时,我们的parameters_basic节点是否就已经有了这些参数呢?但是是否定的:
因为我们还要做一个很重要的事情,让节点自动加载传递进来的参数:automatically_declare_parameters_from_overrides
rclcpp::NodeOptions node_options;
node_options.automatically_declare_parameters_from_overrides(true);
/*创建对应节点的共享指针对象*/
auto node = std::make_shared<ParametersBasicNode>("parameters_basic", node_options);
这时候就具有了我们传递进来的参数了
4.解决方案
4.1.在launch文件中传递参数并启动自己的程序
我们可以在启动moveit、rviz的launch文件中,也用launch_ros.actions.Node来启动我们的Qt程序,从而将必要的参数传递给我们自己的程序。
ld.add_action(
Node(
executable='/home/yong/Desktop/QtPrj/build-myArmTest-Desktop_Qt_5_15_2_GCC_64bit-Profile/myArmTest',
parameters=params,
)
)
自己的程序里面的节点记得要加上automatically_declare_parameters_from_overrides
// 构建带参数的节点
// https://github.com/ros-planning/moveit2/issues/1843
rclcpp::NodeOptions node_options;
node_options.automatically_declare_parameters_from_overrides(true);
MGINode = std::make_shared<rclcpp::Node>(
"my_arm_node", node_options);
QtConcurrent::run([=](){
rclcpp::spin(MGINode); // 阻塞其
});
经过测试,没有问题了:
下面红色字是独立启动的Qt程序输出的内容,可以看到报No kinematics plugins、No kinematics solver等错误;而上面控制台的输出是通过launch_ros.actions.Node来启动Qt程序的输出,是没有类似的错误的。
4.2.通过文件读取配置
在launch文件中传递参数并启动自己的程序这种方式,虽然在release、运行阶段比较方便,但是在写代码、调试阶段不太方便。
既然参数已经保存在了/tmp文件夹中(直到下次开机才会删除),那么我们完全可以通过一个包节点,把传递过来的argc、argv保存到一个txt文件中,然后我们的Qt程序再去读这个txt文件。
如此,只要先启动moveit相关的launch文件,生成(更新)了上述的txt文件,再启动我们的Qt程序,就同样可以解决这个参数相关的问题。