一直没能仔细看的几个文件就是DT(数据传输)、RC(遥控器控制)和flight_ctrl,一是长,二是难,不直观,太多flag啊什么的,与总体控制有关。今晚就看完这些然后对代码做一个更加全面的整理,后面就要去试飞机和自己写控制了。
需要逐个函数进行分析。
void Remote_Control_Init()
{
RC_IN_MODE = Ano_Parame.set.pwmInMode;
if(RC_IN_MODE == SBUS)
{
Drv_SbusInit();
}
else
{
Drv_PpmInit();
}
}
看名字,遥控控制初始化。
有关通信协议的东西,ppm和subs,应该不是我们需要关心的内容。
后面还有两个看门狗函数,不知道在搞什么。。。
然后有一个很长的函数,其实也就这个比较长,又有好多判断,一点一点看:
void unlock(u8 dT_ms)
解锁的意思
if( flag.power_state <=2 && para_sta.save_trig == 0)//只有电池电压非最低并且没有操作flash时,才允许进行解锁
{
if(sens_hd_check.acc_ok && sens_hd_check.gyro_ok)
{
if(sens_hd_check.baro_ok)
{
if(flag.sensor_imu_ok )//imu传感器正常时,才允许解锁
{
flag.unlock_err = 0; //允许解锁标志位
}
else
{
flag.unlock_err = 1;//imu异常,不允许解锁
}
}
else
{
LED_STA.errBaro = 1;
flag.unlock_err = 2;//气压计异常,不允许解锁。
}
}
else
{
LED_STA.errMpu = 1;
flag.unlock_err = 3;//惯性传感器异常,不允许解锁。
}
}
else
{
flag.unlock_err = 4;//电池电压异常,不允许解锁
}
这个很多层的代码块其实逻辑并不复杂,依次对电源、陀螺仪加速度计、气压计、imu、进行有效检验,只有全部ok,解锁错误标志位才为0,否则都为1、2、3等等,非0也就是解锁错误。同时如果有问题,相应的指示灯会亮。
这里的unlock_err,要记住,有关解锁的标志位应该有好几层。
if(flag.unlock_sta == 0)
{
if(flag.unlock_cmd != 0)
{
if(flag.unlock_err == 0)
{
//
flag.unlock_sta = flag.unlock_cmd;
//
ANO_DT_SendString("Unlock OK!");
}
else
{
//reset
flag.unlock_cmd = 0;
//
if(flag.unlock_err == 1)
{
ANO_DT_SendString("Unlock Fail!");
}
else if(flag.unlock_err == 2)
{
ANO_DT_SendString("Unlock Fail!");
}
else if(flag.unlock_err == 3)
{
ANO_DT_SendString("Unlock Fail!");
}
else if(flag.unlock_err == 4)
{
ANO_DT_SendString("Power Low,Unlock Fail!");
}
else
{
}
}
}
else
{
}
}
也是好多层逻辑,但貌似也不复杂:
如果unlock_sta等于0,也就是没有解锁,那么如果unlock_cmd=1,也就是解锁命令有效,而且unlock_err=0,解锁没有错误,那么将解锁置一。
否则如果前面条件满足,但解锁有错误,就将unlock_cmd置0,清楚解锁命令,并给出错误的原因。
else
{
if(flag.unlock_cmd == 0)
{
ANO_DT_SendString(" FC Output Locked! ");
}
flag.unlock_sta = flag.unlock_cmd;
}
如果unlock_sta等于1,也就是已经解锁了,那么再判断当前解锁命令unlock_cmd是否有效,如果解锁命令无效,就说明此时需要锁定,把unlock_cmd赋给unlock_sta。
也就是说,对于解锁或者上锁,我们只要去调整unlock_cmd,而不需要去调整unlock_sta。
接下来又很长:
if(CH_N[CH_THR] < -UN_THR_VALUE )
{
//判断用户是否想要上锁、解锁
if(ABS(CH_N[CH_YAW])>0.1f*UN_YAW_VALUE && CH_N[CH_PIT]< -0.1f*UN_PIT_VALUE)
{
if(flag.locking == 0)
{
flag.locking = 1;
}
}
else
{
flag.locking = 0;
}
//飞控上锁、解锁检测
if(CH_N[CH_PIT]<-UN_PIT_VALUE && CH_N[CH_ROL]>UN_ROL_VALUE && CH_N[CH_YAW]<-UN_YAW_VALUE)
{
stick_fun_0 = 1;
flag.locking = 2;
}
else if(CH_N[CH_PIT]<-UN_PIT_VALUE && CH_N[CH_ROL]<-UN_ROL_VALUE && CH_N[CH_YAW]>UN_YAW_VALUE)
{
stick_fun_0 = 1;
flag.locking = 2;
}
else
{
stick_fun_0 = 0;
}
u8 f = 0;
if(flag.unlock_sta)
{
//如果为解锁状态,最终f=0,将f赋值给flag.unlock_sta,飞控完成上锁
f = 0;
unlock_time = 1000;
}
else
{
//如果飞控为锁定状态,则f=2,将f赋值给flag.unlock_sta,飞控解锁完成
f = 2;
unlock_time = 200;
}
//进行最终的时间积分判断,摇杆必须满足条件unlock_time时间后,才会执行锁定和解锁动作
stick_function_check_longpress(dT_ms,&unlock_f,unlock_time,stick_fun_0,f,&flag.unlock_cmd);
}
如果油门值低于-300,也就是油门拉低,就进入判断。
先判断pitch和yaw,如果yaw绝对值大于那个啥,pitch值小于那个啥,且此时locking等于0,表示没锁,就令locking=1,表示正在上锁(?还并不知locking是啥),否则,如果不满足这个条件,locking等于0,就是没有在上锁(?)
接下来再判断:外八和内八,都会使locking为2,stick_fun_0为1(虽然不知道这是个啥),如果不是外八或者内八,那么不需要管locking,把stick_fun_0置为0(orz)
再判断:如果为解锁状态,f = 0,unlock_time = 1000
如果为上锁状态,f = 2,unlock_time = 200
然后判断:如果stick_fun_0有效(1),那么计时,如果计时超过时间unlock_time,就把f赋值给unlock_cmd。
也就是说,如果内八或者外八,那么stick_fun_0为1,如果此时是解锁状态,且状态维一定的时间,那么就把f=0赋值给unlock_cmd,也就是锁定。如果此时是上锁状态,那么f=2赋值给unlock_cmd,表示要解锁。
如果没有内八或者外八,说明不要锁定,stick_fun_0清零,后面不会计时,也不会对unlock_cmd赋值。
else
{
flag.locking = 0; //油门高
if(flag.unlock_cmd == 2)
{
flag.unlock_cmd = 1;
}
}
如果油门值没有低于-300,那么locking=0,表示没有在上锁,如果unlock_cmd=2,那么就把它赋值为1(暂时还不知道unlock_cmd2和1有什么区别)
if(CH_N[CH_THR]>-350)
{
flag.thr_low = 0;//油门非低
}
else
{
flag.thr_low = 1;//油门拉低
}
很清楚,就是不知道有啥用。
整个函数就是有关解锁的。。。再总结的时候会说。
接下来
void RC_duty_task(u8 dT_ms) //建议2ms调用一次
是轮询函数之一。
如果start_ok=1,则进入判断。
if(RC_IN_MODE == PPM || RC_IN_MODE == PWM)
{
for(u8 i=0;i<CH_NUM;i++)
{
if(chn_en_bit & (1<<i))//(Rc_Ppm_In[i]!=0)//该通道有值
{
CH_N[i] = ((s16)RC_PPM.Captures[i] - 1500); //1000 -- 2000us,处理成大约+-500摇杆量
}
else
{
CH_N[i] = 0;
}
CH_N[i] = LIMIT(CH_N[i],-500,500);//限制到+—500
}
}
如果RC_IN_MODE是ppm或者pwm,那么对chn_en_bit每个位进行判断,如果该位有效,说明有值,那么处理该通道的值,否则该通道的值设为0.
else//sbus
{
for(u8 i=0;i<CH_NUM;i++)
{
if(chn_en_bit & (1<<i))//该通道有值
{
CH_N[i] = 0.65f *((s16)Rc_Sbus_In[i] - 1024); //248 --1024 --1800,处理成大约+-500摇杆量
}
else
{
CH_N[i] = 0;
}
CH_N[i] = LIMIT(CH_N[i],-500,500);//限制到+—500
}
}
如果是sbus,那么仍然做该处理,只是处理方式不太一样,最终都是把各个通道的值处理为±500的油门量。
//解锁监测
unlock(dT_ms);
//摇杆触发功能监测
stick_function(dT_ms);
//通道看门狗
ch_watch_dog(dT_ms);
//失控保护检查
fail_safe_check(dT_ms);//3ms
接下来调用这些,也就是说这些函数会跟随RC_duty_task一起轮询。
接下来看关于fail_safe,也就是失控保护:
void fail_safe()
{
for(u8 i = 0;i<4;i++)
{
CH_N[i] = 0;
}
if(CH_N[CH_THR]>0)
{
CH_N[CH_THR] = 0;
}
CH_N[CH_ROL] = 0;
CH_N[CH_PIT] = 0;
CH_N[CH_YAW] = 0;
//切记不能给 CH_N[AUX1]赋值,否则可能导致死循环。(根据AUX1特殊值判断接收机failsafe信号)
if(flag.unlock_sta)
{
if(switchs.gps_on ==0)
{
flag.auto_take_off_land = AUTO_LAND; //如果解锁,自动降落标记置位
}
else
{
flag.rc_loss_back_home = 1;
}
}
}
先看一下这个枚举里,通道和数字的对应关系:
enum
{
CH_ROL = 0,
CH_PIT ,
CH_THR ,
CH_YAW ,
AUX1 ,
AUX2 ,
AUX3 ,
AUX4 ,
CH_NUM,//8
};
可以看出,这里对前四个值清零了两遍。
后面进行判断:如果此时是解锁状态,
那么如果没有gps,就flag.auto_take_off_land = AUTO_LAND,
如果有gps,就flag.rc_loss_back_home = 1;
也就是说,执行这个函数的时候,会启动自动降落。
再看失控保护检查,应该也就是判断何时调用fail_safe()函数的函数:
cnt += dT_ms;
if(cnt >= 500) //500*dT 秒
{
这个东西,500ms才会调用一次。
if((chn_en_bit & 0x0F) != 0x0F || flag.chn_failsafe ) //前4通道有任意一通道无信号或者受到接收机失控保护信号
{
cnt2 ++;
}
else
{
cnt2 --;
}
如注释所说,前4通道有任意一通道无信号,或者受到接收机失控保护信号,那么对cnt2操作。
if(cnt2>=2)
{
cnt2 = 0;
flag.rc_loss = 1; //认为丢失遥控信号
LED_STA.noRc = 1;
fail_safe();
}
如果cnt2大于等于2,说明至少连续进入函数两次,那么cnt2置零,rc_loss=1,即确认丢失了遥控信号,那么LED_STA.noRc = 1,用灯指示出来,并且执行fail_safe()。
else if(cnt2<=-2) //认为信号正常
{
cnt2 = 0;
if(flag.rc_loss)
{
flag.rc_loss = 0;
LED_STA.noRc = 0;
if(flag.taking_off)
flag.auto_take_off_land = AUTO_TAKE_OFF_FINISH; //解除下降
}
}
如果cnt2<=-2,那么认为信号很正常,cnt2清零。如果上次是flag.rc_loss是1,那么改为0,灯也灭掉。如果起飞了,解除下降。
test_si_cnt = signal_intensity;
signal_intensity=0; //累计接收次数
不知道什么鬼。。。
最后就是这个什么stick_function()摇杆触发功能?
这个东西也跟随轮询。
不写了,内容就是在没有解锁的时候,会不停的检测遥感状态,不同的摇杆状态对应着罗盘、加速度计、陀螺仪的校准。
那遥控部分就完成了。。。。好长,但主要就只有四个量的接收转换、解锁、上锁、失控保护和失控保护检查。。比想象中简单一丢丢。