本教程将尝试解决如何将机器人语言解释器集成或嵌入到 V-REP 中。 该过程与将仿真器(例如特定的微控制器仿真器)集成到 V-REP 中非常相似。 扩展 V-REP 的功能需要大部分时间来开发插件。 在继续本教程之前,请确保已阅读插件教程和外部控制器教程。
与本教程相关的 V-REP 场景文件位于 V-REP 的安装文件夹 scenes\robotLanguageControl.ttt 中。 你可以在此处找到插件项目文件,以及服务器应用程序项目文件。
首先,让我们首先加载相关的场景文件 scenes\robotLanguageControl.ttt:
MTB 机器人是一个虚构的机器人(MTB 代表 Machine Type B),将使用虚构的机器人语言进行控制。
如前所述,使用的机器人语言是虚构的,非常简单。 支持以下命令(每行一个命令,输入区分大小写):
"REM" starts a comment line
"SETLINVEL v": sets the prismatic joint velocity for next movements (v is in m/s)
"SETROTVEL v": sets the revolute joint velocity for next movements (v is in degrees/s)
"MOVE p1 p2 p3 p4": moves to joint positions (p1;p2;p3;p4) (in degrees except for p3 in meters)
"WAIT x": waits x milliseconds
"SETBIT y": sets the bit at position y (1-32) in the robot output port
"CLEARBIT y": clears the bit at position y (1-32) in the robot output port
"IFBITGOTO y label": if bit at position y (1-32) in the robot input port is set, jump to "label"
"IFNBITGOTO y label": if bit at position y (1-32) in the robot input port is not set, jump to "label"
"GOTO label": jumps to "label"
除了 “REM”,“SETLINVEL”,“SETROTVEL”,“MOVE”,“WAIT”,“SETBIT”,“CLEARBIT”,“IFBITGOTO”,“IFNBITGOTO” 和 “GOTO” 的任何单词都被视为标签。 现在运行模拟。 如果未找到相关插件,则显示以下消息(消息的显示在附加到对象 MTB_Robot 和MTB_Robot#0 的子脚本中处理):
如果找到相关插件,则 MTB 插件将启动基本上代表机器人语言解释器和控制器的服务器应用程序(即 mtbServer)。不需要直接使用服务器应用程序,mtbServer 功能也可以直接在 MTB 插件内运行。在服务器应用程序中使用该功能的主要优点是:
MTB插件可以根据需要作为许多不同语言的中间体,也可以作为尚未开发的语言:MTB 插件将根据使用的 robot/language 简单地启动相应的服务器。
如果机器人语言解释器/控制器崩溃,V-REP 将不会崩溃,因为这两者是不同且独立的进程。
目前,MTB 服务器主要负责两项任务:
从 MTB 插件接收程序代码(即缓冲区),编译它,并初始化机器人控制器。
应用输入信号,逐步执行程序代码(不同步骤的步进持续时间可以不同),并返回输出信号和关节角度。
如果 MTB 服务器在编译程序代码期间检测到错误,它将向插件返回一条错误消息,该消息将交给调用子脚本(即在我们的例子中,附加到对象的子脚本 MTB_Robot 和 MTB_Robot#0.),将显示(例如):
如果编译成功,则机器人开始执行其各自的程序。 模拟是最大速度模拟,但可以通过切换相关工具栏按钮切换到实时模拟:
通过多次按相应的工具栏按钮可以进一步加快执行速度:
每个 MTB 机器人程序可以通过其显示的自定义对话框随时单独暂停,停止或重新启动,这些自定义对话框是自定义用户界面:
以上自定义 UI 是 MTB 机器人的用户界面,可以完全自定义。如果要复制 MTB 机器人,那么它的自定义 UI 也将被复制。除了能够控制程序执行状态之外,自定义 UI 还显示当前程序行(Command)和 MTB 的当前关节值。用户还可以更改机器人的输入端口位,并读取机器人的输出端口位。输入和输出端口可以由机器人语言程序读取和分别写入。输入和输出端口也可以通过使用适当的函数调用由外部设备(例如机器人的夹子或吸盘)写入和读取(参见下面的内容)。
有两个子脚本附加到 MTB_Robot 和 MTB_Robot#0 对象。他们负责处理自定义对话框并与 MTB 插件进行通信。子脚本中的大部分代码也可以由插件处理。打开连接到两个 MTB 机器人之一的子脚本(例如,双击场景层次结构中机器人模型旁边的脚本图标)。在脚本的顶部,您将看到机器人语言代码。
尝试修改 MTB 机器人程序,使其执行不同的运动顺序。实验一下。
MTB机器人按以下方式处理:
实际的机器人语言程序由“mtbServer”应用程序编译和执行。 该应用程序还包含 MTB 机器人的状态变量。 对于模拟场景中的每个MTB 机器人,都将有一个由 v_repExtMtb 插件启动的 mtbServer 应用程序实例。
v_repExtMtb 插件负责提供自定义 Lua 功能,并在需要时启动 mtbServer 应用程序,并通过套接字通信与之通信。
附加到 MTB_Robot 和 MTB_Robot#0 的子脚本检查是否加载了 v_repExtMtb 插件,更新每个机器人的基于 OpenGl 的自定义 UI,并处理与插件的通信。
MTB 机器人及其简单的机器人语言是一个简单的原型,旨在演示如何将机器人语言解释器集成到V-REP中。 为更复杂的机器人或机器人语言扩展当前功能非常容易。 所需要的只是:
建立机器人的模型。这包括导入 CAD 数据,添加关节等。此步骤可以完全在 V-REP 中完成。
编写插件以本机处理新机器人,即通过解释其自己的机器人语言来处理新机器人。任何能够访问 C-API 的函数并且能够包装在 dll 中的语言都可以用于创建插件(但首选 c/c ++)。机器人语言解释器可以直接嵌入到插件中,也可以像本教程中一样作为外部应用程序(mtbServer)启动。
编写一个小子脚本,负责处理自定义对话框并将机器人与插件链接。该步骤可以完全在 V-REP 中完成。
现在让我们来看看 MTB 的插件项目。将机器人语言解释器(或其他仿真器)嵌入到 V-REP 中有一个先决条件:
机器人语言解释器应该能够并行执行几次。这意味着应支持多个解释器实例,以支持多个相同的并行操作机器人。通过为每个新机器人启动一个新的解释器,可以最简单地处理这个问题,如本教程中所做的那样。
在编写任何插件时,请确保插件仅从主线程(或从 V-REP 创建的线程)访问 V-REP 的常规 API。插件可以启动新线程,但在这种情况下,这些新线程不应该用于访问V-REP(但它们可以用于与服务器应用程序通信,与某些硬件通信,执行后台计算等) 。
Now let's have a look at the child script that is attached to the MTB robot. The code might seem quite long or complicated. However most functionality handled in the child script could also be directly handled in the plugin, making the child script much smaller/cleaner. The advantage in handling most functionality in the child script is that modifications can be performed without having to recompile the plugin!
Following is the MTB robot's child script main functionality:
- Checking whether the plugin was loaded. If not, an error message is output.
- Communicating with the plugin. This means that information is sent to and received from the MTB plugin with custom Lua functions.
- Applying the newly calculated joint values to the MTB robot model. This could also be handled in the MTB's plugin.
- Reacting to events on the custom dialogs, like button presses.
- Updating the state of the custom dialogs.
Following 3 custom Lua functions are of main interest (others are exported by the plugin):
现在让我们看看附加到MTB机器人的子脚本。 代码可能看起来很长或很复杂。 但是,子脚本中处理的大多数功能也可以直接在插件中处理,从而使子脚本更小/更清晰。 处理子脚本中的大多数功能的优点是可以执行修改而无需重新编译插件!
以下是MTB机器人的子脚本主要功能:
检查插件是否已加载。 如果不是,则输出错误消息。
与插件通信。 这意味着使用自定义 Lua 函数向 MTB 插件发送信息和从 MTB 插件接收信息。
将新计算的关节值应用于 MTB 机器人模型。 这也可以在 MTB 的插件中处理。
对自定义对话框中的事件做出反应,例如按下按钮。
更新自定义对话框的状态。
以下3个自定义Lua函数是主要关注点(其他函数由插件导出):
number mtbServerHandle,string message=simMTB.startServer(string mtbServerExecutable,
number portNumber,charBuffer program,table_4 jointPositions, table_2 velocities)
number result,string message=simMTB.step(number mtbServerHandle,number timeStep)
table_4 jointValues=simMTB.getJoints(number mtbServerHandle)
simMTB.startServer:在指定端口上启动服务器应用程序(例如 mtbServer),连接到它,并向其发送机器人语言代码,初始关节位置和初始速度。 作为回报,该函数返回服务器句柄(如果成功)和消息(通常是编译错误消息)。
simMTB.step:使用指定的 timeStep 逐步执行机器人语言程序,并返回结果值和消息(通常是当前正在执行的代码)。
simMTB.getJoints:检索当前的关节位置。 调用 simMTB.step 时,关节位置会自动更新。
您还可以想象稍微修改步骤函数,并添加一个附加函数,以便能够处理由机器人语言程序执行触发的中间事件。 在这种情况下,每个模拟步骤都必须执行以下脚本代码(在非线程子脚本中):
local dt=sim.getSimulationTimeStep()
while (dt>0) do
result,dt,cmdMessage=simMTB.step(mtbServerHandle,dt) -- where the returned dt is the remaining dt
local event=simMTB.getEvent()
while event~=-1 do
-- handle events here
event=simMTB.getEvent()
end
end
参考资料
1.V-REP官方文档:http://www.coppeliarobotics.com/helpFiles/