构建XMP-1:低成本XMOS-树莓派移动平台
引言
XMOS startKIT在Farnell(或Newark)售价仅£12(含VAT),提供紧凑信用卡大小平台,与树莓派完美配合。仅需螺丝刀、剪线钳、钳子等少量焊接工具,开发者即可组装功能性机器人原型,利用XMOS多核、低抖动并行处理能力。
本文演示XMP-1(XMOS移动平台)构建过程,展示树莓派与XMOS startKIT通过串行外设接口(SPI)高速双向通信,如何通过XMOS板直接产生PWM控制舵机,以及如何暴露基于Web的用户界面实时驱动机器人。
原文包含视频演示:首个视频展示XMP-1学习路径,第二个捕捉机器人用连续旋转舵机尝试重现路径。视频展示了当前硬件和固件的潜力与局限。
更多细节
这是XMOS startKIT实验系列第二篇。第一篇介绍XMOS术语、架构、快速入门和示例程序。XMOS新手建议先阅读第一篇理解本文概念。第三篇("XMOS startKIT: XMOS和树莓派示波器XAE 1000")重访SPI框架,引入ADC用法和实时浏览器图形。
仅关注XMP-1构建和操作的读者可跳过扩展讨论,直接跳至文末代码段。固件按第一篇所述编译烧录至startKIT,树莓派代码运行于Node.js。
解决方案概览——硬件与软件
图1(未显示)展示完成的XMP-1,经5V稳压器供电,由两个连续旋转舵机驱动。树莓派处理所有网络,运行轻量Web服务器服务index.html并将用户指令解析为电机速度/方向消息。
图2(未显示)展示通信流程。树莓派通过发送SPI数据包向XMOS startKIT产生舵机PWM信号。startKIT作为SPI从机,解码数据包并以适当PWM脉冲驱动舵机。
串行外设接口(SPI)
SPI依赖四线:SS、SCLK、MOSI、MISO。本设置中树莓派为主机,提供时钟并在MOSI发送数据。XMOS板在MOSI接收数据,在MISO返回状态或确认。SS线低有效;树莓派CE1引脚选择startKIT。
示波器示波图(Tektronix MSO2024B捕获)确认SPI传输完整性。三字节数据0x02、0x00、0x10从树莓派传至startKIT,可选零长度响应。
控制舵机电机
舵机将1-2毫秒PWM脉宽转换为0-180°机械旋转,1.5毫秒脉冲使轴居中。连续旋转舵机移除电位器和限位,将脉宽解读为速度指令:1.5ms中立、1ms全反、2ms全正向。
XMP-1每个车轮由一连续旋转舵机驱动。此设置简化接线——无需外部H桥——但相比直流电机限制精确速度控制。
开始开发——连接板卡
固件开发时,树莓派和startKIT通过带IDC连接器的26针排线连接。备用IDC连接器可作调试接口,供万用表或示波器探测信号。
在XMOS startKIT上实现SPI(spi_process)
使用xTIMEcomposer IDE,导入内置SPI从机库,源文件置于spi-test/src目录。以下初始化例程配置时钟源、MOSI/MISO端口、SPI从机接口:
void spi_slave_init(spi_slave_interface &spi_if) {
int clk_start;
set_clock_on(spi_if.blk);
configure_clock_src(spi_if.blk, spi_if.sclk);
configure_in_port(spi_if.mosi, spi_if.blk);
configure_out_port(spi_if.miso, spi_if.blk, 0);
start_clock(spi_if.blk);
return;
}
spi_slave_interface结构映射SPI引脚到XMOS端口:
typedef struct spi_slave_interface {
clock blk;
in port ss;
in buffered port:8 mosi;
out buffered port:8 miso;
in port sclk;
} spi_slave_interface;
使用以下例程将传入SPI数据读入缓冲区,实现简单标签-长度-值(TLV)协议以支持变长消息:
void spi_slave_in_buffer(spi_slave_interface &spi_if, unsigned char buffer[], int num_bytes) {
unsigned int data;
unsigned int vlen=0;
clearbuf(spi_if.miso);
clearbuf(spi_if.mosi);
for (int i = 0; i < num_bytes; i++) {
spi_if.mosi :> data;
data=data<<24;
buffer[i]=bitrev(data);
if (i==2) {
vlen=((unsigned int)buffer[1])<<8 | (unsigned int)buffer[2];
if (vlen==0) break;
}
if (i >= vlen+2) { break; }
}
}
数据包首字节为标签(0-255)。后两字节编码载荷长度(最多4096字节)。奇数标签表示树莓派期望响应;偶数标签表示无需响应。
进程间通信
XMOS核心通过基于事务的接口而非简单通道通信。此法允许单次接口调用包含多数据类型和返回值,非常适合协调SPI处理核心、数据处理核心和PWM生成核心。
接口定义示例:
interface program_display {
void backlight(int state, int color);
void plot(int x, int y, int color);
}
设计处理SPI内容的IPC架构
spi_process核心捕获传入SPI数据到4099字节缓冲区,通过可移动数组事务转发指针给data_handler核心。处理后,data_handler可填充响应数据到缓冲区并通知spi_process在下次SPI交换中传回。
interface to_rpi { void code(unsigned char c); };
interface from_rpi { unsigned char* movable array_data(unsigned char* movable bufp); };
核心逻辑片段:
void spi_process(interface to_rpi server s, interface from_rpi client c) {
unsigned char storage[4099];
unsigned char* movable buf=storage;
buf=c.array_data(move(buf));
select {
case s.code(unsigned char c):
if (c==SEND) {
spi_slave_out_buffer(spi_sif, buf, 4099);
}
break;
}
}
void data_handler(interface to_rpi client c, interface from_rpi server s) {
select {
case s.array_data(unsigned char* movable vp) -> unsigned char* movable vq:
vq[0]=0x22; // tag
vq[1]=0x00; // length
vq[2]=0x00;
vq=move(vp);
tosend=1;
break;
}
if (tosend) { c.code(SEND); }
}
此架构在树莓派和XMOS startKIT间提供通用双向通信通道,可适配广泛机器人或物联网项目。
在startKIT上实现PWM(servo_handler)
舵机控制例程运行于专用XMOS核心,管理最多八个舵机。每个舵机PWM信号通过每20ms在适当占空比切换输出引脚产生,微秒分辨率实现精细速度调节。初始值居中(连续旋转舵机为静止),核心每周期基于通过IPC框架接收的最新指令更新信号。
当前XMP-1仅用两连续旋转舵机,但固件支持扩展至更多电机或通过H桥接口控制直流电机。
完整源码和编译说明见文末。
制造工艺
- NodeMCU DHT22接入树莓派3B+ MQTT Broker:无缝物联网集成指南
- 树莓派与 Python 构建远程温度传感器:分步实战指南
- 树莓派配合 EzTemp 实现无缝温湿度监测
- 树莓派多传感器温度光照监测系统:DS18B20 实战构建
- 树莓派传感器与执行器控制实战:加速度计、舵机与数据流
- 树莓派自动化气雾栽培系统:湿度传感器智能控制
- 树莓派 3 B+ – 更新特性、规格与选购指南
- Bridge Shield扩展板:树莓派与Arduino集成打造智能机器人
- ValentFX发布开源FPGA扩展板,兼容BeagleBone与树莓派
- MonkMakes RRB2套件构建树莓派机器人:详细指南
- DIY仿Wall-E树莓派CD盒机器人
- 树莓派与Python构建机器人:完整指南