机器人应用

机器人操作系统ROS(13):service of service和client

service和client的C++和Python实现方式。

  • 10、先建立消息msg和服务srv基础

rosmsg/rossrv/roscp可用于生成msg和srv文件,msg文件描述message,srv文件描述request/response服务。
msg文件有可能包括header,header由时间戳和坐标组成,例如:
Header header
string child_frame_id
geometry_msgs/PoseWithCovariance pose
geometry_msgs/TwistWithCovariance twist
srv文件也类似于msg文件,包括由’—‘分开的request和response两部分,例如:
int64 A
int64 B

int64 Sum
10.1、建立一个简单的msg文件:
$ cd ~/catkin_ws/src/beginner_tutorials
$ mkdir msg
$ echo “int64 num” > msg/Num.msg
1.2、修改package.xml文件,由于build时候需要”message_generation”,运行时候需要 “message_runtime”,所以要在package.xml文件中添加这两者:
<build_depend>message_generation</build_depend>
<run_depend>message_runtime</run_depend>
1.3、修改CMakeLists.txt,在find_package call中添加message_generation的依赖:
catkin_package(
roscpp
rospy
std_msgs
message_generation
…)
1.4、修改CMakeLists.txt,添加运行时的依赖:
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES beginner_tutorials
CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
# DEPENDS system_lib
)
1.5、修改CMakeLists.txt,添加一下代码块:
add_message_files(
FILES
Num.msg
)
1.6、编辑generate_
generate_messages(
DEPENDENCIES
std_msgs
)
1.7、验证:
$ rosmsg show beginner_tutorials/Num
/int64 num

2、建立一个简单的srv文件,功能是返回两个数的和:
$ roscd beginner_tutorials
$ mkdir srv
$ vi AddTwoInts.srv
int64 a
int64 b

int64 sum
2.2、如果有必要,修改package.xml文件,添加这build和runtime时候的消息:
<build_depend>message_generation</build_depend>
<run_depend>message_runtime</run_depend>
2.3、如果必要,修改CMakeLists.txt,在find_package call中添加message_generation的依赖:
catkin_package(
roscpp
rospy
std_msgs
message_generation
…)
2.4、修改CMakeLists.txt,添加一下代码块:
add_service_files(
FILES
AddTwoInts.srv
)
2.5、可以检查:
$ rossrv show AddTwoInts
int64 a
int64 b

int64 sum

  • 14、service 和client(C++)

1、建立service的node:
$ cd ~/catkin_ws/src/beginner_tutorials/src
$ vi add_two_ints_server.cpp
#include “ros/ros.h”
#include “beginner_tutorials/AddTwoInts.h”//由以前AddTwoInts.srv生成的头文件
bool add(beginner_tutorials::AddTwoInts::Request  &req,beginner_tutorials::AddTwoInts::Response &res) { //提供的服务,request和response的类型由AddTwoInts.srv文件定义,返回类型是boolean。
res.sum = req.a + req.b;
ROS_INFO(“request: x=%ld, y=%ld”, (long int)req.a, (long int)req.b);
ROS_INFO(“sending back response: [%ld]”, (long int)res.sum);
return true;
}
int main(int argc, char **argv) {
ros::init(argc, argv, “add_two_ints_server”);
ros::NodeHandle n;
ros::ServiceServer service = n.advertiseService(“add_two_ints”, add);//服务建立,并广播
ROS_INFO(“Ready to add two ints.”);
ros::spin();
return 0;
}
2、vi add_two_ints_client.cpp,建立client的node:
#include “ros/ros.h”
#include “beginner_tutorials/AddTwoInts.h”
#include <cstdlib>
int main(int argc, char **argv) {
ros::init(argc, argv, “add_two_ints_client”);
if (argc != 3) {
ROS_INFO(“usage: add_two_ints_client X Y”);
return 1;
}
ros::NodeHandle n;
ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoInts>(“add_two_ints”); //建立ros::ServiceClient对象,用于后面调用服务
beginner_tutorials::AddTwoInts srv; //实例化这个类
srv.request.a = atoll(argv[1]);
srv.request.b = atoll(argv[2]);
if (client.call(srv)) //调用服务
ROS_INFO(“Sum: %ld”, (long int)srv.response.sum);
else {
ROS_ERROR(“Failed to call service add_two_ints”);
return 1;
}
return 0;
}
3、如果必要,修改CMakeLists.txt:
add_executable(add_two_ints_server src/add_two_ints_server.cpp)
target_link_libraries(add_two_ints_server ${catkin_LIBRARIES})
add_dependencies(add_two_ints_server beginner_tutorials_gencpp)
add_executable(add_two_ints_client src/add_two_ints_client.cpp)
target_link_libraries(add_two_ints_client ${catkin_LIBRARIES})
add_dependencies(add_two_ints_client beginner_tutorials_gencpp)
4、build:
$ cd ~/catkin_ws
$ catkin_make
4、测试
运行service
$ rosrun beginner_tutorials add_two_ints_server
[ INFO] [1465192131.709699255]: Ready to add two ints.

运行client
$ rosrun beginner_tutorials add_two_ints_client 1 3
[ INFO] [1465192219.751503941]: request: x=1, y=3
[ INFO] [1465192219.751688678]: sending back response: [4]

  • 15、service 和client(Python)

1、建立service的node:
$ cd ~/catkin_ws/src/beginner_tutorials/scripts
$ nano add_two_ints_server.py
#!/usr/bin/env python
from beginner_tutorials.srv import *
import rospy

def handle_add_two_ints(req):
print “Returning [%s + %s = %s]”%(req.a, req.b, (req.a + req.b))
return AddTwoIntsResponse(req.a + req.b)

def add_two_ints_server():
rospy.init_node(‘add_two_ints_server’)
s = rospy.Service(‘add_two_ints’, AddTwoInts, handle_add_two_ints) #name,type,func_handler with AddTwoIntsRequest
print “Ready to add two ints.” #keeps your code from exiting until the service is shutdown.
rospy.spin()

if __name__ == “__main__”:
add_two_ints_server()

2、建立cilnet的node:
$ nano add_two_ints_client.py
#!/usr/bin/env python
import sys
import rospy
from beginner_tutorials.srv import *

def add_two_ints_client(x, y):
rospy.wait_for_service(‘add_two_ints’) # one way of calling services, blocks until the service named add_two_ints is available
try:
add_two_ints = rospy.ServiceProxy(‘add_two_ints’, AddTwoInts)
resp1 = add_two_ints(x, y)
return resp1.sum
except rospy.ServiceException, e:
print “Service call failed: %s”%e

def usage():
return “%s [x y]”%sys.argv[0]

if __name__ == “__main__”:
if len(sys.argv) == 3:
x = int(sys.argv[1])
y = int(sys.argv[2])
else:
print usage()
sys.exit(1)
print “Requesting %s+%s”%(x, y)
print “%s + %s = %s”%(x, y, add_two_ints_client(x, y))

3、测试
加权限:
$ chmod +x add_two_ints_server.py
$ chmod +x add_two_ints_client.py
build:
$ cd ~/catkin_ws
$ catkin_make
刷新:
$ source ~/.bashrc
运行:
$ rosrun beginner_tutorials add_two_ints_server.py

$ rosrun beginner_tutorials add_two_ints_client.py 4 5

机器人操作系统ROS(08):msg of publisher和subscriber

publisher和subscriber的C++和Python实现。

  • 11、Publisher和Subscriber(C++语言)

节点node通常就是指连接到ROS网络的一些可执行节点,常见的例如发布者publisher和订阅者subscruber。
1、建一个不停广播消息的发布者(讲者)node。在src下编辑talker.cpp:
$ cd ~/catkin_ws/src/beginner_tutorials
$ mkdir -p ~/catkin_ws/src/beginner_tutorials/src
$ vi talker.cpp
#include “ros/ros.h”
#include “std_msgs/String.h”
#include
int main(int argc, char **argv) {
ros::init(argc, argv, “talker”);//第三个参数是node名称
ros::NodeHandle n;//这是与ROS系统通讯的句柄,注意构造和析构
ros::Publisher chatter_pub = n.advertise<std_msgs::String>(“chatter”, 1000);//消息类型是std_msgs/String ,第二个参数是最大缓存消息数目,该函数生成一个publisher对象,该对象有一个比较重要的方法是publish()
ros::Rate loop_rate(10);//循环周期是10Hz
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);//消息类型要符合advertise<>()
ros::spinOnce();//这个主要用于回调
loop_rate.sleep();//休眠,直到满足10Hz
++count;
}
return 0;
}
2、建一个订阅者(讲者)node。在src下编辑listener.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::Subscriber对象,第二个参数是缓存消息最大数目
ros::spin();//进入循环
return 0;
}
3、编辑CMakeLists.txt,添加:
include_directories(include ${catkin_INCLUDE_DIRS})
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_messages_cpp)
这样就建立了两个可执行的talker和listener,然后可以make:
$ catkin_make
4、可以测试:
$ cd ~/catkin_ws
$ source ./devel/setup.bash
$ roscore
运行publisher:
$ rosrun beginner_tutorials talker
[INFO] [WallTime: 1314931831.774057] hello world 1314931831.77
[INFO] [WallTime: 1314931832.775497] hello world 1314931832.77

运行subscriber:
$ rosrun beginner_tutorials listener
[INFO] [WallTime: 1314931969.258941] /listener_17657_1314931968795I heard hello world 1314931969.26
[INFO] [WallTime: 1314931970.262246] /listener_17657_1314931968795I heard hello world 1314931970.26

13、Publisher和Subscriber(Python语言)
1、如果需要,建立工作区:
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src
catkin_init_workspace
cd ..
catkin_make
2、如果需要,建立类似hello_word这样一个package:
cd ~/catkin_ws/src
catkin_create_pkg hello_world std_msgs rospy
cd ..
catkin_make
source ~/catkin_ws/devel/setup.bash 或者
echo “source ~/catkin_ws/devel/setup.bash” >> ~/.bashrc
3、建立保存脚本的文件夹:
mkdir scripts
4、发布节点hello_world_publisher.py
#!/usr/bin/env python
import rospy
from std_msgs.msg import String
def talker():
pub = rospy.Publisher(‘hello_pub’, String, queue_size = 10) #give topic name and define msg type
rospy.init_node(‘hello_world_publisher’, anonymous = True) #give node name
r = rospy.Rate(10) #10hz, create a Rate object rate.
while not rospy.is_shutdown():
str = “hello world %s” % rospy.get_time()
rospy.loginfo(str)
pub.publish(str)
r.sleep()
if __name__ == ‘__main__’:
try:
talker()
except rospy.ROSInterruptException:
pass
Python脚本对缩进敏感,如图:

def定义了一个函数。if __name__==’__main__’说明仅在直接在CML下面才运行,try-except-pass掉来自ros的exception。
5、订阅者节点hello_world_subscriber.py
#!/usr/bin/env python
import rospy
from std_msgs.msg import String
def callback(data):
rospy.loginfo(rospy.get_caller_id() + “I heard %s”, data.data)
def listener():
rospy.init_node(‘hello_world_subscriber’, anonymous=True)
rospy.Subscriber(“hello_pub”, String, callback)
rospy.spin()
if __name__ == ‘__main__’:
listener()
6、可以测试
运行发布者node:
rosrun hello_world hello_world_publisher.py

运行订阅者node:
rosrun hello_world hello_world_subscriber.py

机器人操作系统ROS(04):ROS基本元素

2、文件系统

package是ros的代码组合,manifests用来描述package。先安装一个演示包:
$ sudo apt-get install ros-kinetic-ros-tutorials
几个工具:
$ rospack find [package_name],allows to get information about packages.
$ roscd [locationname[/subdir]],allows to change directory (cd) directly to a package or a stack.
$ rosls [package_name],allows to ls directly in a package by name rather than by absolute path.
$ Tab Completion,这个和所有unix-like的系统一样的。

3、create package

package必须具有一个package.xml和CMakeLists.txt,最简单像这样:
my_package/
CMakeLists.txt
package.xml

Notes:
1、create package要在src之下:
$ cd ~/catkin_ws/src
$ catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
2、build package要在工作区之下:
$ cd ~/catkin_ws
$ catkin_make
这样获得和/opt/ros/kinetic结构类似的catkin_ws/devel。
3、需要运行build所得到的setup.*sh从而把catkin_ws工作区source到当前ros环境:
$ . ~/catkin_ws/devel/setup.bash
4、查看该package的一阶依赖关系,其实就是package.xml:
$ rospack depends 1 beginner_tutorials
或者查看所有依赖:
$ rospack depends beginner_tutorials
5、这些关系其实保存于Manifests (package.xml)文件:
<description>The beginner_tutorials package</description>
<maintainer email=”user@todo.todo”>user</maintainer>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>roscpp</build_depend>
<run_depend>roscpp</run_depend>

4、build package

1、CMake流程是:
转到CMake project
$ mkdir build
$ cd build
$ cmake ..
$ make
$ make install # (可选)
2、catkin流程是:
转到workspace
$ cd ~/catkin_ws/
$ catkin_make
$ catkin_make install # (可选)

5、Nodes

1、安装一个轻量级的模拟器:
$ sudo apt-get install ros-kinetic-ros-tutorials
2、roscore=ROS-Master + rosout + parameter server,使用roscore启动ROS:
$ roscore
3、rosnode指令
$ rosnode list
/rosout
$ rosnode info /rosout
4、rosrun启动一个package的node,例如:
$ rosrun turtlesim turtlesim_node
$ rosnode list
/rosout
/turtlesim
也可以给以新的名字参数,例如关闭前面打开的小乌龟,然后:
$ rosrun turtlesim turtlesim_node __name:=my_turtle
$ rosnode list
/rosout
/my_turtle
如果还能list出来第一次的turtlesim,是因为用ctl-c退出而不是关闭小乌龟,此时是ping是不通:
$ rosnode ping turtlesim
可以用这个清理:
$ rosnode cleanup

6、Topic

1、运行模拟器的node和控制器的node
$ roscore
$ rosrun turtlesim turtlesim_node
$ rosrun turtlesim turtle_teleop_key
这样,就可以用鼠标控制小乌龟移动。
2、查看node和topic
Turtlesim_node和turtle_teleop_key node通过Topic通讯,turtle_teleop_key在topic中发布用户敲击的键,而turtlesim订阅这个topic以接收用户敲击的键。rqt_graph可以图形化显示当前运行的nodes和topics,安装rqt_graph:
$ sudo apt-get install ros-kinetic-rqt
$ sudo apt-get install ros-kinetic-rqt-common-plugins
运行:
$ rosrun rqt_graph rqt_graph
可以看到蓝色和绿色的两个nodes以及红色的topic,turtlesim_node和turtle_teleop_key这两个nodes通过/turtle1/command_velocity这个topic进行通讯。

3、rostopic指令
list可以显示当前发布和订阅的所有topics:
$ rostopic list -v

echo可以把turtle_teleop_key这个node在topic中public的数据echo出来:
$ rostopic echo /turtle1/cmd_vel
这时候如果刷新一下rpt-graph,可以看到多出来node,这个多出来的node就是rostopic echo:

4、rosmsg
topic上面传递的是各个nodes之间的message,发布者发布和接收者接收的消息必须数据类型一致。
$ rostopic type /turtle1/cmd_vel
geometry_msgs/Twist
查看一下这个消息的数据类型:
$ rosmsg show geometry_msgs/Twist
geometry_msgs/Vector3 linear
float64 x
float64 y
float64 z
geometry_msgs/Vector3 angular
float64 x
float64 y
float64 z
知道确切地知道消息的数据类型之后,可以发布消息:
$ rostopic pub -1 /turtle1/cmd_vel geometry_msgs/Twist — ‘[2.0, 0.0, 0.0]’ ‘[0.0, 0.0, 1.8]’
解释:rostopic pub发布一个消息,-1发布一次消息就停止,/turtle1/cmd_vel是要发布到的topic,geometry_msgs/Twist指定消息的数据类型,–表明在此之后不再是选项而是参数,两个-是因为有的参数是以-开始的负值,这里的参数是线速度2.0、角速度1.8这样YAML格式的参数。
$ rostopic pub -r 2 /turtle1/cmd_vel geometry_msgs/Twist — ‘[2.0, 0.0, 0.0]’ ‘[0.0, 0.0, 1.8]’
这个是连续发布,此时刷新rpt-graph可见多出的node:

$ rostopic echo /turtle1/pose
可以查看连续的发布的数据。或者使用$ rosrun rqt_plot rqt_plot也可以。

-1、YAML
Several ROS tools (rostopic, rosservice) use the YAML markup language on the command line.

YAML was chosen as, in most cases, it offers a very simple, nearly markup-less solution to typing in typed parameters.
canonical: 12345
decimal: +12,345
octal: 014
hexadecimal: 0xC
canonical: 1.23015e+3
exponential: 12.3015e+02
fixed: 1,230.15
string: foo
doublequoted: “Double-quotes allow escape sequences.u263A”
singlequoted: ‘Single quotes do not’
true: true
false: false
true-y: y
false-n: n
string: ‘12345’
dict: {a: 1, b: 2}
list: [1, 2, 3, 4, 5]

5A.1、Representing Messages in YAML
$ rosservice call /foo msg/Type 1 2
这个将产生{1,2}的list类型。
$ rosservice call /foo msg/Type ‘{a: 1, b: 2}’
这个是dict类型。

7、services和param

service是各个node之间除了topic之外的另一种通讯方式,node可以发起请求或接收响应,rosservic指令可以控制ROS的client/service结构。$rosservice list可以发现存在reset,clear,spawn,kill,turtle1/set_pen,/turtle1/teleport_absolute,/turtle1/teleport_relative,turtlesim/get_loggers,turtlesim/set_logger_level等几项服务。
1、rosservice
$ rosservice type clear
std_srvs/Empty
这说明clear为空服务,没有参数,也就是请求时不发送数据响应时不接收数据,尝试call:
$ rosservice call /clear
它清除了turtlesim_node的背景。
再看一个带参数的,先查看spawn这个创建新的小乌龟的service的结构:
$ rosservice type spawn | rossrv show
发现是ixytheta三个位置参数和一个名字参数,然后用默认弥功能自参数尝试call:
$ rosservice call spawn 2 2 0.2 “”
name: turtle2

2、rosparam
rosparam可以操作参数服务器的数据:
$ rosparam list
例如修改背景颜色:
$ rosparam set background_r 150
使其生效:
$ rosservice call clear
查看:
$ rosparam get background_g
86
或者查看整个参数服务器:
$ rosparam get /

8、console和roslanch

1、如果需要则安装一些新包(重复安装并不会造成不良影响):
$ sudo apt-get install ros-kinetic-rqt
$ sudo apt-get install ros-kinetic-rqt-common-plugins
2、rqt_console和rqt_logger_level
依附于ros debugging框架的rqt_console可以显示调试信息,而rqt_logger_level可以设定优先级(DEBUG, WARN, INFO, and ERROR)。
3、启动控制台:
$ rosrun rqt_console rqt_console
$ rosrun rqt_logger_level rqt_logger_level
或者用roslaunch启动launch文件。
$ roscd beginner_tutorials
$ mkdir launch
$ cd launch
建立turtlemimic.launch文件:
<launch>

<group ns=”turtlesim1″>
<node pkg=”turtlesim” name=”sim” type=”turtlesim_node”/>
</group>
<group ns=”turtlesim2″>
<node pkg=”turtlesim” name=”sim” type=”turtlesim_node”/>
</group>
<node pkg=”turtlesim” name=”mimic” type=”mimic”>
<remap from=”input” to=”turtlesim1/turtle1″/>
<remap from=”output” to=”turtlesim2/turtle1″/>
</node>

</launch>

运行:
$ roslaunch beginner_tutorials turtlemimic.launch
驱动两个小乌龟:
$ rostopic pub /turtlesim1/turtle1/cmd_vel geometry_msgs/Twist -r 1 — ‘[2.0, 0.0, 0.0]’ ‘[0.0, 0.0, -1.8]’

9、rosed

如果必要先安装vim:
$ sudo apt-get install vim
设置编辑器:
$ export EDITOR=’nano -w’
使用rosed就免去了繁琐的指定文件路径:
$ rosed roscpp Logger.msg

10、rosbag

$ rosrun turtlesim turtlesim_node
$ rosrun turtlesim turtle_teleop_key
查看有哪些主题:
$ rostopic list -v
准备记录:
$ mkdir ~/bagfiles
$ cd ~/bagfiles
$ rosbag record -a
可以回放:
$ rosbag play <your bagfile>