人真的老了,扔了个周末,完全不记得干了什么...论纪录的重要性啊,当时觉得明白的很,你扔两天试试?扔一年试试?扔几年试试?
最近参加的各种项目脑疼眼乏,一天要同时推进三个项目,且都是技术一线,各项目之间相关性不强,往往是第一个项目上午干了记录下,下午又投入到第二个项目中去,纪录完了后晚上又投入第三个项目,这样将整段时间投入,尽量保证工作进度。因为如此的工作模式,而且也只能这样的工作模式,纪录就非常重要,可以迅速让你脱离当前项目,也可以迅速进入下一个项目快速回忆起上次进度,对于专注度是非常有用的。因此,内心充分认识到了文档的重要性。
从百度RAL首席杨老师那里也知道,中国制造和德国制造的差距——文档!现在的急功近利让人总是沉迷于快点完成任务,快点出产品,快点升级迭代;然而,大大忽视了文档的重要性。为什么一些经典的软件比如matlab,arcgis等等以及一些系统比如ROS,都是国外的?除了技术好,文档完善是其得以广泛应用和传播非常重要的因素!
最近速度看了下ROS的wiki文档,初级教程有中文的还不错,非常详细,很贴心的站到了初学者的角度,很多连环境变量等问题都解释了,这正是令很多初学者困惑的地方。我觉得这个文档非常棒!更新能做的更好就好了。
言归正传,老人还是得重视纪录....
概述:有一个运动平台作为主节点,我的视觉模块负责拍摄识别,将识别得到的障碍物发送给主平台,好指导其下一步行进路线。主平台订阅我的topic,然后我在这个topic上发送识别结果消息(message),然后主平台可以接收。
1. 基础工作
安装非常简单,请见wiki文档:http://wiki.ros.org/cn/ROS/Tutorials
以及:https://blog.csdn.net/okasy/article/details/79448623
sudo sh -c '. /etc/lsb-release && echo "deb http://mirrors.ustc.edu.cn/ros/ubuntu/ $DISTRIB_CODENAME main" > /etc/apt/sources.list.d/ros-latest.list'
sudo apt-key adv --keyserver hkp://ha.pool.sks-keyservers.net:80 --recv-key 0xB01FA116^C
sudo apt-get update
sudo apt-get install ros-kinetic-desktop-full
sudo rosdep init
rosdep update
//以上完成了安装
//将启动设置写到系统的.bashrc文件里(位于当前系统用户的home目录下,为隐藏文件)。这样当你每次登录后系统已经帮你执行这些命令配置好环境
echo "source /opt/ros/kinetic/setup.bash" >> ~/.bashrc
source ~/.bashrc
//
sudo apt-get install python-rosinstall
export | grep ROS
export | grep python
以上安装完成。下面创建工作空间。
打开终端,记为终端1,创建catkin工作空间:
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src
pwd
//下面两句初次创建工作空间采用,第一句用于生成cmakelist
catkin_init_workspace
catkin_make
以上我们创建了一个名字叫做catkin_ws的工作空间,创建好了,可以进行后续工作了。ROS的东西都装在computer/opt目录下。上面创建的工作空间则在home路径下,用pwd命令可以查看到当前路径。
cd到工作空间路径下,进行初始化:
roscore
ROS就开始运转了。想要结束运转,ctrl+C这个终端,就ok了。
工作空间你可以类比matlab想象为一个大文件夹,可以在这个大文件夹下,建立一系列小文件夹,也就是程序包;matlab在运行这些小文件夹下的程序是,需要首先将工作路径切换到这个大文件下,或者将这个大文件夹地址写到PATH里面,类比ROS也是一样的,我们建立的这个工作空间catkin_ws,在下面自己写了很多包,如果让ROS的系统路径能包含它,有两种方法,一种是每次都source一下devel下面的setup.bash文件,另一中方法就是写到系统环境变量里面。否则下次ROS就找不到这个工作空间里的任何包了。下面是两种方法:
//方法1:每次source工作空间下的devel文件夹下面的setup.bash文件:
source ~/catkin_ws/devel/setup.bash
//方法2:将其写到系统环境变量里面:
echo “source ~/catkin_ws/devel/setup.bash” >> ~/.bashrc
source ~/.bashrc
//上面是代码添加,也可以自己手动添加
如何查看是否能识别了:
//方法1:查看ROS_PACKAGE_PATH变量是否包含我们创建工作空间下面的包路径:
echo $ROS_PACKAGE_PATH
//方法2:直接查看包或者包下面的文件如msg
rospack find beginner_tutorials
rosmsg type v_m.msg
2. 创建程序包和message
概述:首先创建程序包,然后在其下建立msg文件夹,然后写需要的消息文档,然后设置路径等,然后build程序包,让ROS可以找到你写的这些msg。
2.1 创建程序包
在ROS非运转状态下(要不然创建完了不认,应该是因为正在运转被占用所以向相关文件写不入路径的原因,这些文件可能是:/home/y/catkin_ws/build下面的cmake_install.cmake和Makefile,待验证)。因此如果ROS正在运转,先Ctrl+C关闭,然后用下面代码创建程序包beginner_tutorials。我们先让它依赖后面这三个文件。
cd ~/catkin_ws/src
catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
首先创建程序包beginner_tutorials,
用rospack list命令查看是否我们创建的程序包可以被ROS识别了。(如果在ROS运转状态下用另一个终端创建程序包,不管结束ROS与否,用这个命令都看不到新创建的这个程序包)。
可以用下面两个命令来分别查看这个程序包的一级依赖关系,所有依赖关系。
rospack depends1 beginner_tutorials
rospack depends beginner_tutorials
到工作空间路径下,编译:
cd ~/catkin_ws
catkin_make
可以看到在build和devel文件夹下会生成有关这个程序包的文件。
2.2 创建程序包下消息文件
根据wiki文档的说明:msg文件存放在package的msg目录下,srv文件则存放在srv目录下。
其实可以创建一个程序包专门用来放消息文件,参见ROS自己的std_msgs就是这种。
alright,lets start! 我们跟文档一致,一是为了规范,二是初学为了方便设置。
在/home/y/catkin_ws/src/beginner_tutorials路径下,建立msg文件夹,创建了三个消息文件:
t_d_m, v_i_m, v_m
在/home/y/catkin_ws/src/beginner_tutorials下面的package.xml文件里,加入下面两句话(注意此处与官方文档不同,官方的为旧版,kinetic应采用以下的语句):
//build 依赖。下面两句任选其1均可,也可以都写上
<build_depend>message_generation</build_depend>
<build_export_depend>message_generation</build_export_depend>
//执行依赖,必须加上以下这句:
<exec_depend>message_runtime</exec_depend>
打开/home/y/catkin_ws/src/beginner_tutorials下面的CMakeLists.txt,在find_packages里面添加message_generation,添加完了后应该为:
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
然后找到如下代码块(默认被注释掉了,放开注释),修改后如下:
## Generate messages in the 'msg' folder
add_message_files(
FILES
t_d_m.msg
v_i_m.msg
v_m.msg
)
然后找到下面的代码块添加如下(不需要添加我们新写的msg,因为这个是当前包的依赖,我们的msg就位于当前包中。ps:std_msgs是程序包名称)(注意此处和中文wiki教程不同,中文的不知为什么这里括号里面是空的,但看英文版里面是如下内容。事实证明英文版正确):
generate_messages(
DEPENDENCIES
std_msgs
)
使用rosmsg查看ROS是否可以识别我们新添加的消息(不需要重新catkin_make就可以查看得到):
rosmsg show beginner_tutorials/t_d_m
添加了新的消息如果需要被使用,是需要生成一系列文件,即被ROS所支持语言的源代码。因此需要重新编译工作空间:
catkin_make
注意:如果出现了 “The specified base path "/home/y/catkin_ws" contains a CMakeLists.txt but "catkin_make" must be invoked in the root of workspace” 这个错误。是因为catkin_init_workspacce的时候,出现下面这句:Creating symlink “/home/y/catkin_ws/CMakeLists.txt” pointing to “/opt/ros/indigo/share/catkin/cmake/toplevel.cmake”, 将当前工作空间下的CMakeLists.txt与/ros/下的cmake做了链接。解决方法是输入如下语句(参考:https://blog.csdn.net/u013294888/article/details/69696956):
unlink /home/ubuntu/catkin_ws/CMakeLists.txt
然后在catkin_make就成功了。
所有在msg路径下的.msg文件都将转换为ROS所支持语言的源代码(部分参考:https://blog.csdn.net/wxz3wxz/article/details/71088098):
生成的C++头文件将会放置在~/catkin_ws/devel/include/beginner_tutorials/
Python脚本语言会在~/catkin_ws/devel/lib/python2.7/dist-packages/beginner_tutorials/msg目录下创建
lisp文件会出现在~/catkin_ws/devel/share/common-lisp/ros/beginner_tutorials/msg/路径下。
java文件会出现在/home/yexin/catkin_ws/devel/share/gennodejs/ros/beginner_tutorials/msg/路径下。
EusLips文件貌似出现在:/home/yexin/catkin_ws/devel/share/roseus/ros/beginner_tutorials/msg/路径下。
这样就可以在代码中使用我们自己定义的msg了。
3. 编写发布器和接收器节点们
发布器和接收器为两个节点,其实是两个可执行文件。我主要写发布,主节点来接收,因此实际上我不用管接收节点。但是为了自我测试我们的发布是否成功,写一个简单的接收器节点也是很必要的。这里主要参考了ROS的wiki帮助以及一些博客:
http://wiki.ros.org/cn/ROS/Tutorials/WritingPublisherSubscriber%28c%2B%2B%29
http://wiki.ros.org/cn/ROS/Tutorials/ExaminingPublisherSubscriber
https://blog.csdn.net/kokerf/article/details/51811835
https://blog.csdn.net/heyijia0327/article/details/41654963
http://wiki.ros.org/navigation/Tutorials/RobotSetup/Sensors
在写发布和接收之前,先说下,我自己写的message叫做v_m.msg,按照上面第2节的方法生成其h文件。我们用rosmsg show v_m看下是这样的:
y@y-Precision-Tower-7910:~$ rosmsg show v_m
[beginner_tutorials/v_m]:
std_msgs/Header header
uint32 seq
time stamp
string frame_id
int8 tT
uint32 n
int64[] tA
float64[] iA
根据这个消息格式,现在我们建立发布器,在发布器内部命名一个topic,在该topic下发送该格式的message。
3.1 发布器节点及测试
在catkin_ws/src/beginner_tutorials文件夹下,有一个src文件夹,在这个文件夹下面建立一个cpp文件,叫做talker.cpp,即创立发布器节点并确定topic和发送消息,内容如下:
#include "ros/ros.h"
#include <beginner_tutorials/v_m.h>
int main(int argc, char **argv)
{
ros::init(argc,argv, "beginner_tutorials");
ros::NodeHandle n;
//topic的名称为chatter,1000为缓冲区,缓冲区中的消息在大于 1000 个的时候就会开始丢弃先前发布的消息。
ros::Publisher chatter = n.advertise<beginner_tutorials::v_m>("chatter",1000);
ros::Rate loop_rate(10); //发布频率为10FPS
while(n.ok())
{
beginner_tutorials::v_m msg;
//给消息里的变量赋值
msg.tT = 1;
msg.n = 2;
msg.tA.resize(2);
msg.iA.resize(2*4);
for (int i = 0;i<msg.n;i++)
{
msg.tA[i] = i;
msg.iA[i*4] = msg.iA[i*4+1] = msg.iA[i*4+2] = msg.iA[i*4+3] = 1.1*i;
}
//不能以以下方式放入[],会报错
// msg.tA = {1,1};
// msg.iA = {1.0,1.1,1.2,1.3,2.0,2.1,2.2,2.3,2.4};
//发布消息
chatter.publish(msg);
ros::spinOnce(); //可用回调函数
loop_rate.sleep();//休眠一段时间以使得发布频率为 10Hz。
}
return 0;
}
然后将以下几句,放在/home/y/catkin_ws/src/beginner_tutorials下面的CMakeLists.txt最后几行:
add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
//下面这一行可以不用加
add_dependencies(talker beginner_tutorials_generate_messages_cpp)
然后在catkin_ws路径下,输入catkin_make编译,可以看到在devel的lib下面有了一个talker执行文件。
我们先用终端来测试下:
打开终端1,输入roscore启动ros环境;
打开终端2,输入rosrun beginner_tutorials talker,启动了发布器,
打开终端3,输入rostopic list,可以看到已经列出了我们发布的chatter,
继续在终端3输入:rostopic echo /chatter
就可看到实时发送的消息内容了。
3.2 接收器节点及测试
我们再编写一个接收器节点,叫做listener。在catkin_ws/src/beginner_tutorials/src文件夹下,创建listener.cpp,内容如下:
#include "ros/ros.h"
#include <beginner_tutorials/v_m.h>
//回调函数,简单来说就是收到了这个消息,就做出什么反应在这里面定义。这里是打印一行东西
void chatterCallback(const beginner_tutorials::v_m::ConstPtr & msg)
{
ROS_INFO("I heard: [%d]", msg->n);
}
int main(int argc, char **argv)
{
ros::init(argc,argv,"listener");
ros::NodeHandle n;
//订阅了“chatter”这个topic
ros::Subscriber sub = n.subscribe("chatter",1000, chatterCallback);
ros::spin();
return 0;
}
然后将以下几句,放在/home/y/catkin_ws/src/beginner_tutorials下面的CMakeLists.txt最后几行:
add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
add_dependencies(listener beginner_tutorials_generate_messages1_cpp)
该程序包的完整CMakeLists.txt里面的内容是这样的:
cmake_minimum_required(VERSION 2.8.3)
project(beginner_tutorials)
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
add_message_files(
FILES
v_m.msg
)
generate_messages(
DEPENDENCIES
std_msgs
)
catkin_package(
CATKIN_DEPENDS message_runtime
)
include_directories(
# include
${catkin_INCLUDE_DIRS}
)
${catkin_EXPORTED_TARGETS})
${catkin_EXPORTED_TARGETS})
add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_dependencies(talker beginner_tutorials_generate_messages_cpp)
add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
add_dependencies(listener beginner_tutorials_generate_messages1_cpp)
然后在工作空间下catkin_make编译ok后,就可以测试了。
打开新终端1,roscore
打开新终端2,rosrun beginner_tutorials talker
打开新终端3, rosrun beginner_tutorials listener,可以看到打印的接收到消息的回应了。
思考:如果我用了外部(非工作空间内)的识别程序,怎么把数据实时传给这个talker节点呢?
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)