我找到了以下文章:
原文:如何使用蓝牙通过 Arduino 微控制器控制无人机
这个文章的思路是,用arduino充当接收机,用PPM信号控制无人机。下图是该文章的插图,第一幅插图是展示接线,第二幅插图是展示与飞控的连接,第三幅插图展示与Arduino的连接。
测试视频:https://www.youtube.com/watch?v=k0k4KmnM2nE
原文:使用Arduino简单生成S.Bus
这个文章是讨论将arduino信号变为sbus信号。
你有没有注意到我最近经常写关于无线电的文章?没错,这并非巧合。我正在做的项目的正式介绍会在接下来的几天里发布,但现在我只想说,这是一款中程、廉价、DIY的无人机无线电链路。我所说的中程是指最远5公里的距离。因此,它的定位将介于2.4GHz系统和像DragonLink或TBS Crossfire这样的正式LRS系统之间。
言归正传。我发现网上关于如何使用 Arduino 生成 S.Bus 的信息很少。好吧,虽然有一些库可以读取Futaba S.Bus协议,比如mikeshub/FUTABA_SBUS或zendes/SBUS,但我找到的唯一一个简化的库是bolderflight/SBUS。可惜它只适用于Teensy设备。所以,经过几个小时的辛苦工作,阅读了OpenTX、MultiWii、INAV 的代码,阅读了RcGroups,并在 Konstantin Sharlaimov(INAV 数字实体)的最终帮助下,我得到了:
使用 Arduino 以简单的方式生成 S.Bus 数据包
但首先,有几个简单的事实:
- S.Bus 协议在硬件层面是反向的。这意味着,Arduino 无法在没有额外逆变器的情况下直接与其他 S.Bus 设备通信。例如这个
- 对于大多数现代飞行控制器来说,逆变器可能并非必需,只要飞行控制器能够禁用板载逆变器即可。F1 和 F4 根本没有内置逆变器,因此可以直接使用任何 UART。对于 F3 和 F7,INAV/Betaflight 可以通过软件禁用逆变器。
- Futaba S.Bus 在“FASSTest 18CH”协议中编码了 16 个 RC 通道和 2 个数字通道(开/关)
- S.Bus 使用 11 位对每个 RC 通道进行编码
- 在内部,通道值映射为:
- -100% = 173(相当于PWM伺服信号中的1000)
- 0% = 992(相当于PWM伺服信号中的1500)
- 100% = 1811(相当于PMW伺服信号中的2000)
- 串行端口必须配置为100000bps,
SERIAL_8E2
(8位,偶数,2个停止位)- 故障安全状态通过单个标志字节传输
- 一个 S.Bus 数据包占用 25 个字节
- 每15ms传输一帧(FASSTest 18CH模式)
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788 #define RC_CHANNEL_MIN 990#define RC_CHANNEL_MAX 2010#define SBUS_MIN_OFFSET 173#define SBUS_MID_OFFSET 992#define SBUS_MAX_OFFSET 1811#define SBUS_CHANNEL_NUMBER 16#define SBUS_PACKET_LENGTH 25#define SBUS_FRAME_HEADER 0x0f#define SBUS_FRAME_FOOTER 0x00#define SBUS_FRAME_FOOTER_V2 0x04#define SBUS_STATE_FAILSAFE 0x08#define SBUS_STATE_SIGNALLOSS 0x04#define SBUS_UPDATE_RATE 15void sbusPreparePacket(uint8_t packet[], int channels[], bool isSignalLoss, bool isFailsafe) {static int output[SBUS_CHANNEL_NUMBER] = {0};/** Map 1000-2000 with middle at 1500 chanel values to* 173-1811 with middle at 992 S.BUS protocol requires*/for (uint8_t i = 0; i < SBUS_CHANNEL_NUMBER; i++) {output[i] = map(channels[i], RC_CHANNEL_MIN, RC_CHANNEL_MAX, SBUS_MIN_OFFSET, SBUS_MAX_OFFSET);}uint8_t stateByte = 0x00;if (isSignalLoss) {stateByte |= SBUS_STATE_SIGNALLOSS;}if (isFailsafe) {stateByte |= SBUS_STATE_FAILSAFE;}packet[0] = SBUS_FRAME_HEADER;//Headerpacket[1] = (uint8_t) (output[0] & 0x07FF);packet[2] = (uint8_t) ((output[0] & 0x07FF)>>8 | (output[1] & 0x07FF)<<3);packet[3] = (uint8_t) ((output[1] & 0x07FF)>>5 | (output[2] & 0x07FF)<<6);packet[4] = (uint8_t) ((output[2] & 0x07FF)>>2);packet[5] = (uint8_t) ((output[2] & 0x07FF)>>10 | (output[3] & 0x07FF)<<1);packet[6] = (uint8_t) ((output[3] & 0x07FF)>>7 | (output[4] & 0x07FF)<<4);packet[7] = (uint8_t) ((output[4] & 0x07FF)>>4 | (output[5] & 0x07FF)<<7);packet[8] = (uint8_t) ((output[5] & 0x07FF)>>1);packet[9] = (uint8_t) ((output[5] & 0x07FF)>>9 | (output[6] & 0x07FF)<<2);packet[10] = (uint8_t) ((output[6] & 0x07FF)>>6 | (output[7] & 0x07FF)<<5);packet[11] = (uint8_t) ((output[7] & 0x07FF)>>3);packet[12] = (uint8_t) ((output[8] & 0x07FF));packet[13] = (uint8_t) ((output[8] & 0x07FF)>>8 | (output[9] & 0x07FF)<<3);packet[14] = (uint8_t) ((output[9] & 0x07FF)>>5 | (output[10] & 0x07FF)<<6);packet[15] = (uint8_t) ((output[10] & 0x07FF)>>2);packet[16] = (uint8_t) ((output[10] & 0x07FF)>>10 | (output[11] & 0x07FF)<<1);packet[17] = (uint8_t) ((output[11] & 0x07FF)>>7 | (output[12] & 0x07FF)<<4);packet[18] = (uint8_t) ((output[12] & 0x07FF)>>4 | (output[13] & 0x07FF)<<7);packet[19] = (uint8_t) ((output[13] & 0x07FF)>>1); packet[20] = (uint8_t) ((output[13] & 0x07FF)>>9 | (output[14] & 0x07FF)<<2);packet[21] = (uint8_t) ((output[14] & 0x07FF)>>6 | (output[15] & 0x07FF)<<5);packet[22] = (uint8_t) ((output[15] & 0x07FF)>>3);packet[23] = stateByte;//Flags bytepacket[24] = SBUS_FRAME_FOOTER; //Footer}uint8_t sbusPacket[SBUS_PACKET_LENGTH];int rcChannels[SBUS_CHANNEL_NUMBER];uint32_t sbusTime = 0;void setup() {for (uint8_t i = 0; i < SBUS_CHANNEL_NUMBER; i++) {rcChannels[i] = 1500;}Serial.begin(100000, SERIAL_8E2);}void loop() {uint32_t currentMillis = millis();/** Here you can modify values of rcChannels while keeping it in 1000:2000 range*/if (currentMillis > sbusTime) {sbusPreparePacket(sbusPacket, rcChannels, false, false);Serial.write(sbusPacket, SBUS_PACKET_LENGTH);sbusTime = currentMillis + SBUS_UPDATE_RATE;}}我希望上面的代码足够简单。
setup
该方法以正确的模式初始化串口Serial.begin(100000, SERIAL_8E2);
,并loop
每 15 毫秒编码和发送一次 S.Bus 帧。数据包编码可以采用更好的方式,但至少它能正常工作!