ROS(Robot Operating System)

简介

        机器人是各种硬件与软件的集成【上层软件设计会采集机器人感知到的外部信息,再进行处理、运算,再将执行命令下达(下达给嵌入式软件设计)。】(不重复发明轮子原则)

        ROS是一套机器人通用软件框架,可以提升功能模块的复用性。

概念

       1、 ROS是使用与机器人的开源元操作系统

        2、ROS集成了大量的工具,库,协议,提供类似OS所提供的功能,简化了对机器人的操作;

        3、ROS提供了用于在多台计算机上获取、构建、编写和运行代码的工具和库,ROS在某些方面类似于“机器人框架”;(分布式架构)

        4、ROS是通讯机制、工具软件包、机器人高层技能以及机器人生态系统的集合体。(ROS=通信+工具+功能+生态)【通信:ROS核心,ROS中常用到数据交换;工具:平台仿真功能可创建机器人,脱离实体;功能:拿别人的功能包来用,主要就是根据自己想要的场景调参。】

设计目标

gethab有众多功能包,遇见问题可以直接去上面找封装好的功能包。

常见问题

话题通信

发布者(C++)

代码:

#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
/*
    发布方实现:
        1、包含头文件;
          ROS中文本类型 --->std_msgs/String.h
        2、初始化ROS节点;
        3、创建节点句柄;
        4、创建发布者对象;
        5、编写发布逻辑并发布数据。
*/

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");//解决中文乱码问题
    //2、初始化ROS节点;
    ros::init(argc,argv,"zhangsan");
    //3、创建节点句柄;
    ros::NodeHandle nh;
    //4、创建发布者对象;
    ros::Publisher pub = nh.advertise<std_msgs::String>("Imfor",10);
    //5、编写发布逻辑并发布数据。
    //先创建被发布的消息
    std_msgs::String msg;
    //发布频率
    ros::Rate rate(50);
    //设置编号
    int count = 0;
    //循环中发布数据
    ros::Duration(3).sleep();
    while(ros::ok())
    {
        count++;
        //实现字符串拼接数字
        std::stringstream ss;
        ss << "hello ---> " << count;
        //msg.data = "hello";
        msg.data = ss.str();
        pub.publish(msg);
        //添加日志:
        ROS_INFO("张三发布的数据是:%s",ss.str().c_str());
        rate.sleep();

        ros::spinOnce();//官方建议回调函数
    }

    return 0;
}

基本实现步骤:

1、包含头文件;

ROS中文本类型 --->std_msgs/String.h

2、初始化ROS节点;

3、创建节点句柄;

4、创建发布者对象;

5、编写发布逻辑并发布数据。

遇见问题及解决

节点名必须在这个拓扑链中唯一标识

解决发布消息的乱码问题:在主函数开头使用函数:setlocale(LC_ALL,"");

如果使用到字符串类型需要添加相应头文件:#include "std_msgs/String.h"

发布频率函数ros::Rate rate(x); x是每秒钟发布的次数

在订阅消息时可能接收不到前几条发送的消息,因为发布者在roscore中还未注册完成,所以需要给一定的时间取完成发布者在roscore中的注册。(先打开订阅,再打开发布)

建议写上回调函数:ros::spinOnce(); 虽然不写也不会报错

订阅者(C++)

代码:

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

/*
    发布方实现:
        1、包含头文件;
          ROS中文本类型 --->std_msgs/String.h
        2、初始化ROS节点;
        3、创建节点句柄;
        4、创建订阅者对象;
        5、处理订阅到的数据;
        6、spin()函数。
*/

void doMsg(const std_msgs::String::ConstPtr &msg){
    //通过msg获取并操作订阅到的数据
    ROS_INFO("李四订阅的消息:%s",msg->data.c_str());
}

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");
    //2、初始化ROS节点;
    ros::init(argc,argv,"lisi");
    //3、创建节点句柄;
    ros::NodeHandle nh;
    //4、创建订阅者对象;
    ros::Subscriber sub = nh.subscribe("Imfor",10,doMsg);
    //5、处理订阅到的数据;

    ros::spin();//无回调函数可能订阅不到消息

    return 0;
}

基本实现步骤:

1、包含头文件;

ROS中文本类型 --->std_msgs/String.h

2、初始化ROS节点;

3、创建节点句柄;

4、创建订阅者对象;

5、处理订阅到的数据;

6、spin()函数。

遇见的问题

节点名必须在这个拓扑链中唯一标识

接收乱码也使用:setlocale(LC_ALL,"");

创建的订阅对象的范型不用写(会根据发布者的自动推导),话题(话题不一致则订阅不到)与队列长度必须与发布者一致,需要有一个回调函数去处理订阅到的数据。

文件

两个程序运行前需先打开roscore,再在每一个程序运行前刷新环境变量:source ./devel/setup.bash

记得每加一个程序文件需要到CMakeLists.txt里面修改或添加相应的add_executable与target_link_libraries

注意事项

检查 CMakeList.txt find_package 出现重复,删除内容少的即可

未创建依赖包虽然可以正常编译,但可能出现中断现象,最好删掉重建

回调函数

每订阅到一条消息就会调用一次回调函数(可以看作中断)

发布者(python)

代码:

#! /usr/bin/env python

import rospy
from std_msgs.msg import String #发布的消息类型

"""
    使用python 实现消息发布:
        1、导包;
        2、初始化ROS节点;
        3、创建发布者对象;
        4、编写发布逻辑并发布数据。
"""

if __name__ == "__main__":
    #2、初始化ROS节点;
    rospy.init_node("wangwu")
    #3、创建发布者对象;
    pub = rospy.Publisher("hh",String,queue_size=10)
    #4、编写发布逻辑并发布数据。
    #创建数据
    msg = String()
    #指定发布频率
    rate = rospy.Rate(1)
    #设置计数
    count = 0
    #建立延时,完成发布方在roscore中的注册
    rate.sleep()
    #编写循环发布数据
    while not rospy.is_shutdown():
        count += 1
        msg.data = "hello" + str(count)
        #发布数据
        pub.publish(msg)
        rospy.loginfo("发布的数据是:%s",msg.data)
        rate.sleep()
    pass

基本实现步骤:

1、导包;

2、初始化ROS节点;

3、创建发布者对象;

4、编写发布逻辑并发布数据。

常见问题及解决

1、注意缩进,python语法的规范性很强,缩进严格

2、发布者对象的话题名称不能和其它的话题名相同

3、仍需解决发布者在roscore中建立注册所用的时间,该点可能导致前几个发布的消息不能被订阅到

4、使用频率函数rate = rospy.Rate(1);通过控制睡眠时间rate.sleep()来完成定时发布

订阅者(python)

代码:

#! /usr/bin/env python
from std_msgs.msg import String
import rospy

"""
    订阅实现流程:
        1、导包
        2、初始化ROS节点
        3、创建订阅者对象
        4、回调函数处理数据
        5、spin()
"""

def doMsg(msg):
    rospy.loginfo("我订阅的数据是:%s",msg.data)

if __name__ == "__main__":
    #2、初始化ROS节点
    rospy.init_node("qianduoduo")
    #3、创建订阅者对象
    sub = rospy.Subscriber("hh",String,doMsg,queue_size=10)
    #4、回调函数处理数据
    #5、spin()
    rospy.spin()

    pass

基本实现步骤:

1、导包

2、初始化ROS节点

3、创建订阅者对象

4、回调函数处理数据

5、spin()

常见问题及解决:

1、需要回调函数才能打印订阅到的消息

2、结束时需要写rospy.spin()

3、导包是要写正确、完整from std_msgs.msg import String

4、订阅到的消息可能没有发布方的前几条,在发布者地代码里添加与ROSMaster注册的时间

注意事项

1、给python文件添加可执行权限(chmod +x *.py)

2、在CMakeLists.txt文件中配置相应python文件

3、运行节点文件前需先启动roscore,再刷新环境变量(source ./devel/setup.bash),最后执行节点

4、订阅节点消息语句(rostopic echo + 话题名)

5、使用rqt_graph可以查看启动了的节点的拓扑关系图/网,里面有相应的节点名称与发布话题

节耦合

        在ROS中,使用不同的语言编写的节点,他们之间也能实现数据的交换,需要保证其有相同的话题。

自定义msg

基本流程(C++实现):

创建msg消息:

1、在功能包下新建msg目录,添加Person.msg文件

2、再编辑2个配置文件:

(1)、在package.xml中添加依赖<build_depend>message_generation</build_depend>(编译时依赖)与<exec_depend>message_runtime</exec_depend>(运行时依赖)

(2)、在CMakeLists.txt文件中找到find_package添加依赖包message_generation;找到add_message_files并取消注释加入自己写的.msg文件的文件名;找到generate_messages语句,打开注释,不做更改;找到catkin_package语句,打开里面的CATKIN_DEPENDS roscpp rospy std_msgs注释并加上message_runtime。(catkin_package里面的功能包依赖于find_package里面的功能包

(3)、可以简单地认为find_package是编译时依赖,catkin_package是运行时依赖

3、编译,重点在于其生成的中间文件:

C++调用的在/devel/include/plumbing_pub_sub/Person.h里面

python调用的在/devel/lib/python3/dist-packages/plumbing_pub_sub/msg/_Person.py里面

调用自定义的msg消息:

1、先复制Person.h的包名路径,终端输入pwd

2、将复制的路径.vscode下的c_cpp_properties.json文件中,includePath下:

3、创建.cpp文件的发布方

发布方:发布人的消息

(1)包含头文件

        #include "plumbing_pub_sub/Person.h"

(2)初始化ROS节点

(3)创建节点句柄

(4)创建发布者对象

(5)编写发布逻辑、发布数据

代码:

#include "ros/ros.h"
#include "plumbing_pub_sub/Person.h"

/* 
    发布方:发布人的消息
        1、包含头文件
            #include "plumbing_pub_sub/Person.h"
        2、初始化ROS节点
        3、创建节点句柄
        4、创建发布者对象
        5、编写发布逻辑、发布数据
 */

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");
    ROS_INFO("这是消息发布方");
    //2、初始化ROS节点
    ros::init(argc,argv,"banzhuren");
    //3、创建节点句柄
    ros::NodeHandle nh;
    //4、创建发布者对象
    ros::Publisher pub = nh.advertise<plumbing_pub_sub::Person>("talk",10);
    //5、编写发布逻辑、发布数据
    //5-1、创建被发布的数据
    plumbing_pub_sub::Person person;
    person.name = "张三";
    person.age = 1;
    person.height = 179;
    //5-2设置发布频率
    ros::Rate rate(1);
    //5-3循环发布数据
    while(ros::ok()){
        //
        //核心:发布数据
        pub.publish(person);
        ROS_INFO("发布的消息是:%s,%d,%.2f",person.name.c_str(),person.age,person.height);
        //休眠
        rate.sleep();
        //建议:调用回头函数
        ros::spinOnce();
    }

    return 0;
}

4、配置CMakeLists.txt文件

(1)在其中找到add_executable,大概在136行左右;然后添加一句add_executable(pub_person src/pub_person.cpp);新创建的cpp文件名

(2)再找到target_link_libraries,150行左右;然后添加(新创建的cpp文件名)

                        target_link_libraries(pub_person

                        ${catkin_LIBRARIES}

                        )

(3)再找到add_dependencies;添加(保证依赖关系)(保证了先编译msg文件再编译cpp文件,严谨逻辑性)

add_dependencies(pub_person ${PROJECT_NAME}_generate_messages_cpp)

(4)发布方实现结果测验:

        在终端中运行ROS核心;再打开一个终端运行功能包下的文件,运行前要刷新环境变量;再打开另一个终端,进入相应工作空间、刷新环境变量,再使用rostopic echo订阅话题(talk)

最终结果显示如下:

5、创建.cpp文件的订阅方

订阅方:订阅发布方发布的人的消息

(1)包含头文件

        #include "plumbing_pub_sub/Person.h"

(2)初始化ROS节点

(3)创建节点句柄

(4)创建订阅者对象

(5)编写回调函数,处理订阅的数据

(6)调用spin()函数

代码:

#include "ros/ros.h"
#include "plumbing_pub_sub/Person.h"
/* 
    订阅方:发布人的消息
        1、包含头文件
            #include "plumbing_pub_sub/Person.h"
        2、初始化ROS节点
        3、创建节点句柄
        4、创建订阅者对象
        5、编写回调函数,处理订阅的数据
        6、调用spin()函数
 */

void doPerson(const plumbing_pub_sub::Person::ConstPtr& person){
    ROS_INFO("订阅的人的信息:%s,%d,%.2f",person->name.c_str(),person->age,person->height);
}

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");
    ROS_INFO("订阅方实现");
    //2、初始化ROS节点
    ros::init(argc,argv,"jiazhang");
    //3、创建节点句柄
    ros::NodeHandle nh;
    //4、创建订阅者对象
    ros::Subscriber sub = nh.subscribe("talk",10,doPerson);
    //5、编写回调函数,处理订阅的数据

    //6、调用spin()函数
    ros::spin();
    return 0;
}

4、配置CMakeLists.txt文件

(1)在其中找到add_executable,大概在136行左右;然后添加一句add_executable(sub_person src/sub_person.cpp);新创建的cpp文件名

(2)再找到target_link_libraries,150行左右;然后添加(新创建的cpp文件名)

                        target_link_libraries(sub_person

                        ${catkin_LIBRARIES}

                        )

(3)再找到add_dependencies;添加(保证依赖关系)(保证了先编译msg文件再编译cpp文件,严谨逻辑性)

add_dependencies(sub_person ${PROJECT_NAME}_generate_messages_cpp)

(4)订阅方实现结果测验:

        在终端中运行ROS核心;再打开一个终端进入相应工作空间,刷新环境变量,运行发布方文件;再打开另一个终端,进入相应工作空间、刷新环境变量,再使用rostopic echo订阅话题(talk)

最终结果显示如下:

使用计算图查看节点间的消息传递及话题:rqt_graph

基本流程(Python实现):

准备操作,在编写python时有自动补齐功能:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值