[关闭]
@Pigmon 2017-12-20T09:40:10.000000Z 字数 4516 阅读 136

V-Rep 挖掘机 1

实习


简介

Matlab 脚本向 V-Rep 中的挖掘机发送控制信号的简单上手指南。

在 V-Rep 中建立测试场景

1. 菜单 File -> New Scene

2. 新建挖掘机

Model Browser -> Vehicles -> excavator.ttm
1.png-42kB

将其拖放至场景中的地板上。

3. 删除原有脚本 (或者直接删除脚本文件内全部程序)

在 Scene Hierarchy 中找到 Excavator,右键点击其右侧的脚本标志。
在弹出菜单中选择 Edit -> Remove -> Associate Child Script
2.png-67.1kB

4. 新建脚本

在 Scene Hierarchy 中找到 Excavator,右键点击。
在弹出菜单中选择 Add -> Associate Child Script -> Non Threaded
3.png-42.5kB

5. 脚本结构

新添加的 Lua 脚本中,预先放好了几个 if 语句块,代表不同的系统回调。
其中:

  1. if (sim_call_type==sim_childscriptcall_initialization) then
  2. end

是初始化过程,只会在场景启动的时候执行一次

  1. if (sim_call_type==sim_childscriptcall_actuation) then
  2. end

是相当于主循环过程中的控制部分,是每帧都执行的程序。
其他2部分分别是 Scensing 和 Cleanup,暂时不用。

6. 添加 V-Rep 端程序

这里我们只示例控制铲斗的过程,其他的挖机臂是类似的情况。
程序主要参考了其自带的UI控制程序(已经删除的脚本)。

首先在 sim_childscriptcall_initialization 的 if 块中添加初始化内容

  1. if (sim_call_type==sim_childscriptcall_initialization) then
  2. excavatorHandle=simGetObjectAssociatedWithScript(sim_handle_self)
  3. -- 得到控制铲斗的液压缸 Object
  4. piston4=simGetObjectHandle('Piston4')
  5. -- 得到铲斗液压缸的运程范围
  6. -- piston4Range是含有2个元素的数组
  7. -- 范围从 piston4Range[1] piston4Range[2]
  8. c,piston4Range=simGetJointInterval(piston4)
  9. -- 得到初始状态下,铲斗液压缸位置在运程中的百分比
  10. current_piston4 = (simGetJointPosition(piston4)-piston4Range[1])/piston4Range[2]
  11. -- 建立铲斗液压缸移动目标变量
  12. target_piston4 = current_piston4
  13. -- 定义跟 Matlab 端的通信接口
  14. simExtRemoteApiStart(19999)
  15. end

添加驱动部分内容

  1. -- 一次执行只是一帧中的运算,因此这里是根据(上一帧位置,最终目标位置,速度)等这些参数
  2. -- 计算出这一帧里,delta 位移的大小,进而设置下一帧的位置。
  3. if (sim_call_type==sim_childscriptcall_actuation) then
  4. -- 当前帧时间
  5. ts=simGetSimulationTimeStep()
  6. -- 模型基本缩放(?)
  7. s=simGetObjectSizeFactor(excavatorHandle)
  8. -- Joint 的速度限制
  9. maxPiston4Vel=0.1*s
  10. -- Piston 4:
  11. -- 目标位置
  12. pistonTargetPos=s*(piston4Range[1]+piston4Range[2]*target_piston4)
  13. -- 当前位置
  14. current_piston4=simGetJointPosition(piston4)
  15. -- Delta 位置
  16. dx=(pistonTargetPos-current_piston4)
  17. if math.abs(dx)>maxPiston4Vel*ts then
  18. dx=maxPiston4Vel*ts*dx/math.abs(dx)
  19. end
  20. -- 设置当前帧铲斗液压缸的位置
  21. simSetJointPosition(piston4,current_piston4+dx)
  22. end

添加远程控制接口

这是给Matlab端调用的自定义函数
参考 V-Rep 自带文档的 《Extending the Remote API》

这里我们需要Matlab指定一个浮点数(液压缸目标位置百分比),将其赋值给target_piston4

在脚本最末尾添加如下函数定义:

  1. remoteSetPiston4=function(inInts,inFloats,inStrings,inBuffer)
  2. target_piston4 = inFloats[1]
  3. return {},{},{},''
  4. end

7. Matlab 端部署

7.1 工程目录

新建一个目录当作【工程目录】。
将 V-Rep 安装目录下,比如:

  1. C:\Program Files\V-REP3\V-REP_PRO_EDU\programming\remoteApiBindings\matlab

中的

  1. remApi.m
  2. remoteApiProto.m
  3. remoteApi.dll

拷贝到新的工作目录中。
注意这个 dll,32位或64位,必须跟 Matlab 的位数对应。

7.2 控制脚本

打开 Matlab,新建脚本,保存在【工程目录】中。
脚本内容:

  1. function myTest1()
  2. vrep = remApi('remoteApi');
  3. vrep.simxFinish(-1);
  4. % 这里的端口号必须和 V-Rep 端声明的相同(比如 19999
  5. clientID = vrep.simxStart('127.0.0.1',19999,true,true,5000,5);
  6. if (clientID > -1)
  7. disp('Test1 connected to V-Rep');
  8. pause(2);
  9. % 调用远程控制接口 'remoteSetPiston4'
  10. % @clientID simxStart 返回的通信句柄
  11. % @'Excavator': V-Rep 场景中,脚本挂载的 Object (挖掘机)
  12. % @vrep.sim_scripttype_childscript:函数的载体是 child script
  13. % @'remoteSetPiston4': 远程函数名,在 V-Rep 脚本中定义
  14. % @[],[1],[],[]: 4 个输入参数,分别是int数组,float数组... 这里我们用 float 数组
  15. % @vrep.simx_opmode_blocking: 阻塞模式通信
  16. vrep.simxCallScriptFunction(clientID,'Excavator',vrep.sim_scripttype_childscript,'remoteSetPiston4',[],[1],[],[],vrep.simx_opmode_blocking);
  17. else
  18. disp('Failed connecting to remote API server');
  19. end
  20. vrep.delete();
  21. disp('Ended.');
  22. end

8. 运行

V-Rep 中启动新建场景。
Matlab 中运行脚本。
看 V-Rep.

铲斗应该会从这个姿势:
4.png-6.2kB

运动到(液压缸位置百分比位1的位置):
5.png-5.3kB

附录A 完整的 V-Rep 脚本

  1. -- DO NOT WRITE CODE OUTSIDE OF THE if-then-end SECTIONS BELOW!! (unless the code is a function definition)
  2. if (sim_call_type==sim_childscriptcall_initialization) then
  3. excavatorHandle=simGetObjectAssociatedWithScript(sim_handle_self)
  4. piston4=simGetObjectHandle('Piston4')
  5. c,piston4Range=simGetJointInterval(piston4)
  6. current_piston4 = (simGetJointPosition(piston4)-piston4Range[1])/piston4Range[2]
  7. target_piston4 = current_piston4
  8. simExtRemoteApiStart(19999)
  9. end
  10. if (sim_call_type==sim_childscriptcall_actuation) then
  11. ts=simGetSimulationTimeStep()
  12. s=simGetObjectSizeFactor(excavatorHandle)
  13. maxPiston4Vel=0.1*s
  14. -- Piston 4:
  15. pistonTargetPos=s*(piston4Range[1]+piston4Range[2]*target_piston4)
  16. current_piston4=simGetJointPosition(piston4)
  17. dx=(pistonTargetPos-current_piston4)
  18. if math.abs(dx)>maxPiston4Vel*ts then
  19. dx=maxPiston4Vel*ts*dx/math.abs(dx)
  20. end
  21. simSetJointPosition(piston4,current_piston4+dx)
  22. end
  23. if (sim_call_type==sim_childscriptcall_sensing) then
  24. -- Put your main SENSING code here
  25. end
  26. if (sim_call_type==sim_childscriptcall_cleanup) then
  27. -- Put some restoration code here
  28. end
  29. remoteSetPiston4=function(inInts,inFloats,inStrings,inBuffer)
  30. target_piston4 = inFloats[1]
  31. return {},{},{},''
  32. end

附录B 完整的 Matlab 脚本

  1. function myTest1()
  2. vrep = remApi('remoteApi');
  3. vrep.simxFinish(-1);
  4. clientID = vrep.simxStart('127.0.0.1',19999,true,true,5000,5);
  5. if (clientID > -1)
  6. disp('Test1 connected to V-Rep');
  7. pause(2);
  8. vrep.simxCallScriptFunction(clientID,'Excavator',vrep.sim_scripttype_childscript,'remoteSetPiston4',[],[1],[],[],vrep.simx_opmode_blocking);
  9. else
  10. disp('Failed connecting to remote API server');
  11. end
  12. vrep.delete();
  13. disp('Ended.');
  14. end
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注