目录
用于记录使用ROS1遇到的一些问题与解决办法。
一、ROS的分布式通讯
- 主机和从机连接同一个局域网
- 用ifconfig指令查看主机和从机的ip
- 修改主机和从机的bashrc
修改bashrc的指令:
gedit ~/.bashrc
主机中添加:
export ROS_MASTER_URI=http://主机IP:11311
export ROS_HOSTNAME=主机IP
从机中添加:
export ROS_MASTER_URI=http://主机IP:11311
export ROS_HOSTNAME=从机IP
二、ROS使用第三方库的方法
-
打开你的ROS包的CMakeLists.txt文件。
-
在文件顶部,使用
find_package()
命令查找ROS中的相关包,例如roscpp
,以确保你的ROS包能够与ROS系统正确链接。find_package(catkin REQUIRED COMPONENTS roscpp )
-
在
include_directories()
命令中添加外部库的头文件路径。假设你的头文件在/usr/local/include
中:include_directories( ${catkin_INCLUDE_DIRS} /usr/local/include )
-
在
link_directories()
命令中添加外部库的库文件路径。假设你的库文件在/usr/local/lib
中:link_directories( ${catkin_LIBRARY_DIRS} /usr/local/lib )
-
在
add_executable()
或add_library()
命令中添加你的源文件,并使用target_link_libraries()
命令链接外部库。假设你的源文件是your_node.cpp
:add_executable(your_node src/your_node.cpp) target_link_libraries(your_node ${catkin_LIBRARIES} your_external_library_name # 替换为你的外部库名称 )
最后,在ROS包中构建和编译catkin_make。这样,ROS包就应该能够使用外部库了。请确保替换示例中的 your_external_library_name
为实际的外部库名称。如果外部库有其他依赖项,也需要在CMakeLists.txt中进行相应的配置。
怎么知道库文件的名称?
库文件的名称是带有一定规律的,包括前缀、后缀和版本号。
在 /usr/local/lib
目录下查看你的库文件,可能会有以下几种常见的命名规则:
-
以
lib
开头,.a
或.so
结尾: 例如,libexample.a
或libexample.so
。 -
带有版本号: 有时,库文件的名称还包含版本号,例如
libexample.so.1.2.3
。在这种情况下,通常还有一个指向当前版本的符号链接,例如libexample.so
指向libexample.so.1.2.3
。 -
没有前缀
lib
: 有些库文件没有以lib
开头,例如example.so
。
可以使用以下方法之一来确定库文件的名称:
-
通过命令行: 在
/usr/local/lib
目录下执行ls
命令,查看所有的库文件。ls /usr/local/lib
找到你的库文件并记录下它的名称。
-
通过 CMakeLists.txt: 在你的 ROS 包的
CMakeLists.txt
文件中,使用target_link_libraries()
命令时,直接指定你认为是正确的库文件名称。target_link_libraries(your_node ${catkin_LIBRARIES} example # 替换为你认为是正确的库文件名称 )
在上述代码中,example
就是你认为是正确的库文件名称。如果库文件有版本号,也可以尝试将版本号包含在其中。
三、当订阅者只调用一次回调函数
#include "ros/ros.h"
#include "your_package/YourMessageType.h" // 请替换为你的消息类型
class Node {
public:
Node() : called_once(false) {
// 初始化ROS节点
ros::NodeHandle nh;
// 订阅消息
sub = nh.subscribe("your_topic", 1, &Node::callback, this);
}
void callback(const your_package::YourMessageType::ConstPtr& msg) {
if (!called_once) {
// 执行仅在第一次调用时执行的操作
ROS_INFO("Callback called for the first time");
// 设置标志变量
called_once = true;
}
}
private:
ros::Subscriber sub;
bool called_once;
};
int main(int argc, char** argv) {
// 初始化ROS节点
ros::init(argc, argv, "your_node_name");
// 创建节点对象
Node node;
// 运行ROS节点
ros::spin();
return 0;
}
四、解决"自定义话题无法引用"
比如在同一工作空间下,一个xxx_msg包用于生成话,aaa包用于使用xxx_msg中的话题,我们在cpp中#include <包名/xxx.h>,但是编译现实找不到包名/xxx.h,.../工作空间/devel/include/包名/xxx.h中有生成的消息格
报错格式:
/home/roslearner/catkin_ws/src/offboard_pkg/src/position_node.cpp:13:10: fatal error: open_manipulator_msgs/JointMani.h: 没有那个文件或目录
#include <open_manipulator_msgs/JointMani.h>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
解决办法:
在aaa包中的:
cmakelist中
- find_package()中添加xxx_msgs
- catkin_package()中添加xxx_msgs
package.xml中
- <depend>xxx_msgs</depend>
再次编译就可以找到消息类型了。
五、urdf,xacro,sdf文件类型相互转换
(1)xacro->urdf
使用 xacro
工具:
rosrun xacro xacro my_robot.xacro > my_robot.urdf
(2)xacro->sdf
使用 xacro
工具:
rosrun xacro xacro my_robot.xacro > my_robot.sdf
使用sdf_tools工具:
rosrun sdf_tools urdf_to_sdf my_robot.urdf my_robot.sdf
(3)sdf->urdf
rosrun sdf_tools sdf_to_urdf my_robot.sdf my_robot.urdf
(4)urdf->sdf
rosrun sdf_tools urdf_to_sdf my_robot.urdf my_robot.sdf
sdf中好像没有transmission,如果是机械臂,最好用xacro/urdf文件来描述。
六、多机器人怎么写launch文件
参考:在gazebo仿真环境中加载多个机器人_gazebo仿真可以多个机器人吗-CSDN博客
总结:在launch文件中用group标签,给ns一个名字,在spawn_model的节点的model参数传入ns的名字
七、ROS话题写到class里
1、需要在class的private中定义ros节点句柄:
ros::NodeHandle node_handle_;
2、需要在class的public中声明订阅者或者发布方,注意:
这样会出错:
ros::Subscriber sub = node_handle_.subscribe<open_manipulator_msgs::JointMani>("/joint_rot_mani",10, &Z1ARM::jointCallback);
这样才对:
ros::Subscriber sub = node_handle_.subscribe("/joint_rot_mani",10, &Z1ARM::jointCallback, this);
否则会报一些这种错:
/usr/include/boost/function/function_template.hpp:720:7: required from ‘boost::function1<R, T1>::function1(Functor, typename boost::enable_if_<(! boost::is_integral<Functor>::value), int>::type) [with Functor = void (Z1ARM::*)(const boost::shared_ptr<const open_manipulator_msgs::JointMani_<std::allocator<void> > >&); R = void; T0 = const boost::shared_ptr<const open_manipulator_msgs::JointMani_<std::allocator<void> > >&; typename boost::enable_if_<(! boost::is_integral<Functor>::value), int>::type = int]’
3、在需要在class的public中声明回调函数
void jointCallback(const open_manipulator_msgs::JointMani::ConstPtr &msg);
在类的外面定义回调函数
void Z1ARM::jointCallback(const open_manipulator_msgs::JointMani::ConstPtr &msg){
//content
}
4、在main中进行ros节点初始化和class的实例化
ros::init(argc, argv, "sim_node");
Z1ARM arm;
八、其他
1、C++报错:
error: ‘constexpr’ needed for in-class initialization of static data member ‘const double inspire_hand::hand_serial::WAIT_FOR_RESPONSE_INTERVAL’ of non-integral type [-fpermissive]
static const double WAIT_FOR_RESPONSE_INTERVAL = 0.5;
^~~~~~~~~~~~~~~~~~~~~~~~~~
解决方法:将const换成constexpr