前言

前几天开源了自制的6通道航模遥控器(开源自制的6通道航模遥控器,超简单不超过100行代码),受到许多粉丝的关注,美中不足的是只实现了6个通道的PWM输出,没有SBUS输出,接线太复杂。经过一段时间的查阅资料和开发,终于实现了SBUS输出,这样就可以用三根线实现16个伺服通道和2个数字通道的输出了!

1. 新增元件

1k电阻一个,10k电阻一个,SS8050三极管一个(贴片体积更小)

2. 电路连接

原理图如下,基本和之前的原理图相同,只是加上了SBUS的取反电路。

如果使用Arduino UNO或者NANO开发板,请将原理图中的11脚和12脚调换位置,因为UNO和NANO的11和12正好与PRO MINI相反!

元件连接图如下:

3. 软件部分

SBUS协议使用波特率为100000、8个数据位,偶数奇偶校验位和2个停止位的反向串行逻辑。SBUS数据包的长度为25个字节,包括:
字节[0]:SBUS头,0x0F
字节[1-22]:16个伺服通道,每个伺服通道采用11位编码
字节[23]:
          位7:数字通道17(0x80)
          位6:数字通道18(0x40)
          位5:丢帧(0x20)
          位4:用来激活故障安全(0x10)
          位0-3:n/a
字节[24]:SBUS结束字节,0x00

S.Bus协议通过硬件电路取反,如果没有反相电路,Arduino将无法直接与其他SBUS设备通信。F1和F4飞控根本没有内置反相器,因此任何UART都可以直接使用;对于F3和F7飞控,INAV / Betaflight固件可以禁用软件中的反相。
程序中采用“ FASSTest 18CH”协议的Futaba S.Bus 编码16个RC通道和2个数字通道(ON / OFF)。

SBUS的每个RC通道值映射为:
-100%= 173(相当于PWM伺服信号中的1000)
0%= 992(相当于PWM伺服信号中的1500)
100%= 1811(相当于PMW伺服信号中的2000)

Arduino的串行端口必须配置为100000bps, SERIAL_8E2(8个数据位,偶校验,2个停止位)。

/* ArduinoProMini-6通道接收机+SBUS输出*     by Bilibili 蔡子CaiZi* 参考链接https://quadmeup.com/generate-s-bus-with-arduino-in-a-simple-way
S.Bus用11位编码每个RC通道
在内部,通道值映射为:
-100%= 173(相当于PWM伺服信号中的1000)
0%= 992(相当于PWM伺服信号中的1500)
100%= 1811(相当于PMW伺服信号中的2000)
串行端口必须配置为100000bps SERIAL_8E2(8位,偶数,2个停止位)
故障安全状态通过单个标志字节传输
一个S.Bus数据包占用25个字节
每9ms发送一帧(FASSTest 18CH模式)
*/
#define RC_CHANNEL_MIN 1000
#define RC_CHANNEL_MAX 2000
#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 4 //ms#include <SPI.h>
#include <nRF24L01.h> // 安装RF24库
#include <RF24.h>
#include <Servo.h>
Servo ch1;
Servo ch2;
Servo ch3;
Servo ch4;
Servo ch5;
Servo ch6;
struct Signal {    byte roll;byte pitch;byte throttle;  byte yaw;byte gyr;byte pit;
};
Signal data; // 定义一个结构体,用来存储信号
const uint64_t pipeIn = 0xBBBBBBBBB; // 与发射端地址相同
RF24 radio(7, 8);     // SPI通信,引脚对应关系:CE ->7,CSN ->8
void ResetData()
{data.roll = 127;    // 横滚通道中心点(254/2 = 127)data.pitch = 127;   // 俯仰通道data.throttle = 0;  // 信号丢失时,关闭油门data.yaw = 127;     // 航向通道data.gyr = 0;       //第五通道data.pit = 0;       //第六通道
}
void sbusPreparePacket(uint8_t packet[], int channels[], bool isSignalLoss, bool isFailsafe){static int output[SBUS_CHANNEL_NUMBER] = {0};//这里一定要16个元素的数组,不然其他通道会干扰/*将chanel值1000-2000映射到SBUS协议的173-1811*/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; //SBUS头,0x0Fpacket[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;         // 标志位packet[24] = SBUS_FRAME_FOOTER; // SBUS结束字节
}uint8_t sbusPacket[SBUS_PACKET_LENGTH];// 25个字节的数据包
int rcChannels[SBUS_CHANNEL_NUMBER];   // 6通道信号,可以增加
uint32_t sbusTime = 0;
bool signalLoss = false;  // true时表示丢失信号void setup() {//设置PWM信号输出引脚ch1.attach(2);ch2.attach(3);ch3.attach(4);ch4.attach(5);ch5.attach(6);ch6.attach(9);//配置NRF24L01模块ResetData();radio.begin();radio.openReadingPipe(1,pipeIn); // 与发射端地址相同radio.startListening(); // 接收模式pinMode(10,OUTPUT);     // LED推挽输出digitalWrite(10,HIGH);Serial.begin(100000, SERIAL_8E2); // 将串口波特率设为100000,数据位8,偶校验,停止位2
}
unsigned long lastRecvTime = 0;
void recvData()
{while ( radio.available() ) {radio.read(&data, sizeof(Signal)); // 接收数据lastRecvTime = millis();           // 当前时间ms}
}
void loop() {recvData();unsigned long now = millis();if ( now - lastRecvTime > 1000 ) {ResetData(); // 两次接收超过1s表示失去信号,输出reset值signalLoss = true;
//    Serial.print("无信号");digitalWrite(10,HIGH);}else{digitalWrite(10,LOW);}rcChannels[0] = map(data.roll,     0, 255, 1000, 2000);// 将0~255映射到1000~2000,即(1ms~2ms)/20ms的PWM输出rcChannels[1] = map(data.pitch,    0, 255, 1000, 2000);rcChannels[2] = map(data.throttle, 0, 255, 1000, 2000);rcChannels[3] = map(data.yaw,      0, 255, 1000, 2000);rcChannels[4] = map(data.gyr,      0, 255, 1000, 2000);rcChannels[5] = map(data.pit,      0, 255, 1000, 2000);for (uint8_t i = 6; i < 16; i++) {rcChannels[i] = 1500;}//未用到的通道全部置中uint32_t currentMillis = millis();if (currentMillis > sbusTime) {sbusPreparePacket(sbusPacket, rcChannels, signalLoss, false); // 6通道数值转换为SBUS数据包Serial.write(sbusPacket, SBUS_PACKET_LENGTH); // 将SBUS数据包通过串口TX0输出sbusTime = currentMillis + SBUS_UPDATE_RATE;}ch1.writeMicroseconds(rcChannels[0]);//写入us值,PWM输出ch2.writeMicroseconds(rcChannels[1]);ch3.writeMicroseconds(rcChannels[2]);ch4.writeMicroseconds(rcChannels[3]);ch5.writeMicroseconds(rcChannels[4]);ch6.writeMicroseconds(rcChannels[5]);
}

4. 实现效果

笔者将Arduino接收机连接F3飞控,已经可以在betaflight-configurator软件中看到接收到信号了。

视频已上传B站

[DIY] 开源自制的航模遥控器(二)-接收机增加SBUS输出,最大支持18通道!

参考链接

Generate S.Bus with Arduino in a simple way | QuadMeUp

开源自制的6通道航模遥控器(二)-Arduino接收机增加SBUS输出相关推荐

  1. 开源自制的6通道航模遥控器(一) 超简单不超过100行代码

    前言 前段时间跟着LOLI大神的教程制作了LOLI三代控,效果很好.但是,由于LOLI三代控的接收机带有数据回传功能,也就是接收机的无线模块也承担了发射数据功能,所以接收机也要使用带有功率放大芯片的N ...

  2. 开源自制的6通道航模遥控器(三)-遥控器端增加MIX混控模式

    1.了解什么是混控 要了解混控,需要先对比一般的遥控模式.一般遥控的每个操作控制都是一个通道,比如美国手的遥控器,左边摇杆前后控制油门,左右控制方向舵:右边摇杆前后控制升降舵,左右控制副翼(横滚).混 ...

  3. 开源自制6通道航模遥控器,Arduino Pro Mini NRF24L01模块

    前言 前段时间跟着LOLI大神的教程制作了LOLI三代控,效果很好.但是,由于LOLI三代控的接收机带有数据回传功能,也就是接收机的无线模块也承担了发射数据功能,所以接收机也要使用带有功率放大芯片的N ...

  4. 《手把手教你学嵌入式无人机》——入门航模遥控器使用(MC6C)

    一. MC6C入门航模遥控器简介 六通道MC6C迈克遥控器是普遍使用的一款入门航模遥控器,价格较为低廉,同时性能比较稳定,性价比较高. 遥控器与接收机 1.基本参数: 遥控器: 遥控范围:大于800米 ...

  5. 建军节献礼!J20航模遥控器开源项目系列教程(一)制作教程 | 基础版V1.0发布,从0到1

    我们的开源宗旨:自由 协调 开放 合作 共享 拥抱开源,丰富国内开源生态,开展多人运动,欢迎加入我们哈~ 和一群志同道合的人,做自己所热爱的事! 项目开源地址:https://github.com/C ...

  6. 《手把手教你学嵌入式无人机》——2.航模遥控器通信协议

    一.接收机的使用 接收机可以直接用来控制舵机.电调(有刷或无刷),同时也可以通过特定的通信协议与单片机通信,单片机再进行对外围设备的控制. 实事上,舵机.电调内部也都有单片机,接收机控制舵机.电调也是 ...

  7. STM32解析航模遥控器的PPM信号

    一.前言 通常遥控器能输出i-BUS.s-BUS.PPM.PWM信号,其中i-BUS.s-BUS需要配套的电平反向器(硬件取反),PWM信号占用引脚较多,对比而言PPM信号使用起来更为方便. 航模遥控 ...

  8. Arduino+2.4G模块做航模遥控器

    Arduino+2.4G模块做航模遥控器 萌新第一次发文,多多关照~ 玩航模估计有七八年了,玩arduino和各类单片机也有一两年啦,今年回家以后因为疫情被困在家里回不去,就寻思着用arduino做个 ...

  9. Arduino接收航模遥控器RC接收机的PWM数据

    本文将介绍如何使用Arduino读取RC接收机的PWM数据 1. 硬件部分 我的设备: 接收机 遥控器发射机 将Arduino Nano的引脚 D8~D11 接到接收机的1~4通道,接收机上的电源正极 ...

最新文章

  1. Laravel中使用模型对数据进行操作
  2. Android热修复升级探索——SO库修复方案 1
  3. zabbix分布式监控环境完全编译安装部署
  4. Sharepoin学习笔记—架构系列--03 Sharepoint的处理(Process)与执行模型(Trust Model) 2
  5. MySQL 数据库导出导入操作
  6. 专题导读:医学大数据
  7. [转载]C#实现软件自动更新思路
  8. 计算机学院学生会宣传稿,计算机与信息工程学院学生会
  9. 编码速度非常慢_有BUG?MySQL中的 utf8 居然并不是真正的UTF-8编码?
  10. RHEL7和RHEL6的主要变化
  11. Ubuntu16.04下基于opencv--实现图像SIFT特征与全景图片的生成
  12. java word 占位符替换,javaword占位符替换
  13. 10. Regular Expression Matching[H]正则表达式匹配
  14. Contest-hunter 暑假送温暖 SRM08
  15. Android必知必会-使用Intent打开第三方应用及验证可用性
  16. Java坦克大战Summary
  17. linux有root权限留后门,linux下获取root权限后安装后门程序rootkit
  18. 20190604第二次月考
  19. 人牙髓干细胞,多能分化,不只用于牙齿组织再生研究
  20. 论文学习笔记:CSRNet: Dilated Convolutional Neural Networks for Understanding the Highly Congested Scenes

热门文章

  1. 2022智源大会议程公开丨AI开源的机遇与挑战:从模型、框架到开发者
  2. Checkerboard Context Model for Efficient Learned Image Compression文献复现(非官方,改动较大)
  3. cocoscreator2.4.3构建发布多平台包并在IOS模拟器中运行游戏
  4. 捡苹果(贪心加背包)
  5. hive split 函数
  6. 计算机系统 流水线技术
  7. 流水线技术的部分总结
  8. “太极”助力,腾讯如何借大模型降本增效?
  9. 基于MATLAB的药物扩散仿真系统设计与实现 文档+上机实验报告+项目源码+运行说明
  10. 你的样子-罗大佑,林志炫