一. 创建工作空间
1.工作空间的创建
mkdir catkin_ws
mkdir src
cd /catkin_ws/src
catkin_init_workspace
2.编译工作空间
需要在()_ws的文件下下进行编译
catkin_make
3.设置环境变量
source devel/setup.bash
4.检查环境变量
echo $ROS_PACKAGE_PATH
二.创建功能包
1.创建功能包
在src文件下创建功能包,<package_name>
是新功能包的名称,[depend1] [depend2] [depend3]
是可选的依赖项。
catkin_create_pkg <文件名>
[depend1] [depend2] [depend3]
如:catkin_creat_pkg test_pkg std_msgs rospy roscpp
2.编译功能包
catkin_make
source /catkin_ws/devel/setup.bash
三.发布者Publisher和订阅者Subscriber
一个ROS话题包括一个消息类型和一个话题名称。在ROS中,消息类型定义了消息的结构和类型,而话题名称则用于标识特定的话题。一个节点可以同时发布和订阅多个话题。节点可以发布消息到多个话题,同时也可以订阅来自多个话题的消息。
当一个节点发布一个消息到话题时,所有订阅该话题的节点都会接收到该消息。一个节点可以通过ROS Master(ROS主节点)来发现其他节点发布的话题,并向其订阅。通过这种方式,ROS节点可以轻松地共享数据和信息。
(一).发布者Publisher和订阅者Subscriber
1.(1).发布者一般步骤
(2).订阅者一般步骤
2.配置CMakeList.txt的编译规则
- 设置需要编译的代码和生成的可执行文件
- 设置链接库
在CMakeList.txt中的install的上方添加以下
add_executable(节点名 .cpp文件地址)#从工作空间src开始:/src/xxxx/xxx.cpp #运行
target_link_libraries(节点名 ${catkin_LIBRARIES}) #库连接
(2)add_executable:用于设置需要编译的代码和生成的可执行文件。第一个参数为期望生成的可执行文件的名称,后边的参数为参与编译的源码文件(cpp),如果需要多个代码文件,则可
在后面依次列出,中间用空格进行分隔。
(3)target_link_libraries:用于设置链接库。很多功能需要使用系统或者第三方的库函数,通过该选项可以配置执行文件链接的库文件,第一个参数是可执行文件的名称,后面依次列出需要链接的库。此处编译没有使用其他库,添加默认链接库${catkin_LIBRARIES}即可。
3.进行编译运行,在编译后需要进行环境变量的设置,在每次运行之前都需要配置环境。
另一种方法在主目录中 .bashrc中最后添加下图命令,就不需要重新配置环境。
source ~/catkin_ws/devel/setup.bash在CMakeList.txt中的install的上方添加以下
add_executable(节点名 .cpp文件地址)#从工作空间src开始:/src/xxxx/xxx.cpp #运行
target_link_libraries(节点名 ${catkin_LIBRARIES}) #库连接
最后运行,如果使用c++来编写,需要进行编译后运行,若是用python,就不用编译,但是需要将python文件中的属性中的允许作为程序执行文件打开
方法一:
方式二:使用命令行,cd到该文件的路径下,然后输入以下命令:
$ chmod +x name.py
在终端中输入roscore,rosrun运行
(二).自定义话题
1.定义msg文件
在catkin_ws/src/中相应功能包下创建文件夹msg,该文件用于存储.msg文件,注意此文件是与编程语言无关的。/.msg文件中的内容相当于是宏定义。
2.在package.xml中添加功能包依赖
3.在CMakeLists.txt中添加编译选项
4.编译生成文件
在catkin_ws中进行编译,编译成功后会在catkin_ws中的devel下面的include生成文件,里面存放了编译成功后的头文件
5.发布者和订阅者的一般步骤
6.配置CMakeLists.txt中的编译规则
- 设置需要编译的代码和可执行文件
- 设置链接库
- 添加依赖项
在CMakeLists.txt中install上方添加依赖项
add_executable(节点名 .cpp文件地址)#从工作空间src开始:/src/xxxx/xxx.cpp #运行
target_link_libraries(节点名 ${catkin_LIBRARIES}) #库连接add_dependencies(节点名 ${PROJECT_NAME}_generate_messages_cpp) #连接依赖,与自定义消息连接
(4)add_dependencies:用于设置依赖。在很多应用中,我们需要定义语言无关的消息类型,消息类型会在编译过程中产生相应语言的代码,如果编译的可执行文件依赖这些动态生成的代码,则
需要使用add_dependencies添加${PROJECT_NAME}_generate_messages_cpp配置,即该功能包动态产生的消息代码。该编译规则也可以添加其他需要依赖的功能包。
7.编译运行
同发布者Publisher和订阅者Subscriber中编译运行相同。
四.客户端Client和服务端service
服务端是一个ROS节点,它通过定义一个服务来提供一个特定的功能。服务通常由一个请求和一个响应组成,并且可以使用不同的数据类型作为它们的参数和返回值。
客户端是另一个ROS节点,它可以请求一个或多个服务。当客户端请求一个服务时,它会发送一个请求消息给服务端,并等待服务端返回一个响应消息。客户端可以通过ROS的API来发送请求和接收响应,并且可以使用不同的编程语言来实现。
在ROS中,服务端和客户端之间的通信通常使用ROS的消息传递机制,这可以确保数据的可靠传输和类型匹配。当一个服务端启动时,它会向ROS的主节点注册自己提供的服务,客户端可以通过查询主节点来找到它需要的服务。
(一).客户端和服务端
1.一般步骤
客户端
服务端
2.配置CMakeLists.txt的编译规则
- 设置需要编译的代码和生成的可执行文件
- 设置链接库
在CMakeList.txt中的install的上方添加以下
add_executable(节点名 .cpp文件地址)#从工作空间src开始:/src/xxxx/xxx.cpp #运行
target_link_libraries(节点名 ${catkin_LIBRARIES}) #库连接
3.编译运行客户端和服务端
如果使用c++来编写,需要进行编译后运行,若是用python,就不用编译,但是需要将python文件中的属性中的允许作为程序执行文件打开,在终端中输入roscore,rosrun运行。
(二).服务数据的定义
1.定义srv文件
2.在package.xml中添加功能包依赖2.在package.xml中添加功能包依赖
在如下图所示的位置上添加依赖
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
3.在CMakeLists.txt添加编译选项
4.编译生成语言相关文件
在catkin_ws中进行编译,编译成功后会在catkin_ws中的devel下面的include生成文件,里面存放了编译成功后的头文件
5.创建服务器、客户端代码一般步骤
5.配置CMakeLists.txt中的编译规则
- 设置需要编译的代码和可执行文件
- 设置链接库
- 添加依赖项
在CMakeLists.txt中install上方添加依赖项
add_executable(节点名 .cpp文件地址)#从工作空间src开始:/src/xxxx/xxx.cpp #运行
target_link_libraries(节点名 ${catkin_LIBRARIES}) #库连接add_dependencies(节点名 ${PROJECT_NAME}_generate_messages_cpp) #连接依赖,与自定义消息连接
7.编译运行
同客户端和服务端相同。
五.参数
1.参数的命令行
2.一般步骤
3.配置CMakeLists.txt
同发布订阅,服务客户端的规则相同。
4.编译运行
六.tf坐标系广播与监听
1.创建功能包
2.编写的一般步骤
(1)tf广播器
(2)tf监听器
3.配置CMakeLists.txt
同发布订阅,服务客户端的规则相同。
4.编译运行
七.launch
1.文件语法
launch:launch文件中的根元素采用<launch>标签定义
node:
①pkg 节点功能包名称。
②type 节点可执行文件名称。
③name 节点运行时名称。
④args 局部变量。
<remap>:节点重映射ROS计算图资源的命名
<include>:包含其他文件(类似头文件)。
等等
八.action
ROS的Action是一个机制,用于在机器人系统中进行长时间运行的任务。与ROS中的service类似,一个Action也是一种服务器/客户端模型,其中客户端可以请求在后台执行长时间运行的任务,服务器可以像服务一样响应这些请求。但是,与service不同的是,Action允许客户端在执行任务的过程中获取中间结果,取消任务,或者在必要时调整任务的目标。
1.动作规范
①goal:用于向服务器发送目标。
②cancel :用于向服务器发送取消请求。
③status :用于通知客户端系统中每个目标的当前状态。
④feedback :用于周期反馈目标的辅助信息。
⑤result :用于向client发送任务的执行结果,这个topic只会发布一次。
自定义 action
动作定义文件中包含了动作的目标,结果,和反馈的消息格式。通常放在 package 的 action 文件夹下,文件扩展名为.action
。
1.定义action文件
int32 requestnumber
---
int32 resultnumber
---
int32 feedbacknumber
2.在package.xml中添加功能包依赖
<build_depend>actionlib</build_depend>
<build_depend>actionlib_msgs</build_depend>
<exec_depend>actionlib</exec_depend>
<exec_depend>actionlib_msgs</exec_depend>
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
3.在CMakeLists.txt文件中添加如下的编译规则
add_action_files(DIRECTORY action FILES checkaction.action)
generate_messages(DEPENDENCIES std_msgs actionlib_msgs )
find_package(catkin REQUIRED COMPONENTS geometry_msgs roscpp rospy std_msgs message_generation actionlib_msgs actionlib)
4.编译生成语言相关文件
在catkin_ws中进行编译,编译成功后会在catkin_ws中的devel下面的include生成文件,里面存放了编译成功后的头文件
5.编写action服务端与客户端代码
客户端
- 定义一个客户端
- 等待服务端
- 创建action的goal
- 发送action的goal给服务端,并设置回调函数,回调函数并处理信息
服务端
- 定义服务器,
- 运行服务器
- 收到action的goal后回调回调函数
- action完成后,向客户端返回结果
6.编译运行
与服务端与客户端方法类似
九.作业
(1) 实验 1: 使用 ROS 话题(Topic) 机制实现消息发布与订阅
要求: 编写代码实现 ROS 中消息的发布与订阅: 创建一个发布者,每隔 100ms 依次发送斐波拉契数列的数字到话题 `/fibonacci` 中; 创建一个订阅者,订阅该话题,输出订阅结果。如,订阅者依次输出: 1 1 2 3 5 8 ··
发布者pyhton
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#导入rospy模块
import rospy
from std_msgs.msg import Int32
#创建发布者
def fibonacci_publisher():
# ROS节点初始化
rospy.init_node('fibonacci_publisher', anonymous=True)
# 创建发布者,发布 Fibonacci 消息到话题 /fibonacci,消息类型为std_msgs.msg::Int32,队列长度10
pub = rospy.Publisher('/fibonacci', Int32, queue_size=10)
#设置循环的频率
rate = rospy.Rate(10)
a=0
b=1
msg = Int32()
while not rospy.is_shutdown():
c=a+b
a=b
b=c
msg.data=a
# 发布消息
pub.publish(msg)
rospy.loginfo("发布的数据 %s",msg.data)
# 按照循环频率延时
rate.sleep()
if __name__ == '__main__':
try:
fibonacci_publisher()
except rospy.ROSInterruptException:
pass
订阅者python
#!/usr/bin/env python
import rospy
from std_msgs.msg import Int32
#回调函数
def callback(msg):
rospy.loginfo(msg.data)
#创建订阅信息
def fibonacci_subscriber():
#ROS节点初始化
rospy.init_node('fibonacci_subscriber', anonymous=True)
#创建一个subscriber,订阅名为/fibonacci的topic,注册回调函数
rospy.Subscriber("/fibonacci",Int32,callback)
#循环等待回调函数
rospy.spin()
if __name__ == '__main__':
fibonacci_subscriber()
(2) 实验 2: 使用 ROS 服务(Service) 机制实现同步请求与答复
要求: 编写代码实现 ROS 中的服务请求与答复: 创建服务端,注册 Service,当服务端收到客户端 Service 请求(携带整型参数 a.b) 后,服务端返回 a.b 的和给客户端,客户端输出结果。如,客户端给服务端 Service 发送参数 3,9,服务端返回 12,客户端输出: 12。
客户端python
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import rospy
from learning_service.srv import AddTwoInts,AddTwoIntsResponse
def add_client(a,b):
#ROS节点初始化
rospy.init_node('add_client')
#发现add_服务后,创建一个服务客户端,连接名为add_的service
rospy.wait_for_service('add_')
try:
add1 = rospy.ServiceProxy('add_', AddTwoInts)
#请求服务调用,输入请求数据
response = add1(a,b)
#返回两者数之和
return response
except rospy.ServiceException, e:
print "服务失败: %s"%e
if __name__ == "__main__":
if len(sys.argv) == 3:
a = sys.argv[1]
b = sys.argv[2]
else:
sys.exit(1)
#服务调用并显示调用结果
print("Requesting %s+%s" % (int(a),int(b)))
print "Show result : %s" %(add_client(int(a),int(b)))
rospy.wait_for_service("service名称")可以使得该client_node节点直到对应service服务器开始工作之后,代码才继续往下运行
启动client的函数接口:rospy.ServiceProxy("service名称",自定义srv数据类型)
服务端python
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function
import rospy
from learning_service.srv import AddTwoInts,AddTwoIntsResponse
def doNum(request):
a=request.A
b=request.B
# 求和
c = a+b
response = AddTwoIntsResponse(c) # 创建一个response对象类型是AddIntsResponse
#显示请求数据
rospy.loginfo("服务器接收到的请求数据是:a=%d,b=%d,结果是c=%d",a,b,c)
#反馈数据
return response
if __name__=="__main__":
#ROS节点初始化
rospy.init_node('add_server')
#创建一个名为add_的server,注册回调函数
server=rospy.Service('add_',AddTwoInts,doNum)
rospy.loginfo("服务器启动成功")
#循环等待回调函数
rospy.spin()
启动服务的函数接口:rospy.Service("service名", srv数据类型, 回调函数)
回调函数中传入的是请求request,返回的是response
返回的数据类型是自定义的
(3) 实验 3: 使用 ROS 动作(Action) 机制实现目标请求、进度与完成结果的反馈。
要求: 编写代码实现 ROS 中动作请求与进度反馈,创建服务端,注册 Action,客户端发送 action 请求检测 40 个零件,服务端接收后,每隔 1s 测一个零件 (每检测一个打印一次),实时给客户端返回检测进度(客户端打印进度百分比),并在检测完毕时告知客户端目标完成。如,服务端实时打印: 检测 1 个零件 检测 2 个零件 ... 检测 40 个零件 检测完成,客户端实时打印: 2.5% 5% ... 100% 检测完成
客户端python
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import rospy
import actionlib
from std_msgs.msg import Float32
from learning_action.msg import checkactionAction,checkactionResult, checkactionGoal
class checkactionClient:
def __init__(self):
# 创建动作客户端
self.client = actionlib.SimpleActionClient('checkaction', checkactionAction)
self.client.wait_for_server()
# 订阅进度消息
rospy.Subscriber('checkaction_progress',Float32, self.progress_callback)
def progress_callback(self, feedback):
self.progress=feedback.data*100
# 返回结果后,打印信息
rospy.loginfo('Progress: %.2f%%', self.progress)
def send_action_request(self):
goal = checkactionGoal()
# 将回调函数作为feedback_cd关键词的参数,传入 send_geal,完成回调的注册
self.client.send_goal(goal, feedback_cb=self.progress_callback)
self.client.wait_for_result()
if __name__ == '__main__':
# ROS节点初始化
rospy.init_node('checkaction_client')
# 创建客户端
client = checkactionClient()
client.send_action_request()
服务端python
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import rospy
import actionlib
from std_msgs.msg import Float32
from learning_action.msg import checkactionAction,checkactionResult, checkactionGoal
class checkactionServer:
def __init__(self):
#创建了一个名为“checkaction”的简单动作服务器,它的类型是“checkactionAction”,以及回调函数,参数False
self.server = actionlib.SimpleActionServer('checkaction', checkactionAction, self.execute, False)
# 启动服务器
self.server.start()
# 创建进度发布者
self.progress_pub = rospy.Publisher('checkaction_progress', Float32, queue_size=10)
#执行函数
def execute(self, goal):
#每秒检测
rate = rospy.Rate(1)
success = True
# 检测零件
for i in range(1, 41):
if self.server.is_preempt_requested():
self.server.set_preempted()
success = False
break
# 发布进度
self.progress_pub.publish(i/40.0)
#打印信息
rospy.loginfo('checkaction part %d', i)
rate.sleep()
if success:
# 发布结果
self.server.set_succeeded(checkactionResult())
if __name__ == '__main__':
#ROS节点初始化
rospy.init_node('checkaction_server')
# 创建服务器
server = checkactionServer()
# 运行节点
rospy.spin()