创建工作空间
mkdir -p ~/yyj_ws/src
//到src下
cd yyj_ws/src
在src文件夹下初始化工作空间,将其变成ROS工作空间的属性
catkin_init_workspace
在src中创建功能包指令
catkin_create_pkg[depend1][depend2][depend3][...]
例如:
catkin_create_pkg learning_communication std_msgs rospy roscpp
此时功能包中src放的是核心代码,include放的是头文件,CMakelists.txt和package.xml是所有功能包都必须具备的文件。前者是放置编译功能包的编译选项和规则,使用cmake接口;后者是描述功能包的具体信息,比如名字、版本号、维护者、声明的依赖等后期加依赖需在此文件修改。
接着在工作空间层级编译,再设置环境变量。
cd ..
catkin_make
source ~/yyj_ws/devel/setup.bash
(同一个工作空间下,不允许存在同名功能包。不同工作空间下,允许存在同名功能包)
查看ros的环境变量,关注ROS_PACKAGE_PATH即ros编译运行的查找功能包和节点的顺序
env | grep ros
//或者
echo $ROS_PACKAGE_PATH
当不同工作空间下,存在同名功能包会先查找后生成的路径
例:(实验完记得删除这个包)
//安装ros功能包例程
sudo apt-get install ros-kinetic-roscpp-tutorials
//查找功能包会在opt/ros/kinetic/share/roscpp_tutotials
rospack find roscpp_tutorials
//复制功能包到工作空间src下
//再次设置环境变量
source ~/yyj_ws/devel/setup.bash
//再次查找即发现查找路径指向工作空间里的功能包了
rospack find roscpp_tutorials
a、进入/home/frany/yyj_ws/src/learning_communication/src创建talker.cpp
b、编写talker.cpp
编程逻辑:
(1)初始化ROS节点;
(2)向ROS Master注册节点信息,包括发布的话题名和话题中的消息类型;
(3)按照一定频率循环发布消息;
/*
该例程将发布chatter话题,消息类型String
*/
#include
#include "ros/ros.h"
#include "std_msgs/String.h"
int main(int argc,char **argv)
{
//ROS节点初始化,“talker“为节点名称,后期可更改
ros::init(argc,argv,"talker");
//创建节点句柄
ros::NodeHandle n;
//创建一个Publisher,发布名为chatter的topic,消息类型为std::msgs::String,1000是发布队列的长度,它的作用是缓冲数据,当队列满了会删除时间戳最早的数据,如发布消息过快可能会导致断帧
ros::Publisher chatter_pub = n.advertise("chatter", 1000);
//设置循环的频率
ros::Rate loop_rate(10);
int count = 0;
while (ros::ok())
{
//初始化std::msgs::String类型的消息
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();
//按照循环频率延时按循环频率(10hz)休眠即100ms,避免cpu占用过高
loop_rate.sleep();
++count;
}
return 0;
}
a、进入/home/frany/yyj_ws/src/learning_communication/src创建listener.cpp
b、编写listener.cpp
编程逻辑:
(1)初始化ROS节点;
(2)订阅需要的话题;
(3)循环等待话题消息,接收到消息后进入回调函数;
(4)在回调函数中完成消息处理;
/*
该例程将订阅chatter话题,消息类型String
*/
#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节点
ros::init(argc, argv, "listener");
//创建节点句柄
ros::NodeHandle n;
//创建一个Subscriber,订阅名为chatter的topic,注册回调函数chatterCallback
ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
//循环等待回调函数
ros::spin();
return 0;
}
c++需要编译,python不需要,因为其本身就是一种可执行文件。
在 CMakeLists.txt 文件中进行编译代码:
a、流程:
(1)设置需要编译的代码和生成的可执行文件
(2)设置链接库
(3)设置依赖
add_executable生成可执行文件,依赖于talker.cpp生成talker,可以有多个源码文件依次加在后面;
target_link_libraries为链接到第三方库,此处只链接了默认库。
add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
b、编译:
在yyj_ws 工作空间层级下生成可执行文件:
catkin_make
a、启动ROS Master
终端1:
roscore
b、启动talker
终端2:
rosrun learning_communication talker
c、启动listener
终端3:
rosrun learning_communication listener
如没把环境变量直接写进.bashrc,则每次打开新终端都需添加环境变量
source ~/yyj_ws/devel/setup.bash
在learning_communication下创建msg目录,在msg目录下创建Person.msg文件
string name
uint8 sex
uint8 age
uint8 unknown = 0
uint8 male = 1
uint8 female = 2
message_generation
message_runtime
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES learning_communication
CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
# DEPENDS system_lib
)
add_message_files(FILES Person.msg)
generate_messages(DEPENDENCIES std_msgs)
最后编译
catkin_make
如没把环境变量直接写进.bashrc,则需添加环境变量
source ~/yyj_ws/devel/setup.bash
rosmsg show Person