matlab中zwros,ROS在MATLAB中的使用笔记_weixin_39690625的博客-程序员秘密

技术标签: matlab中zwros  

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

官方参考文档:

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') % 默认端口为11311

rosinit('master_host') % 默认端口为11311

rosinit('master_host', 12000) % 指定端口为12000

rosinit('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_LaserScan

scandata = rosmessage(scantype)

% 查看candata的ScanTime属性(`.`后使用Tab键补全)

scandata.ScanTime

% 以geometry_msgs/Twist消息为例,假设消息变量为posedata,访问Linear的X

xpos = 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'变量中

ptcloud

xyz = readXYZ(ptcloud)

% 上述点云数据会出现NaN无效值,这是Kinect一种伪像,安全移除NaN值的操作如下:

xyzvalid = xyz(~isnan(xyz(:,1)),:)

% 查看点云RGB数据

rgb = readRGB(ptcloud)

% 点云可视化

scatter3(ptcloud)

7c0d1d41ce4107469129ea6d55cf94ae.png

自定义消息的使用

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

header

height

width

encoding

is_bigendian

step

data

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

Header

Height

Width

Encoding

IsBigendian

Step

Data

消息自定义步骤:

STEP1:自定义消息结构

b83cf7730663d7a8f11997511f50f4d2.png

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 classes

rehash 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 pos

global 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 = 2

testreq.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

c536c715c7119dd691151bc79a00222a.png

tf树的使用

% 加载例程数据

exampleHelperROSStartTfPublisher

% 使用'rostf'创建新的tf树对象

tftree = rostf

% 使用'AvailableFrames'查看

tftree.AvailableFrames

% 获取变换

mountToCamera = getTransform(tftree, 'mounting_point', 'camera_center');

% 获取变换中的平移信息

mountToCameraTranslation = mountToCamera.Transform.Translation

% 获取变换中的旋转信息并将其转为欧拉角

quat = mountToCamera.Transform.Rotation

mountToCameraRotationAngles = 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. 基本订阅者发布者的使用

发布者模块设置及测试

1b8a2d88285ecf3d22b213a5bf8cba3f.png

b217099702fa5c2e85cb7d2dfe211ef1.png

251cefdbbf8f868aed61d343a773b245.png

b4bed4ad80914c1b1a2e84e4d6691466.png

运行以后发现:

f2ec2a989a90027fd63ba9c78168ef0a.png

订阅者模块设置及测试

463440f35b8a931c7054e17f4b8d1f36.png

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

e0d34f24377a8482590bf8c205a56d58.png

c34c243ecad6210aa384ba8fc2db3f4d.png

增加一个使能子系统

6f2032cdd2f07bff9317cc7a32c8c7f6.png

5ac5e2a25a1fc7cd598af7670a8cda60.png

ff56dda8d635726b7ef4c071d8e7fb0b.png

配置并运行Simulink模型

bdb7b5e1e96230c15a0fb5759565b14d.png

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

参考链接:

b. Simulink中ROS消息的使用

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

6c6ed2df4a4d79705a7a0c5d55d063f9.png

c. 反馈控制

具体案例参考如下案例

robotROSFeedbackControlExample

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

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

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.StartTime

bagselect2 = 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网络rosinit

rate = rosrate(desiredRate)

% 创建一个Rate对象,该对象基于链接到指定ROS节点的时间源以固定的速率运行循环 node

rate = ros.Rate(node,desiredRate)

案例1:

rosinit

% 1 Hz

r = rosrate(1);

reset(r)

for i = 1:10

time = r.TotalElapsedTime;

fprintf('Iteration: %d - Time Elapsed: %f\n',i,time)

waitfor(r);

end

rosshutdown

案例2:

rosinit

node = ros.Node('/testTime');

r = ros.Rate(node,20);

reset(r)

for i = 1:30

% User code goes here.

waitfor(r);

end

rosshutdown

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

79f220544fc465e8f67bf460478c7351.png

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_39690625/article/details/115850723

智能推荐

mybatis3中@SelectProvider的应用技巧_iteye_10017的博客-程序员秘密

mybatis3中@SelectProvider的使用技巧mybatis的原身是ibatis,现在已经脱离了apache基金会,新官网是http://www.mybatis.org/。mybatis3中增加了使用注解来配置Mapper的新特性,本篇文章主要介绍其中几个@Provider的使用方式,他们是:@SelectProvider、@UpdateProvider、@InsertPr...

org.json.JSONObject与org.json.JSONArray用法_zEthan的博客-程序员秘密

org.json.JSONObject//JSONObject内部封装了一个HashMap<String, String>,用于存储json对象的属性名(String类型)和属性值。//JSONObject构造1JSONObject obj = new JSONObject();System.out.println(obj.toString());obj.put("100", ...

红帽 liunx7两种方式安装Yum源_红帽安装yum源_Ying799的博客-程序员秘密

 我们先进入/etc/yum.repos.d,并删除这里面所有的包。并且新建一个文件文件内容如下:再挂载一下光盘,查看一下是否成功,(我们安装一下ifconfig命令试验一下,这里我是已经安装过了)实验证明我们安装成功。卸载光盘再次进入/etc/yum.repos.d里面编辑dvd.repo实验一下有没有成功,我们这一次用ftp实验一下,先删除ftp,再...

Java 字节流操作_Single_YAM的博客-程序员秘密

在java中我们使用输入流来向一个字节序列对象中写入,使用输出流来向输出其内容。C语言中只使用一个File包处理一切文件操作,而在java中却有着60多种流类型,构成了整个流家族。看似庞大的体系结构,其实只要使用适合的方法将其分门别类,就显得清晰明了了。而我准备将其按照处理文件类型的不同,分为字节流类型和字符流类型。共两篇文章,本篇从字节流开始。主要包含以下内容:InputStream/OutPu

js操作select标签_js select 属性_hhhh2012的博客-程序员秘密

html中的select标签javascript对它们的操作 一、基础理解 复制代码代码如下:var e = document.getElementById("selectId"); e. options= new Option("文本","值") ; //创建一个option对象,即在标签中创建一个或多个文本 //options是个数组,里面可以存放多个文

随便推点

MySQL中使用group_concat遇到的坑_幽篁晓筑的博客-程序员秘密

在使用group_concat的过程中遇到个问题,这里记录一下:在MySQL中有个配置参数group_concat_max_len,它会限制使用group_concat返回的最大字符串长度,默认是1024。查询group_concat_max_len大小:show variables like 'group_concat_max_len';修改group_concat...

Py之slidingwindow&sliding_window:slidingwindow、sliding_window的简介、安装、使用方法之详细攻略_一个处女座的程序猿的博客-程序员秘密

Py之slidingwindow&sliding_window:slidingwindow、sliding_window的简介、安装、使用方法之详细攻略目录sliding_window的简介sliding_window的安装sliding_window的使用方法slidingwindow、sliding_window的简介sliding_wi...

装两个版本的QT遇到的错误_桌边的qt版本错误_原休的博客-程序员秘密

错误描述电脑上装了Qt5.7.1和Qt5.13.2,用Qt5.13.2来画三维散点图的时候一直报这个错,后来发现是我原来的sln文件使用的是Qt5.7.1,在VS2015的QT5插件里有一个Qt Options选项,我把两个版本的Qt都添加进去了,default选择的是5.13.2,但实际上这样并没有改变sln文件对应的QT版本,所以我相当于用Qt5.7.1来调用5.13.2来库,所以一直报错。...

python 内存泄漏及gc模块的使用_python gc模块_zhou191954的博客-程序员秘密

在 Python 中,为了解决内存泄漏问题,采用了对象引用计数,并基于引用计数实现自动垃圾回收。    因为 Python 有了自动垃圾回收功能,不少初学者就认为自己从此过上了好日子,不必再受内存泄漏的骚扰了。但如果查看一下 Python 文档对 __del__() 函数的描述,就知道好日子里也是有阴云的。下面摘抄一点文档内容:    Some common situations that

今日干货【面试题】在进行服务器的日常检查时,应该检查哪些内容_检查服务器都需要检查什么_刚入门的小师弟的博客-程序员秘密

在进行服务器的日常检查时,应该检查哪些内容1. 每天检查系统日志,对出错的提示做分析并解决2. 每天检查系统磁盘空间,关注系统磁盘的大小变化3. 每天检查数据备份情况4. 每天检查系统内存的使用情况5. 每天检查CPU使用率6. 杀毒软件每二天更新一次7. 每星期检查系统补丁的更新8. 审核管理组的成员资格9. 执行验证恢复,检测备份的可靠性10. 每周重新引导服务器11. 执

GCC编译选项与GDB调试学习总结_gcc 编译gdb选项_Dream_yz的博客-程序员秘密

GCC编译选项与GDB调试学习总结GCC编译选项GCC选项GCC编译相关的选项如下:–help:显示gcc帮助说明-target-help:显示目标机器特定的命令行选项–version:显示gcc版本号和版权信息-E:只进行预处理,不编译-S:只编译,不汇编-c:只编译、汇编,不链接-pipe:使用管道代替临时文件-combine:将多个原文件一次性传递给汇编器-g:包含调试信息

推荐文章

热门文章

相关标签