ROS操作系统学习笔记3

电子说

1.3w人已加入

描述

摘要:这篇文章主要介绍ROS常用工具、ROSPY和ROSCPP常用模块,完全看完三篇文章,可以说ROS就基本入门,可以自己动手做实验了。

ROS常用工具

ROS工具的 功能大概有以下几个方向:仿真、调试、可视化。这里主要介绍常用工具作用,如何添加模块,设置参数B站都有视频,这里不会有过多解读。

gazebo是一种最常用的机器人仿真工具,模拟器,也是目前独立的开源机器人仿真平台。gazebo可以进行机器人的动力学仿真,可以模仿机器人常用的传感器(比如激光雷达、摄像头、IMU等),也可以加载自定义的环境和场景。

RViz是可视化工具,是将接收到的信息呈现出来;rviz和gazebo非常相似,但是gazebo实现的是仿真,提供一个虚拟世界,RVIZ实现的是可视化,呈现接收到的信息。

rqt主要作用和RVIZ一致都是可视化,有了它我们可以直观的看到消息的通信架构和流通路径;

常用命令:

rqt_graph :显示通信架构

rqt_plot :绘制曲线

rqt_console :查看日志

rosbag是一套用于记录和回放ROS主题的工具,此外还提供代码API,对包进行操作编写。

常用命令:cheak 确定一个包是否可以在当前系统中进行,或者是否可以迁移。decompress 压缩一个或多个包文件。filter 解压一个或多个包文件。fix 在包文件中修复消息,以便在当前系统中播放。help 获取相关命令指示帮助信息info 总结一个或多个包文件的内容。play 以一种时间同步的方式回放一个或多个包文件的内容。record 用指定主题的内容记录一个包文件。reindex 重新索引一个或多个包文件。

rosbridge是一个用在ROS系统和其他系统之间的一个功能包,就像是它的名字一样,起到 一个"桥梁"的作用,使得ros系统和其他系统能够进行交互.Rosbridge为非ROS程序提供了 一个JSON API,有许多与Rosbridge进行交互的前端,包括一个用于Web浏览器交互的 WebSocket服务器。Rosbridge_suite是一个包含Rosbridge的元程序包,用于Rosbridge 的各种前端程序包(如WebSocket程序包)和帮助程序包。

moveit它融合了研究者在运动规划、操纵、3D感知、运动学、控制和导航方面的最新进展,为操作 者提供了一个易于使用的平台,使用它可以开发先进的机器人应用,也被广泛应用于工业, 商业,研发和其他领域。move结构图如下:

ROS

roscpp代码演示

ROS为我们机器人开发者提供了不同语言的 接口,比如roscpp是C++语言ROS接口(目前最广泛应用的ROS客户端库,执行效率高),rospy是python语言的ROS接口(开发效率高,通常用在对运行时间没有太大要求的场合,例如配置、初始化等操作),rosjava是java语言的ROS接口(测试版本) 我们直接调用它所 提供的函数就可以实现topic、service等通信功能。

ROS

roscpp位于 /opt/ros/kinetic 之下,用C++实现了ROS通信。在ROS中,C++的代码是通过 catkin这个编译系统(扩展的CMake)来进行编译构建的。每一个node的节点功能可能不一样,但是都包含初始化、销毁、句柄等操作。

  • ROS代码逻辑整体

常见的ros代码逻辑包含下面的执行步骤:

1.调用ros::init()函数初始化节点的名称和其他信息

2.创建ros::NodeHandle对象,也就是节点句柄,用于创建Pub、Sub(NodeHandle就是节点资源的描述,需要借助“把手”才能操作资源)

3调用ros::shutdown()手动关闭节点(一般是系统自动帮我们完成)。

#include
int main(int argc, char** argv)
{
ros::init(argc, argv, "your_node_name");
ros::NodeHandle nh;
//....节点功能
//创建话题的publisher
ros::Publisher advertise(const string &topic, uint32_t queue_size, bool latch=false);
//创建话题的subscriber
ros::Subscriber subscribe(const string &topic, uint32_t queue_size, void(*)(M));
//创建服务的server,提供服务
ros::ServiceServer advertiseService(const string &service, bool(*srv_func)(Mreq &, Mre
s &));
//创建服务的client
ros::ServiceClient serviceClient(const string &service_name, bool persistent=false);
//查询某个参数的值
bool getParam(const string &key, std::string &s);
bool getParam (const std::string &key, double &d) constbool getParam (const std::string &key, int &i) const//给参数赋值
void setParam (const std::string &key, const std::string &s) constvoid setParam (const std::string &key, const char *s) const;
void setParam (const std::string &key, int i) const;
//....
ros::spin();//用于触发topic、service的响应队列
return 0;
}

roscpp的主要部分包括:ros::init() : 解析传入的ROS参数,创建node第一步需要用到的函数ros::NodeHandle : 和topic、service、param等交互的公共接口ros::master : 包含从master查询信息的函数ros::this_node:包含查询这个进程(node)的函数ros::service:包含查询服务的函数****ros::param:包含查询参数服务器的函数,而不需要用到NodeHandleros::names:包含处理ROS图资源名称的函数

具体可见:http://docs.ros.org/api/roscpp/html/index.html

以上功能可以分为以下几类:Initialization and Shutdown 初始与关闭Topics 话题Services 服务Parameter Server 参数服务器Timers 定时器NodeHandles 节点句柄Callbacks and Spinning 回调和自旋(或者翻译叫轮询?)Logging 日志Names and Node Information 名称管理Time 时钟Exception 异常

  • 回调函数与spin()方法

    CallBack回调函数与ros::spin() 方法需要配合使用,当消息传来时,只指定回调函数,系统不会自动触发,必须要 ros::spin() 或 者 ros::spinOnce() 才能真正使回调函数生效。 处理流程:回调函数一般作为参数传到另外一个函数(一般是函数指针),当消息message到达时,先会把消息放到一个队列中,当有spin函数执行时,就会处理消息队列队首的信息。spin具体的处理方法可以分成阻塞/非阻塞,单线程/多线程两种。

    spin方法 阻塞 线程
    ros::spin() 阻塞 单线程
    ros::spinOnce() 非阻塞 单线程
    ros::MultiTreadedSpin() 阻塞 多线程
    ros::AsyncMultiThreadedSpin() 非阻塞 多线程
  • ROS节点编写

    基本流程,首先创建一个工作空间workplace,然后根据实际需要创建相应的包package,编写相应的需求文件,如源文件;根据编译运行需要,补充CMakeLists.txt、package.xml相应说明,如添加依赖,查找相关包,运行所需要的包,消息类型等等。

    mkdir -p xxx_ws   //创建工作空间
    catkin_make     //编译工作空间
    //打开.bashrc 设置xxx_ws工作空间的环境变量
    catkin_create_pkg xxxx(包) xx(依赖)   //创建包
    
  1. 编写一个talker的node

在工作空间的src/目录下,第1步,创建一个talker的包study:$ catkin_create_pkg study roscpp第2步,打开vcode(或者其他ide),study/src,创建源文件study_node.cpp,代码如下:

#include"ros/ros.h"
#include"std_msgs/String.h"
#include
//编写一个node并发布出来
int main(int argc,char **argv){
   ros::init(argc,argv,"study_talker");//定义node的属性
   ros::NodeHandle n;//ros提供的一个类,可以实例化publisher,进行发布数据
   ros::Publisher study_pub=n.advertise

第3步,设置CMakeLists.txt&package.xmlCMakeLists.txt:

find_package(catkin REQUIRED COMPONENTS
roscpp
std_msgs
)//告诉系统编译本包时,需要找到这两个包

catkin_package(
# INCLUDE_DIRS include
# LIBRARIES study
CATKIN_DEPENDS roscpp std_msgs
# DEPENDS system_lib
)//声明依赖本包同时需要里面这两个ros包

add_executable(${PROJECT_NAME}_node src/study_node.cpp)//编译本包生成的可执行文件

add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})//链接可执行文件和依赖库

//一般情况而已,CMakeLists.txt是创建包同时,系统自动生成的,然后,我们需要的工作,一般情况就是把上面基本地方去掉#号就行了(目的告诉系统,关于该包,在哪,依赖是啥)

package.xml:

roscppclass="hljs-name"build_depend>
std_msgsclass="hljs-name"build_depend>
roscppclass="hljs-name"exec_depend>
std_msgsclass="hljs-name"exec_depend>
//主要修改类似样式,当然,本例子比较简单,系统生成的,不需要做其他修改,但是,如果节点添加新的依赖,需要在这些地方添加相应的包

第4步,编译

$ catkin_make  #注意在要做工作空间的一级目录下使用该指令

第5步,验证,终端运行

$ roscore & #后台运行一个ROS master
$ rosrun study study_node & #后台运行包名+节点名
$ rostopic list #
/study_topic //表示定义的topic正常发布
/rosout
/rosout_agg
$ rostopic echo #查看study_topic
data: "hello study world!2360"//表示发布成功
---
data: "hello study world!2361"

这时,从零开始创建的talker节点node,成功创建完成

  1. 编写一个listener的node

在工作空间的src/目录下,第1步,创建一个listener的包study_listen:

$ catkin_create_pkg study_listen roscpp

第2步,study_listen/src,创建源文件study_listen_node.cpp

#include"ros/ros.h"
#include"std_msgs/String.h"

//创建一个listener的node
void studyCallback(const std_msgs::String::ConstPtr& msg){
   //回调函数一定是要求是无返回类型
   ROS_INFO("I can see you again,%s",msg->data.c_str());
}

int main(int argc,char ** argv){
   ros::init(argc,argv,"study_listener");//初始化这么一个node
   ros::NodeHandle n;//命名空间
   ros::Subscriber sub=n.subscribe("study_topic",10,studyCallback);
   //表示聆听study_topic这个主题,每次听到就会启动回调函数,这里的10也表示一个缓冲数量,多了,前面的会被是放掉
   //这里一定要注意,聆听的topic一定要和发布的topic的名称对应上,否则,是没办法接收的
   ros::spin();
   return 0;
}
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分