网站建设公司找哪家,logo设计公司地址,网站开发asp 视频,网站制作流程分为哪三步v-rep官网插件汉化教程
官网教程
插件是什么
插件本质上就是遵循一定规范的API编写出来的程序#xff0c;在v-rep中最终需要编译为动态库。
linux下是libsimXXXX.so#xff1b;
其中XXXX是插件的名称。 请至少使用4个字符#xff0c;并且不要使用下划线#xff0c;因为…v-rep官网插件汉化教程
官网教程
插件是什么
插件本质上就是遵循一定规范的API编写出来的程序在v-rep中最终需要编译为动态库。
linux下是libsimXXXX.so
其中XXXX是插件的名称。 请至少使用4个字符并且不要使用下划线因为该插件会被忽略但是当插件本身加载一些其他库例如simExtXXXX_de.dll等语言资源时您应该使用下划线。 插件和v-rep的交互 lua脚本方式加载过程
1在lua文件中使用loadPlugin()加载插件(动态库文件)
loadPlugin返回映射对象这个对象包含了插件中实现的变量和函数通过这个映射对象可以访问插件提供的全局变量和函数。 linux下的simBubble插件 2require()函数加载并执行.lua文件返回映射对象。
通过返回的映射对象调用插件实现的函数实现相关功能。
function sysCall_thread()sim require(sim)simBubble require(simBubble)local jointHandles {sim.getObject(./leftMotor), sim.getObject(./rightMotor)}local sensorHandle sim.getObject(./sensingNose)local robHandle simBubble.create(jointHandles, sensorHandle, {0.5, 0.25})if robHandle 0 thensimBubble.start(robHandle) -- start the robotlocal st sim.getSimulationTime()sim.wait(20) -- run for 20 secondssimBubble.stop(robHandle)simBubble.destroy(robHandle)end
end
require()函数
在 Lua 中require 函数用于加载和执行指定的 Lua 模块文件或 C 模块。在使用 require 函数加载模块时如果该模块尚未被加载则 Lua 将查找该模块加载并执行它。如果模块已经被加载则 require 函数将不执行任何操作直接返回该模块的引用。require 函数的调用形式如下lua
require(module)
其中 module 参数表示需要加载的模块名称。如果文本字符串 module 符合 Lua 路径规范那么 require 函数会按照以下规则在路径中查找模块1. 如果 module 是一个 Lua 文件require 函数会按照系统环境变量 LUA_PATH 和 LUA_CPATH 中设置的路径查找该文件
2. 如果 module 是一个 C 模块require 函数会按照系统环境变量 LUA_CPATH 中设置的路径查找该模块
3. 用户还可以通过设置 package.path 和 package.cpath 全局变量来扩展 Lua 文件和 C 模块的搜索路径。使用 require 函数将模块加载到程序中可以提高 Lua 程序的可维护性和代码重用性。在某些情况下为了避免反复加载 Lua 模块可以使用 package.loaded 全局变量来维护模块的加载状态以提高程序的性能和效率。 插件中4个函数的实现
create:
// --------------------------------------------------------------------------------------
// simBubble.create
// --------------------------------------------------------------------------------------
//定义create函数的参数列表和参数类型
const int inArgs_CREATE[]{3,sim_script_arg_int32|sim_script_arg_table,2,sim_script_arg_int32,0,sim_script_arg_float|sim_script_arg_table,2,
};
//create函数的回调函数实现。
/*
当脚本调用指定的函数名称比如creat时CoppeliaSim 会调用对应的回调地址执行回调地址对应的函数就执行了这个函数。在 V-REP 中当用户调用某个 Lua 函数时V-REP 会自动查找相应的 C 回调函数并将其作为参数传递给这个 Lua 函数。这个回调函数即是实现 Lua 函数功能的关键。具体来说在这段代码中变量 inArgs_CREATE 定义了一个名为 simBubble.create 的 Lua 函数的输入参数类型。当用户调用 simBubble.create 函数时V-REP 自动将用户的实际参数传递给与之对应的 C 回调函数即 LUA_CREATE_CALLBACK 函数。
*/
void LUA_CREATE_CALLBACK(SScriptCallBack* cb)
{CScriptFunctionData D;int handle-1;if (D.readDataFromStack(cb-stackID,inArgs_CREATE,inArgs_CREATE[0],nullptr)){std::vectorCScriptFunctionDataItem* inDataD.getInDataPtr();sBubbleRob bubbleRob;handlenextBubbleRobHandle;bubbleRob.handlehandle;bubbleRob.scriptHandlecb-scriptID;bubbleRob.motorHandles[0]inData-at(0).int32Data[0];bubbleRob.motorHandles[1]inData-at(0).int32Data[1];bubbleRob.sensorHandleinData-at(1).int32Data[0];bubbleRob.backRelativeVelocities[0]inData-at(2).floatData[0];bubbleRob.backRelativeVelocities[1]inData-at(2).floatData[1];bubbleRob.runfalse;allBubbleRobs.push_back(bubbleRob);}D.pushOutData(CScriptFunctionDataItem(handle));D.writeDataToStack(cb-stackID);
}
其他同理。
// --------------------------------------------------------------------------------------
// simBubble.stop
// --------------------------------------------------------------------------------------
const int inArgs_STOP[]{1,sim_script_arg_int32,0,
};
/*
0所在的位置是表示其他配置比如参数如果是数组0就表示一个元素还可以设置默认值最小值等。
*/
void LUA_STOP_CALLBACK(SScriptCallBack* cb)
{CScriptFunctionData D;bool successfalse;if (D.readDataFromStack(cb-stackID,inArgs_STOP,inArgs_STOP[0],nullptr)){std::vectorCScriptFunctionDataItem* inDataD.getInDataPtr();int handleinData-at(0).int32Data[0];int indexgetBubbleRobIndexFromHandle(handle);if (index!-1){allBubbleRobs[index].runfalse;simSetJointTargetVelocity(allBubbleRobs[index].motorHandles[0],0.0f);simSetJointTargetVelocity(allBubbleRobs[index].motorHandles[1],0.0f);successtrue;}elsesimSetLastError(nullptr,Invalid BubbleRob handle.);}D.pushOutData(CScriptFunctionDataItem(success));D.writeDataToStack(cb-stackID);
}
// -------------------------------------------------------------------------------------- c自定义实现插件加载
插件的生成过程
1编写插件的simXXX入口函数以及和回调函数有关的回调函数入口函数
2xml文件中声明回调函数参数以及其他信息
3利用python解析xml文件将解析出来的信息生成指定的c代码包括v-rep需要调用的各个回调函数输入输出参数结构体。 为什么要编译为共享库
直接使用插件的头文件和源文件不就可以了吗为什么要编译为共享库呢
因为v-rep后台程序(引擎)最终是通过lua语言的loadPlugin()函数去加载动态库提供给v-rep引擎使用的所以需要把插件的资源文件编译为动态库才能被loadPlugin接口加载。 插件是怎么加载的
1在v-rep ui界面脚本框中使用loadPlugin()加载
2v-rep自动加载 外部接口要怎么在插件中实现 插件中实现的接口怎么使用
1可以在xml文件中实现的可以在UI界面调用
2对于其他的比如普通类中实现的函数是怎么使用的在哪使用
自己编写的插件接口v-rep引擎是不知道的所以只能自己用但是问题loadPlugin加载返回共享库的映射对象之后我们需要在哪里使用这个共享库
难道就只是简单的需要使用哪个插件就在UI界面loadPlugin然后需要哪个接口再一个一个在脚本框中调用吗
v-rep的lua接口加载但是我们自己使用怎么使用
loadPlugin加载插件后插件接口需要在哪里调用由谁(v-rep引擎还是用户)调用
由lua语言loadPlugin加载提供给lua语言脚本使用这个loadPlugin返回的映射对象用于v-rep仿真C中不再需要使用这个loadPlugin返回的映射对象和共享库。 接口要怎么实现才能共给lua语言脚本使用
回调函数以及回调函数入口函数实现规则
这两个函数必须要有输入和输出参数。
回调函数内部实现
void testInit_callback(SScriptCallBack *p)
{addStubsDebugLog(testInit_callback: reading input arguments...);
//打印日志addStubsDebugStackDump(p-stackID);
/*
输入参数栈是指 V-REP 将回调函数的输入参数打包成的一个栈结构。在 V-REP 的插件开发中回调函数的输入参数通过这个栈进行传递。当 V-REP 调用插件的回调函数时它将回调函数需要接收的所有输入参数打包成统一的一个栈并将这个栈的 ID 传递给回调函数。开发者可以通过 V-REP 提供的 API 访问这个栈获取栈中的参数值然后进行相应处理。addStubsDebugStackDump(p-stackID); 这个语句的作用就是将当前回调函数的输入参数栈的所有参数取出来打印到日志中以便开发者在调试时能够查看这些参数的具体值和类型。
*/[[maybe_unused]] const char *cmd simTest.testInit;
/*
定义了一个常量字符串 cmd表示当前回调函数的名称。这个字符串在插件开发中可以用于调试或其他需要使用回调函数名称的操作中。
我们在UI界面中调用的simTest.testInit()就来自这里。
*/testInit_in in_args;if(p){std::memcpy(in_args._, p, sizeof(SScriptCallBack));
/*
这行代码将回调函数的输入参数 p 复制到 in_args 中。因为 in_args 是结构体类型为了方便处理这里使用了内存拷贝的方式将数据赋值给 in_args。
*/}testInit_out out_args;try{// check argument countint numArgs sim::getStackSize(p-stackID);if(numArgs 2)throw sim::exception(not enough arguments);if(numArgs 2)throw sim::exception(too many arguments);// read input arguments from stackif(numArgs 1){addStubsDebugLog(testInit_callback: reading input argument 1 \key\ (std::string)...);try{sim::moveStackItemToTop(p-stackID, 0);readFromStack(p-stackID, (in_args.key));
/*对于第一个参数使用 sim::moveStackItemToTop 将其从栈中移动到栈顶然后调用 readFromStack 函数从栈中读取参数值并将其存储到相应的 in_args 结构体对象中。
从这里可以看出
尽管回调函数入口函数的参数类型是结构体而实际输入是普通类型比如string,int但是readFromStack会自动将普通类型的输入参数值存储到结构体对应的成员对象中。*/}catch(std::exception ex){throw sim::exception(read in arg 1 (key): %s, ex.what());}}if(numArgs 2){addStubsDebugLog(testInit_callback: reading input argument 2 \value\ (int)...);try{sim::moveStackItemToTop(p-stackID, 0);readFromStack(p-stackID, (in_args.value));}catch(std::exception ex){throw sim::exception(read in arg 2 (value): %s, ex.what());}}addStubsDebugLog(testInit_callback: stack content after reading input arguments:);addStubsDebugStackDump(p-stackID);addStubsDebugLog(testInit_callback: clearing stack content after reading input arguments);// clear stacksim::popStackItem(p-stackID, 0);addStubsDebugLog(testInit_callback: calling callback (testInit));simTest_testInit(in_args, out_args);
/*
在这里调用回调函数的入口函数
*/}catch(std::exception ex){sim::setLastError(ex.what());}try{addStubsDebugLog(testInit_callback: writing output arguments...);addStubsDebugStackDump(p-stackID);addStubsDebugLog(testInit_callback: clearing stack content before writing output arguments);// clear stacksim::popStackItem(p-stackID, 0);// write output arguments to stackaddStubsDebugLog(testInit_callback: stack content after writing output arguments:);addStubsDebugStackDump(p-stackID);}catch(std::exception ex){sim::setLastError(ex.what());// clear stacktry { sim::popStackItem(p-stackID, 0); } catch(...) {}}addStubsDebugLog(testInit_callback: finished);
}v-rep输入参数栈
输入参数栈是指 V-REP 将回调函数的输入参数打包成的一个栈结构。在 V-REP 的插件开发中回调函数的输入参数通过这个栈进行传递。当 V-REP 调用插件的回调函数时它将回调函数需要接收的所有输入参数打包成统一的一个栈并将这个栈的 ID 传递给回调函数。开发者可以通过 V-REP 提供的 API 访问这个栈获取栈中的参数值然后进行相应处理。
在 V-REP 插件开发中栈中的每一个元素代表一个输入参数。具体来说这些元素包含了输入参数的类型、名称、值等信息。开发者在回调函数中可以通过 API 访问这些输入参数获取相应的参数值并进行相应的处理。
例如以下代码片段演示了如何从一个输入参数栈中获取一个整数类型的参数值
c int int_param; if (simGetStackIntParameter(p-stackID, 1, int_param)) { // 成功获取了一个整数类型的输入参数值 } else { // 获取整数类型的参数值失败 }
这段代码中simGetStackIntParameter 是 V-REP 提供的一个 API 函数它能够从输入参数栈中获取一个整数类型的参数值并将这个值存储在 int_param 变量中。函数的第一个参数是输入参数栈的 ID第二个参数是要获取的参数在栈中的索引第三个参数是存储参数值的变量指针。 插件中的xml文件的作用
在 V-REP 插件开发中插件中的 XML 文件或插件描述文件主要是用来描述插件的元信息信息包括插件的名称、版本号、作者、描述、图标、依赖关系等等内容。这些信息可以被 V-REP 识别和解析。
在 V-REP 中自定义插件的 callbacks.xml 文件是用来声明插件中所有回调函数的位置和名称的。V-REP 在加载插件时会根据这个文件中的声明找到对应的回调函数并注册它们以便在模拟中执行。
《v-rep从xml文件读取插件信息并注册进入v-rep自己的环境中提供给自己使用》
1使用python解析出回调函数的入口函数然后定义回调函数的入口函数
2从解析出来的命令(回调函数的入口函数)中定义参数的结构体
3将解析出来的各种信息(struct,enum等)转化为C语言
4声明各个回调函数和回调函数的入口函数
void cmd.c_name_callback(SScriptCallBack *p);
SIM_DLLEXPORT void plugin.name_cmd.c_name(cmd.c_in_name *in, cmd.c_out_name *out);void cmd.c_name_callback(SScriptCallBack *p);
这个函数定义了 V-REP 环境中的回调函数。当插件在 V-REP 环境中注册了回调函数后当发生某个事件时V-REP 就会回调对应的这个函数。这个函数的参数是一个指向 SScriptCallBack 结构体的指针在函数中可以使用这个指针来访问回调函数的输入和输出数据等信息。SIM_DLLEXPORT void plugin.name_cmd.c_name(cmd.c_in_name *in, cmd.c_out_name *out);这个函数是插件中回调函数的入口函数(也就是上一个函数被v-rep执行时内部就会执行这个函数)用于将 V-REP 环境中的输入参数转换成插件中处理所需的输入格式并将结果保存在输出参数中。 xml中可以定义很多标签
command--命令/回调函数
struct
enum
xml文件格式解析和配置
plugin: 根元素描述一个插件配置文件 command: 命令元素定义了一个插件命令/回调函数 params: 参数列表包含了这个命令的输入参数 param: 参数元素表示一个参数包含了参数的名称、类型和描述信息
param应该是要包含在params中的。 return: 返回值元素表示命令的返回值 name: 参数名称 type: 参数类型 in和out的参数
在xml中如何指定In的参数和out的参数
command name...description.../descriptionparamsin的参数在这里声明/paramsreturnout的参数在这里声明/return
/command
eg: command namemyTestdescription.../descriptionparamsparam namevalue typeintdescription.../description/param/paramsreturnparam namekey typestringdescription.../description/param param namevalue typeintdescription.../description/param/return/command以上的xml的声明生成c代码应该是
struct myTest_in{SScriptCallBack _;int value;myTest_in();
};struct myTest_out{std::string kay;int value;myTest_out();
}; python解析数据转为c代码的文件是怎么生成的
cmake编译生成
coppeliasim_generate_stubs(stubs_output_path,callback_xml_file,lua_file)
coppeliasim生成模板
这个函数有三个参数。 插件加载出来的模块没有添加的回调函数
回调函数以及回调函数的入口正确生成。
但是loadPlugin之后却没有添加的回调函数
必须要实现onInit()函数在宰割函数中调用registerScriptStuff()
registerScriptStuff()
bool registerScriptStuff()
{try{checkRuntimeVersion();auto dbg sim::getNamedBoolParam(simStubsGen.debug);if(dbg *dbg)sim::enableStackDebug();try{// register varables from enums:
#py for enum in plugin.enums:sim::registerScriptVariable(enum.name, {}, 0);
#py for item in enum.items:sim::registerScriptVariable(enum.name.item.name, boost::lexical_caststd::string(plugin.name.lower()_enum.item_prefixitem.name), 0);
#py endfor
#py endfor// register commands:
#py for cmd in plugin.commands:sim::registerScriptCallbackFunction(cmd.name, cmd.c_name_callback);
#py endfor}catch(std::exception ex){throw sim::exception(Initialization failed (registerScriptItems): %s, ex.what());}}catch(sim::exception ex){sim::addLog(sim_verbosity_errors, ex.what());return false;}return true;
}为什么回调函数中的输出内容在UI界面没有输出 插件中的四个文件
1simXXX.lua
其中只是使用lua语言的loadPlugin加载插件返回插件的映射对象。
local simTest loadPlugin simTest;
(require simTest-typecheck)(simTest)return simTest(require simTest-typecheck)(simTest)
lua语言的函数调用可以不加(),而是---函数名 模块--的方式调用。
所以以上lua语法分两步
1这行代码首先调用 require simTest-typecheck 函数来加载 simTest-typecheck 模块并返回该模块的函数对象。
2然后将 simTest 插件对象作为参数传递给该函数执行插件中定义函数参数类型的检查。如果函数参数类型不正确则会抛出一个类型错误异常。
simXXX-typecheck模块怎么添加的
cmake自动生成。 那么返回的对象是提供给v-rep引擎使用吗
我们在ui界面的脚本输入框使用loadPlugin加载某一个插件时这个loadPlugin函数是不是这个文件里的loadPlugin?
2config.h.in
作用 3license.txt
license.txt 文件的作用在于方便用户查看和了解插件的开源协议以及开发者声明的版权和许可证信息。用户在使用插件时可以通过读取这个文件来了解插件的授权信息从而决定是否使用该插件。
4callbacks.xml
这个文件中只能实现插件中拥有in和out参数的函数。
为什么 封装插件和插件信息对象--Plugin和PluginInfo
PluginInfo的lib成员记录插件(共享库)的加载地址Plugin内部实现loadSimLibrary()API加载共享库返回给PluginInfo的lib。
插件需要的函数入口
SIM_DLLEXPORT int simInit(SSimInit*);
SIM_DLLEXPORT void simCleanup();
SIM_DLLEXPORT void simMsg(SSimMsg*);SIM_DLLEXPORT void simInit_ui();
SIM_DLLEXPORT void simMsg_ui(SSimMsg_ui* info);
SIM_DLLEXPORT void simCleanup_ui();
本质上都是在外部调用去执行Plugin内部实现的函数。
simInit中的主要工作
1加载仿真库
2调用PluginOnInit接口去调用v-rep内部API注册插件信息
simMsg的主要工作
向v-rep核发送信息。 必须具备的三个
SIM_DLLEXPORT int simInit(SSimInit*);
SIM_DLLEXPORT void simCleanup();
SIM_DLLEXPORT void simMsg(SSimMsg*);
作用
其他的
SIM_DLLEXPORT void simInit_ui(); // called immediately after simInit
SIM_DLLEXPORT void simMsg_ui(SSimMsg_ui* info);
SIM_DLLEXPORT void simCleanup_ui(); // called immediately before simCleanup 这些函数 simInit, simMsg, simCleanup, simInit_ui, simMsg_ui, simCleanup_ui 都与 Robotic Simulation Software机器人仿真软件 V-REPVirtual Robot Experimentation Platform相关属于 V-REP 提供的 C/C API 中的一部分。
其中simInit, simMsg, simCleanup 是 V-REP 的核心 API用于控制底层(后台)模拟场景、获取传感器信息、执行动作控制等。这三个函数所属的逻辑单元是 Simulator engine它们提供了模拟引擎的初始化、消息调试等功能。
而 simInit_ui, simMsg_ui, simCleanup_ui 则是 V-REP 提供的 UI API所属的逻辑单元是 User interface components它们提供了与用户界面相关的控制逻辑。
具体来说这些函数的差异在于它们所属的逻辑单元和功能用途
- simInit初始化场景模拟引擎并指定场景文件。 - simMsg向 V-REP 内部发送消息用于调试场景运行状态等。 - simCleanup清理场景模拟引擎并释放相关资源。 - simInit_ui初始化用户界面并加载相关设置。 - simMsg_ui向用户界面发送消息并提供给用户各种反馈和操作结果。 - simCleanup_ui清理用户界面并释放相关资源。 插件内部需要实现的功能
插件对象内部主要实现共享库(插件)加载以及实现插件对象和v-rep核的通信接口。
插件和v-rep交互流程
程序调用simInit等插件入口API-----》调用插件对象的接口----》插件对象的接口再调用v-rep核内部的API和v-rep通信。
1v-rep内部接口simGetPluginInfo设置的Plugin属性
Plugin可设置的5个属性
这里是lua语言版本的
sim.plugininfo_extversionstr-----------Extended version string
sim.plugininfo_builddatestr------------Build date string
sim.plugininfo_extversionint-----------Extended version integer
sim.plugininfo_verbosity---------------Console verbosity. see the various verbosity levels
sim.plugininfo_statusbarverbosity------Status bar verbosity. see the various verbosity levels
- sim.plugininfo_extversionstr 属性是一个扩展版本字符串用于描述插件的版本号。它通常包括主版本号、次版本号、修订版本号和构建编号等信息以方便用户区分插件不同版本之间的差异。
这个属性是真正的插件版本的描述。 - sim.plugininfo_builddatestr 属性是一个构建日期字符串用于描述插件的构建时间信息。通常情况下它包括构建插件的日期和时间以便用户了解插件的构建时期。 - sim.plugininfo_extversionint 属性是一个扩展版本整数用于记录插件的版本号。它通常将主版本号、次版本号、修订版本号和构建编号等信息编码成一个整数便于程序在运行期间比较版本号。
这个版本号描述的是插件版本号编码转换之后的那个整形。 sim.plugininfo_verbosity 和 sim.plugininfo_statusbarverbosity 是V-REP插件系统中用于控制日志输出详细程度的属性这两个属性对应的值定义了在控制台以及状态栏中输出日志信息的级别。
sim.plugininfo_verbosity 的值使用以下的枚举值
- sim_verbosity_pass代表输出级别为通过(Pass)即程序执行中没有出现警告或错误。 - sim_verbosity_infos代表输出级别为信息(Infos)用于程序的运行状态、调试等信息的输出。 - sim_verbosity_warnings代表输出级别为警告(Warnings)用于输出程序中存在的错误可能性或者违反规范的用法等情况的警告信息。 - sim_verbosity_errors代表输出级别为错误(Errors)用于输出程序出现未处理异常或者错误等信息。
sim.plugininfo_statusbarverbosity 的值也使用上述的枚举值定义代表输出日志信息在状态栏中显示的详细程度。 问题