logo资料库

ESC32源码分析流程图解析.pdf

第1页 / 共11页
第2页 / 共11页
第3页 / 共11页
第4页 / 共11页
第5页 / 共11页
第6页 / 共11页
第7页 / 共11页
第8页 / 共11页
资料共11页,剩余部分请下载后查看
runWatchDog.vsd
1.runWatchGog
2.runRpm
3.runThrotLim(fetDutyCycle)
4.DMA中断
5.void PWM_IRQ_HANDLER(void)
6.void runNewInput(uint16_t setpoint)
油门曲线图
8.runStart()
9.启动阶段分析
10.bootloader
11.word文档具体说明
runWatchDog() t = timerMicros; 当前时间戳 d = detectedCrossing; 过零时间戳 p = pwmValidMicros; 油门输入时间戳 ESC_STATE_DISARMED = 0, //非正常停止状态 ESC_STATE_STOPPED, //停止状态 ESC_STATE_NOCOMM, //强拖状态 ESC_STATE_STARTING, //启动状态 ESC_STATE_RUNNING //运行状态 电子频率 f = 1/(6 * t ) 其中:t过零时间单位s f单位hz 电子转速 v = f * 60 其中:v单位 erpm 机械转速 w = v / 极对数 其中 w 单位是rpm Start阶段且好的过零检测大于 启动检测值才切换到run阶段 是启动状态.切换到 运行状态 state =ESC_STATE_RUNNING; digitalHi(statusLed); // turn off 得到当前离上次过零时间间隔 即 离过零过了d时间 负 自 果 后 , state == ESC_STATE_STARTING && fetGoodDetects > fetStartDetects 是 否 自动换向 Start run 得到时间差d = (t >= d) ? (t - d) : (TIMER_MASK - d + t); : 189030589 供 学 习 仅 否 , 等 用 是 号 商 调 群 积 取 分 电 赚 源 档 丢失油门信号 p > PWM_TIMEOUT 否 油门输入模式是PWM模式 inputMode == ESC_INPUT_PWM 得到没有油门输入的时间间隔p p = (t >= p) ? (t - p) : (TIMER_MASK - p + t) 到这肯定是 ESC_STATE_DISARMED 状态 state >= ESC_STATE_STOP 是 PED 否 异常状态,每隔100检测下, state==ESC_STATE_DISARMED && !(runMilis % 100) 否 是 adcAmpsOffset = adcAvgAmps;得到偏执电流 digitalTogg(errorLed); BLHeli_S 开 文 此 是 拿 式 adcAmpsOffset = adcAvgAmps; 得到 零偏 否 state == ESC_STATE_STOPPED 方 停止状态 何 任 否 以 要 St ate>=ESC_STATE_STARTING && fetBadDet ects>fetDisarmDet ects) 是 runDisarm(REASON_PWM_TIMEOUT); //pwm输入超时 否 St ate>=ESC_STATE_STARTING&& Start 或者 run状态且 过零时间超过了 d>ADC_CROSSI NG_TIMEOUT ADC_CROSSI NG_TIMEOUT 是 Start 或者 run状态且 坏的检测超了 是 不 请 否 占空比大于0 fetDutyCycle > 0 是 runDisarm(REASON_BAD_DETECTS); //错误停止 占空比大于0 fetDutyCycle > 0 否 runArm();//手动运行起来 pwmIsrRunOn();//PWM开启输入比较 是 runDisarm(REASON_CROSSING_TIME OUT); 过零超时 结束
runRpm() 否 Rpm = 0.0f; 正常运行状态 state > ESC_STATE_STARTING PRM = a*上次的rpm + (1-a)*本次的rpm 加了个滤波算法 这里的a = p[RPM_MEAS_LP] 是 rpm = p[RPM_MEAS_LP] * rpm + ((32768.0f * runRPMFactor) / (float)adcCrossingPeriod) *(1.0f - p[RPM_MEAS_LP]); 是速度闭环 runMode == 是 CLOSED_LOOP_RPM fetSetDutyCycle(runRpmPID(rpm, targetRpm)); 否 是推力模式 runMode == CLOSED_LOOP_THRUS T 否 Return 0; 号 商 分 调 群 积 取 电 赚 源 档 fetSetDutyCycle(int32_t requestedDutyCycle) fetDutyCycle = requestedDutyCycle;BLHeli_S 开 限幅requestedDutyCycle在0到fetPeriod之间 文 此 拿 式 方 何 任 以 要 不 请 负 自 果 fetSetDutyCycle(runRpmPID(rpm, targetRpm)); 后 , Return 1; 是 : 189030589 供 学 习 仅 , 等 用 速度PID int32_t runRpmPID(float rpm, float target) ff = ( target^2 * p[FF1] +target *p[FF2] )/ avgVolts * fetPeriod error = target – rpm 计算偏差 限制error在 1000内 如果error 大于0的时候 rpmP = error * p[PTERM]; 计算加速PID的P相 rpmI += error * p[ITERM]; 计算加速PID的I相 否则如果error 小于0的时候 rpmP = error * p[PTERM] * p[PNFAC]; 计算减速PID的P相 rpmI += error * p[ITERM] * p[INFAC]; 计算减速PID的I相 以下如果制动模式开启的时候才执行: 如果速度小于 300 执行 fetSetBraking(0); 否则如果Error <= -100.0f 执行 fetSetBraking(1) 否则如果 fetBraking && error > -25.0f 执行 fetSetBraking(0); 计算最后的输出 output = ff + (rpmP + rpmI) * (1.0f / 1500.0f) * fetPeriod; if (output >= fetPeriod) 如果最大输出了 就不允许积分还在累积 rpmI = iTerm; Return output;
runThrotLim(fetDutyCycle) fetActualDutyCycle = duty; p[MAX_CURRENT] > 0.0f 否 是 是 p[CL1TERM] != 0.0f 否 maxVolts=p[CL1TERM]+p[CL2TERM]*rpm+p[CL3TERM]*p[MAX_CURREN T] + p[CL4TERM]*rpm*maxCurrentSQRT+p[CL5TERM]*maxCurrentSQRT; maxDuty = maxVolts * (fetPeriod / avgVolts); fetActualDutyCycle限幅 fetActualDutyCycle += fetPeriod * (RUN_MAX_DUTY_INCREASE * 0.01f); 限制fetActualDutyCycle 在duty以内 fetActualDutyCycle = runCurrentPID(fetActualDutyCycle); 负 自 果 后 , 如果电流限制没有校准过,用pid对占空比进行限制,效果有点差 : 189030589 供 学 习 仅 , 等 用 _fetSetDutyCycle(fetActualDutyCycle); 电流环 PID static int32_t runCurrentPID(int32_t duty) 号 商 分 调 群 积 取 电 赚 如果是异常停止状态,tmp=0,否则tmp= fetActualDutyCycle 设置上桥PWM FET_H_TIMER->FET_A_H_CHANNEL = tmp; FET_H_TIMER->FET_B_H_CHANNEL = tmp; FET_H_TIMER->FET_C_H_CHANNEL = tmp; 源 BLHeli_S 开 文 如果开启制动模式 Tmp = fetActualDutyCycle+fetPeriod / 8 设置下桥的PWM FET_MASTER_TIMER->FET_A_L_CHANNEL = tmp; FET_MASTER_TIMER->FET_B_L_CHANNEL = tmp; FET_MASTER_TIMER->FET_C_L_CHANNEL = tmp; 此 档 拿 式 方 何 任 以 如果电流限制校准过,使用以下公式对占空比进行限制,效果比较好 最大电压maxVolts = p1 + p2*rpm + p3*最大电流 + p4*rpm*maxCurrentSQRT + p5*maxCurrentSQRT 最大占空比maxDuty = maxVolts * PWM周期 /avgvolts 要 不 请 maxDuty 实际占空比 fetActualDutyCycle 计算电流偏差 error = avgAmps - p[MAX_CURRENT]; currentIState += error; 且限幅currentIState必须>=0 计算电流环PI iTerm = currentIState * RUN_CURRENT_ITERM; pTerm = error * RUN_CURRENT_PTERM; 且限幅pTerm 必须>=0 计算占空比 duty = duty - iTerm - pTerm; 限幅duty >=0 Return duty; fetActualDutyCycle duty maxDuty 速度环的输出 fetActualDutyCycle duty duty 是速度环的输出 其中 斜坡1公式如下: fetActualDutyCycle += fetPeriod * (RUN_MAX_DUTY_INCREASE * 0.01f); 然后把 fetActualDutyCycle 传入到电流环PID中,经过计算,得到最后的 fetActualDutyCycle
DMA1_Channel1_IRQHandler 获取当前时间戳 currentMicros=timerGetMicros() 滤波算法是1/64的权值滤波,且最后放大 1<adcblankingMicros 读取反电动势到窗口中 histA[histIndex] = valA = (raw[1]+raw[3]);//SENSE_A histB[histIndex] = valB = (raw[4]+raw[6]);//SENSE_B histC[histIndex] = valC = (raw[5]+raw[7]);//SENSE_C 计算平局值 histIndex = (histIndex + 1) % histSize; avgA += valA - histA[histIndex]; avgB += valB - histB[histIndex]; avgC += valC - histC[histIndex]; : 189030589 供 学 习 仅 果 后 , avgA avgB avgC 中存放的是ad滤波窗口的和 (avgA+avgB+avgC)/histSize>ADC_MIN_COMP*3 且电机运行状态不是异常状态也不是强拖动的状态 计算过零时间差 periodMicros= currentMicros - detectedCrossing , 等 用 号 商 调 群 积 取 是 分 电 赚 源 档 过零时间超过了 periodMicros>nextCrossingD etect 是 BLHeli_S 开 文 此 否 拿 式 方 何 任 根据上次的adcStateA和 本次的avgA avgB avgC 更新 adcStateA 和 nextStep 的值 否 NextStep不为0且 periodMicros > adcMinPeriod 限幅过零时间间隔 是 avgA avgB avgC 中存放的是ad滤波窗口的和 如果 (avgA+avgB+avgC)/histSize>ADC_ MIN_COMP*3 成立那么就检测到过 零点 得到本次过零和上次过零的时间差放在 periodMicros中 如果两次过零的时间间隔超过了上次预估的时间 那么就更新下次要换向的状态 否 退出中断 以 要 不 请 限幅periodMicros在adcMaxPeriod内 adcCrossingPeriod += ((periodMicros<<15) - adcCrossingPeriod)>>3; crossingPeriod = adcCrossingPeriod>>15; fetStep = nextStep; //切换到下一个换向 fetCommutationMicros = 0; //电机换向的时间清零 timerSetAlarm1(crossingPeriod/2 - (ADC_DETECTION_TIME*(histSize+2))/2 - ADC_COMMUTATION_ADVANCE, fetCommutate, crossingPeriod); detectedCrossing = currentMicros; // record crossing time adcEvaluateHistSize(); //更新adc历史窗口 nextCrossingDetect = crossingPeriod*3/4; 估算下个过零时间 If (adcAvgAmps > adcMaxAmps) //记录消耗的最大电流 adcMaxAmps = adcAvgAmps; 清除换向时间戳,在换向的时候从新记录 换向的时间戳 过零时间的1/8权值滤波 记录当前过零的时间戳 预估下次过零的时间
void PWM_IRQ_HANDLER(void) 得到边沿类型 Edge = !(PWM_TIM->SR & TIM_IT_CC2); periodValue = PWM_TIM->CCR1; 得到周期 pwmValue = PWM_TIM->CCR2; 得到高电平 Tmp = periodValue - pwmValue ;得到底电平 是 state == ESC_STATE_DISARMED && Edge == 1 &&Tmp > OW_RESET_MIN && Tmp < OW_RESET_MAX) 否 owReset(); ow的初始化 inputMode == ESC_INPUT_PWM periodValue在pwmMinPeriod和pwmMaxPeriod间 pwmValue在pwmMinValue和pwmMaxValue间 是 如果Edge == 0 pwmValidMicros = timerMicros;赋值油门有效时间戳 runNewInput(pwmValue); 进行油门解析 判断下油门的是否合法,如果合法就把目标油门 传入到runNewIput函数中解析 负 自 果 owEdgeDetect(edge); 是1wire通讯协议 后 , 否 : 189030589 供 学 习 仅 , 等 用 号 商 分 调 群 积 取 退出函数 电 源 赚 档 BLHeli_S 开 文 此 拿 式 方 何 任 以 要 不 请
void runNewInput(uint16_t setpoint) 如果p[PWM_LOWPASS]不为0 低通滤波 filteredSetpoint = (p[PWM_LOWPASS] * filteredSetpoint + (float)setpoint) / (1.0f + p[PWM_LOWPASS]); setpoint = filteredSetpoint; 正常运行run状态下 油门有更新 是 State == ESC_STATE_RUNNING && setpoint != lastPwm 否 开环模式: runMode == OPEN_LOOP fetSetDutyCycle(fetPeriod * (int32_t)(setpoint-pwmLoValue) / (int32_t)(pwmHiValue - pwmLoValue)); 并 列 结 构 闭环模式: runMode == CLOSED_LOOP_RPM float target = p[PWM_RPM_SCALE] * (setpoint-pwmLoValue) / (pwmHiValue - pwmLoValue); targetRpm = (target > p[PWM_RPM_SCALE]) ? p[PWM_RPM_SCALE] : target; 推力模式: runMode == CLOSED_LOOP_THRUST targetThrust = maxThrust * (setpoint-pwmLoValue) / (pwmHiValue - pwmLoValue) 如果targetThrust >0 Target = ((sqrtf(p[THR1TERM] * p[THR1TERM] + 4.0f * p[THR2TERM] * targetThrust) - p[THR1TERM] ) / ( 2.0f * p[THR2TERM] )); 否则 Target = 0.0f; 习 targetRpm = (target > p[PWM_RPM_SCALE]) ? p[PWM_RPM_SCALE] : target; 负 自 果 后 , : 189030589 供 学 仅 伺服模式下 runMode == SERVO_MODE fetSetAngleFromPwm(setpoint); , 等 号 用 商 调 群 积 取 分 电 赚 源 档 lastPwm = setpoint; 记录上次的油门值 BLHeli_S 开 文 此 拿 式 方 否则如果(state == ESC_STATE_NOCOMM || state == ESC_STATE_STARTING) && setpoint <= pwmLoValue 执行 fetSetDutyCycle(0); state = ESC_STATE_RUNNING; 否则如果state == ESC_STATE_DISARMED && setpoint > pwmMinValue && setpoint <= pwmLoValue 执行 runArmCount++; if (runArmCount > RUN_ARM_COUNT) runArm(); 并 列 结 构 何 任 否则 runArmCount = 0; 以 要 不 请 否 state == ESC_STATE_STOPPED && setpoint >= pwmMinStart 是 runStart(); 电机运行开始 退出函数
占空比 目标转速 fetPeriod p[PWM_RPM_SCALE] fetSetDutyCycle targetRpm pwmLoValue setpoint pwmHiValue 油门 pwmLoValue setpoint 开环模式下直接计算占空比赋值到fetSetDutyCycle fetSetDutyCycle = (setpoint-pwmLovalue) / (pwmHiValue- pwmLoValue) * fetPeriod 闭环恒速模式下计算目标转速赋值到targetRpm targetRpm = (setpoint-pwmLovalue) / (pwmHiValue- pwmLoValue) * p[PWM_RPM_SCALE] 油门 pwmHiValue 负 自 果 后 , : 189030589 供 学 习 转速和升力的关系如下: Thrust (推力) =RPM* TH1TERM + RPM^2* TH2TERM 进而反推RPM = (Sqrt(TH1TERM ^2 + 4*TH2TERM * Thrust )-TH1TERM )/(2*TH2TERM) 仅 , 等 用 号 商 分 调 群 积 取 电 赚 源 档 BLHeli_S 开 文 此 拿 式 方 targetThrust = (setpoint-pwmLovalue) / (pwmHiValue- pwmLoValue) * maxThrust 闭环推力模式下计算目标推力赋值到targetThrust 在根据推力和速度的关系计算目标转速targetRpm targetRpm = [ sqrt(p1 * p1 + 4p2 * targetThrust ) -p1 ] / (2*p2) 其中批p1=[THR1TERM] p2=[THR2TERM] 目标转速 何 任 以 要 不 目标推力 请 maxThrust p[PWM_RPM_SCALE] targetThrust targetRpm pwmLoValue setpoint pwmHiValue 油门 targetThrust maxThrust 目标推力
runStart() runRpmPIDReset();积分清零 State = ESC_STATE_STARTING; fetStartCommutation(0) //换向启动 是 (p[START_ALIGN_TIME] == 0) && (p[START_STEPS_NUM] == 0) 否 motorStartSeqInit();//普通启动 fetSetBraking(0) 关闭制动模式 fetStartDuty = p[START_VOLTAGE] / avgVolts * fetPeriod; 得到启动占空比 adcSetCrossingPeriod(adcMaxPeriod/2); 设置过零时间间隔 在这个函数面赋值启动时候的过零时间间隔。 adcCrossingPeriod = crossPer<<15; crossingPeriod = crossPer; startSeqCnt=0; 复位启动计数 startSeqStp = fetNextStep; 得到启动相序号 fetSetBraking(0); 关闭制动模式 fetSetStep(startSeqStp); 强制换向启动 State = ESC_STATE_NOCOMM; 状态改为自动换向 timerSetAlarm2(0, motorStartSeq, 0); detectedCrossing = timerMicros; 过零的时间戳 fetDutyCycle = fetStartDuty; 把占空比设置到寄存器中 _fetSetDutyCycle(fetDutyCycle); adcMaxAmps = 0; 复位最大电流值 fetGoodDetects = 0; 复位检测好的计数 fetBadDetects = 0; 复位坏的检查计数 fetTotalBadDetects = 0; 复位坏的总的检查计数 fetNextStep = startStep; 设置下次的换相的相序 timerSetAlarm2(0, fetMissedCommutate, crossingPeriod); 定时crossingPeriod 进行强制换向的函数注册 fetMissedCommutate 负 自 果 后 , : 189030589 供 学 习 仅 , 等 用 号 商 分 If startSeqCnt < p[START_ALIGN_TIME] 计算启动咱空比 这里做了个斜坡,慢慢增加占空比 fetStartDuty = p[START_ALIGN_VOLTAGE] * ((float)startSeqCnt / p[START_ALIGN_TIME]) / avgVolts * fetPeriod; fetDutyCycle = fetStartDuty; _fetSetDutyCycle(fetDutyCycle); // Prepare next function call period = 1000; // 1 ms nextPeriod = 1000; timerSetAlarm2(period, motorStartSeq, nextPeriod); 此 If startSeqCnt < (p[START_ALIGN_TIME] + p[START_STEPS_NUM]) 如果第一次进入这里既 If (startSeqCnt == p[START_ALIGN_TIME]) 那么 Period = p[START_STEPS_PERIOD]; 调 群 积 取 电 赚 源 档 BLHeli_S 开 文 拿 式 方 何 任 以 不 请 要 startSeqStp++; 换相序号自增且限制6内 fetSetStep(startSeqStp); fetStartDuty = p[START_VOLTAGE] / avgVolts * fetPeriod; 设置PWM fetDutyCycle = fetStartDuty; _fetSetDutyCycle(fetDutyCycle); // Prepare next function call nextPeriod = period - p[START_STEPS_ACCEL]; //设置下次换向时间 If (nextPeriod < p[MIN_PERIOD]) nextPeriod = p[MIN_PERIOD]; // avoid negative period timerSetAlarm2(period, motorStartSeq, nextPeriod); 否则 电机运行了 State = ESC_STATE_STARTING; startSeqStp++; 换相序号自增且限制6内 fetStartCommutation(startSeqStp); 执行启动序列的换向 startSeqCnt++; 退出 退出 并 列 结 构
分享到:
收藏