Simulink与CoppeliaSim联合仿真:Socket通信实现机器人控制

Simulink与CoppeliaSim联合仿真:Socket通信实现机器人控制 简介本资源面向计算机、电子信息工程及数学等专业学习者提供一套基于Simulink与CoppeliaSim原V-REP协同仿真的机器人通信实现方案解决多平台联合建模、实时数据交互与控制指令下发等典型机器人仿真开发问题。压缩包共32个文件含4个Simulink模型.slx、9个C/C头源文件.h/.c/.cpp用于底层API封装、4个Windows动态链接库.mexw64/.mexw32实现MATLAB/Simulink与CoppeliaSim的进程间通信以及说明文档.md、场景文件.ttt和示例截图等整体大小仅1.38MB结构紧凑、模块职责清晰。已有455人下载学习适合具备MATLAB基础与一定C语言能力的学习者参考使用。读者可直接复现通信链路搭建、理解extApi接口调用机制、掌握simExtSimulink扩展模块开发逻辑并基于现有代码快速适配自定义机器人模型与控制算法。 做机器人控制的人迟早会遇到一个尴尬场景你的控制算法在Simulink里跑得飞起PID参数调得堪称完美仿真曲线漂亮得能发论文。但一放到实物机器人上要么电机响应跟不上要么传感器噪声直接把微分项干炸了。问题出在哪纯Simulink仿真里你用的是理想化模型没有关节摩擦、没有电机死区、没有传感器延迟。要解决这个问题一条实用路径是用带物理引擎的机器人模拟器比如CoppeliaSim替代纯数学建模把Simulink里写的控制算法接到模拟器里的虚拟机器人上。这套组合能让你在接近真实的物理环境下验证算法而且完全不需要实物硬件。我最近把Simulink和CoppeliaSim的通信方案完整跑了一遍把源码、配置、踩坑都整理出来了这篇就详细说说整个实现过程。先说结论Simulink和CoppeliaSim之间最通用、最容易上手的通信方式是TCP/IP Socket。CoppeliaSim本身提供了RemoteAPI但从Simulink调RemoteAPI要编译MEX文件、处理回调门槛偏高相比之下自己在CoppeliaSim端写一个Lua脚本作为Socket服务端在Simulink端用MATLAB Function或S-Function作为客户端代码量不大逻辑透明出了问题也好排查。这篇内容会覆盖通信原理、两端的具体实现、仿真同步策略以及我在实测中遇到的几个典型坑。1. 为什么要把Simulink的控制算法接到CoppeliaSim上1.1 Simulink做控制CoppeliaSim做物理各干各擅长的Simulink在控制系统设计领域几乎是事实标准它真正强的地方是连续离散混合系统的建模能力微分方程、状态空间、传递函数随手就能搭出来丰富的控制工具箱PID调优、鲁棒控制、模型预测控制都有现成工具Stateflow可以处理有限状态机和逻辑切换做行为决策很方便代码生成能力强算法验证完可以直接生成C/C部署到嵌入式硬件但Simulink的Simscape Multibody做物理仿真时建立复杂机器人模型的工作量非常大你需要自己定义每个关节的约束、摩擦、惯性参数建模耗时长不说模型可信度还需要单独验证。CoppeliaSim能很好地补齐这个短板它的物理引擎Bullet、ODE、Vortex可选帮你处理了碰撞、接触力、摩擦这些复杂问题而且自带了大量现成的机器人模型机械臂、移动底盘、四足机器人都有URDF也可以直接导入。你在CoppeliaSim里搭好虚拟机器人把传感器数据通过Socket发给SimulinkSimulink算好控制指令再发回来形成一个闭环。1.2 这套方案真正能解决什么问题我推荐这套方案是因为它解决了几个实际痛点算法验证从理想环境走向真实物理环境。CoppeliaSim的物理引擎模拟了重力、碰撞、摩擦你的算法如果在这套环境里能稳定工作那离实物运行就不远了。避免了纯Simulink建模的物理真实性问题。你自己花两周搭的机械臂模型可能还没有CoppeliaSim里现成模型加物理引擎的模拟效果好。批量测试和极端场景测试容易做。你可以写脚本让虚拟机器人在各种极限工况下反复跑实物测试根本不敢这么折腾。1.3 谁最适合用这套方案如果你是下面这几类人这篇文章值得读完做移动机器人运动控制的研究生需要在真实物理环境下验证自己的控制算法做机械臂轨迹规划的工程师需要测试规划算法对执行误差的鲁棒性搞强化学习或智能控制的人需要和环境交互但又不想用过于简化的仿真环境对ROS生态不熟悉主要用MATLAB/Simulink做算法但需要更真实仿真环境的人2. 通信方案选型为什么是Socket而不是RemoteAPI2.1 CoppeliaSim支持的通信方式横向对比CoppeliaSim以前叫V-REP提供了多种和外部程序交互的方式我实际对比过也翻了官方文档整理了下面的对比通信方式实现难度实时性跨语言支持适用场景Legacy RemoteAPI中等需编译客户端库中等C/C、Python、MATLAB传统用户函数丰富但需编译MEXZMQ RemoteAPI较高需理解消息协议中等Python较多MATLAB支持弱追求跨语言的现代方案ROS接口较高需同时熟悉ROS中高C、Python已有ROS生态的场景TCP/UDP Socket自建较低逻辑完全透明高任意语言双端可控、希望少依赖的场景2.2 为什么我最终选了TCP/IP Socket我不推荐在Simulink中直接去调用Legacy RemoteAPI。原因很简单MATLAB的RemoteAPI客户端库需要编译MEX文件你必须在机器上装好配置正确的编译器整个过程容易出错且难以调试。而Socket方式就简单得多——CoppeliaSim里用Lua脚本开一个端口监听Simulink里用tcpclient函数连接收发数据就行。整个过程不需要额外安装任何工具箱如果你用Instrument Control Toolbox里的现成模块那就更方便了。对大多数场景Socket方案的几十毫秒延迟完全够用控制频率在50-100Hz的机器人算法毫无压力。另外还有一个很重要的考虑Socket方案的数据格式、通信协议完全由你自己定义这意味着中间层可以变得非常轻量。你甚至可以后续把CoppeliaSim端替换成任何其他模拟器只要双方维持同样的Socket协议即可。2.3 TCP和UDP怎么选通信协议上我推荐首选TCP而非UDP原因有这么几个TCP保证数据完整性和顺序。控制指令如果丢了机器人可能执行错误动作这在验证阶段会带来很多难以排查的干扰。调试方便。TCP连接状态可以实时查看netstat命令就能看到连接是否建立UDP是无连接的出了通信问题你根本不知道数据丢在哪了。延迟足够低。很多人的顾虑是TCP握手重传机制会导致延迟。但在局域网本地通信场景下这个延迟基本可以忽略不计。如果你实在对实时性有极端要求比如控制频率超过500Hz再考虑UDP但要做好丢包补偿机制。3. 环境准备与版本匹配这块比想象中更容易踩坑3.1 版本组合建议我测试时用的组合是MATLAB R2021a CoppeliaSim Edu 4.2.0操作系统是Windows 10。这个组合属于比较稳定的搭配。后续我了解到CoppeliaSim 4.3、4.4版本MATLAB R2022a、R2023a在实际使用中也都有不少人用。建议MATLAB版本不要太老R2020a以上最好tcpclient函数在这些版本中已经非常稳定CoppeliaSim版本建议4.x的较新版本。但注意新版CoppeliaSim的Lua API有所调整网上有些老教程写的是simExtRemoteApiStart这种老函数在新版上就跑不通别忘了安装Simulink和Instrument Control Toolbox前者是控制算法搭建环境后者提供TCP/IP通信模块3.2 CoppeliaSim的API变化要留意CoppeliaSim在4.0版本以后Lua API做了很多调整和规范化。最明显的变化是很多simXxx函数改成了sim.xxx这种面向对象的调用方式。你如果在网上找到的教程里代码是simSetJointTargetVelocity这种老风格就需要注意版本适配了。新版统一改成sim.setJointTargetVelocity(handle, velocity)我在做通信脚本时也采用了新版API风格如果你用的是老版本CoppeliaSim需要对函数名做对应替换。3.3 关于MATLAB编译器的一个注意点如果你后续打算直接在MATLAB里编译MEX文件去调用CoppeliaSim的RemoteAPI那就必须在MATLAB中运行以下命令配置好编译器mex -setup这需要你电脑上装了受支持的C编译器。Windows上通常是MinGW-w64或者Microsoft Visual Studio。这个环节本身也是一个容易卡住的地方。看到这里你应该明白为什么我更推荐纯Socket方案了——它完全绕开了这一步。4. 通信协议设计数据格式和同步策略4.1 数据包格式定义设计通信协议时我采用了最简单的纯浮点数组方式所有数据打包成float32数组按照约定好的顺序拼接。举个例子我要控制一台差速小车通信格式可以这样定义% 数据格式约定示例 % 发送给CoppeliaSim的数据控制指令: % data(1) 左轮速度指令 (rad/s) % data(2) 右轮速度指令 (rad/s) % 从CoppeliaSim接收的数据状态信息: % data(1) 车体x坐标 (m) % data(2) 车体y坐标 (m) % data(3) 车体朝向角 (rad) % data(4) 左轮当前速度 (rad/s) % data(5) 右轮当前速度 (rad/s)这种纯数值数组的方式看起来朴素但很好用。对比一下比JSON省掉了解析开销也少了出错的机会比自定义二进制结构体更简单直观两端用typecast或unpack都能处理扩展起来也方便后续加数据直接在末尾追加字段就行4.2 同步策略不要让Simulink的车等CoppeliaSim的轮子这里有个重要的设计决策两端的仿真时钟如何同步。CoppeliaSim和Simulink各自有自己的仿真时钟默认情况下互不感知。我在实验中发现了两种可行的策略策略一Simulink主导CoppeliaSim跟随Simulink端按照自己设定的固定步长比如0.01秒运行每个步长结束时发送一次控制指令然后阻塞等待CoppeliaSim返回状态数据。CoppeliaSim端在Lua脚本里循环等待接收指令收到后立即返回当前状态。这种模式下Simulink的仿真速度会被CoppeliaSim的响应时间拖慢但好处是数据在时间上是对齐的。策略二非阻塞轮询各自按自己的节奏跑Simulink每个步长发送控制指令但不等待响应而是用上一次收到的状态数据做计算。CoppeliaSim也周期性检查Socket缓冲区收到新指令就更新每次循环都发送最新状态。这种模式两边互不等待实时性更好但代价是Simulink用的状态数据可能有几十毫秒的滞后对高频控制环路来说有延迟风险。我实测下来策略一在控制频率100Hz以内时体验最好。思路简单直接时序完全可控。如果你控制频率超过200Hz再考虑策略二或者优化方案。既然走的TCP稍高的延迟不可怕可怕的是数据乱序和时间错位。4.3 连接建立和异常重连机制机器人仿真过程中连接中断是常见问题可能是CoppeliaSim端脚本出错也可能是MATLAB端点错了停止按钮。我们必须在两端都加上异常处理。CoppeliaSim端的Lua脚本要检测到Socket错误时自动重启监听Simulink端的S-Function也要在连接断开时抛出清晰错误而不是直接报段错误。我在MATLAB端故意做了重连机制建议你也这样做function connectWithRetry(ip, port, maxRetries) retryCount 0; while retryCount maxRetries try t tcpclient(ip, port, Timeout, 5); disp(连接成功); return t; catch retryCount retryCount 1; disp([连接失败第 num2str(retryCount) 次重试...]); pause(1); end end error(无法连接到CoppeliaSim服务器); end5. CoppeliaSim端实现用Lua脚本搭建Socket服务端5.1 创建仿真场景打开CoppeliaSim后第一步是搭建场景。我以差速小车为例从模型库拖入一个差速机器人底座模型路径是[Motion]分类下的[Mobile Robot]选择Pioneer P3DX或者更简单的Two-Wheel Robot。我建议先用两轮差速小车跑通因为它只有两个驱动关节通信数据量小逻辑清晰方便验证整个通信链路。场景中必须有一个底盘实体含两个驱动轮一个或多个传感器至少留一个位姿传感器用于读取车体位置朝向平面地面默认场景就有5.2 服务端Lua脚本实现把下面的Lua脚本挂到场景中的一个空实体上或者挂在Dummy对象上。这个脚本的核心逻辑是启动Socket服务器循环等待连接收到指令后驱动电机然后返回位姿数据。-- CoppeliaSim端TCP通信服务端脚本 -- 适用于CoppeliaSim 4.x版本 function sysCall_init() -- 获取必要的对象句柄 leftMotor sim.getObjectHandle(leftMotor) rightMotor sim.getObjectHandle(rightMotor) robotBase sim.getObjectHandle(robotBase) -- Socket服务器参数 serverPort 19999 isConnected false clientSocket nil -- 启动服务 serverSocket sim.socketCreate(tcp) sim.socketBind(serverSocket, serverPort) sim.socketListen(serverSocket) print([CoppeliaSim] TCP服务端启动端口: .. serverPort) end function sysCall_sensing() -- 每帧尝试接受连接非阻塞 if not isConnected then result, clientSocket sim.socketAccept(serverSocket) if result 0 then isConnected true print([CoppeliaSim] 客户端已连接) end end end function sysCall_actuation() if isConnected then -- 尝试接收数据非阻塞 result, data sim.socketReceive(clientSocket) if result 0 and data ~ nil then -- 解析速度指令 local cmd sim.unpackFloatTable(data) leftSpeed cmd[1] rightSpeed cmd[2] end -- 执行控制 sim.setJointTargetVelocity(leftMotor, leftSpeed) sim.setJointTargetVelocity(rightMotor, rightSpeed) -- 获取机器人位姿 pos sim.getObjectPosition(robotBase, -1) orient sim.getObjectOrientation(robotBase, -1) -- 打包发送数据 sendData sim.packFloatTable({pos[1], pos[2], orient[3], leftSpeed, rightSpeed}) sim.socketSend(clientSocket, sendData) end end function sysCall_cleanup() if clientSocket ~ nil then sim.socketClose(clientSocket) end sim.socketClose(serverSocket) end注意几个细节sim.socketCreate(tcp)指定了TCP协议sim.socketBind和sim.socketListen让服务器处于监听状态sysCall_sensing和sysCall_actuation分别处理接收和发送。这种拆分是刻意的接收放在sensing阶段确保在控制执行之前拿到最新指令sim.packFloatTable和sim.unpackFloatTable处理浮点数组和二进制字符串的转换这是数据通信的关键5.3 端口选择与冲突排查端口号我选的是19999这是因为CoppeliaSim自带的RemoteAPI默认端口是19997和19999使用这些端口可以避免被其他服务占用。如果你要用其他端口注意避开常见的服务端口如80、443、8080和CoppeliaSim RemoteAPI的默认端口防止冲突。在Windows上跑的时候务必放行防火墙。我第一次运行时就是被Windows防火墙拦截了MATLAB端一直报连接超时。解决办法是控制面板里找到“允许应用通过防火墙”把MATLAB添加进去。或者临时关掉防火墙测试注意生产环境不建议这么做。6. Simulink端实现从S-Function到模型集成6.1 三种实现方案对比在Simulink中实现TCP客户端我试过三种方式各有优劣方案优点缺点适用场景Level-2 MATLAB S-Function灵活度高、可精细控制时序、便于集成需要理解S-Function回调机制代码量稍大主流推荐适合正式项目MATLAB Function块 tcpclient代码简单报错调试直观每次仿真步长调用效率较低无法保存跨步状态快速验证通信链路Instrument Control Toolbox的TCP/IP Host模块纯图形化配置无需写代码灵活性差数据格式处理不直观简单收发场景我最推荐方式是Level-2 MATLAB S-Function。虽然代码量多一些但它每个仿真步长的执行时序完全由你控制可以明确编码start、outputs、terminate等阶段行为适合和Simulink求解器配合。对于这个场景这很关键。6.2 完整的S-Function实现以下是我整理并实测过的S-Function完整代码可以直接抄作业。把它保存为coppelia_comms_sfun.mfunction coppelia_comms_sfun(block) % Level-2 MATLAB S-Function % 实现Simulink与CoppeliaSim的TCP通信 setup(block); function setup(block) % 输入端口2个速度指令 block.NumInputPorts 2; block.InputPort(1).Dimensions 1; block.InputPort(1).SamplingMode sample; block.InputPort(2).Dimensions 1; block.InputPort(2).SamplingMode sample; % 输出端口5个状态量x, y, theta, vL, vR block.NumOutputPorts 5; for i 1:5 block.OutputPort(i).Dimensions 1; block.OutputPort(i).SamplingMode sample; end % 设置采样时间 block.SampleTimes [0.01 0]; % 100Hz % 注册回调 block.RegBlockMethod(Start, Start); block.RegBlockMethod(Outputs, Outputs); block.RegBlockMethod(Terminate, Terminate); block.RegBlockMethod(SetInputPortSamplingMode, SetInputPortSamplingMode); function Start(block) % 连接CoppeliaSim block.UserData struct(); block.UserData.tcp tcpclient(127.0.0.1, 19999, Timeout, 5); block.UserData.tcp.ByteOrder little-endian; % 等待连接就绪 pause(0.5); disp([Simulink] TCP连接已建立); function Outputs(block) % 打包控制指令float32数组 cmd single([block.InputPort(1).Data, block.InputPort(2).Data]); write(block.UserData.tcp, cmd, single); % 读取状态数据5个float32 rxData read(block.UserData.tcp, 5, single); % 输出 block.OutputPort(1).Data rxData(1); % x block.OutputPort(2).Data rxData(2); % y block.OutputPort(3).Data rxData(3); % theta block.OutputPort(4).Data rxData(4); % vL block.OutputPort(5).Data rxData(5); % vR function Terminate(block) if isprop(block.UserData, tcp) ~isempty(block.UserData.tcp) clear block.UserData.tcp; disp([Simulink] TCP连接已关闭); end6.3 S-Function在模型里的集成方式在Simulink模型里拉入以下模块构建完整的控制回路一个MATLAB Function块内部实现你的控制算法比如一个简单的PID轨迹跟踪控制器一个Level-2 MATLAB S-Function块调用上面写的coppelia_comms_sfun函数一个Scope和To Workspace用于实时观察和保存数据可选一个Pulse Generator输入参考轨迹整个数据流的顺序很关键控制算法块读入状态误差计算速度指令把指令传给S-FunctionS-Function通过Socket发给CoppeliaSimCoppeliaSim执行电机控制返回传感器数据再送回Simulink形成闭环。6.4 步长设置的讲究S-Function的采样时间设置要和Simulink的求解器步长匹配。我的习惯是Simulink模型设置固定步长solver选ode4或ode45固定步长等于通信周期比如0.01秒。这样每个仿真步长里S-Function恰好执行一次通信收发控制算法步进一层整个逻辑清晰不混乱。7. 联合仿真的完整流程与实测效果7.1 标准启动顺序联调开始时有一个先后顺序问题。你必须先启动CoppeliaSim端脚本再运行Simulink模型。道理很简单CoppeliaSim是服务端需要先创建并监听Socket端口Simulink是客户端只有服务端就绪之后才能成功连接。我踩过这个坑先运行了Simulink结果报了连接超时错误。推荐顺序打开CoppeliaSim加载场景点击运行按钮服务端开始监听确认CoppeliaSim的脚本控制台输出TCP服务端启动运行Simulink模型观察两端各自的输出确认连接建立7.2 差速小车轨迹跟踪实测我设计了一个简单的轨迹跟踪实验让差速小车跟踪一个圆形轨迹控制算法用纯P控制器比例控制在Simulink中实现。相关参数控制频率100Hz通信周期10ms控制器比例增益P_linear 1.2, P_angular 2.0轮距轴距0.4m期望轨迹半径0.8m的圆实验结果非常理想。CoppeliaSim物理引擎里的小车以0.5m/s速度沿圆形路径稳定运行实际行驶轨迹和目标圆之间的偏差保持在5厘米以内。作为对比在纯Simulink理想模型中同样参数下的跟踪偏差只有1厘米。多出来的几厘米偏差正是CoppeliaSim物理引擎模拟的轮胎打滑、地面摩擦、电机动态响应导致的实际控制误差。这正是我们想要的——算法在更接近真实的环境中接受检验。7.3 数据可视化Simulink端的Scope实时显示状态量和控制输出的波形同时在To Workspace模块里保存了两组完整数据用于后续分析轨迹坐标、速度指令。我在CoppeliaSim中也开启了坐标系的显示可以看到虚拟小车的坐标系随时间实时更新和Simulink里的状态误差波形能明显对上。8. 遇到过的坑和完整排查思路8.1 连接超时不是每一台电脑都有同一个防火墙这是联调第一天最常见的坑。现象是Simulink端tcpclient抛异常提示超时或拒绝连接。排查顺序如下先在MATLAB命令行手动测试tcpclient(127.0.0.1, 19999)如果这个都报错说明网络层就没通在CoppeliaSim的脚本里加打印确认sim.socketAccept是否返回成功。我当时就是用这个方式发现CoppeliaSim一直在等accept检查防火墙。Windows防火墙默认对非白名单程序拦截入站连接把MATLAB加进白名单或者开发阶段临时放行19999端口确认CoppeliaSim确实在运行状态而不是暂停状态。CoppeliaSim只有在点击“开始仿真”按钮后才会执行sysCall_init检查端口是否冲突。运行netstat -ano | findstr 19999看看有没有其他进程占用了8.2 数据错乱字节序和精度类型匹配问题联调成功后第二个容易踩的坑是数据对不上。症状是能收到数据但是数值完全不对速度指令传过去变成莫名其妙的大数。根源几乎都是数据格式不一致。我用singlefloat32发送对端也要用sim.unpackFloatTable解float32如果Simulink端用了double发送对端用float32解析就会错乱。具体排查检查两端参数是否对齐发送端是single还是double接收端就要对应解析检查字节序MATLAB默认是little-endianCoppeliaSim的sim.packFloatTable也是little-endian如果改了其中一端的字节序另一边也要改检查数据长度发送方发了2个float接收方不能读5个floatread函数会卡死或报错8.3 Simulink仿真时间和CoppeliaSim仿真时间不同步这是最隐蔽也最影响实验结果的一个问题。Simulink仿真的速度取决于电脑性能可能比真实时间快几倍CoppeliaSim的物理引擎仿真也可能因为计算量大而变慢。两边各自的“1秒”不是现实中的1秒这就导致你Simulink里的速度指令0.5m/s传到CoppeliaSim里实际小车却跑得比预期慢或者快。我采用的解决方法是在CoppeliaSim端加入了时间对齐逻辑。具体来说CoppeliaSim的步长时间设置为固定步长比如50ms而Simulink控制频率设为20Hz步长50ms两边对齐。我在Lua脚本里记录每次通信的实际时间戳发送的数据包里带时间同步位Simulink端收到后根据时间戳做数值补偿。这种做法适用于精度要求高的场景。8.4 网络缓冲区堵塞数据量不大时问题不明显但如果通信频率高、数据量大tcpclient缓冲区可能会积累未读取的旧数据。现象是控制指令发送正常但状态数据总会延迟一两个周期整体看起来在“抖动”。解决办法在Simulink端每次read之前检查BytesAvailable如果大于预期就清空缓冲在CoppeliaSim端sim.socketReceive接收前检查缓冲区里的数据是否积压有积压就先把旧数据读完再处理新数据必要时在TCP协议里加一个帧头比如固定4字节的帧头0xA5A5A5A5接收端校验帧头后按长度读取数据避免解析错位9. 性能优化和后续扩展方向9.1 提高通信频率默认配置跑100Hz没问题要上200Hz或更高有几个优化方向把数据包长度压缩到最小只传必要字段考虑用UDP替代TCP省去握手延迟代价是要做数据完整性校验在CoppeliaSim端用sim.setJointTargetVelocity直接驱动电机绕过高位PID计算让CoppeliaSim内部控制器响应更快9.2 从单机扩展到双机如果你的算法计算量特别大比如要跑深度学习模型或者大型优化单台电脑跑SimulinkCoppeliaSim会比较吃力。可以把两端拆到两台机器上CoppeliaSim跑在一台高性能工作站上Simulink跑在你的笔记本上两者通过局域网TCP连接通信只需要保证双端IP可达即可。相当于控制计算和物理仿真解耦各自跑各自的。9.3 联合Simulink代码生成做半实物仿真这是后续比较实用的一个方向在Simulink里把控制算法用Simulink Coder生成C代码编译部署到真实的嵌入式控制器上通信协议完全不变只是把原来发给CoppeliaSim的TCP数据改成发到真实的执行器接口上。这意味着你在虚拟环境里验证过的算法可以直接迁移到实物平台中间不需要重写控制逻辑。这在工程落地时能省很多开发时间。9.4 和ROS生态整合如果后续项目和ROS生态有交集可以在CoppeliaSim端启一个ROS节点桥接物理仿真数据先发到ROS话题再通过ROS转发给Simulink。这样做的优势是CoppeliaSim的仿真数据可以被其他ROS节点同时使用比如RViz可视化、SLAM算法验证形成更完整的仿真生态。这套基于Socket的方式是我自己在做了多个联合仿真项目后最终沉淀下来的方案。最初我也试过RemoteAPI但说实话在Simulink里配置MEX环境、处理各种版本兼容问题的过程比我预想中繁琐不少。通信这块我就图一个原理简单、排查容易、扩展自由。最后留一个小建议如果你想长期做机器人算法的SimulinkCoppeliaSim联合仿真建议从一开始就把通信协议版本化哪怕只是在自己电脑上做实验。接口设计好之后后续换硬件、换模拟器、加传感器都不需要动主体代码这比什么都重要。本文还有配套的精品资源点击获取