[连载 2]Vrep小车建模——内嵌脚本
- [连载 0]Vrep入门介绍
- [连载 1]Vrep小车建模——前进和转向
- [连载 2]Vrep小车建模——内嵌脚本
- [连载 3]Vrep小车建模——matlab控制
- [连载 4]Vrep导入三维模型——PUMA560机械臂
- [番外1]Vrep小车机械臂抓取
-
知乎专栏:Vrep机器人动力学建模仿真
恭喜大家完成上一节[连载 1]Vrep小车建模——前进和转向的教程,能够通过调节左轮和右轮不同的转速实现前进和转向等功能,虽然仍然需要手动调节,但是起点是好的,我们这就基于上一节的教程继续,通过脚本和GUI控制窗口来实现对小车的控制。
建议购买完整仿真模型和代码,请访问链接
Step0基础知识
Vrep最强大的功能之一就是能够通过各种脚本来控制,想必大家在学习vrep的时候已经具备一点基本的编程能力,更多的同学可能已经掌握了Matlab或者是python。本来我原计划是想先用matlab控制小车,想来想去还是决定用Vrep自带的lua来控制,因为这种偏底层的驱动控制我觉得用lua实现最好了,复杂的上层控制再交给matlab,这样就不用涉及到同步模式(synchronous operation mode,这种模式仿真速度会大大降低,软件的通信占据了太多的时间)。
大家可能会疑惑怎么又要学一门语言,而且可能都没有听过lua,没关系的,非常简单。而且既然大家要研究机器人仿真,学习一门语言来极大的加速你的学习过程,这个我想是非常值得的。做机器人,大家就要有这个心理准备,机械、电子、编程啥都不会点,还怎么搞机器人,是吧?
废话少说,下面的安排是:
- 用脚本驱动小车运动
- 用GUI驱动控制小车运动参数(重要)
- 显示数据曲线
Step1用脚本控制小车运动
Vrep的脚本类型非常多,最常用的就4种,non-thread child script,threaded child script,joint control callback scripts和customization scripts。各种脚本之间使用非常类似,今天就先讲non-thread child script。
Non-thread child script,从名字上也能看出来,这个脚本是单线程的,不能并行执行。记得有位知友在知乎上曾经说过Vrep有个问题就是脚本执行的顺序是未知的,其实这个问题可以通过两个方式来避免,第一个就是设置不同脚本的优先级,另一个就是一般复杂度的问题并不会遇到,所以大家刚开始时候不要过于担心。
废话说的有点多,只是希望大家不要有惧怕心理,开始吧。
这一节依然使用上一节的做好的小车,第一个功能是我们添加一个脚本,让小车能够按照不同的速度运动。
按照图2添加一个Non-thread child script,将其绑定在Car_body实体上,见图3。
注:添加完child 脚本后不能直接绑定实体,需要先切换到另一个脚本上(如Main script),然后再切换回来,才可以绑定。
图2 添加脚本
图3 绑定Car_body后在实体后出现脚本的标志
添加脚本后,我们双击Car_body后的脚本图标,打开脚本编辑器:
图4 打开脚本编辑器
到这里我们可以先看一下脚本的大结构:
if (sim_call_type==sim_childscriptcall_initialization) then
--完成初始化工作
end
if (sim_call_type==sim_childscriptcall_actuation) then
--做执行动作,比如控制关节运动,位置移动等
end
if (sim_call_type==sim_childscriptcall_sensing) then
-- 执行感知操作,比如读取距离传感器数据,读取关节力矩等
end
if (sim_call_type==sim_childscriptcall_cleanup) then
--执行清理工作,比如要清楚掉建立的GUI窗口什么的
end
看了这个结构大家就很清楚了嘛,如果有点工程经验就会更清楚了。
- 初始化(Initialization):初始化这个语句只执行一次,也是在仿真开始的时候执行,主要完成变量初始值的初始化,获取你需要的实体的handle(句柄,或者理解成指向仿真环境中的某个部件的指针,随意理解,接受为主)
- 执行(Actuation):“执行”相当于在提交到动力学引擎计算之前进行的操作,比如你这里设置了关节的转速,然后动力学引擎就驱动这个关节按照这个转速运动,直到下次再执行到此部分。
- 感知(Sensing):控制里最重要的一块内容,也是我认为控制系统设计的核心。一切控制算法都是基于反馈来做的,大家做机器人控制一定要注意有些值很难测量或者误差特别大(电机电流,受摩擦影响大),有些值可以精准测量并且误差小(关节角度)。这一部分的执行顺序是位于Actuation之后
- 清理(cleanup):清理是个好习惯,尤其是后面会给大家介绍使用QT_based GUI的时候,一定要在程序仿真结束后清理。
现在就让我们编写第一个控制小车控制程序吧。将下面的程序覆盖到Car_body脚本中,试一下仿真效果。
if (sim_call_type==sim_childscriptcall_initialization) then
MotorHandle_Left=simGetObjectHandle('LeftMotor')
MotorHandle_Right=simGetObjectHandle('RightMotor')
Left_vel = -10
Right_vel = -30
end
if (sim_call_type==sim_childscriptcall_actuation) then
simSetJointTargetVelocity(MotorHandle_Left,Left_vel)
simSetJointTargetVelocity(MotorHandle_Right,Right_vel)
end
if (sim_call_type==sim_childscriptcall_sensing) then
end
if (sim_call_type==sim_childscriptcall_cleanup) then
end
添加一个辅助工具,就是Graph
,使用此工具显示小车运动的轨迹。在Add菜单里选择Graph,打开属性对话框(后面打开属性对话框这些简单操作就不一一截图了),分别添加Car_body
的x、y、z坐标,修改名字为Car_body_X
等,操作见图5.
添加完坐标之后,即可添加3D曲线,按照图6的方式添加,可以更改Curve width改变线宽。关闭Graph的属性窗口,运行仿真,得到图7的结果。
图6 添加3D曲线
图7 3D Curve效果
3D Curve是非常有用的,比如你要观察机械臂的末端的运动轨迹的时候,就可以利用此方式添加一条轨迹。
采用脚本编程一定要学会读文档,按照下面两张图,找到simSetJointTargetVelocity
这个函数的说明,注意他的输入值和返回值。
查看函数手册
Step2利用GUI驱动控制小车运动参数
上面介绍了一种用初始化转速的方式控制小车的运动,如果将你的控制代码嵌入到控制程序中即可使用。但是另一种使用场景为我们希望采用界面操作的方式手动输入一些参数,或者是采用一些滑块等方式调整仿真状态,这就涉及到了采用GUI实现的方式。
Vrep中在3.3.2版本中支持两种GUI的构建,一种是基于OenGl-based custom UIs,另一种是基于Qt-based custom UIs。OpenGl这种方式刚开始使用的时候比较方便,但是灵活性太差,OpenGl在3.4版本中已经废弃了。Qt的构建方式虽然入门稍微稍微难一点,但是还是使用一段时间后就会发现非常好用,而且修改起来很方便,所以这里就直接给大家介绍基于Qt的构建方式。
Qt构建方式是基于xml的方式构建的,就是利用一种约定俗成的方式描述各个控件,如果你有做网页等相关的基础,做这个就还是很easy啦。具体的语法我就不一一讲解了,这种标记语言你就接受就可以了,有什么不清楚的地方大家还是自己查一下xml的格式。
将下面的代码复制到Car_body的脚本中,仿真查看仿真效果见图8。
xml = [[
<ui closeable="true" onclose="closeEventHandler" resizable="true">
<label text="Car control pan" wordwrap="true" />
<group>
<label text="Right wheel speed:" wordwrap="true" />
<spinbox minimum="-30" maximum="30" onchange = "Right_speed_set" />
<label text="Left wheel speed:0" wordwrap="true" />
<spinbox minimum="-30" maximum="30" onchange = "Left_speed_set" />
<stretch />
</group>
<group>
<button text="Start move" onclick = "Start_move" />
<button text="Stop move" onclick = "Stop_move" />
<stretch />
</group>
</ui>
]]
function Start_move(h)
Start_flag = true
end
function Stop_move(h)
Start_flag = false
end
function Right_speed_set(ui,id,newVal)
Right_vel = newVal
end
function Left_speed_set(ui,id,newVal)
Left_vel = newVal
end
function closeEventHandler(h)
simAddStatusbarMessage('Window '..h..' is closing...')
simExtCustomUI_hide(h)
end
if (sim_call_type==sim_childscriptcall_initialization) then
MotorHandle_Left=simGetObjectHandle('LeftMotor')
MotorHandle_Right=simGetObjectHandle('RightMotor')
ui=simExtCustomUI_create(xml)
Left_vel = 0
Right_vel = 0
Start_flag = false
end
if (sim_call_type==sim_childscriptcall_actuation) then
if Start_flag then
simSetJointTargetVelocity(MotorHandle_Left,Left_vel)
simSetJointTargetVelocity(MotorHandle_Right,Right_vel)
else
simSetJointTargetVelocity(MotorHandle_Left,0)
simSetJointTargetVelocity(MotorHandle_Right,0)
end
end
if (sim_call_type==sim_childscriptcall_sensing) then
end
if (sim_call_type==sim_childscriptcall_cleanup) then
simExtCustomUI_destroy(ui)
end
图8 简版小车控制GUI
除此之外我还提供了一个功能比较完备的控制台,具备参数更新等功能,也增加了一些控件支持,足够大部分功能的应用需求,后续仅需要修改部分代码就可以移植,购买请点击本节教程链接。(由于Vrep中不支持中文,因此代码中文注释版也放在教程链接中了,上面给出的代码为可执行代码,并没有注释)
Step3显示数据曲线
在实际仿真过程中,我们往往需要查看一些运动数据,采用图表的形式展示出来。刚才我们采用Graph,用于绘制车体运动的轨迹曲线,接下来,我们同样采用Graph,用于绘制运动过程中驱动关节的实际速度。
使用菜单栏Add添加Graph,按照图9的方式分别添加两轮的速度数据流(Data stream),修改数据流的名称为Left_speed
和Right_speed
,如图10所示。
图10
关闭Graph属性窗口,我们这里建立一个窗口用于显示曲线。我们采用floating view的手段(在3.4版本中会自动建立一个图表窗口,3.3版本没有)。在仿真的page任意点击鼠标右键,按照图11的方式添加,一个空白的floating view窗口。
图11 添加floating View
添加一个空白的窗口后需要将此窗口和刚才添加的Graph0进行链接,按照图12进行操作(注意第二部为在floating view处右击)。链接好了之后可以进行仿真,就可以看到图线了。(由于默认的曲线颜色均是红色,不便于区分,可以在Graph中进行设置,可以在图13中设置曲线颜色)
图12 链接Graph0和floating view窗口
图13设置曲线颜色
结语
采用lua实现一些功能绝对是你之后进行机器人仿真的一大利器,我在第二篇的连载教程里就讲完,是因为后面很多功能需要用到,所以希望大家一定要将本文的例程研究透彻,当然最好购买完整的代码,尽快的掌握Vrep的使用。
下一期就介绍matlab与vrep的通信,希望大家能够继续关注。
更新分割线
很多同学问我编写lua脚本用什么编辑器,我这里推荐两款,一款是notepad++,另一款是Vs code,如果程序超过了300多行,建议还是用VS code。