文章目录
- 前言
- 一、VS Connect 概念引入
- 二、VS Connect 通讯框架
- 三、Carsim 工程配置
- 1、车辆模型配置
- 2、procedure配置
- 3、Run Control配置
- 4、受控车辆名称配置
- 四、VS Connect Server代码
- 1、打开Sln工程
- 2、代码修改
- 五、VS Connect Client代码
- 1、函数的调用关系
- 2、carsim_variable代码
- 3、VsConnect_demo代码
- 六、Vs Connect联合仿真
- 1、Server代码编译
- 2、运行carsim
- 3、运行Server端
- 4、运行Client端
前言
为什么要使用VS Connect:
联合仿真:VS Connect API 允许在多个仿真软件之间进行同步仿真。这意味着可以在同一时间步内,多个仿真程序共享数据和状态信息,从而实现更复杂的联合仿真场景。例如,CarSim 可以与 TruckSim 或 BikeSim 同步运行,以模拟不同类型车辆在同一交通环境中的相互影响。
分布式仿真:VS Connect API 支持分布式仿真,这意味着仿真程序可以运行在不同的计算机上,通过网络( UDP)进行通信和数据交换。这对于需要大量计算资源的仿真场景特别有用,因为可以利用多台计算机的计算能力来分担仿真负载。
实时通信:通过 UDP 协议,VS Connect API 能够实现低延迟的实时数据通信。这对于需要实时交互和快速响应的仿真应用非常重要,例如实时驾驶模拟器、交通仿真系统等。
关键: carsim求解器与VS Connect方法不同的是,carsim求解器调用方法无法在运行的时候加入时间延迟以控制求解器的运行频率,一旦加入时间延迟将无法正常输出动力学信息。
正常情况下,carsim求解器的运行周期大概为0.0005s,显然我们正常的显卡是无法让仿真软件画面的更新频率达到0.0005s,当然你也可以让carsim以0.0005s的运行频率计算动力学信息,然后仿真软件以0.01s或者其他时间去获取动力学信息并更新仿真动画。Vs Connect已经兼容这种方式,并且支持多个通讯服务。
CARLA官方集成CARSIM的方法,其实就是CARSIM给UE专门开发了一个VehicleSim Dynamics插件,原理就是通过Vs Connect实现;
一、VS Connect 概念引入
名称 | 描述 |
---|---|
VscNode | 表示本地通信端点,并包含多个 VscLink。应用程序可以创建任意数量的 VscNode。 |
VscLink | 表示与远程 VS Connect 节点的通信通道。要建立连接,一个 VscLink 需要与本地的 VscNode 对象关联。一个 VscNode 可以关联多个 VscLink。 |
VscField | 通俗的讲就是要用于存放 carsim 变量参数的结构体,如变量名为“IMP_PCON_BK”,属性为“ADD 0.0”。 |
VscSchema | VscField 的有序集合。schema 描述了发送或接收的数据更新的结构。一个 schema 可以关联多个 VscField。 |
VscUpdateDefinition | 描述将发送哪些数据以及何时发送。VscUpdateDefinition 包括一个 VscSchema(将发送什么)和调度参数(何时发送数据)。 |
VscContract | 两个连接节点之间的协议,描述了要发送的数据以及发送时间。VscContract 将 VscUpdateDefinition 与 VscLink 关联。Contract 是节点之间传输数据的完整描述,包括传输方向、数据结构(Schema)和数据发送的时间表。 |
VscUpdateData | 在单一更新时间(仿真时间)内的一包仿真数据。VS Connect 的主要目的是允许应用程序交换 VscUpdateData 实例中包含的数据。VscUpdateData 的实例与 VscContract 及其关联的 VscSchema 相关联,后者描述了更新中包含的数据的结构。 |
二、VS Connect 通讯框架
三、Carsim 工程配置
1、车辆模型配置
随便选择个车辆模型
2、procedure配置
1)开环的节气门开度控制-油门
2)开环的制动主缸压力控制-刹车
3)开环的方向盘角度控制
4)运行条件选择Run forver
3、Run Control配置
1)选择Transfer to Local Windows Directory
2)选择工作目录,即simfile要保存的地方
4、受控车辆名称配置
车辆名称配置:VSC_VEHICLE_NAME Vs Vehicle 0 ,以便我们客户端定义需要控制的车辆
四、VS Connect Server代码
1、打开Sln工程
1、首先下载Visual Studio(我用的是2022和2019),打开Carsim项目工程路径,如:C:\Program Files (x86)\CarSim2022.1_Data\Extensions\Custom_C\wrapper_live_animation
中的wrapper_live_animation.sln
;
2、代码修改
1)为什么要修改工程?
因为Carsim官方的案例只支持从Carsim输出变量,不支持输入变量到Carsim,因此需要增加接收Client发送过来的输入变量;打开vs_connect_live_animation.cpp
代码进行修改
2)修改Build()函数,在创建Node节点的时候增加ReceiveUpdateCallback回调函数;
VscNode node = msVscApi->Node_Create_UDPIP( mListenHost.c_str() // listenAddress, mListenPort // listenPort, mMaxConnections // maxConnections, VSC_TSM_NONE // requiredTsMode, LinkConnectCallback // linkConnectCallback, LinkDisconnectCallback // linkdisconnectCallback, ContractRequestCallback // contractRequestCallback, ContractCanceledCallback // contractCanceledCallback, SendUpdateCallback // sendUpdateCallback, ReceiveUpdateCallback // receiveUpdateCallback, NULL // pingResultsCallback, &tempResult // out_result);
3)修改ContractRequestCallback()函数,增加接收Client端传输过来的变量,在if ( VSC_ROLE_SENDER != VsLiveAnimation::GetVscApi()->Contract_GetLocalRole(contract) )
条件中增加此部分代码;
//外部传入sLogFunc("Incomming Contract request received... ");//获取Link链接const auto node = VsLiveAnimation::GetVscApi()->Link_GetNode(link);//获取车辆Handleauto veh = (VSEW_VEHICLE_HANDLE)VsLiveAnimation::GetVscApi()->Node_GetAppData(node);if (!veh || !vsew_IsOk(veh)){sLogFunc("Contract cannot be processed because vehicle is not OK. ");retRes = VSC_RES_ERROR_UNAVAILABLE;}else{// Find each solver variable named in the Schema of this contract.auto schema = VsLiveAnimation::GetVscApi()->Contract_GetSchema(contract);const auto numFields = VsLiveAnimation::GetVscApi()->Schema_GetNumFields(schema);retRes = VSC_RES_ERROR_INVALID_DATA; // We'll return this error (rejecting the Contract) if we don't find any solver variables to send.for (int i = 0; i < numFields; ++i){auto field = VsLiveAnimation::GetVscApi()->Schema_GetField(schema, i);const auto dataType = VsLiveAnimation::GetVscApi()->Field_GetDataType(field);const auto sizeInBits = VsLiveAnimation::GetVscApi()->Field_GetElementSizeInBits(field);const auto numElements = VsLiveAnimation::GetVscApi()->Field_GetNumElements(field);// We only support fields that are a single 64-bit floating point value. Ignore others:if (VSC_DATATYPE_FLOAT == dataType&& 64 == sizeInBits&& 1 == numElements){//获取Client发送过来的变量信息const auto objectName = VsLiveAnimation::GetVscApi()->Field_GetObjectName(field);const auto propertyName = VsLiveAnimation::GetVscApi()->Field_GetPropertyName(field);const auto Parameters = VsLiveAnimation::GetVscApi()->Field_GetParams(field);// 将const char* 转换为std::stringstring parametersString(Parameters);// 使用std::stringstream来提取数字部分stringstream ss(parametersString);string command;double Parameters_double;// 读取第一个字符串(例如 "ADD")ss >> command;// 读取第二个字符串(数字部分)ss >> Parameters_double;//添加变量到carsim importvsew_Import_Add3(veh, propertyName, Parameters_double, FALSE, "REPLACE", VSEW_IVA_DEFAULT, VSEW_IVCO_DEFAULT);const auto varId = vsew_Import_GetId(veh, propertyName);if (varId >=0){ cout << endl;cout << "Add CARSIM IMPORT VARIABLE: "<< propertyName << " SUCCESS" << endl;}else {cout << endl;cout << "CAN NOT ADD VARIABLE: " << propertyName << ",PLEASE CHECK THE RIGHT FORMAT <ADD 0>" << endl;}}}retRes = VSC_RES_OK; // Returning "OK" accepts this Contract request.}
4)增加ReceiveUpdateCallback()函数,用于周期地将变量值传入Carsim(可以在SendUpdateCallback()下方的空白处加入次函数);
VscResult ReceiveUpdateCallback( const VscLink link, const VscContract contract, const VscRecord out_data)
{VscResult retRes = VSC_RES_UNDEFINED;if (VSC_ROLE_SENDER != VsLiveAnimation::GetVscApi()->Contract_GetLocalRole(contract)){const auto node = VsLiveAnimation::GetVscApi()->Link_GetNode(link);auto veh = (VSEW_VEHICLE_HANDLE)VsLiveAnimation::GetVscApi()->Node_GetAppData(node);if (!veh || !vsew_IsOk(veh)){sLogFunc("Contract cannot be processed because vehicle is not OK. ");retRes = VSC_RES_ERROR_UNAVAILABLE;}else{// Find each solver variable named in the Schema of this contract.auto schema = VsLiveAnimation::GetVscApi()->Contract_GetSchema(contract);const auto numFields = VsLiveAnimation::GetVscApi()->Schema_GetNumFields(schema);retRes = VSC_RES_ERROR_INVALID_DATA; // We'll return this error (rejecting the Contract) if we don't find any solver variables to send.for (int i = 0; i < numFields; ++i){auto field = VsLiveAnimation::GetVscApi()->Schema_GetField(schema, i);const auto dataType = VsLiveAnimation::GetVscApi()->Field_GetDataType(field);const auto sizeInBits = VsLiveAnimation::GetVscApi()->Field_GetElementSizeInBits(field);const auto numElements = VsLiveAnimation::GetVscApi()->Field_GetNumElements(field);// We only support fields that are a single 64-bit floating point value. Ignore others:if (VSC_DATATYPE_FLOAT == dataType&& 64 == sizeInBits&& 1 == numElements){const auto propertyName = VsLiveAnimation::GetVscApi()->Field_GetPropertyName(field);double* fieldData = (double*)VsLiveAnimation::GetVscApi()->Record_GetFieldValue(out_data, i);//get carsim variable idconst auto varId = vsew_Import_GetId(veh, propertyName);if (varId >= 0){//set init import valuevsew_Import_SetValue(veh, varId, *fieldData);}}}retRes = VSC_RES_OK; // Returning "OK" accepts this Contract request.}}return retRes;
}
VS Connect Server就加这部分代码。
五、VS Connect Client代码
1、函数的调用关系
代码已上传资源,carsim vs-connect-client代码
2、carsim_variable代码
1)这里就是用来实现carsim变量定义,carsim输入变量请求,carsim输出变量获取;
2)Field变量定义的规则
incoming
outgoing
import ctypes
from ctypes import *import VsConnectAPIvscapi = VsConnectAPI.vsc_dll.VsConnectApi_Get # VsConnectApi_GetDefaultvscapi.argtypes=[ctypes.c_int]
vscapi.restype = ctypes.POINTER(VsConnectAPI.Vsc_API)api_ver3 = vscapi(3)
api_ver3_contents = api_ver3.contentsdef StrToChar(string):string_utf8 = string.encode('UTF-8')string_buffer = ctypes.create_string_buffer(string_utf8)return ctypes.cast(string_buffer, c_char_p)def ResetData():global gxglobal gyglobal gzglobal gpitchglobal gyawglobal grollref_x = ctypes.POINTER(ctypes.c_double)api_ver3_contents.InvalidateDouble(ref_x(ctypes.c_double(gx)))ref_y = ctypes.POINTER(ctypes.c_double)api_ver3_contents.InvalidateDouble(ref_y(ctypes.c_double(gy)))ref_z = ctypes.POINTER(ctypes.c_double)api_ver3_contents.InvalidateDouble(ref_z(ctypes.c_double(gz)))ref_pitch = ctypes.POINTER(ctypes.c_double)api_ver3_contents.InvalidateDouble(ref_pitch(ctypes.c_double(gpitch)))ref_yaw = ctypes.POINTER(ctypes.c_double)api_ver3_contents.InvalidateDouble(ref_yaw(ctypes.c_double(gyaw)))ref_roll = ctypes.POINTER(ctypes.c_double)api_ver3_contents.InvalidateDouble(ref_roll(ctypes.c_double(gyaw)))def SendUpdate(out_data):# IMP_THROTTLE_ENGINEfieldData = ctypes.cast(api_ver3_contents.RecordGetFieldValue(out_data, 0), ctypes.POINTER(ctypes.c_double))fieldData[0] = 0.1fieldData1 = ctypes.cast(api_ver3_contents.RecordGetFieldValue(out_data, 1), ctypes.POINTER(ctypes.c_double))fieldData1[0] = 0def ReceiveUpdate(incomingData):global gxglobal gyglobal gzglobal gpitchglobal gyawglobal grollgx = ((ctypes.cast(api_ver3_contents.RecordGetFieldValue(incomingData, 0), ctypes.POINTER(ctypes.c_double))).contents).value # return pointer doublegy = ((ctypes.cast(api_ver3_contents.RecordGetFieldValue(incomingData, 1), ctypes.POINTER(ctypes.c_double))).contents).value # return pointer doublegz = ((ctypes.cast(api_ver3_contents.RecordGetFieldValue(incomingData, 2), ctypes.POINTER(ctypes.c_double))).contents).value # return pointer doublegpitch = ((ctypes.cast(api_ver3_contents.RecordGetFieldValue(incomingData, 3), ctypes.POINTER(ctypes.c_double))).contents).value # return pointer doublegyaw = ((ctypes.cast(api_ver3_contents.RecordGetFieldValue(incomingData, 4), ctypes.POINTER(ctypes.c_double))).contents).value # return pointer doublegroll = ((ctypes.cast(api_ver3_contents.RecordGetFieldValue(incomingData, 5), ctypes.POINTER(ctypes.c_double))).contents).value # return pointer doubledef PrintStatementWhenConnected():print("Dist x: %.2f" % gx, end=" ") if api_ver3_contents.IsValidDouble(gx) \else print("Dist x:?")print("Dist y: %.2f" % gy, end=" ") if api_ver3_contents.IsValidDouble(gy) \else print("Dist y:?")print("Dist z: %.2f" % gz, end=" ") if api_ver3_contents.IsValidDouble(gz) \else print("Dist z:?")print("pitch: %.2f" % gpitch, end=" ") if api_ver3_contents.IsValidDouble(gpitch) \else print("pitch:?")print("yaw: %.2f" % gyaw) if api_ver3_contents.IsValidDouble(gyaw) \else print("yaw:?")print("roll: %.2f" % groll) if api_ver3_contents.IsValidDouble(groll) \else print("roll:?")# define variables
gx = 0.0
gy = 0.0
gz = 0.0gpitch = 0.0
gyaw = 0.0
groll = 0.0#定义Carsim输出变量
incoming_variables = [{"objectName": StrToChar("Vs Vehicle 0"), "propertyName": StrToChar("Xo"), "propertyParam": StrToChar("")},{"objectName": StrToChar("Vs Vehicle 0"), "propertyName": StrToChar("Yo"), "propertyParam": StrToChar("")},{"objectName": StrToChar("Vs Vehicle 0"), "propertyName": StrToChar("Zo"), "propertyParam": StrToChar("")},{"objectName": StrToChar("Vs Vehicle 0"), "propertyName": StrToChar("pitch"), "propertyParam": StrToChar("")},{"objectName": StrToChar("Vs Vehicle 0"), "propertyName": StrToChar("Yaw"), "propertyParam": StrToChar("")},{"objectName": StrToChar("Vs Vehicle 0"), "propertyName": StrToChar("roll"), "propertyParam": StrToChar("")},
]#定义Carsim输入变量
outgoing_variables = [{"objectName": StrToChar("Vs Vehicle 0"), "propertyName": StrToChar("IMP_THROTTLE_ENGINE"), "propertyParam": StrToChar("ADD 0.0")},{"objectName": StrToChar("Vs Vehicle 0"), "propertyName": StrToChar("IMP_PCON_BK"), "propertyParam": StrToChar("ADD 0.0")}
]
3、VsConnect_demo代码
1)这里就是client端的主代码,具体作用请查看《二、VS Connect 通讯框架》
import sys
import platform
import ctypes
from ctypes import *
import timeimport VsConnectAPI
from VsConnectAPI import *
import carsim_variablecurrent_os = platform.system()
if (current_os == "Linux"):import termiosimport selectimport atexit# save the terminal settingsfd = sys.stdin.fileno()new_term = termios.tcgetattr(fd)old_term = termios.tcgetattr(fd)# new terminal setting unbufferednew_term[3] = (new_term[3] & ~termios.ICANON & ~termios.ECHO)# switch to normal terminaldef set_normal_term():termios.tcsetattr(fd, termios.TCSAFLUSH, old_term)# switch to unbuffered terminaldef set_curses_term():termios.tcsetattr(fd, termios.TCSAFLUSH, new_term)def kbhit():dr,dw,de = select.select([sys.stdin], [], [], 0)return dr != []def getch():return sys.stdin.read(1).encode('utf-8')else:import msvcrtdef kbhit():return msvcrt.kbhit()def getch():return msvcrt.getch()gWantConnection = True
gQuit = Falseif (current_os == "Linux"):import ctypes.utilpathlib = ctypes.util.find_library("c")libc = ctypes.cdll.LoadLibrary(pathlib)vsprintf = libc.vsprintf
else:vsprintf = ctypes.cdll.msvcrt.vsprintfdef logcallback_fnc(loglevel, node, link, contract, format, argptr):logPrefix = ""byteString = create_string_buffer(4096)realString = ""if (loglevel == VsConnectAPI.VscLogLevel.VSC_LOG_ERROR.value):logPrefix = "ERROR"elif (loglevel == VsConnectAPI.VscLogLevel.VSC_LOG_WARNING.value):logPrefix = "WARNING"else:logPrefix = "Log"byteString = "VS Connect " + logPrefixrealString += byteString.value.decode("utf-8")if (node or link or contract):realString += ","if (node):byteString = " N-" + str(hex(ctypes.addressof(node)))realString += byteString.value.decode("utf-8")if (link):byteString = " L-" + str(hex(ctypes.addressof(link)))realString += byteString.value.decode("utf-8")if (contract):byteString = " C-" + str(hex(ctypes.addressof(contract)))realString += byteString.value.decode("utf-8")realString += ": "# python casted format and argptr to ints. recast to c_void_pvsprintf(byteString, ctypes.cast(format, c_void_p), ctypes.cast(argptr, c_void_p))realString += byteString.value.decode("utf-8")print(realString)return len(realString)def ProcessKeyboardInput():if kbhit():pressedKey = getch()global gWantConnectionglobal gQuitif (pressedKey == b'q') or (pressedKey == b'Q'):gWantConnection = FalsegQuit = Trueelif (pressedKey == b'd') or (pressedKey == b'D'):gWantConnection = Falseelif (pressedKey == b'c') or (pressedKey == b'C'):gWantConnection = Trueelse:print("Unknown command.\n")print("Press C to connect, D to disconnect, Q to quit.\n")@CFUNCTYPE(ctypes.c_int, ctypes.POINTER(VsConnectAPI.VscLink), ctypes.POINTER(VsConnectAPI.VscContract), ctypes.POINTER(VsConnectAPI.VscRecord))
def sendupdatecallback_fnc(link, contract, out_data):if __debug__:pass# schema = api_ver3_contents.ContractGetSchema(contract) # check this# field = api_ver3_contents.SchemaGetField(schema, 0)# assert (1 == api_ver3_contents.SchemaGetNumFields(schema))# assert (1 == api_ver3_contents.FieldGetDataTypes(field))# assert (1 == api_ver3_contents.FieldGetNumElements(field))carsim_variable.SendUpdate(out_data)return int(VsConnectAPI.VscResult.VSC_RES_OK)@CFUNCTYPE(ctypes.c_int, ctypes.POINTER(VsConnectAPI.VscLink), ctypes.POINTER(VsConnectAPI.VscContract), ctypes.POINTER(VsConnectAPI.VscRecord))
def receiveupdatecallback_fnc(link, contract, incomingData):if __debug__:pass# schema = api_ver3_contents.ContractGetSchema(contract)# assert (2 == api_ver3_contents.SchemaGetNumFields(schema))# assert (1 == api_ver3_contents.FieldGetDataTypes(api_ver3_contents.SchemaGetField(schema, 0)))# assert (1 == api_ver3_contents.FieldGetNumElements(api_ver3_contents.SchemaGetField(schema, 0)))# assert (1 == api_ver3_contents.FieldGetDataTypes(api_ver3_contents.SchemaGetField(schema, 1)))# assert (1 == api_ver3_contents.FieldGetNumElements(api_ver3_contents.SchemaGetField(schema, 1)))carsim_variable.ReceiveUpdate(incomingData)return int(VsConnectAPI.VscResult.VSC_RES_OK)def get_VsConnectApi():# accessing api_ver3vscapi = VsConnectAPI.vsc_dll.VsConnectApi_Get # VsConnectApi_GetDefaultvscapi.argtypes = [ctypes.c_int]vscapi.restype = ctypes.POINTER(VsConnectAPI.Vsc_API)# initialize the VS connect library.api_ver3 = vscapi(3)api_ver3_contents = api_ver3.contentsreturn api_ver3_contentsdef create_link(address, portnum):address_buf = address.encode('UTF-8')address_char = ctypes.cast(address_buf, c_char_p)portnum_int = ctypes.c_int(portnum)glink = api_ver3_contents.LinkCreateUDPIP(address_char, portnum_int, cast(None, ctypes.POINTER(c_int)))return glinkdef create_SchemaInitField(variables):Schema = api_ver3_contents.SchemaCreate((len(variables)))for i, variable in enumerate(variables):api_ver3_contents.SchemaInitField(Schema, i, 1, 64, 1, variable.get("objectName"), variable.get("propertyName"), variable.get("propertyParam"), 0, 0, 0)return Schemadef create_IncomingContract(glink, Schema, UpdatePeriod_ms):to_c_double= ctypes.c_doubleUpdatePeriod = to_c_double(UpdatePeriod_ms)UpdateDef = api_ver3_contents.UpdateDefinitionCreate(Schema, 1, UpdatePeriod) #dfefind update periodapi_ver3_contents.LinkCreateIncomingContract(glink, UpdateDef, receiveupdatecallback_fnc, 0, -1, None)return UpdateDefdef create_OutgoingContract(glink, Schema, UpdatePeriod_ms):to_c_double= ctypes.c_doubleUpdatePeriod = to_c_double(UpdatePeriod_ms)UpdateDef = api_ver3_contents.UpdateDefinitionCreate(Schema, 1, UpdatePeriod) #dfefind update periodapi_ver3_contents.LinkCreateOutgoingContract(glink, UpdateDef, sendupdatecallback_fnc, 0, -1, None)return UpdateDefdef release_DataHandle(Schema, UpdateDef):ref_Schema = ctypes.POINTER(ctypes.POINTER(VsConnectAPI.VscSchema))ref_UpdateDef = ctypes.POINTER(ctypes.POINTER(VsConnectAPI.VscUpdateDefinition))api_ver3_contents.SchemaHandleRelease(ref_Schema(Schema))api_ver3_contents.UpdateDefinitionHandleRelease(ref_UpdateDef(UpdateDef))def sync_LinkConnect(node, glink):#If it is not synchronized, synchronize itif ((VsConnectAPI.VscConnectionStatus.VSC_CONNSTAT_UNCONNECTED.value == connStat) and gWantConnection):res = api_ver3_contents.LinkConnectAsync(node, glink)res_val = api_ver3_contents.DescribeResult(res)print('Initiating connection: %s' % res_val.decode("utf-8"))elif (((VsConnectAPI.VscConnectionStatus.VSC_CONNSTAT_CONNECTED.value == connStat) and not gWantConnection) or \(( VsConnectAPI.VscConnectionStatus.VSC_CONNSTAT_CONNECTING.value == connStat) and not gWantConnection)):res = api_ver3_contents.LinkDisconnect(glink)print("Initiating disconnection: %s", api_ver3_contents.DescribeResult(res))def run_NodeService(localSimTime):localSimTimeDouble = ctypes.c_doublelocalSimTimeInput = localSimTimeDouble(localSimTime)timeDilationDouble = ctypes.c_doubletimeDilation = timeDilationDouble(1.0)processEventBool = ctypes.c_boolprocessEventInput = processEventBool(True)api_ver3_contents.NodeService(node, localSimTimeInput, timeDilation, processEventInput)def release_NetWorkHandle(glink, node):ref_glink = ctypes.POINTER(ctypes.POINTER(VsConnectAPI.VscLink))ref_node = ctypes.POINTER(ctypes.POINTER(VsConnectAPI.VscNode))api_ver3_contents.LinkHandleRelease(ref_glink(glink))api_ver3_contents.NodeHandleRelease(ref_node(node))api_ver3_contents.ShutDown()# main start here...api_ver3_contents = get_VsConnectApi()# Set logging function
VsConnectAPI.SetLogFuncPtr(logcallback_fnc)api_ver3_contents.Init()node = api_ver3_contents.NodeCreateUDPIP( None, #None则自动选择IPv4 ip0, #0则自动通过GetDefaultListenPort()获取-1,0, cast(None, VscLinkConnectedFunc_t), cast(None, VscLinkDisconnectedFunc_t), cast(None, VscProcessContractRequestFunc_t), cast(None, VscContractCanceledFunc_t), sendupdatecallback_fnc, receiveupdatecallback_fnc, cast(None, VscPingResultFunc_t), cast(None, ctypes.POINTER(c_int)))glink = create_link("127.0.0.1", 4380)update_period = 50# this can be loop?
incomingSchema = create_SchemaInitField(carsim_variable.incoming_variables)
incomingUpdateDef = create_IncomingContract(glink, incomingSchema, update_period)
release_DataHandle(incomingSchema, incomingUpdateDef)# now create outgoing contract
# this can be loop?
outgoingSchema = create_SchemaInitField(carsim_variable.outgoing_variables)
outgoingUpdateDef = create_OutgoingContract(glink, outgoingSchema, update_period)
release_DataHandle(outgoingSchema, outgoingUpdateDef)print("Press C to connect, D to disconnect, or Q to quit.")# carsim.ResetData()timeStep = update_period / 1000
timeStepCount = 0
localSimTime = 0.0if (current_os == "Linux"):atexit.register(set_normal_term)set_curses_term()# # while statement will wrap the following statements
while (not gQuit):timeStepCount += 1connStat = api_ver3_contents.LinkGetConnectionStatus(glink)#sync link connect sync_LinkConnect(node, glink)#运行NodeService,数据收发/回调参数处理run_NodeService(localSimTime)if (0 == timeStepCount % 20): # reduce output to every nth iterationprint("%.2f" % localSimTime)if (connStat == VsConnectAPI.VscConnectionStatus.VSC_CONNSTAT_UNCONNECTED.value):print("Disconnected ")elif (connStat == VsConnectAPI.VscConnectionStatus.VSC_CONNSTAT_CONNECTING.value):print("Connecting ")elif (connStat == VsConnectAPI.VscConnectionStatus.VSC_CONNSTAT_CONNECTED.value):# print("Connected. ")carsim_variable.PrintStatementWhenConnected()elif (connStat == VsConnectAPI.VscConnectionStatus.VSC_CONNSTAT_ERROR.value):print("ERROR ")elif (connStat == VsConnectAPI.VscConnectionStatus.VSC_CONNSTAT_DISCONNECTING.value):print("Disconnectcing ")else:print("************** ")# a primative timing mechanism. Should be used with this example only.time.sleep(timeStep)localSimTime += timeStepProcessKeyboardInput()print("Program exiting, disconnecting link (if it's connected).")
api_ver3_contents.LinkDisconnect(glink)while (VsConnectAPI.VscConnectionStatus.VSC_CONNSTAT_UNCONNECTED.value != api_ver3_contents.LinkGetConnectionStatus(glink)):print(".")api_ver3_contents.NodeService(node, api_ver3_contents.GetInvalidSimtime(), 1, True)release_NetWorkHandle(glink, node)
六、Vs Connect联合仿真
1、Server代码编译
编译之后有个wrapper_live_animation_Release_x64.exe
2、运行carsim
3、运行Server端
.\wrapper_live_animation_Release_x64.exe “C:\Program Files (x86)\CarSim2022.1_Data\simfile.sim” -host “127.0.0.1” -port 4380
IP 和端口号都在Client代码中定义了
运行Server之后,显示连接数量为0
4、运行Client端
成功输出我定义的变量,哗啦啦的!
综上,完成Carsim Vs Connect demo开发;