科研自动驾驶物理引擎【免费下载链接】webotsWebots Robot Simulator项目地址https://gitcode.com/gh_mirrors/web/webots点击查看免费下载导读Emitter是 Webots 机器人仿真器中负责数据发送的核心通信节点与Receiver接收端配合即可在多个仿真机器人之间构建单向或双向的无线通信链路。本文以官方参考文档 docs/reference/emitter.md 为骨架结合仓库源码src/webots/nodes/WbEmitter.cpp、src/webots/nodes/WbReceiver.cpp、src/controller/c/emitter.c与 API 测试用例系统讲解 Emitter 的字段语义、发射判定算法、wb_emitter_send等全部 API 函数以及红外通信中的障碍物碰撞检测等底层原理。读完本文你将能够独立配置 Emitter 节点、编写多语言控制器发送数据并理解数据包在仿真引擎内部的完整流转路径。Emitter 节点概览Emitter派生自 Device 和 Solid用于建模射频radio、串口serial或红外infra-red发射器。一个 Emitter 节点必须作为机器人Robot或监督者Supervisor的子节点添加到场景中。Emitter 的核心特性与约束只能发送、不能接收Emitter 只负责发射数据无法直接接收任何数据。单向通信模型两个机器人之间的单向通信需要一个 Emitter 和一个 Receiver双向通信则需要双方各自同时具备 Emitter 和 Receiver。消息绝不发回自身仿真器保证一个机器人的消息永远不会被该机器人自身的 Receiver 接收到。与物理插件通信Emitter 还可以用于与物理插件physics plugin通信详见 physics-plugin.md 与下文专门章节。节点在.wbt世界文件中的典型声明形式如下完整默认字段来自参考文档Emitter { SFString type radio # {radio, serial, infra-red} SFFloat range -1 # {-1, [0, inf)} SFFloat maxRange -1 # {-1, [0, inf)} SFFloat aperture -1 # {-1 ,[0, 2*pi]} SFInt32 channel 0 # [0, inf) SFInt32 baudRate -1 # {-1, [0, inf)} SFInt32 byteSize 8 # [8, inf) SFInt32 bufferSize -1 # {-1, [0, inf)} MFInt32 allowedChannels [ ] # [0, inf) }在仓库的 API 测试世界文件 emitter_receiver_determinism.wbt 中可以看到最简用法每个Robot的 children 里直接放一个空字段的Emitter {}配合controller emitter_receiver_determinism即可运行确定性收发测试。字段语义详解type信号介质类型type决定信号的传播介质可选值为radio默认、serial和infra-redradio与serial信号传输不考虑障碍物属于无遮挡假设的理想化传播模型。从源码结构看这两种类型在WbReceiver::transmitPacket()中直接进入接收队列不会经过碰撞检测详见下文底层实现原理。infra-red信号考虑发射端与接收端之间的潜在障碍物。任何带有已定义boundingObject的实体对象固体、机器人等都可能成为红外通信的障碍物。不过发射或接收机器人自身的结构不会阻挡红外传输——源码中rayCollisionCallback()明确忽略与发射机器人自身的碰撞obstacle-robot() ! t-emittingRobot()时才标记碰撞。在WbEmitter.cpp的updateTransmissionSetup()中type通过WbDataPacket::decodeMediumType()见 src/webots/nodes/utils/WbDataPacket.cpp解析为UNKNOWN / RADIO / SERIAL / INFRA_RED枚举值若传入非法字符串会发出解析警告并回退为RADIO。注意目前引擎对 radio 与 serial 没有实现层面的区别。range发射球半径range表示发射球半径单位米。接收者只有在位于发射球之内时才能收到消息。取值-1默认视为无限范围。range必须是正数或-1WbFieldChecker::resetDoubleIfNonPositiveAndNotDisabled()会校验该约束。若设置了maxRangeupdateRange()WbEmitter.cpp还会强制约束range maxRange当range大于maxRange或为-1无限而maxRange有限时会发出警告并把range重置为maxRange。maxRange运行时可设置的最大值maxRange定义了range的允许最大值上限。它限制了运行期通过wb_emitter_set_range函数可以设置的range值。取值-1默认表示不限无限大。在wb_emitter_set_range的实现src/controller/c/emitter.c中可以看到完整的裁剪逻辑请求-1无限时若maxRange有限则range会被设置为maxRange请求值大于有限maxRange时range被裁剪为maxRange请求值合法且在maxRange内时直接采用请求值。aperture发射锥开口角仅红外aperture是发射锥的开口角单位弧度仅对infra-red类型生效。圆锥顶点位于发射器坐标系原点[0 0 0]锥轴与发射器坐标系的x 轴重合。红外发射器只能向当前位于发射锥之内的接收者发送数据。取值为-1默认视为无限大即信号全向发射。取值范围为[0, 2*pi]updateTransmissionSetup()通过WbFieldChecker::resetDoubleIfNotInRangeWithIncludedBoundsAndNotDisabled()校验。对radio和serial发射器该字段被忽略。下图直观展示了range发射球半径与aperture发射锥角对红外通信的作用范围该图来自 docs/reference/images/emitter_receiver.png在WbReceiver::checkApertureAndRange()src/webots/nodes/WbReceiver.cpp中判定条件包含三层范围检查emitter-range() ! -1.0时计算发射器与接收器的距离平方超过range²即拒绝发射锥检查emitter-aperture() 0.0时计算发射器 x 轴单位向量与发射器指向接收器向量的夹角若大于aperture / 2则拒绝接收锥检查接收器的aperture() 0.0时检查接收器 x 轴与指向发射器方向的夹角是否在接收锥之内对称判定。channel传输通道channel是传输通道标识对红外发射器而言是识别号对射频发射器而言是频率号。通常接收者必须使用与发射者相同的通道才能收到数据。特殊值-1即WB_CHANNEL_BROADCAST允许向所有通道广播消息。通道 0默认值保留给物理插件通信机器人间通信请使用正整数通道。源码中的通道匹配逻辑WbReceiver.cpp为if ((packet-channel() r-channel()) || (packet-channel() WB_CHANNEL_BROADCAST) || (r-channel() WB_CHANNEL_BROADCAST))即通道相同、发射端广播、或接收端广播任一条件满足即可完成配对。baudRate波特率通信速率baudRate表示通信速度单位为比特每秒bit/s。取值为-1默认视为无限速率数据在一个基本时间步内立即从发射器到达接收器。当设置为有限值时数据包按速率排队发送。在WbEmitter.cpp的updateTransmissionSetup()中波特率被换算为每毫秒字节数mByteRate (double)mBaudRate-value() / (double)mByteSize-value() / 1000.0;即byteRate baudRate / byteSize / 1000字节/毫秒。在客户端侧emitter.cemitter_write_request()每个仿真步累计bytes_to_send byte_rate * step_duration只有当队首包大小不超过已累计的字节数时才出队发送从而实现速率限制byte_rate -1.0时则无条件出队立即发送。byteSize每字节位数byteSize表示传输一个字节信息所需的比特数。通常为 8默认值如果使用了控制位则可以更大。取值范围[8, inf)源码中通过WbFieldChecker::resetIntIfLess(this, mByteSize, 8, 8)强制下限为 8。该字段参与波特率到字节速率的换算baudRate / byteSize / 1000。bufferSize发送缓冲区大小bufferSize指定发送缓冲区的容量单位字节。发射器中所有排队数据包的总字节数不能超过该值。取值-1默认表示缓冲区大小不限。当缓冲区已满时wb_emitter_send调用会失败并返回 0。wb_emitter_get_buffer_size返回该字段的当前值。客户端实现emitter.c中入队前会检查size es-buffer_size - es-buffer_used缓冲区不足时直接返回 0。allowedChannels允许使用的通道列表allowedChannels指定发射器被允许发射的通道列表。空列表默认表示不限可自由使用任意通道。若列表非空则当前channel必须包含在该列表中。WbEmitter::isChannelAllowed()WbEmitter.cpp逐项比对当前通道若不在列表中updateChannel()/updateAllowedChannels()会发出解析警告并把channel重置为列表中的第一个元素。客户端调用wb_emitter_set_channel时同样会校验若目标通道不在allowedChannels中会打印错误信息并拒绝修改见 emitter.c。与物理插件通信的特殊配置参考文档特别指出Emitter 节点也可以用于与物理插件通信此时channel必须设为 0默认值强烈建议将baudRate设为-1以获得最快的通信速度type、range和aperture字段将被忽略。在源码中这一机制有直接对应WbReceiver::transmitPacket()WbReceiver.cpp在处理完所有常规接收者后会检查是否存在物理插件接收者WbWorld::instance()-worldInfo()-physicsReceiver()若e-channel() 0且物理接收者存在则通过dataReceived信号把原始数据交给物理插件。Emitter 函数 API 详解参考文档定义了 6 个核心函数C API 声明见 include/controller/c/webots/emitter.h各语言封装见下文表格。wb_emitter_send发送数据包C 语言原型其余语言见下文多语言封装与用法#include webots/emitter.h int wb_emitter_send(WbDeviceTag tag, const void *data, int size);功能与行为将大小为size字节、位于data地址的数据包加入发射器队列。入队的数据包将按baudRate字段规定的速率发送给潜在接收者同时从发射器队列中移除。无论baudRate如何发射器至少需要一个基本时间步才能发出数据包但接收者会立即收到。数据包不会被发送给发射器自身的机器人。返回1表示消息成功放入发送队列返回0表示发送队列已满。队列已满的定义是所有当前排队数据包的字节总和超过bufferSize指定的缓冲区大小。数据包至少 1 个字节。客户端实现emitter.c中data NULL或size 1都会打印错误并返回 0。数据格式自由Emitter/Receiver API 不强制任何数据格式只要发射端与接收端代码约定一致任何用户自定义格式都可以。参考文档给出了两个 C API 示例发送以\0结尾的 ASCII 字符串char message[128]; sprintf(message, hello%d, i); wb_emitter_send(tag, message, strlen(message) 1);发送二进制数据double 数组double array[5] { 3.0, x, y, -1/z, -5.5 }; wb_emitter_send(tag, array, 5 * sizeof(double));wb_emitter_set_channel/wb_emitter_get_channel设置与获取通道C 语言原型#include webots/emitter.h #define WB_CHANNEL_BROADCAST -1 void wb_emitter_set_channel(WbDeviceTag tag, int channel); int wb_emitter_get_channel(WbDeviceTag tag);功能与行为wb_emitter_set_channel允许控制器在运行时改变传输通道目标通道必须包含在allowedChannels中或allowedChannels为空修改后同步更新对应 Emitter 节点的channel字段。正常情况下发射器只能向使用相同通道的接收者发送数据但可以使用特殊的WB_CHANNEL_BROADCAST值向所有通道广播。通过切换通道号一个发射器可以有选择地向不同接收者发送数据。wb_emitter_get_channel返回发射器当前通道号。客户端校验channel -1会打印错误并拒绝设置emitter.c。各语言广播常量CWB_CHANNEL_BROADCAST-1C / Java / PythonEmitter::CHANNEL_BROADCAST面向对象 API 中以 Emitter 类的静态整型常量提供Python 封装中定义为CHANNEL_BROADCAST -1见 lib/controller/python/controller/emitter.pyMATLABWB_CHANNEL_BROADCASTwb_emitter_set_range/wb_emitter_get_range设置与获取范围C 语言原型#include webots/emitter.h void wb_emitter_set_range(WbDeviceTag tag, double range); double wb_emitter_get_range(WbDeviceTag tag);功能与行为wb_emitter_set_range允许控制器在运行时改变传输范围数据包只能到达发射器范围内的接收者。该函数修改对应 Emitter 节点的range字段。如果指定的range参数大于 Emitter 节点的maxRange字段则当前范围被设置为maxRange。wb_emitter_get_range返回发射器当前范围。对两个函数而言值-1都表示无限范围。wb_emitter_get_buffer_size获取发送缓冲区大小C 语言原型#include webots/emitter.h int wb_emitter_get_buffer_size(WbDeviceTag tag);功能与行为返回发送缓冲区大小字节数对应 Emitter 节点的bufferSize字段。缓冲区大小表示发射器队列总共能容纳的最大数据字节数若值为-1则表示不限。当缓冲区满时wb_emitter_send调用将失败并返回 0。多语言封装与用法示例参考文档为每种语言提供了对应的 API 声明与示例。C#include webots/Emitter.hpp namespace webots { class Emitter : public Device { virtual int send(const void *data, int size); enum {CHANNEL_BROADCAST}; virtual void setChannel(int channel); int getChannel() const; // ... } }Pythonfrom controller import Emitter class Emitter (Device): CHANNEL_BROADCAST def send(self, data): def setChannel(self, channel): def getChannel(self): # ...Python 的send函数发送的是字符串。若要向字符串中发送基本数据类型可使用struct模块——该模块执行 Python 值与表示为 Python 字符串的 C 结构体之间的转换。参考文档示例import struct #... message struct.pack(chd,a,45,120.08) emitter.send(message)值得注意的是仓库中的 Python 封装lib/controller/python/controller/emitter.py对send做了进一步的类型兼容扩展除了str和bytes还支持由同类型元素组成的 list/tuple——首元素为float时打包为ddouble、为int时打包为i、为bool时打包为?并自动调用struct.pack生成二进制载荷。Javaimport com.cyberbotics.webots.controller.Emitter; public class Emitter extends Device { public final static int CHANNEL_BROADCAST; public int send(byte[] data); public void setChannel(int channel); public int getChannel(); // ... }Java 的send方法没有size参数因为大小通过data参数隐式传递。参考文档给出了发送与 C 字符串兼容的 Java 字符串示例这样可以在 C/C 控制器中接收String request You are number num \0; try { emitter.send(request.getBytes(US-ASCII)); } catch (java.io.UnsupportedEncodingException e) { System.out.println(e); }MATLABsuccess wb_emitter_send(tag, data) WB_CHANNEL_BROADCAST wb_emitter_set_channel(tag, channel) channel wb_emitter_get_channel(tag) wb_emitter_set_range(tag, range) range wb_emitter_get_range(tag) size wb_emitter_get_buffer_size(tag)MATLAB 中发送字符串需要先转换为无符号整型数组wb_emitter_send(emitter, uint8(Hello World));底层实现原理数据包在仿真引擎中的流转结合仓库源码可以还原 Emitter 发送数据的完整调用链控制器侧入队wb_emitter_send()emitter.c校验参数后创建Packet包含通道号、范围、数据体若缓冲区未满则将其挂入发射器的单链表队列并累加buffer_used。控制器侧限速出队每个控制步emitter_write_request()emitter.c依据byte_rate决定哪些包可以出队并通过C_EMITTER_SEND消息把包的内容通道、范围、大小、数据连同C_EMITTER_SET_RANGE/C_EMITTER_SET_CHANNEL等变更消息一起发送给仿真引擎。引擎侧入队WbEmitter::handleMessage()WbEmitter.cpp解析C_EMITTER_SEND消息将数据封装为WbDataPacket见 src/webots/nodes/utils/WbDataPacket.cpp内部深拷贝数据并记录发射器指针、通道、大小放入mQueue。引擎侧转发WbEmitter::prePhysicsStep()WbEmitter.cpp在每个物理步把队列中所有包依次交给静态方法WbReceiver::transmitPacket()广播给所有启用状态的接收者。接收端匹配与分类WbReceiver::transmitPacket()WbReceiver.cpp按如下条件过滤每个接收者接收者必须处于启用状态mSensor-isEnabled()介质类型必须匹配e-mediumType() r-mediumType()即 radio 只能配 radio、infra-red 只能配 infra-red通道必须匹配相同、发射端广播或接收端广播不能发给发射机器人自身eRobot ! rRobot非红外类型直接加入接收者的mWaitingQueue范围在后续物理步中再校验红外类型则登记到mTransmissionList等待碰撞检测。红外碰撞检测在postPhysicsStep()WbReceiver.cpp中红外包会经过射线碰撞回调rayCollisionCallback()WbReceiver.cpp——利用 ODE 空间检测发射端与接收端连线是否被障碍物阻挡并忽略发射机器人自身的阻挡同时再次执行checkApertureAndRange()校验发射锥、接收锥与距离。信号强度与方向postPhysicsStep()还会为每个收到的包计算发射方向与信号强度。默认无噪声时信号强度按距离平方反比计算signalStrength 1 / (dist * dist)若配置了directionNoise/signalStrengthNoise则叠加高斯噪声见 WbReceiver.cpp。交付控制器接收者在下一个传感器刷新周期把mWaitingQueue移入mReadyQueue供wb_receiver_get_data等接收 API 读取此为 Receiver 侧行为详见 receiver.md。实战配置示例与测试佐证仓库的 API 测试为 Emitter 的各字段用法提供了权威示例。以 emitter_receiver_infra-red.wbt 为例红外发射器机器人1type infra-red、range 1.3、maxRange 2、channel 24。该组合演示了有限range与maxRange同时使用时的配置方式广播红外发射器机器人0type infra-red、channel -1、bufferSize 100演示广播通道与受限缓冲区世界中的WALL障碍物boundingObject指向 Box 几何体专门用于验证红外通信被实体障碍物阻挡的机制接收端机器人3channel 24、bufferSize 120与机器人1的发射器通道配对。对应的控制器 tests/api/controllers/emitter_receiver_infra-red/emitter_receiver_infra-red.c 覆盖了以下典型场景值得作为控制器编程范本参考通过wb_emitter_set_channel()切换通道channel1 1、channel2 7、channel3 24并使用-1广播发送多种载荷类型字符串、double数组4 * sizeof(double)、int数组2 * sizeof(int)构造超过bufferSize的超长消息验证缓冲区溢出处理验证wb_emitter_get_range()/wb_emitter_get_buffer_size()等查询函数的返回值。另一个测试 emitter_receiver_determinism.c 则用最简洁的形式演示了基本用法wb_emitter_send(emitter, message, strlen(message) 1);小结Webots 的Emitter节点是一个功能完整、行为可预测的单向数据发射装置三类介质radio / serial / infra-red中仅红外类型考虑障碍物阻挡并受range与aperture双重几何约束九个字段覆盖了类型、范围、锥角、通道、速率、字节宽度、缓冲区与通道白名单几乎所有约束都可在引擎源码WbFieldChecker系列校验中找到对应实现六个 API 函数send、set/get_channel、set/get_range、get_buffer_size在五种主流语言C/C/Python/Java/MATLAB中均有完整封装底层流转链路控制器入队 → 限速出队 → 引擎转发 → 接收端匹配 → 碰撞与几何判定 → 交付清晰体现了仿真器确定性、可配置、可观测的设计哲学。进一步阅读接收端行为与参数请参考 receiver.mdEmitter 与物理插件的数据通道机制见 physics-plugin.md节点继承关系可查阅 device.md 与 solid.md。赞分享科研自动驾驶物理引擎【免费下载链接】webotsWebots Robot Simulator项目地址https://gitcode.com/gh_mirrors/web/webots点击查看免费下载相关推荐Webots Charger 节点详解机器人无线充电站的建模、能量流动与视觉指示实现Webots Charger 节点详解机器人无线充电站的建模、能量流动与视觉指示实现 导读 本文基于 Webots 官方参考文档 docs/reference科研自动驾驶物理引擎Webots R2022b 版本全解析新机器人、CadShape 节点与云端仿真Webots R2022b 版本全解析新机器人、CadShape 节点与云端仿真 Webots R2022b 是 Webots 机器人仿真器在 2022 年科研自动驾驶物理引擎awesome-sentence-embedding评估框架全解析从SentEval到GLUEawesome sentence embedding评估框架全解析从SentEval到GLUE awesome sentence embedding是一个精心上一篇如何用开源工具箱Snap.Hutao优化你的原神游戏体验下一篇Hyperswitch开源支付编排平台的革命性介绍创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考