Home » ROS与Matlab入门教程 » ROS与Matlab语言入门教程-基本ROS消息的使用

ROS与Matlab语言入门教程-基本ROS消息的使用

在ROS数据交换中消息是最主要的容器,主题(通过发布器和订阅器交换数据)和服务(请求和提供服务)都是使用消息在节点之间传递数据。每个消息都有消息类型来确认数据结构,例如,激光扫描仪的传感器数据通常以“typesensor_msgs/LaserScan”的消息类型传递。每一个消息类型都确定了包含在消息中的数据元素。每个消息类型的名称都由包名、斜杠“/”和类型名组成

请输入图片描述

MATLAB支持在机器人学应用领域常见的许多ROS消息类型,在本例中,你将会在MATLAB中尝试几种创建、探索和发布ROS消息的方法。预备知识:1.2开始使用ROS和1.3连接到ROS网络。

查找消息类型

初始化ROS主控节点和全局变量。代码运行如下:

rosinit Initializing ROS master onhttp://bat5136glnxa64.mathworks.com:11311/. 

Initializing global node /matlab_global_node_8332 with NodeURIhttp://bat5136glnxa64:33534/

使用“exampleHelperROSCreateSampleNetwork”指令给ROS网络填充三个节点和发布器、订阅器例子。代码运行示例:

exampleHelperROSCreateSampleNetwork

现在系统中有了若干不同的节点和主题以及相关的发布器和订阅器。你可以使用“rostopic list”查看所有可用的主题,“/scan”存在主题列表当中。

rostopic list /pose /rosout /scan

如果你想要进一步了解通过“/scan”主题传递的数据类型,可以使用“rostopic info/scan”指令检查。“/scan”的消息类型是“sensor_msgs/LaserScan”。代码运行示例:

scandata = rosmessage('sensor_msgs/LaserScan') scandata =

ROS LaserScan message with properties:

MessageType: 'sensor_msgs/LaserScan'
  Header: [1x1 Header]
AngleMin: 0
AngleMax: 0

AngleIncrement: 0 TimeIncrement: 0 ScanTime: 0 RangeMin: 0 RangeMax: 0                 
Ranges: [0x1 single] Intensities: [0x1 single]

创建的消息“scandata”拥有许多与激光扫描仪接收的数据相关的属性,例如,最小的传感器距离存在“RangeMin”属性,最大传感器距离存储在“RangeMax”属性。

如果你想要定义消息的类型,可以使用“rostype”指令,该指令可以方便的使用一系列消息类型。“rostype”支持tap键填充指令并能够寻找与先前的字符创匹配的消息类型。代码运行示例:

scantype = rostype.sensor_msgs_LaserScan scantype =

sensor_msgs/LaserScan

使用这个字符串,可以创建一个与之前的消息相同类型的空消息:

scandata = rosmessage(scantype) scandata =

ROS LaserScan message with properties:

 MessageType: 'sensor_msgs/LaserScan'
    Header: [1x1 Header]
  AngleMin: 0
  AngleMax: 0
AngleIncrement: 0
 TimeIncrement: 0
      ScanTime: 0
      RangeMin: 0
      RangeMax: 0
        Ranges: [0x1 single]
   Intensities: [0x1 single]

使用“rosmsg list”查看主题和服务所能使用的所有消息类型:

rosmsg list ackermann_msgs/AckermannDrive               
ackermann_msgs/AckermannDriveStamped actionlib_msgs/GoalID     
actionlib_msgs/GoalStatus actionlib_msgs/GoalStatusArray 
adhoc_communication/BroadcastCMgrRobotUpdate 
adhoc_communication/BroadcastCMgrRobotUpdateRequest 
adhoc_communication/BroadcastCMgrRobotUpdateResponse 
adhoc_communication/BroadcastString 
adhoc_communication/BroadcastStringRequest 
adhoc_communication/BroadcastStringResponse 
adhoc_communication/CMgrDimensions adhoc_communication/CMgrRobotUpdate 
adhoc_communication/ChangeMCMembership 
adhoc_communication/ChangeMCMembershipRequest 
adhoc_communication/ChangeMCMembershipResponse 
adhoc_communication/ExpAuction adhoc_communication/ExpCluster 
adhoc_communication/ExpFrontier adhoc_communication/ExpFrontierElement 
adhoc_communication/GetGroupState 
adhoc_communication/GetGroupStateRequest 
adhoc_communication/GetGroupStateResponse 
adhoc_communication/GetNeighbors 
adhoc_communication/GetNeighborsRequest 
adhoc_communication/GetNeighborsResponse adhoc_communication/MmControl 
adhoc_communication/MmListOfPoints adhoc_communication/MmMapUpdate 
adhoc_communication/MmPoint

探索消息结构和获取消息数据

ROS消息是对象,消息数据存储在属性里,MATLAB提供了方便的方法发现和探索消息里的内容。如果你要订阅了“/scan”主题,你可以接收和检测被传输的数据。代码运行示例:

posesub = rossubscriber('/pose') posesub =

Subscriber with properties: posesub = rossubscriber('/pose')

    TopicName: '/pose'
  MessageType: 'geometry_msgs/Twist'
LatestMessage: [0x1 Twist]
   BufferSize: 1
NewMessageFcn: []

使用“receive”函数,能够从订阅器获得数据,一旦接收到新的消息,函数返回并存储数据到“posedata”变量。代码运行示例:

posedata = receive(posesub, 10) posedata =

ROS Twist message with properties:

MessageType: 'geometry_msgs/Twist'
 Linear: [1x1 Vector3]
Angular: [1x1 Vector3]

消息的类型是“geometry_msgs/Twist”,消息中含有两个字段:“Linear”和“Angular”,你可以直接地获取消息中这些字段的值,代码运行示例:

posedata.Linear ans =
ROS Vector3 message with properties:
MessageType: 'geometry_msgs/Vector3'
      X: 0.0438
      Y: 0.0385
      Z: 0.0520

posedata.Angular ans =
ROS Vector3 message with properties:
MessageType: 'geometry_msgs/Vector3'
      X: -0.0288
      Y: 0.0484
      Z: 0.0528

显然,消息中的字段的每一个数值事实上本身也是个消息,消息类型是“geometry_msgs/Vector3”。“ geometry_msgs/Twist”的消息由两个“geometry_msgs/Vector3”类型的消息组成。获得这些嵌套的消息的方法其实和获得其它消息一样,例如,获得“Linear”的组成“X”的指令:

xpos = posedata.Linear.X xpos =

0.0438

“showdetails”函数可以快速的查看消息中包含的全部数据,“showdetails”对所有消息类型均可用,并且循环地显示消息的数据属性。

showdetails(posedata)

Linear X : 0.0438049105 Y : 0.03847741206 Z : 0.052015073 Angular X : -0.02882663895 Y : 0.04838687119 Z : 0.05278724967

“showdetails”能够帮助你在调试的时候,快速地查看消息中的内容。

设定消息数据

你还能够设定消息属性的值,创建“geometry_msgs/Twist”类型的消息:

twist = rosmessage(rostype.geometry_msgs_Twist) twist =

ROS Twist message with properties:

MessageType: 'geometry_msgs/Twist'
 Linear: [1x1 Vector3]
Angular: [1x1 Vector3]

消息的属性值会被默认设置为“0”,你可以任意的修改消息的属性值,例如设置“Linear.Y”的值为5。

twist.Linear.Y = 5;

显示消息的数据确认所做的修改的效果:

twist.Linear ans =

ROS Vector3 message with properties:

MessageType: 'geometry_msgs/Vector3'
      X: 0
      Y: 5
      Z: 0

一旦消息被填充数据,你可以通过“publishers”,“ subscribers”,“ services”使用消息。查看通过发布器和订阅器交换数据和请求和提供服务的例子。

复制消息

有两种方式复制消息中的内容:
① 可以创建一个“reference copy”,复制的消息和原消息共享同样的数据
② 可以创建一个“deep copy”,复制的消息和原消息拥有各自的消息。
当想要在不同的函数和对象之间共享消息数据时,“reference copy”是非常有用的,而如果你想要独立的复制消息,“deep copy”是必须的方法。
使用赋值符“=”创建“reference copy”,这种方法创建的变量与原变量拥有一样的消息内容。代码运行示例:

twistCopyRef = twist twistCopyRef =
ROS Twist message with properties:
MessageType: 'geometry_msgs/Twist'
 Linear: [1x1 Vector3]
Angular: [1x1 Vector3]

修改“twistCopyRef”的字段“Linear.Z”,发现“twist”中的相应字段的内容也发生变化:

twistCopyRef.Linear.Z = 7; twist.Linear ans =

ROS Vector3 message with properties:

MessageType: 'geometry_msgs/Vector3'
      X: 0
      Y: 5
      Z: 7

创建一个“twist”的“deep copy”,这样在改变复制消息的内容的时候不会影响原数据。使用“copy”指令创建新消息“twistCopyDeep”:

twistCopyDeep = copy(twist) twistCopyDeep =

ROS Twist message with properties:

MessageType: 'geometry_msgs/Twist'
 Linear: [1x1 Vector3]
Angular: [1x1 Vector3]

修改“twistCopyDeep”消息的字段“Linear.X”的内容,注意到“twist”中相应的字段没有变化:

twistCopyDeep.Linear.X = 100; twistCopyDeep.Linear ans =
ROS Vector3 message with properties:
MessageType: 'geometry_msgs/Vector3'
      X: 100
      Y: 5
      Z: 7
twist.Linear ans =
ROS Vector3 message with properties:
MessageType: 'geometry_msgs/Vector3'
      X: 0
      Y: 5
      Z: 7

保存和下载消息
你可以保存消息的内容用于后期使用。
从订阅器获得新消息:

posedata = receive(posesub,10) posedata =
ROS Twist message with properties:
MessageType: 'geometry_msgs/Twist'
    Linear: [1x1 Vector3]
    Angular: [1x1 Vector3]

使用MATLAB的“save”函数,保存姿态数据到.mat文件。

save('posedata.mat','posedata')

在重新加载文件到工作空间之前,清除“posedata”变量:

clear posedata

现在可以调用“load”函数载入消息数据,上述“posedata”数据将被载入“messageData”结构中,“posedata”是该结构的数据字段:

messageData = load('posedata.mat') messageData =

posedata: [1x1 Twist]

检查“messageData.posedata”查看消息的内容:

messageData.posedata ans =
ROS Twist message with properties:
MessageType: 'geometry_msgs/Twist'
    Linear: [1x1 Vector3]
    Angular: [1x1 Vector3]

删除MAT文件的方法如下:

delete('posedata.mat')

消息中的对象阵列

ROS中的一些消息存放在对象阵列中,这与典型的数据阵列不同。
在工作空间中,“tf”变量包含了一些样本消息(“exampleHelperROSCreateSampleNetwork”脚本创建该变量),本例中,这是一个表示坐标变换的:

tf tf =
ROS tfMessage message with properties:
MessageType: 'tf/tfMessage'
 Transforms: [53x1 TransformStamped]

“tf”拥有两个字段:“MessageType”包含了标准的数据阵列,“Transforms”包含了对象阵列。“Transforms”里包含了53个对象,每一个对象具有相同的结构。
展开“tf”的“Transforms“查看其结构:

tf.Transforms ans =
53x1 ROS TransformStamped message array with properties:
MessageType
Header
ChildFrameId
Transform

从代码的运行输出可以看出,“Transforms”里的每一个对象都有四个属性,查看其中的“Transform”字段:

tf.Transforms.Transform ans =
ROS Transform message with properties:
MessageType: 'geometry_msgs/Transform'
Translation: [1x1 Vector3]
   Rotation: [1x1 Quaternion]
Use showdetails to show the contents of the message
ans =
ROS Transform message with properties:
MessageType: 'geometry_msgs/Transform'
Translation: [1x1 Vector3]
   Rotation: [1x1 Quaternion]
Use showdetails to show the contents of the message
ans =
ROS Transform message with properties:
MessageType: 'geometry_msgs/Transform'
Translation: [1x1 Vector3]
   Rotation: [1x1 Quaternion]
...

注意,得到53个独立的输出,因为每一个对象都被评估并返回各自的“Transform”字段的值。这种格式并不总是有效,你可以转换如下的方法:

cellTransforms = {tf.Transforms.Transform} cellTransforms =
Columns 1 through 4
[1x1 Transform]    [1x1 Transform]    [1x1 Transform]    [1x1 Transform]
Columns 5 through 8
[1x1 Transform]    [1x1 Transform]    [1x1 Transform]    [1x1 Transform]
Columns 9 through 12
[1x1 Transform]    [1x1 Transform]    [1x1 Transform]    [1x1 Transform]
Columns 13 through 16
[1x1 Transform]    [1x1 Transform]    [1x1 Transform]    [1x1 Transform]
Columns 17 through 20
[1x1 Transform]    [1x1 Transform]    [1x1 Transform]    [1x1 Transform]
Columns 21 through 24
[1x1 Transform]    [1x1 Transform]    [1x1 Transform]    [1x1 Transform]
Columns 25 through 28
[1x1 Transform]    [1x1 Transform]    [1x1 Transform]    [1x1 Transform]
...

该方法将53个对象实体放到一个单元阵列中,这允许用户通过索引的方式访问每个对象实体。
此外,用户还可用访问标准的MATLAB向量的方法访问对象阵列的元素。

tf.Transforms(5) ans =

ROS TransformStamped message with properties:
 MessageType: 'geometry_msgs/TransformStamped'
      Header: [1x1 Header]
ChildFrameId: '/imu_link'
   Transform: [1x1 Transform]

用户可以通过下述方法访问单个阵列元素的属性:

tf.Transforms(5).Transform.Translation ans =
ROS Vector3 message with properties:
MessageType: 'geometry_msgs/Vector3'
          X: 0.0599
          Y: 0
          Z: -0.0141

关闭ROS网络

从ROS网络中移除示例节点、发布器、订阅器:

exampleHelperROSShutDownSampleNetwork

关闭ROS主控节点并删除全局节点:

rosshutdown Shutting down global node /matlab_global_node_8332 with     
NodeURIhttp://bat5136glnxa64:33534/Shutting down ROS master 
onhttp://bat5136glnxa64.mathworks.com:11311/

纠错,疑问,交流: 请进入讨论区点击加入Q群

获取最新文章: 扫一扫右上角的二维码加入“创客智造”公众号


标签: ros与matlab语言入门教程