Carsim高级开发:VS Connect通讯开发指南


前言

为什么要使用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”。
VscSchemaVscField 的有序集合。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开发;

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

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

相关文章

5G消息 x 文旅 | 一站式智慧文旅解决方案

5G消息 x 文旅 | 一站式智慧文旅解决方案 文旅 x 5G 消息将进一步强化资源整合&#xff0c;满足游客服务需求、企业营销需求、政府管理需求&#xff0c;推进文化旅游项目的智慧化、数字化&#xff0c;增强传播力、竞争力和可持续性。5G 消息的“原生入口”、“超强呈现”、“智…

帕金森病的食疗建议

帕金森病&#xff08;PD&#xff09;是一种慢性、进展性的神经退行性疾病&#xff0c;主要影响中老年人。虽然目前尚无法根治&#xff0c;但及早规范治疗可显著改善症状&#xff0c;提高患者的生活质量。饮食调理作为帕金森病综合治疗的重要组成部分&#xff0c;对于维持患者较…

接口测试详解

接口测试详解 本文主要讲软件接口 一、什么是接口&#xff1f;硬件接口&#xff1a;硬件接口指的是硬件提供给外界的一种实体。主要作用是内部数据分离出外 部的沟通方法 目的是&#xff1a;沟通外部来改变内部的数据。如&#xff1a;USB接口&#xff0c;投影仪接口 软件接口…

【CDN】逆天 CDN !BootCDN 向 JS 文件中植入恶意代码

今天在调试代码&#xff0c;突然控制台出现了非常多报错。 这非常可疑&#xff0c;报错指向的域名也证实了这一点。 因为我的 HTML 中只有一个外部开源库&#xff08;qrcode.min.js&#xff09;&#xff0c;因此只有可能是它出现了问题。 我翻看了请求记录&#xff0c;发现这…

【无线感知】【P3】无线感知手势识别-Ubicomp2022论文分享

前言&#xff1a; 本篇主要关于手势识别的方向的,主要参考 北京大学-《无线感知手势识别-Ubicomp2022论文分享》 目录&#xff1a; 技术背景 主要问题&#xff08;异质性问题&#xff09; 感知模型 EDP DPSense 实现效果 一 技术背景 基于WIFI的手势识别在智能家具,以…

ShardingSphere-proxy添加自定义分片规则(踩坑日记)

文章目录 一、新建spring boot项目二、编写代码(1) 新建一个类(2) doSharding方法详解(3) 实际例子 三、增加spi文件&#xff08;很关键&#xff09;四、打包五、把生成的文件放到ext-lib中六、yaml配置&#xff08;怎么用&#xff09;七、测试 版本环境 mysql 5.7.40 sharding…

湘潭大学信息与网络安全复习笔记2(总览)

前面的实验和作业反正已经结束了&#xff0c;现在就是集中火力把剩下的内容复习一遍&#xff0c;这一篇博客的内容主要是参考教学大纲和教学日历 文章目录 教学日历教学大纲 教学日历 总共 12 次课&#xff0c;第一次课是概述&#xff0c;第二次和第三次课是密码学基础&#x…

[渗透测试学习] Runner-HackTheBox

Runner-HackTheBox 信息搜集 nmap扫描端口 nmap -sV -v 10.10.11.13扫描结果如下 PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (Ubuntu Linux; protocol 2.0) 80/tcp open http nginx 1.18.0 (Ubuntu) 8000…

中小制造业工厂要不要上MES系统

MES系统的主要功能包括制造数据管理、计划排产管理、生产调度管理、库存管理、质量管理、人力资源管理、工作中心/设备管理、工具工装管理、采购管理、成本管理、项目看板管理、生产过程控制、底层数据集成分析、上层数据集成分解等。通过这些模块&#xff0c;MES为企业打造一个…

基于springboot实现农产品直卖平台系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现农产品直卖平台系统的设计演示 摘要 计算机网络发展到现在已经好几十年了&#xff0c;在理论上面已经有了很丰富的基础&#xff0c;并且在现实生活中也到处都在使用&#xff0c;可以说&#xff0c;经过几十年的发展&#xff0c;互联网技术已经把地域信息的隔…

快速构建本地RAG聊天机器人:使用LangFlow和Ollama实现无代码开发

基于LangChain的快速RAG应用原型制作方法 还记得构建智能聊天机器人需要数月编码的日子吗&#xff1f; LangChain这样的框架确实简化了开发流程&#xff0c;但对非程序员来说&#xff0c;数百行代码仍然是一道门槛。 有没有更简单的方法呢&#xff1f; 图片由 Ravi Palwe 在…

适用于 macOS 的最佳免费数据恢复软件

升级到 macOS 后&#xff0c;它可以帮助您从 HDD、SSD、存储卡、USB 闪存驱动器、数码相机或其他存储介质设备中完全恢复已删除、格式化或无法访问的数据。 当 macOS Monterey 用户寻找数据恢复解决方案时&#xff0c;免费数据恢复软件始终是一个不错的选择。实际上&#xff0…

Linux基础命令[29]-chown

文章目录 1. chown 命令说明2. chown 命令语法3. chown 命令示例3.1 修改属主3.2 修改属组3.3 修改属主和属组3.4 修改文件夹所属 4. 总结 1. chown 命令说明 chown&#xff1a;更改文件的用户或用户组&#xff0c;需要 root 用户或 sudo 权限的用户执行该命令。基本信息如下&…

Mac M3 Pro 部署Spark-2.3.2 On Hive-3.1.3

mac的配置如下 1、下载安装包 官网 Apache Projects Releases 在search中搜索hadoop、hive spark &#xff1a; Index of /dist/spark/spark-2.3.2 网盘 Hadoop https://pan.baidu.com/s/1p4BXq2mvby2B76lmpiEjnA?pwdr62r 提取码: r62r Hive https://pan.baidu.com/s/…

el-table表头修改文字或者背景颜色,通过header-row-style设置样式

方式一 <el-table :header-cell-style"{text-align: center}" />方式二 <template><el-table :header-cell-style"tableHeaderColor" /> </template> <script> export default {methods: {tableHeaderColor ({row, column…

RabbitMQ实践——交换器(Exchange)绑定交换器

在《RabbitMQ实践——交换器&#xff08;Exchange&#xff09;和绑定&#xff08;Banding&#xff09;》一文中&#xff0c;我们实验了各种交换器。我们可以把交换器看成消息发布的入口&#xff0c;而消息路由规则则是由“绑定关系”&#xff08;Banding&#xff09;来定义&…

小分子水半幅宽检测 低氘水同位素氘检测 富氢水检测

小分子水半幅宽检测 低氘水同位素氘检测 富氢水检测 检测范围: 矿泉水等饮用水 检测概述 小分子团水活化性很强&#xff0c;具有强渗透力&#xff0c;强溶解力&#xff0c;强扩散力。水的含氧量高&#xff0c;能给人体内的组织细胞带来更多的氧。长自来水大分子团核磁共振测得…

【计算机毕业设计】基于springboot的大创管理系统【源码+lw+部署文档】

包含论文源码的压缩包较大&#xff0c;请私信或者加我的绿色小软件获取 免责声明&#xff1a;资料部分来源于合法的互联网渠道收集和整理&#xff0c;部分自己学习积累成果&#xff0c;供大家学习参考与交流。收取的费用仅用于收集和整理资料耗费时间的酬劳。 本人尊重原创作者…

C# TextBox模糊查询及输入提示

在程序中&#xff0c;我们经常会遇到文本框中不知道输入什么内容&#xff0c;这时我们可以在文本框中显示提示词提示用户&#xff1b;或者需要查询某个内容却记不清完整信息&#xff0c;通常可以通过文本框列出与输入词相匹配的信息&#xff0c;帮助用户快速索引信息。 文本框…

外链建设如何进行?

理解dofollow和nofollow链接&#xff0c;所谓dofollow链接&#xff0c;就是可以传递权重到你的网站的链接&#xff0c;这种链接对你的网站排名非常有帮助&#xff0c;这种链接可以推动你的网站在搜索结果中的位置向上爬&#xff0c;但一个网站全是这种有用的链接&#xff0c;反…