今天来介绍一下BubbleRob 的教程。
在设计简单的移动机器人BubbleRob时,本教程将尝试介绍许多V-REP功能。与本教程相关的V-REP场景文件位于V-REP的安装文件夹的教程/BubbleRob文件夹中。下图为我们将要设计的仿真场景:
由于本教程将涵盖许多不同的方面,请确保也看一看公众号的其他文章。首先,刚启动的V-REP,模拟器显示一个默认场景。我们将从BubbleRob的身体开始。
我们使用 [Menu bar --> Add --> Primitive shape --> Sphere].[菜单栏—>添加—>原体形状—>球体]为场景添加一个直径为0.2的原体球体。我们将X-size项调整为0.2,然后单击OK。默认情况下,创建的球体将出现在可见层1中,并且是动态和可响应的(因为我们保持了项目创建动态和可响应的形状启用)。这意味着BubbleRob的身体将会下落,并且能够对与其他可响应形状的碰撞做出反应(即由物理引擎模拟)。我们可以看到这是形状动态属性:物体是可响应的,物体是动态的。我们开始模拟(通过工具栏按钮或按<控制空间>在现场窗口),和复制粘贴创建的领域(与[Menu bar --> Edit --> Copy selected objects] [菜单栏- - >编辑- - >复制选择的物体)然后(菜单栏- - >编辑- >粘贴缓冲区),或 control - c control - v:两个领域将反应碰撞。我们停止模拟:重复的球体将自动被移除。可以在模拟对话框中修改此默认行为。
我们还希望通过其他计算模块(例如最小距离计算模块)来使用BubbleRob的主体。因此,如果尚未启用,我们将在该形状的对象公共属性中启用可碰撞、可测量、可呈现和可检测的特性。如果我们愿意,我们现在还可以在形状属性中改变球体的视觉外观。
现在我们打开translation选项卡上的position对话框,选择代表BubbleRob主体的球体,并为Along z输入0.02。我们确保相关的to-item被设置为World。然后点击translation选择。这将使所有选中的对象沿绝对z轴移动2厘米,并有效地提升了我们的球体。在场景层次结构中,我们双击球体的名字,这样我们就可以编辑它的名字。我们输入bubbleRob并按回车键。
接下来,我们将添加一个接近传感器,以便BubbleRob知道何时它正在接近障碍物:我们选择 [Menu bar --> Add --> Proximity sensor --> Cone type][菜单栏—>添加—>接近传感器—>锥型]。在方向选项卡上的方向对话框中,输入90代表Y轴和Z轴,然后单击“旋转选区”。在position选项卡上的position对话框中,我们为X-coord输入0.1。Z-coord是0.12。接近传感器现在相对于BubbleRob的身体正确定位。我们双击场景层次结构中的接近传感器图标,以打开它的属性对话框。我们点击显示音量参数来打开接近传感器音量对话框。我们调整项目偏移量为0.005,角度为30,范围为0.15。然后,在接近传感器属性中,点击显示检测参数。这将打开接近传感器检测参数对话框。我们取消检查项目不允许检测,如果距离小于然后再次关闭对话框。在场景层次结构中,我们双击proximity传感器的名字,这样我们就可以编辑它的名字。输入bubbleRob_sensingNose并按enter键。
我们选择bubbleRob_sensingNose,然后control-select bubbleRob,然后单击 [Menu bar --> Edit --> Make last selected object parent][菜单栏——>编辑——>制作最后选中的对象父对象]。这将传感器连接到机器人的身体上。我们也可以将bubbleRob_sensingNose拖放到场景层次结构中的bubbleRob上(推荐)。这是我们现在拥有的:
接下来,我们将处理BubbleRob的车轮。我们用[Menu bar --> File --> New scene][菜单栏—>文件—>新场景]创建一个新场景。跨多个场景工作通常非常方便,以便只对特定的元素进行可视化和工作。我们添加一个尺寸为0.08、0.08、0.02的纯原始圆柱体。对于BubbleRob的主体,如果尚未启用,我们将在该圆柱体的对象通用属性中启用可碰撞、可测量、可呈现和可检测的特性。然后我们将圆柱体的绝对位置设为(0.05,0.1,0.04),其绝对方向设为(-90,0,0)。我们将名称更改为bubbleRob_leftWheel。我们复制并粘贴轮子,并将复制的绝对Y坐标设置为-0.1。我们将副本重命名为bubbleRob_rightWheel。我们选择两个轮子,复制他们,然后切换回场景1,然后粘贴轮子。
现在我们需要为车轮添加关节(或马达)。我们点击 [Menu bar --> Add --> Joint --> Revolute][菜单栏->添加->关节->转动关节]添加一个转动关节到场景中。大多数情况下,当向场景添加一个新对象时,该对象会出现在世界的原点。我们保持关节处于选中状态,然后control-select bubbleRob_leftWheel。在“位置”对话框中,在“位置”选项卡上,单击“应用到选择”按钮:这将关节定位在左轮的中心位置。然后,在朝向对话框中,在朝向选项卡上,我们做同样的事情:这个朝向关节的方式和左滚轮一样。我们将关节重命名为bubbleRob_leftMotor。现在,双击场景层次结构中的关节图标,打开关节属性对话框。然后点击显示动态参数,打开关节动态属性对话框。启动电机,当目标速度为零时检查自锁电机。现在,我们对右马达重复相同的过程,并将其重命名为bubbleRob_rightMotor。现在我们把左边的轮子连接到左边的电机上,右边的轮子连接到右边的电机上,然后把两个电机连接到bubbleRob上。这就是我们所拥有的:
我们运行模拟程序,注意到机器人在向后下落。我们仍然没有找到第三个与地面的接触点。现在我们添加一个小的滑块(或脚轮)。在一个新场景中,我们添加了一个直径为0.05的纯原始球体,并使球体具有可碰撞性、可测量性、可呈现性和可检测性(如果尚未启用),然后将其重命名为bubbleRob_slider。我们在形状动力学特性中将材料设置为无摩擦材料。为了将滑块与机器人的其余部分进行刚性连接,我们添加了一个带有[Menu bar --> Add --> Force sensor]的力传感器对象。我们将其重命名为bubbleRob_connection并向上移动0.05。我们把滑块连接到力传感器上,然后复制两个物体,切换到场景1并粘贴它们。然后我们将力传感器沿绝对x轴移动-0.07,然后将其连接到机器人身上。如果我们现在运行模拟,我们可以注意到滑块相对于机器人身体有轻微的移动:这是因为两个对象(即bubbleRob_slider和bubbleRob)相互碰撞。为了避免奇怪的效果在动力学仿真,我们必须告知V-REP两个对象都不是相互碰撞,我们用以下方法:动态形状属性,bubbleRob_slider我们当地respondable掩码设置为00001111,对于bubbleRob,我们当地respondable掩码设置为11110000。如果我们再次运行模拟,我们可以注意到两个对象不再相互干扰。这是我们现在拥有的:
我们再次运行模拟,并注意到BubbleRob即使在电机锁定的情况下也会轻微移动。我们还尝试使用不同的物理引擎运行模拟:结果将会不同。动态模拟的稳定性与所涉及的非静态形状的质量和惯性密切相关。我们现在试着纠正这个不希望出现的结果。我们选择两个轮子和滑动器,在形状动态对话框中我们点击三次M=M*2(用于选择)。结果是所有选定的形状的质量都乘以8。我们对3个选定形状的惯量做同样的处理,然后再次运行模拟:稳定性得到了改善。在关节动力学对话框中,我们将两个电机的目标速度设置为50。我们运行模拟:BubbleRob现在向前移动,并最终从地板上跌落。我们将两个电机的目标速度项重置为零。
对象bubbleRob位于以后将形成bubbleRob模型的所有对象的基础。稍后我们将定义模型。同时,我们希望定义一个表示BubbleRob的对象集合。为此,我们定义了一个集合对象。我们点击[Menu bar --> Tools --> Collections][菜单栏——>工具——>集合]来打开集合对话框。或者,我们也可以点击适当的工具栏按钮来打开对话框:
在收集对话框中,单击添加新收集。一个新的集合对象出现在下面的列表中。目前,新添加的集合仍然是空的(没有定义)。在列表中选择新的集合项时,在场景层次结构中选择bubbleRob,然后在集合对话框中单击Add。我们的集合现在被定义为包含从bubbleRob对象开始的层次树的所有对象(集合的组合显示在composition elements和attributes部分)。要编辑集合名称,我们双击它,并将其重命名为bubbleRob_collection。我们关闭collection对话框。
在此阶段,我们希望能够跟踪BubbleRob与任何其他对象之间的最小距离。为此,我们使用[Menu bar --> Tools --> Calculation module properties][菜单栏—>工具—>计算模块属性]打开距离对话框。或者,我们也可以用适当的工具栏按钮打开计算模块属性对话框:
在距离对话框中,我们点击添加新的距离对象,并选择一个距离对:[collection] bubbleRob_collection——场景中所有其他可测量的对象。这只是增加了一个距离对象,它将测量集合bubbleRob_collection(即该集合中的任何可测量对象)和场景中的任何其他可测量对象之间的最小距离。我们将distance对象重命名为bubbleRob_distance,并在其名称中双击。我们关闭距离对话框。当我们现在运行模拟时,我们不会看到任何差异,因为距离对象将尝试测量(并显示)BubbleRob与场景中任何其他可测量对象之间的最小距离段。问题是在这个阶段,场景中没有其他可测量的对象(定义地板的形状默认关闭了可测量属性)。在本教程的后面,我们将为场景添加一些障碍。
接下来,我们将向BubbleRob添加一个图形对象,以便在最小距离之上显示,同时也显示BubbleRob随时间的轨迹。我们单击[Menu bar --> Add --> Graph] [菜单栏—>添加—>图形]并将其重命名为bubbleRob_graph。我们将图形附加到bubbleRob,并将图形的绝对坐标设置为(0,0,0.005)。现在我们通过双击场景层次结构中的图形属性对话框的图标来打开图形属性对话框。我们取消显示xyz平面,然后单击Add new data stream来记录并选择对象:数据流类型的绝对x位置,要记录的对象/项目的bubbleRob_graph。数据流记录列表中出现了一个项。该项是bubbleRob_graph的绝对x坐标的数据流(即,将记录bubbleRobGraph的对象的绝对x位置)。现在我们还想记录y和z位置:我们以与上面类似的方式添加这些数据流。现在我们有3个数据流来表示BubbleRob的x-、y-和z-轨迹。我们要添加一个数据流,这样我们就可以跟踪我们的机器人及其环境之间的最小距离:我们点击添加新的数据流来记录和选择距离:区段长度的数据流类型,和bubbleRob_distance对象/项目记录。在数据流记录列表中,我们现在将数据重命名为bubbleRob_x_pos,将Data0重命名为bubbleRob_y_pos,将Data1重命名为bubbleRob_z_pos,将Data2重命名为bubbleRob_obstacle_dist。
我们在数据流记录列表和时间图属性部分选择bubbleRob_x_pos, uncheck Visible。我们对bubbleRob_y_pos和bubbleRob_z_pos执行相同的操作。通过这样做,在时间图中只能看到bubbleRob_obstacle_dist数据流。以下是我们应该拥有的:
接下来,我们将设置一个显示BubbleRob轨迹的3D曲线:单击“编辑3D曲线”打开XY图形和3D曲线对话框,然后单击“添加新曲线”。在弹出的对话框中,我们为x值项选择bubbleRob_x_pos,为y值项选择bubbleRob_y_pos,为z值项选择bubbleRob_z_pos。我们将新添加的曲线重命名为bubbleRob_path。最后,我们检查相对世界项目,并设置曲线宽度为4:
我们关闭所有与图形相关的对话框。现在,我们将一个电机目标速度设置为50,运行模拟,并将看到在场景中显示的BubbleRob的轨迹。然后停止仿真,将电机目标速度重置为零。
我们添加一个纯原柱体,其尺寸为:(0.1,0.1,0.2)。我们希望这个圆柱体是静态的(即不受重力或碰撞的影响),但仍然对非静态可响应的形状施加一些碰撞响应。为此,我们禁用了体动态中的形状动态属性。我们还希望我们的圆柱体是可碰撞的,可测量的,可渲染的和可检测的。我们在对象公共属性中这样做。现在,当圆柱体仍然被选中时,我们点击对象转换工具栏按钮:
现在我们可以拖动场景中的任意点:圆柱体将跟随移动,同时总是被约束保持相同的z坐标。我们复制和粘贴圆柱体几次,并将它们移动到BubbleRob周围的位置(从顶部查看场景时执行该操作最为方便)。在对象移动过程中,按住shift键可以执行更小的移动步骤。按住ctrl键可以在垂直方向上移动到常规方向。完成后,再次选择相机平移工具栏按钮:
我们将左侧电机的目标速度设置为50,并运行模拟:现在图形视图显示了到最近障碍物的距离,并且在场景中也可以看到距离片段。我们停止模拟并将目标速度重置为零(教程中的每次停止模拟都需要将目标速度设置为0)。
现在我们需要完成BubbleRob作为模型定义。我们选择模型库(即对象bubbleRob),然后检查项目对象是否为模型库,对象/模型是否可以在对象的公共属性中传输或接受DNA:现在有一个点状边界框,它包含了模型层次结构中的所有对象。我们选择了两个关节,接近传感器和图形,然后使项目不显示在模型选择内,点击应用到选择,在同一个对话框:模型包围框现在忽略了两个关节和接近传感器。在同样的对话框中,我们禁用了相机可见层2,并为两个关节和力传感器启用了相机可见层10:这有效地隐藏了两个关节和力传感器,因为9-16层在默认情况下是禁用的。在任何时候,我们可以修改整个场景的可见层。完成模型定义,我们选择视觉传感器,两个轮子,滑块,和图表,然后启用项目选择的基础模型相反:如果我们现在试着在我们的模型中选择一个对象在现场,整个模型都将选择相反,这是一个方便的方式来处理和操作整个模型作为一个单独的对象。此外,这可以保护模型不受意外修改的影响。模型中的单个对象仍然可以在场景中通过按下control-shift选择它们,或者通常在场景层次结构中选择它们。最后我们将场景层次结构中的模型树折叠起来。这就是我们所拥有的:
(参照BubbleRob tutorial里的相关内容)
接下来,我们将在与BubbleRob的接近传感器相同的位置和方向上添加一个视觉传感器。再次打开模型层次,点击 [Menu bar --> Add --> Vision sensor --> Perspective type],【菜单栏—>添加—>视觉传感器—>透视类型】,将视觉传感器附加到邻近传感器上,将视觉传感器的本地位置和方向设置为(0,0,0)。我们还确保视觉传感器是不可见的,不是模型边界框的一部分,如果点击,模型将被选中。为了定制视觉传感器,我们打开它的属性对话框。我们将远剪切平面项设置为1,而分辨率x和分辨率y项设置为256和256。然后单击“显示筛选”对话框打开“视觉传感器筛选”对话框。在工作图像上选择滤镜组件边缘检测,点击添加滤镜。我们将新添加的过滤器放置在第二个位置(使用up按钮向上放置一个位置)。我们双击新添加的筛选器组件,并将其阈值项调整为0.2,然后单击OK。我们在场景中添加一个浮动视图,在新添加的浮动视图上右键单击[Popup menu --> View --> Associate view with selected vision sensor] [弹出菜单—>视图—>关联视图与选中的视觉传感器](我们确保在此过程中选中了视觉传感器)。为了能够看到视觉传感器的图像,我们开始模拟,然后再次停止。(参照Vision Sensor部分)
我们的场景最后需要的是一个控制BubbleRob行为的子脚本。我们选择bubbleRob并单击 [Menu bar --> Add --> Associated child script --> Non threaded]。这只是向场景添加了一个非线程的子脚本,并将其与bubbleRob关联起来。我们还可以通过脚本对话框添加、删除或修改脚本,该对话框可以用 [Menu bar --> Tools --> Scripts][菜单栏—>工具—>脚本]或通过适当的工具栏按钮打开:
我们双击出现在场景层次结构中的bubbleRob名字旁边的小脚本图标:这会打开我们刚刚添加的子脚本。我们复制并粘贴以下代码到脚本编辑器,然后关闭它:
我们运行模拟。BubbleRob现在向前移动,同时试图避开障碍物(以一种非常基本的方式)。当模拟还在运行时,更改BubbleRob的速度,并复制/粘贴几次。在模拟还在运行时,还可以尝试扩展其中的一些。请注意,根据环境的不同,最小距离计算功能可能会大大减慢模拟的速度。您可以在距离对话框中开启或关闭该功能,方法是选中/取消选中“启用所有距离计算”项。
使用脚本控制机器人或模型只是一种方法。V-REP提供了许多不同的方法,看看外部控制器教程。
结合此文章与用户手册英文教程,实操结果如下:
控制代码如下:
function speedChange_callback(ui,id,newVal)
speed=minMaxSpeed[1]+(minMaxSpeed[2]-minMaxSpeed[1])*newVal/100
end
function sysCall_init()
-- This is executed exactly once, the first time this script is executed
bubbleRobBase=sim.getObjectAssociatedWithScript(sim.handle_self) -- this is bubbleRob's handle
leftMotor=sim.getObjectHandle("bubbleRob_leftMotor") -- Handle of the left motor
rightMotor=sim.getObjectHandle("bubbleRob_rightMotor") -- Handle of the right motor
noseSensor=sim.getObjectHandle("bubbleRob_sensingNose") -- Handle of the proximity sensor
minMaxSpeed={50*math.pi/180,300*math.pi/180} -- Min and max speeds for each motor
backUntilTime=-1 -- Tells whether bubbleRob is in forward or backward mode
-- Create the custom UI:
xml = '<ui title="'..sim.getObjectName(bubbleRobBase)..' speed" closeable="false" resizeable="false" activate="false">'..[[
<hslider minimum="0" maximum="100" onchange="speedChange_callback" id="1"/>
<label text="" style="* {margin-left: 300px;}"/>
</ui>
]]
ui=simUI.create(xml)
speed=(minMaxSpeed[1]+minMaxSpeed[2])*0.5
simUI.setSliderValue(ui,1,100*(speed-minMaxSpeed[1])/(minMaxSpeed[2]-minMaxSpeed[1]))
end
function sysCall_actuation()
result=sim.readProximitySensor(noseSensor) -- Read the proximity sensor
-- If we detected something, we set the backward mode:
if (result>0) then backUntilTime=sim.getSimulationTime()+4 end
if (backUntilTime<sim.getSimulationTime()) then
-- When in forward mode, we simply move forward at the desired speed
sim.setJointTargetVelocity(leftMotor,speed)
sim.setJointTargetVelocity(rightMotor,speed)
else
-- When in backward mode, we simply backup in a curve at reduced speed
sim.setJointTargetVelocity(leftMotor,-speed/2)
sim.setJointTargetVelocity(rightMotor,-speed/8)
end
end
function sysCall_cleanup()
simUI.destroy(ui)
end
此BubbleRob 教程是对BubbleRob tutorial的翻译,可以与用户手册的教程
部分结结合使用,亲测可。
谢谢大家支持,
有任何问题欢迎大家批评指正!