ROS在MATLAB中的使用笔记
发布日期:2021-07-01 04:03:06 浏览次数:2 分类:技术文章

本文共 9106 字,大约阅读时间需要 30 分钟。

文章目录

声明:本文整理自网络,内容仅作博主学习笔记记录,版权归原作者所有!

官方参考文档:

本文版本: MATLAB R2019b

1. ROS环境变量设置

% 检测标准ROS环境变量的值getenv('ROS_MASTER_URI')getenv('ROS_HOSTNAME')getenv('ROS_IP')% 设置ROS环境变量的值setenv('ROS_MASTER_URI','http://192.168.1.1:11311')setenv('ROS_IP','192.168.1.100')rosinit

参考链接:

2. ROS初始化及常用指令

默认情况下, “rosinit” 指令在MATLAB中创建一个ROS主控节点并开始了一个“global node”节点,该节点与主控节点相连。“global node”节点能够自动的被其它ROS函数使用。该节点被分配给一个随机产生的独一无二的名称。所有的发布器、订阅器、服务终端和服务器都将在这个全局节点运行。

% 初始化ROS网络rosinit % 连接到外部ROS主控节点rosinit('192.168.1.1')  	  % 默认端口为11311rosinit('master_host')  	  %	默认端口为11311rosinit('master_host', 12000) % 指定端口为12000rosinit('http://192.168.1.1:12000') % 通过主控节点完整URI连接并创建全局节点% 列出当前节点rosnode list% 列出当前话题rostopic list% 列出当前服务rosservice list% 查看指定节点的具体信息rosnode info /node_name% 查看指定话题的具体信息rostopic info /topic_name% 查看指定服务的具体信息rosservice info /service_name% 查看指定消息类型rostopic type /topic_name% 查看指定消息类型的属性rosmsg show geometry_msgs/Twist% 查看MATLAB中所有可用消息类型rosmsg list% 关闭ROS网络rosshutdown

参考链接:

3. ROS消息的使用

基本消息的使用

% 查看ROS话题数据类型的具体结构scandata = rosmessage('sensor_msgs/LaserScan')% 定义一个与LaserScan相同类型的消息scantype = rostype.sensor_msgs_LaserScanscandata = rosmessage(scantype)% 查看candata的ScanTime属性(`.`后使用Tab键补全)scandata.ScanTime% 以geometry_msgs/Twist消息为例,假设消息变量为posedata,访问Linear的Xxpos = posedata.Linear.X% 快速查看消息中包含的所有数据showdetails(posedata)% 设置或填充消息数据twist = rosmessage(rostype.geometry_msgs_Twist)twist.Linear.Y = 5% 共享数据式消息复制twistCopyRef = twist %如果修改twistCopyRef,twist也会跟着改变,两者类似于两个指针指向同一个变量% 独立式消息复制(复制体与原消息体不发生干涉)twistCopyDeep = copy(twist)% 数据保存save('posedata.mat','posedata')% 重新加载文件到工作空间之前需要清除'posedata'变量clear posedata% 加载保存的消息数据messageData = load('posedata.mat')% 查看消息内容messageData.posedata% 删除MAT文件delete('posedata.mat')

参考链接:

ROS消息的进阶使用

  • 激光传感器消息的使用
% 消息的创建,其他数据填充参考上述内容scanMsg = rosmessage(rostype.sensor_msgs_LaserScan)% 为了后面的演示,此处使用例程载入激光数据exampleHelperROSLoadMessages% 获取笛卡尔坐标下的测量点xy = readCartesian(scan)% 数据可视化plot(scan,'MaximumRange',5)
  • 图像消息的使用
% 消息的创建,其他数据填充参考上述内容emptyimg = rosmessage(rostype.sensor_msgs_Image)% 为了后面的演示,此处使用例程载入图像数据exampleHelperROSLoadMessages% 注意,'Data'存储的是原始图像数据,MATLAB不能直接处理或可视化% 原始的图像的编码格式为'rgb8'% 我们可使用'readImage'将其恢复成MATLAB可读的图像格式% 默认情况下'readImage'返回的是480x640x3的uint8格式imageFormatted = readImage(img)% 查看图像imshow(imageFormatted)% 使用'rosmessage'创建一个空的压缩图像消息emptyimgcomp = rosmessage(rostype.sensor_msgs_CompressedImage)% 用户可以使用'readImage'函数标准的RGB格式的图像,即使图像原始编码格式是bgr8,readImage也能做相应的转换compressedFormatted = readImage(imgcomp)% 查看图像imshow(compressedFormatted)
  • 点云消息的使用
使用'rosmessage'创建一个空的标准点云消息emptyptcloud = rosmessage(rostype.sensor_msgs_PointCloud2)% 查看例程中的点云数据,该消息存储在'ptcloud'变量中ptcloudxyz = readXYZ(ptcloud)% 上述点云数据会出现NaN无效值,这是Kinect一种伪像,安全移除NaN值的操作如下:xyzvalid = xyz(~isnan(xyz(:,1)),:)% 查看点云RGB数据rgb = readRGB(ptcloud) % 点云可视化scatter3(ptcloud)

在这里插入图片描述

参考链接:

自定义消息的使用

将ROS消息定义转换为MATLAB时,字段名称将转换为消息对象的属性。对象属性始终以大写字母开头,并且不包含下划线。修改字段名称以适合此命名约定。下划线的第一个字母和第一个字母大写,下划线删除。例如,sensor_msgs/Image消息在ROS中具有以下字段:

  • header
  • height
  • width
  • encoding
  • is_bigendian
  • step
  • data

根据这一规则,转换成MATLAB结构后:

  • Header
  • Height
  • Width
  • Encoding
  • IsBigendian
  • Step
  • Data

消息自定义步骤:

  • STEP1:自定义消息结构
    在这里插入图片描述
  • STEP2:调用rosgenmsg函数将消息类型转换为有效的MATLAB代码
folderpath = "C:/Users/user1/Documents/robot_custom_msg/";rosgenmsg(folderpath)
  • STEP3:将生成的类文件添加到MATLAB路径当中
addpath('matlab/myfiles')  savepath matlab/myfiles/pathdef.m %将当前搜索路径保存到位于matlab/myfiles/pathdef.m
  • STEP4:刷新所有消息类定义
clear classesrehash toolboxcache
  • STEP5:验证消息是否可用
rosmsg list

参考链接:

4. 订阅者和发布者的使用

% 查看可用的消息类型rostype.getMessageList

订阅者的使用

% 订阅/scan话题laser = rossubscriber('/scan')% 数据接收(参数二:超时时间/s)scandata = receive(laser,10)% 数据可视化('MaximumRange'指定了曲线的最大值范围)plot(scandata,'MaximumRange',7)% 使用回调函数代替receive的数据订阅robotpose = rossubscriber('/pose',@exampleHelperROSPoseCallback)% 定义两个全局变量用来实现主工作空间与回调函数之间的数据共享global posglobal orient % 从“/pose”主题中接收到新消息时,全局变量'pos”'和'orient'将在'exampleHelperROSPoseCallback'回调函数中赋值。% 订阅者的终止(通过清除相关变量来实现)clear robotpose

发布者的使用

% 创建发布者到'/chatter'话题chatterpub = rospublisher('/chatter',rostype.std_msgs_String)% 创建一个测试用的订阅者chattersub = rossubscriber('/chatter', @exampleHelperROSChatterCallback)% 创建并填充ROS消息chattermsg = rosmessage(chatterpub)chattermsg.Data = 'hello world'% 发布数据到'/chatter'话题上send(chatterpub,chattermsg)

参考链接:

5. 服务端和客户端的使用

% 查看可用的服务类型rostype.getServiceList

服务端的使用

% 使用'rossvcserver'创建一个服务器testserver = rossvcserver('/test', rostype.std_srvs_Empty, @exampleHelperROSEmptyCallback)% 查看'/test'服务的信息rosservice info /test

客户端的使用

% 使用'rossvcclient'创建一个客户端testclient = rossvcclient('/test')% 创建服务请求函数testreq = rosmessage(testclient)% 请求的参数设置(此处假设MessageType中有两个参数A、B)testreq.A = 2testreq.B = 1% 获取服务器响应testresp = call(testclient,testreq,'Timeout',3)

参考链接:

6. ROS参数服务器的使用

% 启动一个新的参数服务器ptree = rosparam% 检查是否存在指定名称的参数(如果没有返回0)has(ptree,'ROBOT_IP')% 添加新参数至参数服务器set(ptree,'ROBOT_IP','192.168.1.1');set(ptree, '/myrobot/ROBOT_IP','192.168.1.100');set(ptree,'MAX_SPEED',1.5);set(ptree, '/myrobot/ROBOT_NAME','TURTLE');set(ptree, '/myrobot/MAX_SPEED',1.5);set(ptree, '/newrobot/ROBOT_NAME','NEW_TURTLE');% 获取参数值robotIP = get(ptree, '/myrobot/ROBOT_IP')% 获取所有储存在参数服务器上的参数列表plist = ptree.AvailableParameters% 修改已有参数(对参数进行修改的数值可以与之前分配的数据类型不同)set(ptree, 'MAX_SPEED', 1.0);% 删除参数del(ptree, 'ROBOT_IP');% 测试是否删除成功has(ptree, 'ROBOT_IP')% 搜索包含指定名称空间的参数results = search(ptree, 'myrobot')

7. ROS - tf树的访问及使用

tf数据的访问

% 查看tf信息tf% 查看tf的Transforms结构tf.Transforms% 查看tf.Transforms中Transforms对象的属性tf.Transforms.Transform% 返回Transform字段的值cellTransforms = {
tf.Transforms.Transform}% 通过索引方式访问指定对象实体tf.Transforms(5)tf.Transforms(5).Transform.Translation

在这里插入图片描述

tf树的使用

% 加载例程数据exampleHelperROSStartTfPublisher% 使用'rostf'创建新的tf树对象tftree = rostf% 使用'AvailableFrames'查看tftree.AvailableFrames% 获取变换mountToCamera = getTransform(tftree, 'mounting_point', 'camera_center');% 获取变换中的平移信息mountToCameraTranslation = mountToCamera.Transform.Translation% 获取变换中的旋转信息并将其转为欧拉角quat = mountToCamera.Transform.RotationmountToCameraRotationAngles = rad2deg(quat2eul([quat.W quat.X quat.Y quat.Z]))% 等待有效的变换(将会堵塞,知道变换可获得)waitForTransform(tftree, 'robot_base', 'camera_center');% 将相机中心坐标系下的点转换到robot_base坐标下% 数据填充pt = rosmessage('geometry_msgs/PointStamped');pt.Header.FrameId = 'camera_center';pt.Point.X = 3;pt.Point.Y = 1.5;pt.Point.Z = 0.2;% 变换tfpt = transform(tftree, 'robot_base', pt)% 获取变换结果tfpt.Point% 发布变换% 数据填充tfStampedMsg = rosmessage('geometry_msgs/TransformStamped');tfStampedMsg.ChildFrameId = 'wheel';tfStampedMsg.Header.FrameId = 'robot_base';tfStampedMsg.Transform.Translation.X = 0;tfStampedMsg.Transform.Translation.Y = -0.2;tfStampedMsg.Transform.Translation.Z = -0.3;quatrot = axang2quat([0 1 0 deg2rad(30)])tfStampedMsg.Transform.Rotation.W = quatrot(1);tfStampedMsg.Transform.Rotation.X = quatrot(2);tfStampedMsg.Transform.Rotation.Y = quatrot(3);tfStampedMsg.Transform.Rotation.Z = quatrot(4);tfStampedMsg.Header.Stamp = rostime('now');% 发送上述设置的变换sendTransform(tftree, tfStampedMsg)% 查看变换列表,看是否发布成功tftree.AvailableFrames

参考链接:

8. ROS在Simulink中的使用

首先要启动ROS:rosinit

用到的Simulink模块:

  • Simulink → Signal Routing → Bus Assignment
  • Simulink → Signal Routing
  • ROS Toolbox → ROS → Blank Message
  • ROS Toolbox → ROS → Publish
  • Simulink → Sources → Sine Wave
  • Simulink → Signal Routing → Bus Selector
  • Simulink → Sinks → Terminator
  • Simulink → Sinks → XY Graph
  • Simulink → Sinks → Display
  • Simulink → Ports & Subsystems → Enabled

a. 基本订阅者发布者的使用

发布者模块设置及测试

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
运行以后发现:
在这里插入图片描述

订阅者模块设置及测试

在这里插入图片描述

Subscribe模块中的IsNew属性输出在时间步进期间消息是否已被接收

在这里插入图片描述
在这里插入图片描述

增加一个使能子系统

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

配置并运行Simulink模型

在这里插入图片描述

注意:仿真并不是以实际或真实时间工作,仅仅是仿真进程时间而已!

参考链接:

b. Simulink中ROS消息的使用

具体通过Blank Message模块来实现,参考案例robotROSMessageUsageExample

在这里插入图片描述

c. 反馈控制

具体案例参考如下案例

robotROSFeedbackControlExample

注意:如果画出IsNew的信号将会发现,输入消息并不是周期的,该现象是由于仿真进程时间与真实时间不同造成的,仿真执行循环是由模型复杂度和计算机计算速度决定的,具体参阅。

如果使能的子系统没有被应用,那么模型将一直重复处理相同的消息(最新接收的),从而导致控制消息的浪费处理和多余发布,使能子系统可以帮助确认模型仅仅处理真正的新消息。

参考链接:

d. 从Simulink中创建单独的ROS节点

具体参考如下链接。

参考链接:

9. ROSbag的使用

% 使用'rosbag'载入bag文件,路径可使用绝对或相对方式bag = rosbag(filepath)% 获取'AvailableTopics'属性,查看bag文件中有关话题和消息类型等信息bag.AvailableTopics% 恢复消息前,用户须基于时间戳、话题名称或消息类型选择一系列消息% 查看当前选择的所有消息(第一列为时间戳):bag.MessageList% 使用'select'筛选消息bagselect1 = select(bag, 'Topic', '/odom')% 筛选前30s发布的'/odom'消息列表start = bag.StartTimebagselect2 = select(bag, 'Time', [start start + 30], 'Topic', '/odom')% 筛选指定时间段的消息列表bagselect3 = select(bagselect2, 'Time', [205 206])% 多项筛选规则的使用selectOptions = {
'Time', [start, start+1; start+5, start+6], 'MessageType', {
'sensor_msgs/LaserScan', 'nav_msgs/Odometry'}};bagselect4 = select(bag, selectOptions{
:})% 读取选择的消息数据msgs = readMessages(bagselect3);% 查看消息规模或长度size(msgs)% 按时间序列提取消息数据ts = timeseries(bagselect3, 'Pose.Pose.Position.X', 'Twist.Twist.Angular.Z')% 访问消息序列中的数据('Data'属性)ts.Data% 消息数据可视化plot(ts, 'LineWidth', 3)

参考链接:

10. rosrate的使用

% 创建一个Rate对象,使您能够以固定的频率执行循环DesiredRate。时间源链接到全局ROS节点的时间源,这需要您使用将MATLAB连接到ROS网络rosinitrate = rosrate(desiredRate)% 创建一个Rate对象,该对象基于链接到指定ROS节点的时间源以固定的速率运行循环 noderate = ros.Rate(node,desiredRate)

案例1:

rosinit% 1 Hzr = rosrate(1);reset(r)for i = 1:10	time = r.TotalElapsedTime;	fprintf('Iteration: %d - Time Elapsed: %f\n',i,time)	waitfor(r);endrosshutdown

案例2:

rosinitnode = ros.Node('/testTime');r = ros.Rate(node,20);reset(r)for i = 1:30	% User code goes here.	waitfor(r);endrosshutdown

在Simulink中的使用参考工具箱自带案例robotROSFeedbackControlExample

在这里插入图片描述

参考链接:

转载地址:https://miracle.blog.csdn.net/article/details/111115287 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:信号作用于系统后产生的变化
下一篇:各路大神对于观测器的文章总结【持续更新】

发表评论

最新留言

做的很好,不错不错
[***.243.131.199]2024年04月11日 03时50分25秒