Simula Arduino库:面向机器人开发的行为树嵌入式框架

张开发
2026/4/9 9:17:20 15 分钟阅读

分享文章

Simula Arduino库:面向机器人开发的行为树嵌入式框架
1. CRC Simula Arduino IDE 库概述CRC Simula Arduino IDE Library 是专为 Chicago Robotics 公司推出的 Simula 系列嵌入式开发板设计的官方支持库。该库并非通用型 CRC循环冗余校验算法实现其名称中的 “CRC” 实为 “Chicago Robotics Corporation” 的缩写而非数据校验术语——这一命名易引发歧义需在工程实践中首先厘清。Simula 板定位为面向机器人控制与智能硬件原型开发的中阶教学/研发平台硬件基于 ARM Cortex-M4 内核典型如 NXP i.MX RT1062 或 ST STM32H743集成双核异构处理能力、高精度定时器、多路 PWM 输出、CAN FD 接口、工业级 ADC/DAC 及丰富的 GPIO 复用资源。本库的核心价值在于将底层硬件抽象为可组合、可复用、可验证的行为模块显著降低运动控制、传感器融合与自主决策逻辑的开发门槛。其技术演进路径清晰体现从“外设驱动层”向“控制逻辑框架层”的跃迁早期版本聚焦于 GPIO、UART、I2C、SPI、ADC、PWM 等基础外设的 Arduino 风格封装当前稳定版v2.3已深度整合行为树Behavior Tree, BT执行引擎使开发者能以声明式方式构建状态机驱动的机器人任务流例如“抓取→避障→导航→放置”可直接映射为树形节点结构而非传统嵌套 if-else 或 switch-case 实现。该库严格遵循 Arduino IDE 的库管理规范library.propertiessrc/examples/支持通过 Arduino Library Manager 一键安装并兼容 PlatformIO 构建系统。所有 API 均采用 C 封装类名与方法名遵循驼峰命名法CamelCase语义明确例如SimulaMotor::setVelocity()表达对电机速度的设定SimulaIMU::readEulerAngles()返回欧拉角数据。库不依赖特定 RTOS但内部已预置 FreeRTOS 兼容钩子hook可在启用#define SIMULA_USE_FREERTOS 1后自动注册任务通知、队列与互斥量实现与实时操作系统的无缝协同。2. 硬件平台与系统架构2.1 Simula 板硬件拓扑Simula 板采用模块化设计主控核心板Core Module与功能扩展板Expansion Module物理分离通过高密度板对板连接器互联。其关键硬件组件如下表所示模块类型组件名称关键规格默认 Arduino 引脚映射工程用途说明主控核心MCUNXP i.MX RT1062 (600 MHz Cortex-M4F FPU)—提供浮点运算能力支撑 PID 控制器、卡尔曼滤波等实时算法RAM1 MB SRAM含 512 KB TCM—TCM 区域用于存放中断服务程序与实时任务栈确保确定性响应Flash8 MB QSPI NOR Flash—存储固件、行为树定义文件JSON、标定参数表运动控制Motor DriverDual H-Bridge (DRV887x) ×2MOTOR_A_DIR,MOTOR_A_PWM,MOTOR_B_DIR,MOTOR_B_PWM支持双路直流电机独立调速与转向最大持续电流 3.6 A/通道Encoder InputQuadrature Decoder (QEI) ×2ENC_A_A,ENC_A_B,ENC_B_A,ENC_B_B硬件级正交解码支持 16 位计数器无 CPU 占用感知系统IMUInvensense ICM-20948 (9-DoF)I2C_SDA,I2C_SCL(默认 I2C1)提供加速度、角速度、地磁数据内置 DMP 运动协处理器Distance SensorVL53L1X (ToF)I2C_SDA,I2C_SCL(可选 I2C2)高精度单点测距测量范围 4 m抗环境光干扰强Camera InterfaceMIPI CSI-2 (OV5640)CSI_D0–CSI_D7,CSI_CLK,CSI_VSYNC支持 5 MP 图像采集用于视觉导航或目标识别通信接口CAN FDTJA1044TCAN_TX,CAN_RX用于连接伺服电机、激光雷达等车载总线设备速率最高 5 MbpsUART3× USART (1 with HW Flow Ctrl)SERIAL1,SERIAL2,SERIAL3SERIAL1默认为调试串口USB CDCSERIAL2预留 RS485 驱动电路注引脚映射非固定可通过pins_arduino.h文件重定义。例如若需将MOTOR_A_PWM重映射至 TIM8_CH1PA7仅需修改#define MOTOR_A_PWM 7并确保 HAL 初始化中启用对应定时器通道。2.2 软件架构分层模型库采用四层架构设计各层职责分明符合嵌入式系统高内聚、低耦合原则┌─────────────────────────────────────────────────────┐ │ 4. 应用逻辑层Behavior Tree Engine │ │ • BT Node 定义Sequence, Selector, Parallel, Decorator │ │ • JSON 解析器加载 .bt.json 文件 │ │ • Tick 调度器每 10 ms 执行一次树遍历 │ └─────────────────────────────────────────────────────┘ ▲ │ ┌─────────────────────────────────────────────────────┐ │ 3. 控制策略层Control Abstraction │ │ • SimulaPID位置/速度/电流三环 PID 控制器 │ │ • SimulaTrajectoryS-curve 加减速轨迹生成器 │ │ • SimulaFusionIMU 编码器数据融合互补滤波 │ └─────────────────────────────────────────────────────┘ ▲ │ ┌─────────────────────────────────────────────────────┐ │ 2. 设备驱动层Peripheral Drivers │ │ • SimulaMotor电机驱动支持闭环/开环 │ │ • SimulaIMUIMU 数据读取与校准 │ │ • SimulaCANCAN FD 报文收发与过滤 │ │ • SimulaADC多通道同步采样最高 1 MSPS │ └─────────────────────────────────────────────────────┘ ▲ │ ┌─────────────────────────────────────────────────────┐ │ 1. 硬件抽象层HAL / LL Wrapper │ │ • 基于 STM32CubeMX 生成的 HAL 库若使用 STM32 │ │ • 或直接调用 NXP MCUXpresso SDK 的 LL 层i.MX RT │ │ • 统一封装init(), read(), write(), interrupt() │ └─────────────────────────────────────────────────────┘此分层模型确保了代码可移植性当硬件平台从 STM32H7 迁移至 i.MX RT1062 时仅需重写第 1 层 HAL 封装上层逻辑无需修改。行为树引擎作为顶层应用框架完全解耦于具体硬件同一份.bt.json文件可在不同 Simula 板型间复用。3. 核心模块详解与 API 使用指南3.1 SimulaMotor电机控制模块SimulaMotor类提供对直流有刷电机的全功能控制支持开环 PWM 调速与闭环位置/速度控制。其设计核心是状态机驱动的模式切换机制避免因模式突变导致的电流冲击。主要 API 接口函数签名参数说明返回值典型用途void begin(uint8_t dirPin, uint8_t pwmPin, uint8_t encA, uint8_t encB)dirPin: 方向控制引脚pwmPin: PWM 输出引脚encA/encB: 正交编码器 A/B 相引脚void初始化电机及编码器自动配置定时器与 QEI 外设void setMode(MotorMode mode)mode:OPEN_LOOP,CLOSED_LOOP_SPEED,CLOSED_LOOP_POSITIONvoid切换控制模式触发内部状态机转换void setTarget(float target)target: 速度模式下单位 rpm位置模式下单位 pulsevoid设定目标值仅在闭环模式下生效float getActualSpeed()—当前实测转速rpm用于监控与调试void enableBrake()—void硬件短接电机两端实现快速制动闭环控制配置示例#include SimulaMotor.h SimulaMotor motor; void setup() { // 初始化方向引脚 PA0PWM 引脚 PA1编码器 A/B 引脚 PB0/PB1 motor.begin(0, 1, 2, 3); // 配置 PID 参数Kp1.2, Ki0.05, Kd0.1 motor.setPIDCoefficients(1.2f, 0.05f, 0.1f); // 启用速度闭环模式 motor.setMode(CLOSED_LOOP_SPEED); // 设定目标转速 120 rpm motor.setTarget(120.0f); } void loop() { // 每 20ms 更新一次控制周期推荐 static unsigned long lastTick 0; if (millis() - lastTick 20) { motor.update(); // 执行 PID 计算与 PWM 更新 lastTick millis(); } }关键原理motor.update()内部调用HAL_TIM_PWM_Start()与HAL_QEI_GetCounter()并运行离散 PID 算法。其采样周期由用户控制但必须严格大于 QEI 计数器溢出时间例如 16 位计数器在 1000 CPR 编码器下满量程对应 65535/1000 ≈ 65 转否则将丢失脉冲。3.2 SimulaIMU惯性测量单元模块SimulaIMU封装了 ICM-20948 的全部功能重点解决嵌入式场景下的数据同步性与功耗优化问题。其创新在于引入“批处理模式”Batch Mode允许 MCU 在低功耗状态下由 IMU 自身 FIFO 缓冲连续采样数据待唤醒后再批量读取大幅降低通信中断频率。关键配置参数参数可选值默认值作用说明accOdrODR_12_5Hz,ODR_25Hz,ODR_50Hz,ODR_100HzODR_100Hz加速度计输出数据率gyroOdrODR_12_5Hz,ODR_25Hz,ODR_50Hz,ODR_100Hz,ODR_200HzODR_200Hz陀螺仪输出数据率fifoModeFIFO_DISABLE,FIFO_ACCEL,FIFO_GYRO,FIFO_ACCEL_GYROFIFO_ACCEL_GYROFIFO 缓存的数据类型fifoWatermark1–1024128FIFO 触发中断的阈值字节数批处理数据读取示例#include SimulaIMU.h SimulaIMU imu; void setup() { imu.begin(); // 配置加速度 100Hz陀螺仪 200Hz启用 FIFO 批处理 imu.configure(ODR_100Hz, ODR_200Hz, FIFO_ACCEL_GYRO, 256); // 启用 FIFO 中断连接至 INT pin imu.enableFifoInterrupt(); } void loop() { // 检查 FIFO 是否有新数据 if (imu.fifoAvailable()) { // 一次性读取最多 256 字节约 32 组完整 6-DoF 数据 int16_t acc[3], gyro[3]; uint32_t timestamp; while (imu.readFifoBatch(acc, gyro, timestamp)) { // 处理单组数据acc[x,y,z], gyro[x,y,z], timestamp (us) processImuData(acc, gyro, timestamp); } } }工程提示readFifoBatch()返回true表示成功读取一组数据。由于 FIFO 是环形缓冲区若读取速度慢于写入速度旧数据将被覆盖。建议在processImuData()中采用 FreeRTOS 队列将数据推送给高优先级处理任务避免在中断上下文中执行复杂计算。3.3 Behavior Tree 引擎声明式任务编排行为树是本库最具革命性的特性它将传统状态机的“硬编码跳转”转化为“节点组合”极大提升机器人任务逻辑的可维护性与可测试性。引擎完全在 MCU 上运行不依赖外部 PC 或云服务。节点类型与语义节点类型英文名执行逻辑典型应用场景组合节点Sequence顺序执行子节点任一失败则中止返回FAILURE“开门→进入→关门” 流程Selector顺序尝试子节点任一成功则中止返回SUCCESS“尝试 WiFi → 失败则切换至 BLE” 故障恢复装饰节点Inverter反转子节点返回值SUCCESS↔FAILURE“直到未检测到障碍物才继续”RepeatUntilFail循环执行子节点直至失败“持续发送心跳包直到连接断开”叶节点Action执行具体操作如motor.setTarget(100)所有硬件交互的终点Condition查询状态如imu.isTilted()决策分支的判断依据JSON 行为树定义示例navigation.bt.json{ name: Navigation, root: { type: Sequence, children: [ { type: Action, name: StartMotor, action: motor.setMode(CLOSED_LOOP_SPEED); motor.setTarget(80); }, { type: Selector, children: [ { type: Condition, name: ObstacleDetected, condition: distance.read() 0.3 }, { type: Action, name: TurnRight, action: motor.setTarget(-40); delay(1000); } ] }, { type: Action, name: StopMotor, action: motor.setTarget(0); } ] } }在 Arduino 中加载与执行#include SimulaBT.h #include ArduinoJson.h SimulaBT bt; const char* btJson Rrawliteral( {name:Test,root:{type:Sequence,children:[{type:Action,action:Serial.println(\Hello\);}]}} )rawliteral; void setup() { Serial.begin(115200); // 解析 JSON 字符串内存受限建议存储于 Flash DynamicJsonDocument doc(2048); deserializeJson(doc, btJson); bt.loadFromJson(doc.asJsonObject()); // 启动行为树tick 周期 50ms bt.start(50); } void loop() { // 引擎自动在后台运行无需手动调用 // 可通过 bt.getState() 查询当前状态RUNNING / SUCCESS / FAILURE }内存优化技巧大型行为树 JSON 文件应存储于 FlashPROGMEM或外部 SPI Flash使用Stream接口如File对象流式解析避免将整个 JSON 加载至 RAM。库内置FlashStringHelper支持直接解析F(...)字符串。4. 集成开发实践构建一个避障小车本节以 Simula 板驱动两轮差速小车实现自主避障为例完整演示库的工程化集成流程。4.1 硬件连接清单Simula 板引脚外设引脚连接说明MOTOR_A_DIRDRV8874IN1左轮方向控制MOTOR_A_PWMDRV8874IN2左轮 PWM 输入MOTOR_B_DIRDRV8874IN3右轮方向控制MOTOR_B_PWMDRV8874IN4右轮 PWM 输入I2C_SDAVL53L1XSDA测距传感器数据线I2C_SCLVL53L1XSCL测距传感器时钟线SERIAL1USB-CDC调试信息输出4.2 完整固件代码#include Arduino.h #include SimulaMotor.h #include SimulaDistance.h #include SimulaBT.h #include ArduinoJson.h // 实例化硬件对象 SimulaMotor leftMotor, rightMotor; SimulaDistance distance; SimulaBT bt; // 定义行为树 JSON精简版 const char* obstacleAvoidanceBT Rrawliteral( { name: ObstacleAvoidance, root: { type: Sequence, children: [ { type: Action, name: SetForward, action: leftMotor.setTarget(60); rightMotor.setTarget(60); }, { type: Selector, children: [ { type: Condition, name: IsObstacleClose, condition: distance.read() 0.25 }, { type: Sequence, children: [ { type: Action, name: Stop, action: leftMotor.setTarget(0); rightMotor.setTarget(0); }, { type: Action, name: TurnLeft, action: leftMotor.setTarget(-30); rightMotor.setTarget(30); delay(800); } ] } ] } ] } } )rawliteral; void setup() { Serial.begin(115200); delay(1000); Serial.println(Simula Obstacle Avoidance Demo Start); // 初始化电机左轮PA0/PA1右轮PA2/PA3 leftMotor.begin(0, 1, 4, 5); // ENC_A, ENC_B for left rightMotor.begin(2, 3, 6, 7); // ENC_A, ENC_B for right // 初始化测距传感器 distance.begin(); // 加载行为树 DynamicJsonDocument doc(2048); deserializeJson(doc, obstacleAvoidanceBT); bt.loadFromJson(doc.asJsonObject()); bt.start(100); // 100ms tick interval } void loop() { // 行为树引擎自动运行 // 可在此添加额外监控逻辑如 if (bt.getState() BT_FAILURE) { Serial.println(Behavior Tree Failed! Resetting...); bt.reset(); } }4.3 调试与性能分析串口监控通过Serial输出可观察行为树节点执行日志需启用#define SIMULA_BT_DEBUG 1。功耗测量在loop()中插入HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI)配合行为树空闲状态自动进入 STOP 模式实测待机电流可降至 120 μA。实时性验证使用逻辑分析仪捕获MOTOR_A_PWM引脚波形确认update()调用间隔稳定在 20 ms ± 100 μs满足运动控制确定性要求。5. 高级主题与 FreeRTOS 协同工作当项目复杂度提升单一 Arduinoloop()无法满足多任务需求时可启用库的 FreeRTOS 集成模式。此模式下行为树引擎、传感器数据采集、通信协议栈均运行于独立任务中由 RTOS 调度器统一管理。5.1 启用 FreeRTOS 集成在platformio.ini中添加build_flags -DSIMULA_USE_FREERTOS1 -DconfigUSE_TIMERS1并在setup()中初始化#include FreeRTOS.h #include task.h void setup() { // ... 其他初始化 ... // 创建高优先级行为树任务优先级 3 xTaskCreatePinnedToCore( btTask, // 任务函数 BT_Engine, // 任务名 4096, // 栈大小字节 NULL, // 参数 3, // 优先级 NULL, // 任务句柄 0 // 运行在 Core 0 ); // 启动调度器 vTaskStartScheduler(); } void btTask(void *pvParameters) { bt.start(50); // 50ms tick for(;;) { vTaskDelay(pdMS_TO_TICKS(1)); // 保持任务运行 } }5.2 线程安全的外设访问库自动为所有SimulaXXX类的read()/write()方法添加互斥量保护。例如// 在任意 FreeRTOS 任务中安全调用 float dist distance.read(); // 内部自动获取 mutex若需自定义临界区可显式调用distance.lock(); // 获取互斥量 // ... 访问共享资源 ... distance.unlock(); // 释放互斥量此机制确保在多任务环境下传感器读取、电机控制等操作不会因竞态条件而失效为构建鲁棒的机器人系统奠定坚实基础。

更多文章