本章以乐迪AT9S(已停产)为代表举例,如有不同,请根据所持遥控器查看厂商说明书。
遥控器是一种用于控制无人系统操作的设备。它通常由一个手持的控制器和一个接收器组成。遥控器上配有各种按钮、摇杆和滑块,用于控制无人系统的各种功能,如起飞、降落、悬停、前进、后退、左转、右转等。
无人系统遥控器使用无线信号将操作指令传输给无人系统的接收器。接收器将信号解码后发送给无人系统的飞行控制系统,从而实现用户的指令
遥控器一般具有多个通道,具体数量取决于遥控器的设计和用途。
AT9S有十个通道,其中前四个通道对应摇杆,5通道以上为拨扭开关,可以自定义。其自定义概念为可以将任意拨扭开关映射到5通道以上任意通道上。
遥控器协议分为SBUS、PPM等
SBUS协议详见另一篇文章:遥控器协议解析—SBUS篇
接收机接收到遥控器数据后进行处理后会得到各个通道值,不同协议接收机接收到的数据范围是不一样的,比如SBUS传来的每个通道值的数据大概范围为300~1700,PPM传来的每个通道值的数据大概范围为500~1500等。其具体的通道值数据范围可以通过将数据读出来查看。
_Bool get_rc_sbus_health()
{
//rc_connect_flag为接收机接收到的数据中标志着遥控器和接收机是否失去连接
if( (xTaskGetTickCountFromISR() - last_sbus_update_ms > 100) || rc_connect_flag == false){
return false;
}
else return true;
}
死区(deadband)有时也称为中性区(neutral zone)或不作用区,是指控制系统的传递函数中,对应输出为零的输入信号范围。
float data_to_deadzone(float x,float ref,float zoom)
{
float t;
if(x>ref)
{
t = x - zoom; //x不管在ref~ref+zoom之间怎么变,输出t始终为ref
if(t<ref)
{
t = ref;
}
}
else
{
t = x + zoom;
if(t>ref)
{
t = ref;
}
}
return (t);
}
static float data_to_unit_dead(int16_t rawData, int16_t deadband)
{
float norm = ((float)data_to_deadzone(rawData,0,deadband) / (float)(500-deadband));
return norm;
}
enum
{
ROL ,
PIT ,
THR ,
YAW ,
AUX1 ,
AUX2 ,
AUX3 ,
AUX4 ,
//其实可以更多,根据遥控器通道和所需多少通道来设置
CH_NUM
};
typedef enum
{
LO = 0,
CE = 1,
HI = 2,
//拨扭开关有的为两档,有的为三档,这里分为三个档位来标志开关位置
}CH_Pos;
/* 结构体数组,指示每个通道低中高三种状态 */
CH_Pos channelPos[CH_NUM]; //辅助通道位置状态
int16_t rc_original[CH_NUM] = {0}; //储存遥控器原始数据
float rc_value_unit[3]; //遥控器原始数据加死区后单位化
uint16_t rc_sbus_in[18];
int sbus_data_update(void)
{
for (uint8_t i = 0; i < CH_NUM; ++i) {
//使数据在1000~2000之间,原始数据在300~1700之间
rc_sbus_in[i] = 1000 + (int)((sbus.ch[i]-300)*((float)1000/(1700-300)));
}
return HAL_OK;
}
void main_channel_value_update(void)
{
rc_health = get_rc_sbus_health();
for(uint8_t i=0; i<CH_NUM; ++i)
{
if(rc_sbus_in[i] >= 1000) //如果该通道有值,处理通道数据
{
if (rc_sbus_in[1]<910||rc_sbus_in[2]<910) {
rc_health = false;
}
// else rc_health = true;
rc_original[i] = 1.1f *(rc_sbus_in[i] - 1500); //处理成+-500摇杆量,1.1是为遥控器做的适配
rc_original[i] = (int16_t)limit(rc_original[i],-500,500); //限制到+—500
if(
}
/*接收机掉落仍进不去此判断,如果之前_rc_health已经为ture则此时_rc_health仍为ture*/
else
{
rc_original[i] = 0; //没值全部默认设为中位(1500)//遥控器不开相当于遥控器输入0
rc_health = false;
}
if(rc_original[i] < (-300))
{
channelPos[i] = LO; //处理通道 档位
}
else if(rc_original[i] > (300))
{
channelPos[i] = HI; //高档
}
else
{
channelPos[i] = CE; //中档
}
}
/*遥控数据单位化和加死区*/
rc_value_unit[ROL] = data_to_unit_dead(rc_original[ROL], 40);
rc_value_unit[PIT] = data_to_unit_dead(rc_original[PIT], 40);
rc_value_unit[YAW] = data_to_unit_dead(rc_original[YAW], 50);
rc_value_unit[THR] = data_to_unit_dead(rc_original[THR], 100);
}
/*遥控数据单位化和加死区后的数据*/
float get_channel_roll_control_in() //线性数据 -1 to 1
{
return rc_value_unit[ROL];
}
/*遥控数据单位化和加死区后的数据*/
float get_channel_pitch_control_in() //线性数据 -1 to 1
{
return rc_value_unit[PIT];
}
/*遥控数据单位化和加死区后的数据*/
float get_channel_yaw_control_in() //线性数据 -1 to 1
{
return rc_value_unit[YAW];
}
/*遥控数据单位化和加死区后的数据*/
float get_channel_thr_control_in() //线性数据 -1 to 1
{
return rc_value_unit[THR];
}
/*遥控数据单位化和加死区后的数据*/
float get_one_way_throttle() //线性数据 0 to 1 一般用于手动控制油门
{
if(rc_original[THR] == 0) return 0;
return (rc_original[THR]+500)*0.001f;
}
_Bool get_rc_health(void)
{
return (_rc_health && rc_connect_flag);
}