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++;
退出
退出
并
列
结
构