CoppeliaSim(Vrep)与VS使用多线程交互

CoppeliaSim(Vrep)与VS使用多线程交互

一. 前言

​ 本文主要内容为在VS中以C++调用Windows提供的API,来实现Vrep与VS交互过程中的多线程效果。详细实现思路及步骤在第三部分中。

二.为什么想使用多线程

​ 实际工程中往往都是多任务的,同时进行外设驱动,定位,PID控制器等,使用UCOS或者FreeRTOS的实时操作系统进行协调处理。而在学习Vrep这一仿真软件到目前为止,都是使用的线性结构程序代码,无法满足后续的实际需求。就开始学习有什么方法能够实现这一点。

三. 具体内容

1. 关于Vrep的thread scirpt

​ 感觉使用Vrep的Lua语言脚本并不是特别方便,之前用过的也只是non-threaded。讲究父子结构树关系,包括设置优先级时也要注意这些限制。搜索了相关资料作些了解吧。对于Lua的“多线程”用协程来描述更妥些。

《Vrep线程之间的切换》

《Vrep脚本的执行顺序》

《vrep中thread scirpt以及simRemoteApi.start()的一点点微小的认识》

​ 至于里面提及的API,官方文档API表单中都能查询到,只需要注意一些输入输出参数的信息并不是很详细全面。

2. 关于在VS中使用多线程

​ 自C++11标准之后,已经提供了"thread.h"专门的线程文件,相关使用介绍,可以看下面两篇博客的介绍。

《C++使用thread类多线程编程》

《C++ 多线程编程之在类中使用多线程(thread)的方法》

​ 这边还有一个C++11标准之前,通过“process.h”,自写仿java的Thread类实现多线程的方法。

《C++ 实现多线程编程(通过process.h)》

​ 而本次使用的则是Windows系统提供的相关API。

《C++ 实现多线程编程(通过Windows提供的API)》

3. 具体步骤详解

3.1 搭建好Vrep三轮小车模型

​ 这里具体步骤就不细说了,熟悉Vrep操作之后算是很简单的操作了。详细可以参考这一篇,我初学时看的《Vrep小车建模——前进和转向》。

CoppeliaSim(Vrep)与VS使用多线程交互_第1张图片

​ 稍有不同的就是添加了两侧驱动轮的转速,并通过框图表显示出来。如何添加可以参考同一作者的这一篇《Vrep小车建模——Lua内嵌脚本》。

3.2 VS上编写相应测试代码

#include
#include
using namespace std;

extern "C" {
#include "extApi.h"
}
int clientID;
int leftvalue;
int rightvalue;

int countLeft = 0;
int countRight = 0;

simxInt LeftMotor;
simxInt RightMotor;

DWORD WINAPI myfun1(LPVOID lpparm);
DWORD WINAPI myfun2(LPVOID lpparm);

int main()
{
	clientID = simxStart("127.0.0.1", 19997, true, true, 5000, 5);
	if (clientID != -1)
	{
		cout << "Success!" << endl;
	}
	else
	{
		cerr << "error" << endl;
	}
	leftvalue = 3;
	rightvalue= 3;
	simxStartSimulation(clientID, simx_opmode_oneshot_wait);
	simxGetObjectHandle(clientID, "LeftMotor", &LeftMotor, simx_opmode_blocking);
	simxGetObjectHandle(clientID, "RightMotor", &RightMotor, simx_opmode_blocking);
	HANDLE h1, h2;
	h1 = CreateThread(NULL, 0, myfun1, NULL, 0, NULL);
	cout << "线程1开始运行\n" << endl;
	h2 = CreateThread(NULL, 0, myfun2, NULL, 0, NULL);
	cout << "线程2开始运行" << endl;
	CloseHandle(h1);
	CloseHandle(h2);

	while (1)
	{
		if (getchar() == 'q')
		{
			simxStopSimulation(clientID, simx_opmode_oneshot);
			simxFinish(clientID);
			return 0;
		}
		else
		{
			Sleep(100);
		}
	}
}

DWORD WINAPI myfun1(LPVOID lpparm)
{
	while (clientID != -1)
	{
		simxSetJointTargetVelocity(clientID, LeftMotor, leftvalue, simx_opmode_oneshot);
		Sleep(10);
		countLeft++;
		if(countLeft == 300)
		{
			rightvalue = -rightvalue;
			countLeft = 0;
		}
	}
	return 0;
}
DWORD WINAPI myfun2(LPVOID lpparm)
{
	while (clientID != -1)
	{
		simxSetJointTargetVelocity(clientID, RightMotor, rightvalue, simx_opmode_oneshot);
		Sleep(10);
		countRight++;
		if (countRight == 300)
		{
			leftvalue = -leftvalue;
			countRight = 0;
		}
	}

	return 0;
}

3.3 运行测试效果

CoppeliaSim(Vrep)与VS使用多线程交互_第2张图片

​ 可以看到小车如同代码程序一样。

DWORD WINAPI myfun1(LPVOID lpparm)
{
	while (clientID != -1)
	{
		simxSetJointTargetVelocity(clientID, LeftMotor, leftvalue, simx_opmode_oneshot);
		Sleep(10);
		countLeft++;
		if(countLeft == 300)
		{
			rightvalue = -rightvalue;
			countLeft = 0;
		}
	}
	return 0;
}

​ 每间隔3000ms,电机转速取反,这边为了测试,能否线程之间对同一数据修改,如同上面代码缩写,在控制左轮的线程中,给右轮转速取反。同样,在控制右轮的线程中,给左轮转速取反。

​ 上面大图中的轮速数据表图不太清楚,下面给一个清晰的。

CoppeliaSim(Vrep)与VS使用多线程交互_第3张图片

​ 可以看到两条红线的变化,基本实现了3000ms同时换向一次。

四.总结

​ 以下面的框架结构,即可实现多任务的效果。

...
int main()
{
	...
	HANDLE h1, h2;
	h1 = CreateThread(NULL, 0, myfun1, NULL, 0, NULL);
    ...
	CloseHandle(h1);
    ...
	while (1)
	{
	}
	return 0;
}

...
DWORD WINAPI myfun1(LPVOID lpparm)
{
	while (1)
	{
		...
		Sleep(10);	
	}
}
...

​ 需要注意的就是目前的设立方法,并没有注重线程的同步和优先级的考虑。意味着,多线程的资源是随机分配的。若想在这两点上也加以限制,可以参考下面两篇博文:

《C++ 线程同步的四种方式》

《VS C++ 线程篇之三设置优先级》

你可能感兴趣的:(c++,经验分享,多线程)