文件名:_BruGi第三部分(loop 主循环 第一部分)

这个部分是整个云台控制的核心流程,通过分析他可以了解整个云台在一个周期内所进行的计算,了解整个控制流程,对于我来说还是太复杂了,欢迎大家一起帮助我完善。


void loop()//主循环函数

{

int32_t pitchPIDVal;//用来存储俯仰轴的PID计算结果

int32_t rollPIDVal;//用来存储横滚轴的PID计算结果

static char pOutCnt = 0;

static char tOutCnt = 0;

static char tOutCntSub = 0;

static int stateCount = 0;

static uint8_t ledBlinkCnt = 0;

static uint8_t ledBlinkOnTime = 10;

static uint8_t ledBlinkPeriod = 20;

if (motorUpdate) // loop runs with motor ISR update rate (500 Hz),motorUpdate就是电机中断程序的标志位,当它为ture时候,表示中断程序执行一次,并执行完毕,也就是说电机的状态发生了变化。我们这里可以提前看一下中断程序中都做了什么:

这里插入一下中断程序代码:


ISR( TIMER1_OVF_vect )//ISR是ardunio的库函数,是专门用来处理中断的程序,参数TIMER1_OVF_vect是中断向量也就是中断触发,TIMER1_OVF_vect就是当TIMER1溢出的时候为TRUE,具体这个溢出周期时间是多少呢,需要看TIMER1的具体设置了。在BLcontroller.h中有这么一行:TIMSK1 |= _BV(TOIE1);这句代码就是开启timer1的溢出中断。而具体timer1如何配置是跟选择PWM的输出频率有关,8KHZ,32KHZ,4KHZ三种选择。这里已32KHZ设置举例,

TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM10);//timer1为phase

 corrected,8bit模式 PWM模式,最大值为)0xFF(255),A通道和B通道都为升序清零,降序置位

TCCR1B = _BV(CS10);//表示不分频,那就是32KHz,但是什么时候去触发溢出寄存器置位还是不清楚。。。有待继续学习

{

freqCounter++;//初始化改值为0,每次触发一次溢出中断,该数值+1,

if(freqCounter==(CC_FACTOR*1000/MOTORUPDATE_FREQ))//CC_FACTOR*1000代表PWM的频率,定义MOTORUPDATE_FREQ的是电机状态更新频率是500HZ,这句代码的含义就是每到需要更新电机状态的时候执行下列语句。

{

freqCounter=0;//把计数器清零

PWM_A_MOTOR0 = pwm_a_motor0;//默认pwm_a_motor0=128,把驱动电机的PWM占空比设置为计算出的数据

PWM_B_MOTOR0 = pwm_b_motor0;

PWM_C_MOTOR0 = pwm_c_motor0;

PWM_A_MOTOR1 = pwm_a_motor1;

PWM_B_MOTOR1 = pwm_b_motor1;

PWM_C_MOTOR1 = pwm_c_motor1;

// update event

motorUpdate = true;//并将电机状态更新置位,标明状态已经更新。

}

// care for standard timers every 1 ms

if ((freqCounter & 0x01f) == 0) {

TIMER0_isr_emulation();//这里是什么意思还有待研究

}

}


{

motorUpdate = false;//将电机状态更新置位

CH2_ON

// loop period

//    2.053/2.035 ms max/min, error = +5/-13 us (w/o rc)

//    2.098/2.003 ms max/min, error = +50/-45 us (1 x PPM16 1 x PWM)

// update IMU data

readGyros();  // td = 330us

if (config.enableGyro) updateGyroAttitude(); // td = 176 us

if (config.enableACC) updateACCAttitude(); // td = 21 us

getAttiduteAngles(); // td = 372 us//以上这几行是获取最新的状态参数

//****************************

// pitch PID

//****************************

if (fpvModeFreezePitch==false) {//当不在FPV模式下锁定俯仰轴

// td = 92 us

pitchPIDVal = ComputePID(DT_INT_MS, DT_INT_INV, angle[PITCH], pitchAngleSet*1000, &pitchErrorSum, &pitchErrorOld, pitchPIDpar.Kp, pitchPIDpar.Ki, pitchPIDpar.Kd);//PID的计算频率与电机更新状态频率要保持一致,因此PID的DT_INT为2ms,频率为500HZ,通过计算得出新的俯仰轴输出值。

// motor control

pitchMotorDrive = pitchPIDVal * config.dirMotorPitch;//默认config.dirMotorPitch为1

}

//****************************

// roll PID

//****************************

if (fpvModeFreezeRoll==false) {

// td = 92 us

rollPIDVal = ComputePID(DT_INT_MS, DT_INT_INV, angle[ROLL], rollAngleSet*1000, &rollErrorSum, &rollErrorOld, rollPIDpar.Kp, rollPIDpar.Ki, rollPIDpar.Kd);//同理计算出横滚的PID输出值

// motor control

rollMotorDrive = rollPIDVal * config.dirMotorRoll;

}

// motor update t=6us (*)

if (enableMotorUpdates)//

{

// set pitch motor pwm

MoveMotorPosSpeed(config.motorNumberPitch, pitchMotorDrive, maxPWMmotorPitchScaled);//真正驱动电机来自这一行,这个函数定义在BLcontroller.h中,这里详细分析一下


void MoveMotorPosSpeed(uint8_t motorNumber, int MotorPos, uint16_t maxPWM)//这个函数具有三个参数,1.控制电机的序号,2.电机的位置.3PWM的放大因数,意义是控制具体是向哪个电机以正弦表中那三个值来生成PWM波,并且增益会是多少。

{

uint16_t posStep;

uint16_t pwm_a;

uint16_t pwm_b;

uint16_t pwm_c;

// fetch pwm from sinus table 

posStep = MotorPos & 0xff;//要将pid计算出的位置与0xff相与,MotorPos是一个int型数据,16位吧,现在与0xff相与,意味着只保留第八位的数据。也就是值的范围控制在0-256

pwm_a = pwmSinMotor[(uint8_t)posStep];

pwm_b = pwmSinMotor[(uint8_t)(posStep + 85)];

pwm_c = pwmSinMotor[(uint8_t)(posStep + 170)];//驱动电机的三项PWM电角度应该相差120°,360°/120°=3,也就是把正弦数组的长度(256)除以3分为三份,每每两项之间在数组中相隔85(256/3)个元素,那么我们再看一下正弦数组是怎么计算的呢,根据其定义该数组长度256,也就是说将一个电角度周期划为了256等分,数组中数值大小范围是-128到127,但是这里存在一个问题,因为这里(posStep+170)是不能超过255的,因此posStep值不能超过85?但是并没有看到程序中有对应的限制呢。睡了一晚我突然明白了,他把这里变成了一个无符号数,然后如果相加过255就会溢出,那么这里最后就是溢出的那个值,恰好满足了要求,因此posStep的范围还是0-255。但是posStep的范围是根据PID计算中进行限定的,在PID函数的语句中最后output除以4096又除以8,原来output是32位的有符号整形,除以4096又除以8相当于右移动15位,就还剩下17位,如果是正数的话,其中最高位是符号位,剩下16位为数据位。数据范围为0-65535,在这个函数中又与posStep = MotorPos & 0xff;相当于只保留低八位,数据范围最终变为0-255.之所以这么做,是要保证PID的精度,不要浮点数减少运算量,将所有的数都放大,保证都在整数范围内计算,最后再将数据变小到0-255的范围内。

// apply power factor

pwm_a = maxPWM * pwm_a;//maxPWM是一个0~256的数,乘以一个-127-127的数,范围会变话,但是下面紧接着又向右移动8位,相当于是pwm_a乘以了一个小于等于1的数,范围还是在-127到127变化,但是应该是变小了。

pwm_a = pwm_a >> 8;//

pwm_a += 128;//这里最终又加上128,将范围变化到了1-255。

pwm_b = maxPWM * pwm_b;

pwm_b = pwm_b >> 8;

pwm_b += 128;

pwm_c = maxPWM * pwm_c;

pwm_c = pwm_c >> 8;

pwm_c += 128;

// set motor pwm variables

if (motorNumber == 0)

{

pwm_a_motor0 = (uint8_t)pwm_a;

pwm_b_motor0 = (uint8_t)pwm_b;

pwm_c_motor0 = (uint8_t)pwm_c;

}//将PWM占空比值送到控制对应电机的通道中

if (motorNumber == 1)

{

pwm_a_motor1 = (uint8_t)pwm_a;

pwm_b_motor1 = (uint8_t)pwm_b;

pwm_c_motor1 = (uint8_t)pwm_c;

}

}


// set roll motor pwm

MoveMotorPosSpeed(config.motorNumberRoll, rollMotorDrive, maxPWMmotorRollScaled);

}//控制横滚轴的电机运动

// Evaluate RC-Signals, td = 120 us//这一段跟遥控信号有关,暂时先不分析

if (fpvModePitch==true) {

pitchAngleSet = utilLP3_float(qLPPitch, PitchPhiSet, rcLPFPitchFpv_tc);

} else if(config.rcAbsolutePitch==1) {

pitchAngleSet = utilLP3_float(qLPPitch, PitchPhiSet, rcLPFPitch_tc); // 63us

} else {

pitchAngleSet = utilLP3_float(qLPPitch, PitchPhiSet, LOWPASS_K_FLOAT(0.03));

}

if (fpvModeRoll==true) {

rollAngleSet = utilLP3_float(qLPRoll, RollPhiSet, rcLPFRollFpv_tc);

} else if(config.rcAbsoluteRoll==1) {

rollAngleSet = utilLP3_float(qLPRoll, RollPhiSet, rcLPFRoll_tc);

} else {

rollAngleSet = utilLP3_float(qLPRoll, RollPhiSet, LOWPASS_K_FLOAT(0.03));

}

// tElapsed = 1.250 ms

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容