ROS备忘录

本文详细介绍了ROS(RobotOperatingSystem)的开发流程,包括创建工作空间和功能包、编译、管理话题和节点、使用rosbag、参数配置、服务和行为的实现,以及多线程编程的应用。还提到了rqt工具的使用和相关命令行工具,如`rostopic`、`rosnode`等。

非代码

一、创建工作空间

mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src
catkin_init_workspace

二、创建功能包

cd (workspace)/src
catin_create_pkg (name) std_msgs rospy roscpp

三、编译

catkin_make或者catkin build
#单个包的情况下是一样的,前者相当于cmake多个包同时编译,后者会将所有的包同时单独(isolated)编译,编译过程互不影响。
source devel/setup.bash或者zsh

四、查看ros相关的环境变量

env | grep ros
#ros会从ROS_PACKAGE_PATH中依次查找

五、查找功能包

rospack find (name)#找到功能包的位置

六、运行功能包

rosrun 功能包 可执行文件名字#需要roscore
roslaunch 功能包 launch文件名#不需要roscore

七、自定义话题消息

#查看可用基本msg
rosmsg list

#查看msg信息
rosmsg show

#定义msg文件
string name
uint8 age
uint8 unknown=0
uint8 male=1
uint8 female=2

#在package.xml中添加
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>

#在CMakeLists.txt中添加
find_package(message_generation)
catkin_package(CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs message_runtime) 
add_message_files(FILES (NAME).msg)
generate_messages(DEPENDENCIES std_msgs)

add_executable(listener src/listener.cpp )
add_dependencies(listener topic_demo_generate_messages_cpp)#这个用于生成自定义msg的h文件
target_link_libraries(listener ${catkin_LIBRARIES})

八、话题相关

rostopic list#查看所有发布的话题

rostopic hz (name)#查看话题的发布频率

rostopic echo (name)#查看话题内容

rostopic pub +话题名+话题类型+需要改的参数以及值 #发布话题

rostopic info

九、节点相关

rosnode list
rosnode info
rosnode kill

十、rosbag相关

rosbag play name.bag -d 2 -l -r 0.5 #延迟两秒,以0.5倍播放速度循环播放rosbag

rosbag info name.bag#查看rosbag信息

rosbag record 话题名字#记录话题名 #所有话题-a

十、params相关

launch文件中也可以

这个是指运行xacro.py文件,传入robot.xacro参数,这个运行的结果给到robot_description。

一般情况使用

相当于rosparam load file_name

#我在写代码过程中学习到了怎么从yaml文件中读取数组,特别记录一下,里面的路径都没修改,只是作为参考
#.launch文件中,放在全局位置,也就是<node>外面
 <rosparam command="load" file="$(find process_data)/params/sensor_covariance.yaml" />
#注意位置,如果在<node后面,</node>前,所有的参数前面要加个“/命名空间”,空间名就是你的节点名“name”。

#.yaml文件中
imu_orientation_covariance: [8e-4 , 8e-4 , 8e-4]
#这里使用double或者科学计数法都可以

#.cpp文件中
double imu_ori_co[3];
XmlRpc::XmlRpcValue config;
n.getParam("imu_orientation_covariance", config);
#或者,提供默认值的版本
#n.param<vector<string>>("imu_orientation_covariance", config,XmlRpc::XmlRpcValue() )
#转为double
std::ostringstream ostr;
ostr << config[i];
std::istringstream istr(ostr.str());
istr >> imu_orientation_covariance[i];

#默认值用数组或许比vector更好??
#不知道是不是获取到参数,可以用n.hasParam("name"),也可以用上面两个返回的bool判断

十一、launch相关

十二、tf树

rosrun rqt_tf_tree rqt_tf_tree

十三、服务service相关

rosservice list
rosservice info
rosservice call

rossrv list
rossrv show

十四、行为action相关

分客户端和服务端,服务端可以回传status、result和feedback给客户端,客户端给服务端goal和cancel指令,所以服务端可以被另外的客户端抢断或者被客户端发来的请求抢断。通常用与长时间、可抢占的任务中。

  1. .action文件

2、添加依赖
#package.xml中加入
<build_depend>actionlib</build_depend>
<build_depend>actionlib_msgs</build_depend>
<exec_depend>actionlib</exec_depend> 
<exec_depend>actionlib_msgs</exec_depend>

#Cmakelist.txt中加入
find_package(catkin REQUIRED actionlib_msgs actionlib)
add_action_files(DIRECTORY action FILES DoDishes.action) 
generate_messages(DEPENDENCIES actionlib_msgs)

3、编写

//服务端
#include <ros/ros.h>
#include <actionlib/server/simp1e_action_server.h>
#include "learning_communication/DoDishesAction.h"
typedef actionlib::SimpleActionServer<learning_communication::DoDishesAction> Server;
// 收到action的goa1后调用该回调函数
void execute (const learning_communication::DoDishesGoalConstPtr& goal, Server* as)
{
    ros::Rate r(1);
    1earning_communication::DoDishesFeedback feedback;
    ROS_INFO("Dishwasher %d is working.", goal->dishwasher_id) ;
    //按照1hz的频率发布进度feedback
    for(int i=1; i<=10; i++)
    {
        feedback.percent_complete = i * 10;
        as->publishFeedback(feedback) ;
        r.sleep() ;
    }    

    ROS_ INFO ("Dishwasher %d finish working.", goal->dishwasher_id);
    as->setSucceeded();
}

int main(int argc, char** argv)
{
    ros::init(argc,argv, "do_dishes_server") ;
    ros::NodeHandle n;
    //定义一个服务器
    Server server(n, "do_dishes", boost::bind(&execute,_1, &server) ,false) ;
    //服务器开始运行
    server.start();
    ros::spin() ;
    return 0;
}

 

#客户端
#include <action1ib/client/simp1e_action_client.h>
#include "learning_communication/DoDishesAction.h"

typedef actionlib::SimpleActionClient<learning_communication::DoDishesAction> Client;

//当action完成后会调用该回调函数一次
void doneCb (const actionlib::SimpleClientGoalState& state ,const learning_communication::DoDishesResultConstPtr& result)
{
    ROS_INFO("Yay! The dishes are now clean") ;
    ros::shutdown() ;
}
// 当action激活后会调用该回调函数一 次
void activeCb ()
{
    ROS_INFO("Goal just went active") ;
}
//收到feedback后调用该回调函数
void feedbackCb (const learning_ communication: :DoDi shesFeedbackConstPtr& feedback)
{
    ROS_INFO(" percent_ complete: %f ",feedback->percent_complete); 
}

int main(int argc, char** argv)
{
    ros::init(argc, argv, "do_dishes_client") ;
    //定义一个客户端
    Client client("do_dishes", true) ;
    //等待服务器端
    ROS_INFO("Waiting for action server to start.");
    client.waitForServer();
    ROS_INFO("Action server started, sending goal.");

    //创建一个action的goal
    learning_communication::DoDishesGoal goal ;
    goal.dishwasher_id = 1;
    //发送action的goal给服务器端,并且设置回调函数
    client.sendGoal(goal,&doneCb, &activeCb, &feedbackCb) ;
    ros::spin() ;
    return 0;
}

十五、常用rqt

rqt_graph显示节点和话题的连接关系

rqt_plot动态绘制曲线(如果wsl中遇到窗口无法控制的情况,rqt_plot --clear-config)

rqt_console查看日志

十六、C++编程

#订阅+发布topic
class sub_pub
{
public:
    sub_pub(){
      sub = n.subscribe("IMU", 1, &sub_pub::Callback , this);
      pub = n.advertise<[your msgs_type]>("outtopic", 1);
    }
    void callback(const [sensor_msgs::Imu]::Ptr &msg);
    //topic_demo::gps::ConstPtr &msg值不可修改,消息类型自行修改
    ros::NodeHandle n;
    //n.getParam("imu_topic", imu_topic);
    ros::Subscriber sub;
    ros::Publisher pub;
};

void sub_pub::Callback(const sensor_msgs::Imu::Ptr &msg)
{  
//。。。。一顿操作
    pub.publish(msg);
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "【你的节点名字】");
  sub_pub sub_pub;
  ros::spin(); //这里也可以用while循环中用ros::spinOnce()
  return 0;
}

十七、多线程

参考:

(9条消息) 【ROS】回调的多线程问题_ros 回调函数 多线程_Amelie_xiao的博客-优快云博客

1、pub.cpp

//
// Created by uestc213 on 23-7-24.
//
//这段代码主要是实现定时向Topic发布消息
#include "ros/ros.h"
#include <boost/thread.hpp>
#include <std_msgs/String.h>

int main(int argc, char **argv){
    ros::init(argc, argv, "multi_publisher");
    ros::NodeHandle n;
    ros::Publisher pub_1 = n.advertise<std_msgs::String>("topic_1", 1, true);
    ros::Publisher pub_2 = n.advertise<std_msgs::String>("topic_2", 1, true);
    ros::Publisher pub_3 = n.advertise<std_msgs::String>("topic_3", 1, true);

    int count = 0;
    //创建一个ros::Timer每1秒进行发布,回调函数采用lamda4方法的格式
    ros::Timer timer = n.createTimer(ros::Duration(1),
                                     [&](const ros::TimerEvent&)
    {
        std_msgs::String msg;
        std::stringstream ss;
        ss << "topic1: " << count;
        msg.data = ss.str();
        pub_1.publish(msg);

        std::stringstream ssa;
        ssa << "topic2: " << 100+count;
        msg.data = ssa.str();
        pub_2.publish(msg);

        std::stringstream ssab;
        ssab << "topic3: " << 200+count;
        msg.data = ssab.str();
        pub_3.publish(msg);
        ++count;
    });

    //确保定时器回调被调用
    ros::spin();

    return 0;
}

2、sub.cpp

//
// Created by uestc213 on 23-7-25.
//
//为每个subscriber指定队列
#include <ros/ros.h>
#include <boost/thread.hpp>
#include <std_msgs/String.h>
#include <ros/callback_queue.h>


//回调函数,注意参数是const类型的boost::shared_ptr指针
void Callback1(const std_msgs::StringConstPtr& msg)
{
    ROS_INFO_STREAM("Thread["<< boost::this_thread::get_id()
                             <<"],before topic1:"<< msg->data.c_str());
    //循环
    boost::this_thread::sleep(boost::posix_time::seconds(1.2));

    ROS_INFO_STREAM("Thread["<< boost::this_thread::get_id()
                             <<"], topic1:"<< msg->data.c_str());
}

void Callback2(const std_msgs::StringConstPtr& msg)
{
    ROS_INFO_STREAM("Thread["<< boost::this_thread::get_id()
                             <<"],topic2:"<< msg->data.c_str());
}

//回调函数,注意参数是const类型的boost::shared_ptr指针
void Callback3(const std_msgs::StringConstPtr& msg)
{
    ROS_INFO_STREAM("Thread["<< boost::this_thread::get_id()
                             <<"],topic3:"<< msg->data.c_str());
    boost::this_thread::sleep(boost::posix_time::seconds(2));
}

int main(int argc, char **argv){
    ros::init(argc, argv, "multi_subscriber");
    ros::NodeHandle n;
    ros::SubscribeOptions ops;
    ops.init<std_msgs::String>("topic_1", 1, Callback1);
    ops.allow_concurrent_callbacks = true;
    ros::Subscriber sub1 = n.subscribe(ops);
    //ros::Subscriber sub1 = n.subscribe("topic_1", 1, Callback1);
    ros::Subscriber sub2 = n.subscribe("topic_2", 1, Callback2);

    ros::NodeHandle n_1;
    ros::CallbackQueue my_queue;
    n_1.setCallbackQueue(&my_queue);
    ros::SubscribeOptions ops3;
    ops3.init<std_msgs::String>("topic_3", 1, Callback3);
    ops3.allow_concurrent_callbacks = true;
    ros::Subscriber air_sub = n_1.subscribe(ops3);

    ROS_INFO_STREAM("Thread["<< boost::this_thread::get_id()<<"]This is main thread.");

    ros::AsyncSpinner spinner(2);
    spinner.start();

    //启动一个线程处理AirQuality单独的队列
    ros::AsyncSpinner spinner_1(2, &my_queue);
    spinner_1.start();

    ros::waitForShutdown();
}

十八、结合boost::bind

(9条消息) 【C++】ROS与boost:bind()详解_Amelie_xiao的博客-优快云博客

十九、nodelet学习

分享一个不错的记录

【ROS】ROS常用命令_linux_EngineerX_-DevPress官方社区 (youkuaiyun.com)

### 如何使用ROS2录制点云数据 为了实现通过ROS2录制点云数据,可以采用`rosbag2`工具来完成这一目标。此方法允许用户记录来自不同传感器的数据流,包括点云数据。 #### 使用 `rosbag2` 录制点云数据 启动用于发布点云消息的节点之后,可以通过命令行运行如下指令: ```bash ros2 bag record /point_cloud_topic_name -o output_directory ``` 上述命令中的 `/point_cloud_topic_name` 需要替换为实际发布的点云主题名称[^1];而 `-o output_directory` 参数则指定了保存录得文件的目标路径以及目录名。如果不指定该参数,默认会在当前用户的家目录下创建名为 `rosbags` 的文件夹,并在此文件夹内按照时间戳命名新建立的子文件夹存储录制的内容。 停止录制可通过按下 Ctrl+C 来终止正在执行的 rosbag 命令。 #### 查看已录制的点云数据 当完成了点云数据的录制后,可利用rviz2可视化这些数据。首先打开一个新的终端窗口并输入下面这条命令加载之前所录制下来的包: ```bash ros2 bag play recorded_bag_file_path --clock ``` 这里 `recorded_bag_file_path` 应被替换成具体的 .db3 文件位置。加上 `--clock` 选项是为了同步仿真时间和系统时间以便于回放过程中更好地控制播放速度和其他依赖时钟的功能。 接着,在另一个终端里启动 rviz2 并配置好相应的显示设置即可查看到历史时刻下的三维环境重建效果。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XiangrongZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值