v-rep插件

news2024/10/5 13:04:02

v-rep官网插件汉化教程

官网教程

插件是什么

插件本质上就是遵循一定规范的API编写出来的程序,在v-rep中最终需要编译为动态库。

linux下是libsimXXXX.so;

其中XXXX是插件的名称。 请至少使用4个字符,并且不要使用下划线,因为该插件会被忽略(但是,当插件本身加载一些其他库(例如simExtXXXX_de.dll等语言资源)时,您应该使用下划线。)

插件和v-rep的交互

lua脚本方式加载过程

1,在lua文件中使用loadPlugin()加载插件(动态库文件);

loadPlugin返回映射对象,这个对象包含了插件中实现的变量和函数,通过这个映射对象可以访问插件提供的全局变量和函数。

linux下的simBubble插件:

2,require()函数加载并执行.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 then
        simBubble.start(robHandle) -- start the robot
        local st = sim.getSimulationTime()
        sim.wait(20) -- run for 20 seconds
        simBubble.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::vector<CScriptFunctionDataItem>* inData=D.getInDataPtr();
        sBubbleRob bubbleRob;
        handle=nextBubbleRobHandle++;
        bubbleRob.handle=handle;
        bubbleRob.scriptHandle=cb->scriptID;
        bubbleRob.motorHandles[0]=inData->at(0).int32Data[0];
        bubbleRob.motorHandles[1]=inData->at(0).int32Data[1];
        bubbleRob.sensorHandle=inData->at(1).int32Data[0];
        bubbleRob.backRelativeVelocities[0]=inData->at(2).floatData[0];
        bubbleRob.backRelativeVelocities[1]=inData->at(2).floatData[1];
        bubbleRob.run=false;
        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 success=false;
    if (D.readDataFromStack(cb->stackID,inArgs_STOP,inArgs_STOP[0],nullptr))
    {
        std::vector<CScriptFunctionDataItem>* inData=D.getInDataPtr();
        int handle=inData->at(0).int32Data[0];
        int index=getBubbleRobIndexFromHandle(handle);
        if (index!=-1)
        {
            allBubbleRobs[index].run=false;
            simSetJointTargetVelocity(allBubbleRobs[index].motorHandles[0],0.0f);
            simSetJointTargetVelocity(allBubbleRobs[index].motorHandles[1],0.0f);
            success=true;
        }
        else
            simSetLastError(nullptr,"Invalid BubbleRob handle.");
    }
    D.pushOutData(CScriptFunctionDataItem(success));
    D.writeDataToStack(cb->stackID);
}
// --------------------------------------------------------------------------------------

c++自定义实现插件加载

插件的生成过程

1,编写插件的simXXX入口函数以及和回调函数有关的回调函数入口函数;

2,xml文件中声明回调函数,参数,以及其他信息;

3,利用python解析xml文件,将解析出来的信息生成指定的c++代码,包括v-rep需要调用的各个回调函数,输入,输出参数结构体。

为什么要编译为共享库:

直接使用插件的头文件和源文件不就可以了吗,为什么要编译为共享库呢?

因为v-rep后台程序(引擎)最终是通过lua语言的loadPlugin()函数去加载动态库提供给v-rep引擎使用的,所以需要把插件的资源文件编译为动态库才能被loadPlugin接口加载。

插件是怎么加载的:

1,在v-rep ui界面脚本框中使用loadPlugin()加载;

2,v-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 count

        int 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 stack

        if(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 stack
        sim::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 stack
        sim::popStackItem(p->stackID, 0);


        // write output arguments to stack


        addStubsDebugLog("testInit_callback: stack content after writing output arguments:");
        addStubsDebugStackDump(p->stackID);
    }
    catch(std::exception &ex)
    {
        sim::setLastError(ex.what());
        // clear stack
        try { 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>...</description>
        <params>
          in的参数在这里声明
        </params>
        <return>
		  out的参数在这里声明
		</return>
</command>

eg:

    <command name="myTest">
        <description>...</description>
        <params>
            <param name="value" type="int">
                <description>...</description>
            </param>
        </params>
        <return>
		  <param name="key" type="string">
			<description>...</description>
		  </param >
		  <param name="value" type="int">
			<description>...</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_cast<std::string>(`plugin.name.lower()`_`enum.item_prefix``item.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界面没有输出

插件中的四个文件:

1,simXXX.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?

2,config.h.in

作用:

3,license.txt

`license.txt` 文件的作用在于方便用户查看和了解插件的开源协议,以及开发者声明的版权和许可证信息。用户在使用插件时,可以通过读取这个文件来了解插件的授权信息,从而决定是否使用该插件。
 

4,callbacks.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-REP(Virtual 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通信。

1,v-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` 的值也使用上述的枚举值定义,代表输出日志信息在状态栏中显示的详细程度。


 

问题:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1467741.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

力扣精选100道——外观数列(模拟专题)

外观数列算法题链接 &#x1f6a9;了解题意 该题的下面充分的给你说明了这个题目的意思。 3 3 2 2 2 5 1 我们根据我们正常读的顺序读 俩个3 三个2 一个5 一个1 连起来就是 2 3 3 2 1 5 1 这就是最终输出的字符串。 题目开头说了&#xff0c;我们最初是 1开始读…

c语言经典测试题4

1.题1 #include <stdio.h>//没有break的话&#xff0c;输入什么都会往下一直执行下去&#xff0c;而且default在最后就会全都执行 int main() {char c;int v0 0, v1 0, v2 0;do{switch (c getchar())// 输入ADescriptor{casea:caseA:casee:caseE:casei:caseI:caseo:…

HTTP概要

文章目录 什么是HTTP?URL的结构请求报文结构请求方法GETHEADPOSTPUTDELETETRACEOPTIONSCONNECTPATCH解释 请求头字段 响应报文结构响应状态响应头字段 HTTP会话3次握手无状态协议 什么是HTTP? HTTP&#xff0c;即Hypertext Transfer Protocol(超文本传输协议) 它是一个”请…

有没有哪些适合程序员的副业?

夸克网盘这个软件出来好久了&#xff0c;官方前不久才开通了推广渠道&#xff0c;这就给了我们以此赚钱的机会。具体时间应该是在2022年12月份。 所谓夸克网盘拉新&#xff0c;就是夸克网盘为了抢占市场&#xff0c;与其他网盘竞争对手&#xff08;百度网盘、迅雷网盘等&#…

CVE-2023-44313 Apache ServiceComb Service-Center SSRF 漏洞研究

本次项目基于go语言&#xff08;本人不精通&#xff09;&#xff0c;虽不是java web框架了 &#xff0c;但搭建web服务的框架一些思想理念却是通用的&#xff0c;我们由此可以得到一些蛛丝马迹....... 目录 漏洞简介 漏洞分析 漏洞复现 漏洞简介 Apache ServiceComb Servi…

Python环境下一种简单的基于域自适应迁移学习的轴承故障诊断方法

域自适应是指在源域和目标域之间进行相同的迁移学习任务&#xff0c;由于两个领域的数据分布不一致&#xff0c;源域中存在大量的带标签的样本&#xff0c;目标域则没有&#xff08;或极少&#xff09;带标签的样本。通过这种方式可以将在源域样本中学到的知识迁移到目标域上&a…

com.alibaba.nacos.api.exception.NacosException: Request nacos server failed

问题描述 安装nacos2.0以上版本&#xff0c;启动报错:com.alibaba.nacos.api.exception.NacosException: Request nacos server failed com.alibaba.nacos.api.exception.NacosException: Request nacos server failed: at com.alibaba.nacos.client.naming.remote.gprc.Nami…

[C#]winform基于opencvsharp结合CSRNet算法实现低光图像增强黑暗图片变亮变清晰

【算法介绍】 "Conditional Sequential Modulation for Efficient Global Image Retouching" 是一种图像修饰方法&#xff0c;主要用于对图像进行全局的高效调整。该方法基于深度学习技术&#xff0c;通过引入条件向量来实现对图像特征的调制&#xff0c;以达到改善…

Polyspace静态检测步骤

Polyspace 是一个代码静态分析和验证的工具&#xff0c;隶属于MATLAB&#xff0c;用于检测代码中的错误和缺陷&#xff0c;包括内存泄漏、数组越界、空指针引用等。帮助开发团队提高代码质量&#xff0c;减少软件开发过程中的错误和风险。 1、打开MATLAB R2018b 2、找到Polys…

“从根到叶:深入理解排序数据结构“

一.排序的概念及引用 1.1排序的概念 排序是指将一组数据按照一定的规则重新排列的过程。排序的目的是为了使数据具有有序性&#xff0c;便于查找、插入、删除等操作&#xff0c;提高数据的组织和管理效率。 稳定性是指如果序列中存在相等元素&#xff0c;在排序完成后&#…

【简单明了,一文讲解】数据结构与算法基础入门篇--算法之排序篇

图1. 小林Coding整理图 排序算法是计算机科学中常见的一类算法&#xff0c;用于将一组数据按照一定规则进行排序。 常见的排序算法包括以下几种&#xff1a; 冒泡排序&#xff08;Bubble Sort&#xff09;&#xff1a;通过相邻元素的比较和交换来实现排序&#xff0c;每一轮将最…

GEE必须会教程—邂逅线代中的矩阵(Array类型)

矩阵&#xff0c;一个令人头疼的名字&#xff0c;学过线性代数的友友们想必对矩阵的运算规则烂熟于心&#xff0c;与它延申出来的向量知识曾经让我们深陷其中。矩阵在高级的数据存储中占据着重要的地位。定义字典类型的过程&#xff0c;其实就是寻找key和value关系的过程&#…

OpenCV 4基础篇| OpenCV图像基本操作

目录 1. 图像读取1.1 cv2.imread() 不能读取中文路径和中文名称1.2 cv2.imdecode() 可以读取中文路径和中文名称 2. 图像的显示2.1 openCV显示图像 cv2.imshow()2.2 matplotlib显示图像 plt.imshow() 3. 图像的保存 cv2.imwrite()4. 图像的复制4.1 img.copy()4.2 np.copy()4.3 …

贪婪算法入门指南

想象一下&#xff0c;你在玩一款捡金币的游戏。在这个游戏里&#xff0c;地图中散布着各种大小不一的金币&#xff0c;而你的目标就是尽可能快地收集到最多的金币。你可能会采取一个直观的策略&#xff1a;每次都去捡最近的、看起来最大的金币。这种在每一步都采取局部最优解的…

ONLYOFFICE 桌面编辑器现已更新至v8.0啦

希望你开心&#xff0c;希望你健康&#xff0c;希望你幸福&#xff0c;希望你点赞&#xff01; 最后的最后&#xff0c;关注喵&#xff0c;关注喵&#xff0c;关注喵&#xff0c;佬佬会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我真的…

ETL:数据转换与集成的关键过程

ETL&#xff1a;数据转换与集成的关键过程 在现代数据驱动的世界中&#xff0c;有效地管理和处理数据对于企业的成功至关重要。ETL&#xff08;提取、转换、加载&#xff09;是一种关键的数据处理过程&#xff0c;有助于将数据从源系统提取、清洗、转换并加载到目标系统中&…

【LeetCode-337】打家劫舍III(动态规划)

目录 题目描述 解法1&#xff1a;动态规划 代码实现 题目链接 题目描述 在上次打劫完一条街道之后和一圈房屋后&#xff0c;小偷又发现了一个新的可行窃的地区。这个地区只有一个入口&#xff0c;我们称之为“根”。 除了“根”之外&#xff0c;每栋房子有且只有一个“父“…

华为OD机试真题-虚拟游戏理财-2023年OD统一考试(C卷)---Python3--开源

题目&#xff1a; 考察内容&#xff1a; for if max 代码&#xff1a; """ 题目分析&#xff1a;投资额*回报率投资回报 要在可接受范围内选择最优的投资方式获得最大回报最多投资2个理财产品输入&#xff1a; 产品数int; 总投资额int; 总风险int 产品投资…

[word] 怎么把word表格里的字放在正中间? #职场发展#知识分享#知识分享

怎么把word表格里的字放在正中间&#xff1f; word表格中文字在中间的处理方式如下&#xff1a; 1、在表格中选择需要居中的文字的单元格&#xff0c;具体如下图。 2、全选后&#xff0c;鼠标在工具栏中找到&#xff1a;对齐方式&#xff0c;点击它后面的倒三角&#xff0c;如…

Vue学习之计算属性

模板中的表达式虽然方便&#xff0c;但也只能用来做简单的操作。如果在模板中写太多逻辑&#xff0c;会让模板变得臃肿&#xff0c;难以维护。比如说&#xff0c;我们有这样一个包含嵌套数组的对象&#xff1a; const author reactive({name: John Doe,books: [Vue 2 - Advan…