VREP中的二维激光雷达
目前,轮式机器人的研究中已经大量使用激光雷达辅助机器人的避障导航,考虑到使用成本,一般二维激光雷达使用较多,如下图。由于只能扫描一个平面,如果想用二维激光雷达获取环境三维点云,则需要通过移动机器人或加装机械结构提供第三个维度的支持。


激光雷达通常有四个性能衡量指标:测距分辨率、扫描频率(有时也用扫描周期)、角度分辨率及可视范围。测距分辨率衡量在一个给定的距离下测距的精确程度,通常与距离真实值相差在5-20mm;扫描频率衡量激光雷达完成一次完整扫描的快慢,通常在10Hz及以上;角度分辨率直接决定激光雷达一次完整扫描能返回多少个样本点;可视范围指激光雷达完整扫描的广角,可视范围之外即为盲区。
- 使用视觉传感器模拟激光雷达
为了模拟二维激光雷达,将视觉传感器设为透视模型并只获取深度信息。near clipping plane和far clipping plane设置为激光雷达的最小/最大扫描距离;视场角Persp. angle设为雷达可视范围(角度);将Y轴分辨力率设为1,X轴分辨率可根据需求设置(分辨率越大结果越精确,分辨率过低可能会造成某些尺寸小的物体无法被探测到)。
视觉传感器filter设置如下,其中加入Extract coordinates from work image用来提取深度图像中坐标信息,这一环节返回的数据可以通过函数simReadVisionSensor来获取。参数设置界面上的Point count along X/Y设为X/Y轴分辨率,即调用一次相关API函数可以读取包含256个像素点的坐标信息的数据:

为了显示激光雷达“看到”的环境,可以通过Graph来记录用户自定义数据流:按照下图所示在数据类型栏中选择user-defined,将自定义数据名分别修改为"x"和"y"用来记录障碍物相对于激光雷达的位置,并通过函数simSetGraphUserData(graphHandle, dataStreamName, data)来设置自定义数据的值。

Graph:
if (sim_call_type==sim_childscriptcall_initialization) then
-- Put some initialization code here
graphHandle = simGetObjectAssociatedWithScript(sim_handle_self)
end
if (sim_call_type==sim_childscriptcall_sensing) then
-- Put your main SENSING code here
simResetGraph(graphHandle)
data = simGetStringSignal("UserData")
if data then
measuredData = simUnpackFloatTable(data)
for i=,#measuredData/, do
simSetGraphUserData(graphHandle,'x',measuredData[*(i-)+])
simSetGraphUserData(graphHandle,'y',measuredData[*(i-)+])
simHandleGraph(graphHandle,)
end
end
end
if (sim_call_type==sim_childscriptcall_cleanup) then
-- Put some restoration code here
simResetGraph(graphHandle)
end
--[[
Normally, simHandleGraph is called for you, in the main script. In that case, you can record one value in each
simulation step. When you explicitely handle the graph, then you have the possibility to record more than one
new graph point in each simulation step.
--]]
Vision_sensor:
if (sim_call_type==sim_childscriptcall_initialization) then
-- Put some initialization code here
visionSensor1Handle = simGetObjectHandle("Vision_sensor")
red={,,}
points=simAddDrawingObject(sim_drawing_points,,,-,,red,nil,red,red)
end
if (sim_call_type==sim_childscriptcall_sensing) then
-- Put your main SENSING code here
measureData = {}
m1=simGetObjectMatrix(visionSensor1Handle,-)
r,t1,u1=simReadVisionSensor(visionSensor1Handle)
if u1 then
for j=,u1[]-, do -- point count along Y
for i=,u1[]-, do -- point count along X
w=+*(j*u1[]+i) -- index
v1=u1[w+] -- x
v2=u1[w+] -- y
v3=u1[w+] -- z
v4=u1[w+] -- dist
if(v4 < 0.99) then
--[[
p={v1,v2,v3}
p=simMultiplyVector(m1,p) -- convert point from visionSensor1 coordinates to world coordinates
simAddDrawingObjectItem(points, p)
--]]
table.insert(measureData, v1)
table.insert(measureData, v3)
end
end
end
stringData = simPackFloats(measureData) -- Packs a table of floating-point numbers into a string
simSetStringSignal("UserData", stringData)
end
end
if (sim_call_type==sim_childscriptcall_cleanup) then
-- Put some restoration code here
simRemoveDrawingObject(points)
end
在场景中加入浮动窗口,并将Graph与窗口关联,切换到X-Y曲线显示(取消坐标轴自动缩放,坐标轴比例设为1:1)

- SICK TiM310
VREP模型浏览器的components/sensors目录中包含多种激光雷达,其中德国SICK传感器推出的迷你激光测量系统TiM310可视范围为270°,角度分辨率为1°,探测距离为0.05m~4m,扫描频率15Hz,功耗4W。

operating range diagram
由于是用视觉传感器来模拟激光雷达,因此270°的可视范围对于一般视觉传感器来说太大(普通广角镜头视角在60-84度,超广角镜头的视角为94-118度,鱼眼镜头视角在220-230度),可以拆分为2个视角135°的视觉传感器来凑成270°:

视角参数和远近剪切平面设置如下:

激光雷达获取的位置数据要在参考坐标系SICK_TiM310_ref中描述,而simReadVisionSensor获取的像素点坐标是相对于视觉传感器坐标系的,因此需要使用矩阵变换将其转换到SICK_TiM310_ref参考系中。用画笔在场景中画出激光雷达的扫描线,需要得知线段起点和终点坐标,这一坐标是在世界坐标系下描述的,因此一共涉及3个坐标系之间的变换。
if (sim_call_type==sim_childscriptcall_initialization) then
visionSensor1Handle=simGetObjectHandle("SICK_TiM310_sensor1")
visionSensor2Handle=simGetObjectHandle("SICK_TiM310_sensor2")
joint1Handle=simGetObjectHandle("SICK_TiM310_joint1")
joint2Handle=simGetObjectHandle("SICK_TiM310_joint2")
sensorRefHandle=simGetObjectHandle("SICK_TiM310_ref") -- the base of SICK LiDAR maxScanDistance=simGetScriptSimulationParameter(sim_handle_self,'maxScanDistance')
if maxScanDistance> then maxScanDistance= end
if maxScanDistance<0.1 then maxScanDistance=0.1 end
simSetObjectFloatParameter(visionSensor1Handle,sim_visionfloatparam_far_clipping,maxScanDistance)
simSetObjectFloatParameter(visionSensor2Handle,sim_visionfloatparam_far_clipping,maxScanDistance)
maxScanDistance_=maxScanDistance*0.9999 scanningAngle=simGetScriptSimulationParameter(sim_handle_self,'scanAngle')
if scanningAngle> then scanningAngle= end
if scanningAngle< then scanningAngle= end
scanningAngle=scanningAngle*math.pi/
simSetObjectFloatParameter(visionSensor1Handle,sim_visionfloatparam_perspective_angle,scanningAngle/)
simSetObjectFloatParameter(visionSensor2Handle,sim_visionfloatparam_perspective_angle,scanningAngle/) simSetJointPosition(joint1Handle,-scanningAngle/)
simSetJointPosition(joint2Handle,scanningAngle/)
red={,,}
lines=simAddDrawingObject(sim_drawing_lines,,,-,,nil,nil,nil,red) if (simGetInt32Parameter(sim_intparam_program_version)<) then
simDisplayDialog("ERROR","This version of the SICK sensor is only supported from V-REP V3.0.4 and upwards.&&nMake sure to update your V-REP.",sim_dlgstyle_ok,false,nil,{0.8,,,,,},{0.5,,,,,})
end
end if (sim_call_type==sim_childscriptcall_cleanup) then
simRemoveDrawingObject(lines)
end if (sim_call_type==sim_childscriptcall_sensing) then
measuredData={} if notFirstHere then
-- We skip the very first reading
simAddDrawingObjectItem(lines,nil)
showLines=simGetScriptSimulationParameter(sim_handle_self,'showLaserSegments') r,t1,u1=simReadVisionSensor(visionSensor1Handle)
r,t2,u2=simReadVisionSensor(visionSensor2Handle) m1=simGetObjectMatrix(visionSensor1Handle,-)
m01=simGetInvertedMatrix(simGetObjectMatrix(sensorRefHandle,-))
m01=simMultiplyMatrices(m01,m1) -- transformation matrix between base and visionSensor m2=simGetObjectMatrix(visionSensor2Handle,-)
m02=simGetInvertedMatrix(simGetObjectMatrix(sensorRefHandle,-))
m02=simMultiplyMatrices(m02,m2) if u1 then
p={,,}
p=simMultiplyVector(m1,p) -- convert the origin of visionSensor1 coordinates to world coordinates
t={p[],p[],p[],,,} for j=,u1[]-, do -- point count along Y
for i=,u1[]-, do -- point count along X
w=+*(j*u1[]+i) -- index
v1=u1[w+] -- coordinate x of detected point(Coordinates are relative to the vision sensor position/orientation.)
v2=u1[w+] -- coordinate y of detected point
v3=u1[w+] -- coordinate z of detected point
v4=u1[w+] -- distance to detected point
if (v4<maxScanDistance_) then
p={v1,v2,v3}
p=simMultiplyVector(m01,p) -- describe position in LiDAR base coordinates
table.insert(measuredData,p[])
table.insert(measuredData,p[])
table.insert(measuredData,p[])
end
if showLines then -- draw laser line
p={v1,v2,v3}
p=simMultiplyVector(m1,p) -- convert point from visionSensor1 coordinates to world coordinates
t[]=p[]
t[]=p[]
t[]=p[]
simAddDrawingObjectItem(lines,t)
end
end
end
end
if u2 then
p={,,}
p=simMultiplyVector(m2,p)
t={p[],p[],p[],,,}
for j=,u2[]-, do
for i=,u2[]-, do
w=+*(j*u2[]+i)
v1=u2[w+]
v2=u2[w+]
v3=u2[w+]
v4=u2[w+]
if (v4<maxScanDistance_) then
p={v1,v2,v3}
p=simMultiplyVector(m02,p)
table.insert(measuredData,p[])
table.insert(measuredData,p[])
table.insert(measuredData,p[])
end
if showLines then
p={v1,v2,v3}
p=simMultiplyVector(m2,p)
t[]=p[]
t[]=p[]
t[]=p[]
simAddDrawingObjectItem(lines,t)
end
end
end
end
end
notFirstHere=true -- measuredData now contains all the points that are closer than the sensor range
-- For each point there is the x, y and z coordinate (i.e. 3 number for each point)
-- Coordinates are expressed relative to the sensor frame.
-- You can access this data from outside via various mechanisms. The best is to first
-- pack the data, then to send it as a string. For example:
--
--
-- data=simPackFloatTable(measuredData)
-- simSetStringSignal("measuredDataAtThisTime",data)
--
-- Then in a different location:
-- data=simGetStringSignal("measuredDataAtThisTime")
-- measuredData=simUnpackFloatTable(data)
--
--
-- Of course you can also send the data via tubes, wireless (simTubeOpen, etc., simSendData, etc.)
--
-- Also, if you send the data via string signals, if you you cannot read the data in each simulation
-- step, then always append the data to an already existing signal data, e.g.
--
--
-- data=simPackFloatTable(measuredData)
-- existingData=simGetStringSignal("measuredDataAtThisTime")
-- if existingData then
-- data=existingData..data
-- end
-- simSetStringSignal("measuredDataAtThisTime",data)
end

获得测量数据后,可以使用函数将包含坐标值的一维列表打包成字符串,并设置字符串信号。在另一个需要使用传感器数据的脚本中读取字符串信号,然后将其解压成列表:
data = simPackFloatTable(measuredData)
simSetStringSignal("measuredDataAtThisTime", data) -- Then in a different location:
data = simGetStringSignal("measuredDataAtThisTime")
measuredData = simUnpackFloatTable(data)
参考:
LabVIEW Robotics中如何借助二维激光雷达感知三维场景
VREP中的二维激光雷达的更多相关文章
- FastReport 中添加二维码功能.(Delphi)
http://www.cnblogs.com/fancycloud/archive/2011/07/24/2115240.html FastReport 中添加二维码功能.(Delphi) 在实际 ...
- Swift开发小技巧--识别选中照片中的二维码
识别选中照片中的二维码 点击相册按钮,打开用户相册 @IBAction func photoBtnClick(sender: AnyObject) { // 打开相册 // 1.判断是否能够打开相册 ...
- C#中读取二维数组每位的长度
C#中的二维数组,如int[,] A=new int[a,b];则 a=A.GetLength(0);即可获得二维数组中第一维的长度. b=A.GetLength(1);即可获得二维数组中第二维的长度 ...
- Java中的二维数组
Java 中的二维数组 所谓二维数组,可以简单的理解为是一种"特殊"的一维数组,它的每个数组空间中保存的是一个一维数组. 那么如何使用二维数组呢,步骤如下: 1. 声明数组并分配空 ...
- 【转】 Android 基于google Zxing实现对手机中的二维码进行扫描--不错
原文网址:http://blog.csdn.net/xiaanming/article/details/14450809 转载请注明出处:http://blog.csdn.net/xiaanming/ ...
- 在java中生成二维码,并直接输出到jsp页面
在java中生成的二维码不存到磁盘里要直接输出到页面上,这就需要把生成的二维码直接以流的形式输出到页面上,我用的是myeclipse 和 tomcat 它的原理是:在加载页面时,根据img的src(c ...
- word/excel/cad中插入二维码
1.有需求为在word文档中插入二维码,寻访度娘后,大部分人推荐使用QRmaker制作. 2.找寻QRmaker,网上很多都是1.1版本,后来才知道这个版本有问题(对中文支持不好),偶然得到1.3的版 ...
- C# 动态创建SQL数据库(二) 在.net core web项目中生成二维码 后台Post/Get 请求接口 方式 WebForm 页面ajax 请求后台页面 方法 实现输入框小数多 自动进位展示,编辑时实际值不变 快速掌握Gif动态图实现代码 C#处理和对接HTTP接口请求
C# 动态创建SQL数据库(二) 使用Entity Framework 创建数据库与表 前面文章有说到使用SQL语句动态创建数据库与数据表,这次直接使用Entriy Framwork 的ORM对象关 ...
- iOS中的二维数组
首先我们知道OC中是没有二维数组的,二维数组是通过一位数组的嵌套实现的,但是别忘了我们有字面量,实际上可以和C/C++类似的简洁地创建和使用二维数组.这里总结了创建二维数组的两种方法以及数组的访问方式 ...
随机推荐
- 深入理解java虚拟机(六)字节码指令简介
Java虚拟机指令是由(占用一个字节长度.代表某种特定操作含义的数字)操作码Opcode,以及跟随在其后的零至多个代表此操作所需参数的称为操作数 Operands 构成的.由于Java虚拟机是面向操作 ...
- 【BZOJ】【4145】【AMPPZ2014】The Prices
状压DP/01背包 Orz Gromah 容易发现m的范围很小……只有16,那么就可以状压,用一个二进制数来表示买了的物品的集合. 一种简单直接的想法是:令$f[i][j]$表示前$i$个商店买了状态 ...
- c++ 使用json的库。cJSON
cJSON官网是:http://sourceforge.net/projects/cjson/?source=recommended 最新版本是2013年的,与2009年的变化不是很大. 看了代码,觉 ...
- @几种OutOfMemory异常
Java虚拟机运行时数据区 在Java虚拟机规范的描述中,除了程序计数器之外,虚拟机内存的其他几个运行时区域都会发生OutOfMemory异常的可能. 我们可以在IDE(如IDEA)中设置虚拟机启动参 ...
- android自定义风格的toast
先上图看一下我的自定义toast的样式 源码下载地址: CustomToastActivity.java源码 package com.jinhoward.ui_customtoast; /** * A ...
- 聊一聊Spring中的线程安全性
Spring作为一个IOC/DI容器,帮助我们管理了许许多多的“bean”.但其实,Spring并没有保证这些对象的线程安全,需要由开发者自己编写解决线程安全问题的代码. Spring对每个bean提 ...
- javascript中的分支判断与循环
分支判断与循环 分支结构 单一选择结构(if) 二路选择结构(if/else) 内联三元运算符 ?: 多路选择结构(switch) var condition = true; if (conditio ...
- iOS截屏方法
//获取屏幕截屏方法 - (UIImage *)capture { // 创建一个context UIGraphicsBeginImageContextWithOptions(self.view.bo ...
- Mac-OSX下Ruby更新
Mac下是自带Ruby环境的,在有些情况我们是需要更新Ruby的,安装和更新Ruby环境可以通过rvm命令进行操作,rvm在安装过程中通过HomeBrew安装依赖包,如果之前没有装过HomeBrew, ...
- AAAI 2018 论文 | 蚂蚁金服公开最新基于笔画的中文词向量算法
AAAI 2018 论文 | 蚂蚁金服公开最新基于笔画的中文词向量算法 2018-01-18 16:13蚂蚁金服/雾霾/人工智能 导读:词向量算法是自然语言处理领域的基础算法,在序列标注.问答系统和机 ...