前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SimpleFOC-多路PWM驱动,相电流监测

SimpleFOC-多路PWM驱动,相电流监测

作者头像
云深无际
发布2023-05-24 11:48:15
6130
发布2023-05-24 11:48:15
举报
文章被收录于专栏:云深之无迹云深之无迹

三天助力一个不知死活的本科生毕业论文,开搞!

3PWM

6PWM

在BLDC电机控制上,6路PWM 控制模式比3路PWM更自由,因为6个半桥式晶体管的每一个都可以单独控制。

死区时间

开关元器件的和严格意义并不是相同的。IGBT,MOS并不是理想开关器件,其开通时间和关断时间不是严格一致的,如果两端有电压,将导致直流电源短路,损坏桥臂功率器件,称之为“桥臂直通”。所以在驱动开关元器件门极的时候需要增加一段延时,确保另一个开关管完全关断之后再去打开这个开关元器件,通常存在两种情况;

上半桥关断后,延迟一段时间再打开下半桥;

下半桥关断后,延迟一段时间再打开上半桥;

这样就不会同时导通,从而避免功率元件烧毁。

相对于PWM来说,死区时间是在PWM输出的这个时间,上下管都不会有输出,当然会使波形输出中断,死区时间一般只占百分之几的周期。但是当PWM波本身占空比小时,空出的部分要比死区还大,所以死区会影响输出的纹波,但应该不是起到决定性作用的。

另外如果死区设置过小,但是仍然出现上下管同时导通,因为导通时间非常非常短,电流没有变得很大,不足以烧毁系统,那此时会导致开关元器件发热严重,所以选择合适的死区时间尤为重要,过大过小都不行。

因为门极上升和下降时间通常比延迟时间小很多,所以这里可以不用考虑它们。则死区时间满足;

:最大的关断延迟时间;

:最小的开通延迟时间;

:最大的驱动信号传递延迟时间;

:最小的驱动信号传递延迟时间;

上面就是三种基本的转子获得的方式,第一个是正交的光栅,第二个是电磁,最后一个是霍尔原件。

采样电阻是电流采样和对电压采样。对电流采样则串联一个阻值较小的电阻,对电压采样则并联一个阻值较大的电阻。

采样电阻的工作原理是欧姆定律,即I=U/R,通过IC检测电阻两端的电压,用电压除以电阻标称值即得到通过电阻的电流值。因此采样电阻的精度直接影响到电流采样的准确性。

老传统的采样电路了

采样电阻的采样原理:采样电阻将一个阻值较小的电阻,串联在电路中用于把电流转换为电压信号进行测量。采样电阻是一种限流元件,导体对电流的阻碍作用大,我们便说其采样电阻大,反之,称其采样电阻小。但是采样电阻并不会因为导体上没有电流通过而消失,采样电阻是一个导体的固有属性,即便导体上没有电流流过,其采样电阻也是存在的。采样电阻只是一个统称,对其深入了解之后会知道采样电阻多种多样,采样电阻连接采样电阻的阻值会选在1欧姆以下,属于毫欧级电阻,但是部分电阻,有个采样电压等要求,必须选择大阻值电阻,但是这样电阻基数大,产生的误差大。

电流检测结构要求高精度双向放大器具有比常规低侧或高侧放大器更好的PWM抑制。

这个是在线测量相电流的方式

我认为的PWM抑制是,这个地方测量到的相电流的大小,其实是在一个PWM的信号源里面知道电流的大小,所以就是要压制PWM。这就像是在飓风期间测量海上漂浮的杯子中的液体一样。

在这样的情况下测量电流的大小

SimpleFOC直接使用的是在线测量,而且还是双向测量

原理图

INA240的原理框图

大多数低端无刷电机驱动器没有电流测量功能,SimpleFOC提供了一种通过设置电机电压而不是电流来控制电机扭矩的方法。这使无刷直流电机有效地成为直流电机。

也叫直列式测量

电机的驱动电路可生成脉宽调制 (PWM) 信号来控制电机的运行。这些调制信号使得位置与各电机相位一致的测量电路进行共模电压 (VCM) 转换,在转换过程中,电压将在极短时间内在不同高电压电平之间进行切换。

完美的放大器产品能够完全抑制测量的 VCM 分量,仅放大与流经分流电阻器 的电流相对应的差分电压。不幸的是,实际的放大器产品并不理想,会受到大 PWM 驱动输入电压阶跃的影响。由于实际的放大器产品无法进行无限的抑制共模,因此放大器输出端可能会出现与每个输入电压阶跃相对应的大幅度意外干扰。

此类测量的常用方法是选择带宽较高的电流检测放大器。为了保持在可听频率范围之上,典型的调制频率 范围为 20kHz 至 30kHz。用于在这些 PWM 驱动应用 中进行直列式电流测量的放大器选择以信号带宽在 200kHz 至 500kHz 范围内的放大器为目标。以往选择放大器时并不基于显著低于 PWM 信号带宽的实际信号带宽。选择更高的放大器带宽可以使输出干扰在输入电压转换后快速稳定下来。

抑制过后得到的样子

消除噪声后表示的每个相位的输出电压信号。红色波形表示信号,表明经过电子换向的功率晶体管将正弦波形尽可能准确地复制到电机。电流感应放大器将经受从电源轨(例如 V BATT = 48V)到接地端的输入共模电压信号。

低侧相位检测可以更轻松地确定电动机的相电流,但这不是一种精确的方法。它可能会引入与相电流有关的误差。

主要挑战在于,共模电压是PWM信号,除非启用了适当的PWM抑制电路,否则会导致输出信号中断。这导致对电流感测放大器的要求更加严格,该电流感测放大器必须具有出色的DC和AC共模抑制比(CMRR)以及高DC精度(低输入失调电压)。一些设备测量在一个方向上流动的电流。

下面给出一个Arduino控制的FOC电流在线测量实例

对于放大器给出的电流就是直接使用ADC采集就行

让我们来过滤一下这个电流,因为频率的原因,就低通滤波就好

使用操作符重载一下

我们直接使用这个函数就行

相电流的变化,代码在文后

低侧电流测试

低侧电流检测可能是最常见的电流检测技术。主要原因是它既不需要高性能PWM抑制电流检测放大器(如在线检测放大器),也不需要支持高压的放大器(如高侧放大器)。

采样电阻始终置于低侧MOSFET和地之间,确保放大器的端子上始终具有非常低的电压。这种方法的主要缺点是,由于只有相应的低侧mosfet开启时,通过采样电阻的电流才是相电流,而我们只能在这些时刻测量到相电流。PWM频率通常为20至50 kHz,这意味着低侧MOSFET每秒开关20000至50000次,因此PWM设置和ADC采集之间的同步非常重要。

目前这个在开发中。

这个是高测测量一般也不用

代码语言:javascript
复制
https://www.ti.com.cn/product/cn/INA240
代码语言:javascript
复制
https://www.elecfans.com/analog/202007151246626.html
代码语言:javascript
复制
https://zhuanlan.zhihu.com/p/401573207
代码语言:javascript
复制
https://www.sohu.com/a/439655421_468638
代码语言:javascript
复制
https://baijiahao.baidu.com/s?id=1753450617334241521&wfr=spider&for=pc
代码语言:javascript
复制
https://m.elecfans.com/article/1107269.html
代码语言:javascript
复制
https://www.elecfans.com/d/1412716.html
代码语言:javascript
复制

// 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

#include <SimpleFOC.h>

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();
}

相电流的检测函数

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-03-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云深之无迹 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档