ROS工程小结

  • Post author:
  • Post category:其他




一、工作空间概览

建立工作空间目录,一般的结构如下:

|--my_ws
  |--build		#存放有关CMake、make的编译设置文件等
  |--install	#放置最终编译生成的可执行文件,这个文件可没有
  |--devel		#存放编译好的可执行文件等
  |--src		#存放源文件,即我们所需要编写的各种代码和ros包
    |--package_1	#每个ros包下又包含如下结构
      |--include
      |--launch
      |--src
      CMakeList.txt	#重要文件
      package.xml	#重要文件
    ...
    |--package_n
    CMakeList.txt	#src文件夹下也有一个全局性的



/ws/src

目录下初始化:

catkin_init_workspace



/ws/src

目录下创建ros包

package

,如:

catkin_creat_pkg package_name depend1 depend2 depend3

完成源码编写后,在工作空间

/ws

编译:

catkin_make

运行前需对工作空间的环境变量做导入:

source path/to/ws/devel/setup.bash



二、包与节点

包(package)是若干个节点(node)组成的一个集合,可用来实现一定的组合功能,也是发布和下载的资源单位。

在使用前,先用

roscore

命令运行整个ros系统,相当于启动了master线程,等待其他子线程的执行请求。

在需要使用包里某一节点的功能时,可使用

rosrun [packagename] [nodename]

格式调用。

注意,终端若没读入工作空间的环境变量

ws/devel/setup.bash

,则不能找到包和节点,设置如下:

source /path/to/catkin_ws/devel/setup.bash 



实现消息的发布

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

#include <sstream>


int main(int argc, char **argv)
{
    ros::init(argc, argv, "talker");

    ros::NodeHandle n;

    ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);

    ros::Rate loop_rate(10);

    int count = 0;
    while (ros::ok())
    {
        std_msgs::String msg;

        std::stringstream ss;
        ss << "hello world " << count;
        msg.data = ss.str();

        ROS_INFO("%s", msg.data.c_str());
        chatter_pub.publish(msg);

        ros::spinOnce();

        loop_rate.sleep();
        ++count;
    }

    return 0;
}



实现消息接收

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

void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
    ROS_INFO("I heard: [%s]", msg->data.c_str());
}

int main(int argc, char **argv)
{
    ros::init(argc, argv, "listener");

    ros::NodeHandle n;
    ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);

    ros::spin();

    return 0;
}



添加CmakeLists.txt文件内容以将上述发布者与订阅者节点包含进包结构中

add_executable(talker src/pub_eg.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})

add_executable(listener src/sub_eg.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})



三、消息与可视化



自定义消息

大致分为4步:

  1. 定义msg文件(…/ws/src/package/msg目录下)
  2. 在package.xml文件中添加功能包依赖
<build_depend> message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
  1. 在CmakeLists.txt文件中添加编译选项
find_package(... message_generation)

add_message_files(FILES xxx.msg)
generate_messages(DEPENDENCIES std_msgs)	//假设依赖了`std_msgs`

catkin_package(
... 
# message_runtime
)
  1. 编译生成语言相关文件



使用自定义消息

  1. 包含头文件
#include "package_name/msgs_name.h"
  1. 创建Publisher,发布自定义消息类型的话题topic,话题名为 “event”,消息队列长度为1000
ros::Publisher event_pub = n.advertise<package_name::msgs_name>("event", 1000);



RVIZ显示三维点图

发布

PointStamped

类型的点消息,引入头文件:

#include <geometry_msgs/PointStamped.h>

发布RVIZ支持的点消息格式:

ros::init(argc, argv,"event_publisher");
ros::NodeHandle n;

ros::Publisher point_pub = n.advertise<geometry_msgs::PointStamped>("point",1000, true);	//实例化对点消息的话题发布机

ros::Rate loop_rate(10);	//注意消息发布的频率要与rviz中的设置一致,不一致也可以

geometry_msgs::PointStamped epmsg;	//实例化一个点消息对象 epmsg

epmsg.header.frame_id = "epmap";	//给点消息对象命名一个框架id,方便在rviz中选择其坐标系

vector<Event>::iterator ite = EPoint.begin();
while (ros::ok())
{
    if(ite != EPoint.end())
    {
        epmsg.point.x = ite->x;
        epmsg.point.y = ite->y;
        epmsg.point.z = ite->t;

        ROS_INFO("publishing event now!!!");
        point_pub.publish(epmsg);	//发布当前事件点的消息

        ros::spinOnce();
        ite++;
        loop_rate.sleep();
    }

在RVIZ中

通过

add

添加要显示的话题

point

更改全局坐标与对象坐标

frame_id

一致




四、调试

ROS_INFO

//调试信息输出类C风格
ROS_INFO("position=(%0.2f,%0.2f) direction=%0.2f", msg.x, msg.y, msg.theta);
//调试信息输出类Cpp风格
ROS_INFO_STREAM( std::setprecision (2) << std::fixed<< " position=(" << msg.x << " ," << msg.y << ")" << "direction=" << msg.theta );

注意ROS_INFO不能直接输出

string

对象,需要先将对象转成

c_str()

,若是使用ss(stringstream)创建的流文本,需先将其转化为纯

string

(使用str方法):

std::stringstream ss;
ss << "the event's ts is " << emsg->ts;		#emsg->ts为ros::Time类型
OS_INFO("I heard: [%s]", ss.str().c_str());	#流对象先转字符串,再转C类型字符串



五、引用其他包的节点或消息

复制包文件夹(如

B_package

)至自己的工作空间



法一

  1. 创建自己的包(如

    A_package

    )时添加对目标包的依赖,如
catkin_create_pkg std_msgs roscpp rospy B_package
  1. 编译

    B_package

catkin_make -DCATKIN_WHITELIST_PACKAGES='B_package'
  1. 在自己的包中操作

  2. 全局编译:

catkin_make -DCATKIN_WHITELIST_PACKAGES=''



法二

  1. 对已创建的

    A_package

    文件夹中的

    CMakeLists.txt



    package.xml

    文件进行修改:
#CMakeLists.txt
find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  B_package  #添加这一条
)
#...
include_directories(
  include	 #取消这一条的注释
  ${catkin_INCLUDE_DIRS}
)

<build_depend>B_package</build_depend>
<build_export_depend>B_package</build_export_depend>
<exec_depend>B_package</exec_depend>
  1. 编译

    B_package

catkin_make -DCATKIN_WHITELIST_PACKAGES='B_package'
  1. 操作并编译

    A_package

    即可



版权声明:本文为zhxyou1原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。