ROS1_进阶笔记

本文概述了在ROS中遇到的问题与解决方案,包括如何实现分布式通讯、如何在ROS包中使用第三方库、处理订阅者只调用一次回调函数、解决自定义话题引用问题,以及urdf、xacro和sdf文件间的转换以及多机器人在launch文件中的配置。
摘要由CSDN通过智能技术生成

目录

一、ROS的分布式通讯

二、ROS使用第三方库的方法

三、当订阅者只调用一次回调函数

四、解决"自定义话题无法引用"


用于记录使用ROS1遇到的一些问题与解决办法。

一、ROS的分布式通讯

  1. 主机和从机连接同一个局域网
  2. 用ifconfig指令查看主机和从机的ip
  3. 修改主机和从机的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使用第三方库的方法

  1. 打开你的ROS包的CMakeLists.txt文件。

  2. 在文件顶部,使用find_package()命令查找ROS中的相关包,例如roscpp,以确保你的ROS包能够与ROS系统正确链接。

    find_package(catkin REQUIRED COMPONENTS roscpp )
  3. include_directories()命令中添加外部库的头文件路径。假设你的头文件在 /usr/local/include 中:

    include_directories( ${catkin_INCLUDE_DIRS} /usr/local/include )

  4. link_directories()命令中添加外部库的库文件路径。假设你的库文件在 /usr/local/lib 中:

    link_directories( ${catkin_LIBRARY_DIRS} /usr/local/lib )
  5. 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 目录下查看你的库文件,可能会有以下几种常见的命名规则:

  1. lib 开头,.a.so 结尾: 例如,libexample.alibexample.so

  2. 带有版本号: 有时,库文件的名称还包含版本号,例如 libexample.so.1.2.3。在这种情况下,通常还有一个指向当前版本的符号链接,例如 libexample.so 指向 libexample.so.1.2.3

  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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值