三天助力一个不知死活的本科生毕业论文,开搞!
3PWM
6PWM
在BLDC电机控制上,6路PWM 控制模式比3路PWM更自由,因为6个半桥式晶体管的每一个都可以单独控制。
死区时间
上面就是三种基本的转子获得的方式,第一个是正交的光栅,第二个是电磁,最后一个是霍尔原件。
采样电阻是电流采样和对电压采样。对电流采样则串联一个阻值较小的电阻,对电压采样则并联一个阻值较大的电阻。
老传统的采样电路了
采样电阻的采样原理:采样电阻将一个阻值较小的电阻,串联在电路中用于把电流转换为电压信号进行测量。采样电阻是一种限流元件,导体对电流的阻碍作用大,我们便说其采样电阻大,反之,称其采样电阻小。但是采样电阻并不会因为导体上没有电流通过而消失,采样电阻是一个导体的固有属性,即便导体上没有电流流过,其采样电阻也是存在的。采样电阻只是一个统称,对其深入了解之后会知道采样电阻多种多样,采样电阻连接采样电阻的阻值会选在1欧姆以下,属于毫欧级电阻,但是部分电阻,有个采样电压等要求,必须选择大阻值电阻,但是这样电阻基数大,产生的误差大。
电流检测结构要求高精度双向放大器具有比常规低侧或高侧放大器更好的PWM抑制。
这个是在线测量相电流的方式
我认为的PWM抑制是,这个地方测量到的相电流的大小,其实是在一个PWM的信号源里面知道电流的大小,所以就是要压制PWM。这就像是在飓风期间测量海上漂浮的杯子中的液体一样。
在这样的情况下测量电流的大小
SimpleFOC直接使用的是在线测量,而且还是双向测量
原理图
INA240的原理框图
也叫直列式测量
电机的驱动电路可生成脉宽调制 (PWM) 信号来控制电机的运行。这些调制信号使得位置与各电机相位一致的测量电路进行共模电压 (VCM) 转换,在转换过程中,电压将在极短时间内在不同高电压电平之间进行切换。
完美的放大器产品能够完全抑制测量的 VCM 分量,仅放大与流经分流电阻器 的电流相对应的差分电压。不幸的是,实际的放大器产品并不理想,会受到大 PWM 驱动输入电压阶跃的影响。由于实际的放大器产品无法进行无限的抑制共模,因此放大器输出端可能会出现与每个输入电压阶跃相对应的大幅度意外干扰。
此类测量的常用方法是选择带宽较高的电流检测放大器。为了保持在可听频率范围之上,典型的调制频率 范围为 20kHz 至 30kHz。用于在这些 PWM 驱动应用 中进行直列式电流测量的放大器选择以信号带宽在 200kHz 至 500kHz 范围内的放大器为目标。以往选择放大器时并不基于显著低于 PWM 信号带宽的实际信号带宽。选择更高的放大器带宽可以使输出干扰在输入电压转换后快速稳定下来。
抑制过后得到的样子
消除噪声后表示的每个相位的输出电压信号。红色波形表示信号,表明经过电子换向的功率晶体管将正弦波形尽可能准确地复制到电机。电流感应放大器将经受从电源轨(例如 V BATT = 48V)到接地端的输入共模电压信号。
对于放大器给出的电流就是直接使用ADC采集就行
让我们来过滤一下这个电流,因为频率的原因,就低通滤波就好
使用操作符重载一下
我们直接使用这个函数就行
相电流的变化,代码在文后
低侧电流测试
低侧电流检测可能是最常见的电流检测技术。主要原因是它既不需要高性能PWM抑制电流检测放大器(如在线检测放大器),也不需要支持高压的放大器(如高侧放大器)。
采样电阻始终置于低侧MOSFET和地之间,确保放大器的端子上始终具有非常低的电压。这种方法的主要缺点是,由于只有相应的低侧mosfet开启时,通过采样电阻的电流才是相电流,而我们只能在这些时刻测量到相电流。PWM频率通常为20至50 kHz,这意味着低侧MOSFET每秒开关20000至50000次,因此PWM设置和ADC采集之间的同步非常重要。
目前这个在开发中。
这个是高测测量一般也不用
https://www.ti.com.cn/product/cn/INA240
https://www.elecfans.com/analog/202007151246626.html
https://zhuanlan.zhihu.com/p/401573207
https://www.sohu.com/a/439655421_468638
https://baijiahao.baidu.com/s?id=1753450617334241521&wfr=spider&for=pc
https://m.elecfans.com/article/1107269.html
https://www.elecfans.com/d/1412716.html
// IN1 pwm1 9 27
// IN2 pwm2 6 26
// IN3 pwm3 5 25
// INH1 enable1 8 12
// INH2 enable2 7 13
// INH3 enable3 4 14
// in-line current sense - phase 1/A 35
// in-line current sense - phase 1/C 34
class LowPassFilte
{
public:
LowPassFilte(float Tf); // 低通滤波器时间常量
~LowPassFilte() = default;
float operator()(float x);
float Tf; //!< 低通滤波器时间常量
protected:
unsigned long timestamp_prev; //!< 上次执行时间戳
float y_prev; //!< 经过上次执行后过滤到的值
};
LowPassFilte::LowPassFilte(float time_constant)
: Tf(time_constant), y_prev(0.0f)
{
timestamp_prev = micros();
}
float LowPassFilte::operator()(float x)
{
unsigned long timestamp = micros();
float dt = (timestamp - timestamp_prev) * 1e-6f;
if (dt < 0.0f || dt > 0.5f)
dt = 1e-3f;
float alpha = Tf / (Tf + dt);
float y = alpha * y_prev + (1.0f - alpha) * x;
y_prev = y;
timestamp_prev = timestamp;
return y;
}
LowPassFilte LF_a(0.01); // 原始数据滤波器
LowPassFilte LF_b(0.01); // A相电流滤波器
LowPassFilte LF_c(0.01); // C相电流滤波器
// AS5600编码器支持spi,iic和模拟量三种数据传输方式,这里用iic(同时也是最常用的方式)
// magnetic sensor instance - I2C
MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);
TwoWire I2Cone = TwoWire(0);
// BLDC motor & driver instance
BLDCMotor motor = BLDCMotor(11);
BLDCDriver3PWM driver = BLDCDriver3PWM(27, 26, 25, 12, 13, 14);
InlineCurrentSense Cs_motor(0.001, 50.0, 35, 36, 34);
// voltage set point variable
float target_voltage = 5.0;
// instantiate the commander
Commander command = Commander(Serial);
void doTarget(char *cmd)
{
command.scalar(&target_voltage, cmd);
}
void setup()
{
// initialise magnetic sensor hardware
I2Cone.begin(18, 5, 400000);
sensor.init(&I2Cone);
// link the motor to the sensor
motor.linkSensor(&sensor);
// power supply voltage
driver.voltage_power_supply = 12;
driver.init();
motor.linkDriver(&driver);
// aligning voltage
motor.voltage_sensor_align = 5;
// choose FOC modulation (optional)
motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
// set motion control loop to be used
motor.controller = MotionControlType::torque;
// use monitoring with serial
Serial.begin(115200);
// comment out if not needed
motor.useMonitoring(Serial);
// initialize motor
motor.init();
// align sensor and start FOC
motor.initFOC();
// add target command T
command.add('T', doTarget, "target voltage");
Serial.println(F("Motor ready."));
Serial.println(F("Set the target voltage using serial terminal:"));
_delay(1000);
Cs_motor.init();
}
void loop()
{
// main FOC algorithm function
// the faster you run this function the better
// Arduino UNO loop ~1kHz
// Bluepill loop ~10kHz
motor.loopFOC();
// Motion control function
// velocity, position or voltage (defined in motor.controller)
// this function can be run at much lower frequency than loopFOC() function
// You can also use motor.move() and set the motor.target in the code
motor.move(target_voltage);
// Cs_motor.getPhaseCurrents();
Serial.print(LF_b((Cs_motor.getPhaseCurrents()).a));
Serial.print(",");
Serial.println(LF_c((Cs_motor.getPhaseCurrents()).c));
// Serial.print(LF_a(analogRead(35)));
// Serial.print(",");
// Serial.print(LF_b((3.3 * ((float)analogRead(35) - 1930) / 4096.0) * 20.0));
// Serial.print(",");
// Serial.println(LF_c((-3.3 * ((float)analogRead(34) - 1930) / 4096.0) * 20.0));
// user communication
command.run();
}
相电流的检测函数