simpleFOC控制无刷电机理论及实践

目录

前言和基础知识

simplefoc

无刷电机

例程

例程1:驱动电机固定在某一角度

例程2:驱动电机在两个角度位置之间切换

例程3:驱动电机在两个角度位置之间平滑切换

例程4:驱动电机转圈

例程5:驱动电机在六个基矢量之间切换运转

例程6:驱动电机平滑转圈(模拟正弦波)

例程7:通过编码器读取电机位置

例程8:通过IIC通信发现IIC总线上的AS5600设备

例程9:通过IIC通信读取AS5600的原始数据

例程10:通过iic通讯读取AS5600位置数据(用simplefoc库函数)

例程11:开环速度控制

例程12:闭环速度控制

例程13:开环位置控制

例程14:闭环位置控制

例程15:电压模式的开环扭矩控制

例程16:电流模式的闭环力矩控制

参考文献:


前言和基础知识

simplefoc

simplefoc各个版本

V1.3.3                                                         V2.0.3                                                         V0.2

在这里插入图片描述

 灯哥simplefoc各版本

V1.0

V2.0

V3.0

这里的foc驱动器我用的灯哥的foc v1.0和v3.0版本的,同时有时候也会用官方V0.2版本的,我们通过灯哥foc v1.0原理图可以看到第一个电机的控制引脚是esp32的32,33,25,26四个引脚。其中26引脚表示电机使能,其余的32,33,25三个引脚是控制无刷电机的三相输出。

 如果使用的是simplefoc v0.2版本的

我们可以看官方的github链接:

​​​​​​GitHub - simplefoc/Arduino-SimpleFOC-PowerShield: A powerful Arduino shield for running BLDC motors using the FOC algorithm 这里需要把8,7,4三个使能引脚都置为高电平,电机才会转,需要注意!

这里有原理图:

无刷电机

例程

例程1:驱动电机固定在某一角度

代码:

void setup() {
  pinMode(22,OUTPUT);
  digitalWrite(22,HIGH);
  pinMode(32,OUTPUT);
  pinMode(33,OUTPUT);
  pinMode(25,OUTPUT);
  
}

void loop() {
  digitalWrite(32,HIGH);
  digitalWrite(33,LOW);
  digitalWrite(25,LOW);
}

效果:

无刷电机1

例程2:驱动电机在两个角度位置之间切换

代码:

#define sl 500

#define enable_pinA 12
#define enable_pinB 13
#define enable_pinC 14
 
#define piA 27
#define piB 26
#define piC 25


void setup() {
  pinMode(enable_pinA,OUTPUT);
  digitalWrite(enable_pinA,HIGH);
  pinMode(enable_pinB,OUTPUT);
  digitalWrite(enable_pinB,HIGH);
  pinMode(enable_pinC,OUTPUT);
  digitalWrite(enable_pinC,HIGH);

  pinMode(piA,OUTPUT);
  pinMode(piB,OUTPUT);
  pinMode(piC,OUTPUT);
}
 
void loop() {
  digitalWrite(piA,HIGH);
  digitalWrite(piB,LOW);
  digitalWrite(piC,LOW);
  delay(sl);
  digitalWrite(piA,HIGH);
  digitalWrite(piB,HIGH);
  digitalWrite(piC,LOW);
  delay(sl);
}

效果:

无刷电机2

我们可以看到这个效果不是很好,因为电机的转子是在这两个角度之间步进切换的,并没有平滑过渡,只是在这两个位置之间切换,如果想电机能够平滑的在这两个角度之间切换,就需要我们在这两个角度之间插值,可以平均插,也可以根据需要的算法进行插值,我们这里平均插值试试。 

代码:

 图片来源:无刷电机的工作原理,动图演示,一目了然 - 知乎

例程3:驱动电机在两个角度位置之间平滑切换

#define sl 500

void setup() {
  pinMode(22,OUTPUT);
  digitalWrite(22,HIGH);
  pinMode(32,OUTPUT);
  pinMode(33,OUTPUT);
  pinMode(25,OUTPUT);
  ledcSetup(0,5000,8);//频道0,5000Hz,8位分辨率
  ledcAttachPin(32,0);
  ledcSetup(1,5000,8);//频道0,5000Hz,8位分辨率
  ledcAttachPin(25,1);
}

void loop() {
  ledcWrite(0,255);
  digitalWrite(33,HIGH);
  ledcWrite(1,0);
  delay(sl);
  for(int i=0;i<=255;i++)
  {
    ledcWrite(0,255-i);
    ledcWrite(1,i);
    delay(5);
  }
  ledcWrite(0,0);
  digitalWrite(33,HIGH);
  ledcWrite(1,255);
  delay(sl);
  for(int i=0;i<=255;i++)
  {
    ledcWrite(0,i);
    ledcWrite(1,255-i);
    delay(5);
  }
}

我们可以看到这里pwm波的频率可以修改,理论上说频率越高,电机运转越平滑,因为频率越高代表着这个pwm波的有效电压越接近模拟值, 我们可以修改pwm波的频率看效果。下面视频中是修改了50Hz,500Hz,5000Hz,50000Hz着四种频率的运行效果。

效果:

无刷电机3

例程4:驱动电机转圈

代码:

#define sl 500

void setup() {
  pinMode(22,OUTPUT);
  digitalWrite(22,HIGH);
  pinMode(32,OUTPUT);
  pinMode(33,OUTPUT);
  pinMode(25,OUTPUT);
}

void loop() {
  digitalWrite(32,HIGH);
  digitalWrite(33,HIGH);
  digitalWrite(25,LOW);
  delay(sl);

  digitalWrite(32,LOW);
  digitalWrite(33,HIGH);
  digitalWrite(25,HIGH);
  delay(sl);

  digitalWrite(32,HIGH);
  digitalWrite(33,LOW);
  digitalWrite(25,HIGH);
  delay(sl);
}

效果:

无刷电机0

例程5:驱动电机在六个基矢量之间切换运转

 图片来源:【自制FOC驱动器】深入浅出讲解FOC算法与SVPWM技术 - 知乎

根据上图,我们可以看到,只要我们控制电机的三相依次从:001,011,010,110,100,101运转,电机同样也可以旋转起来。由于我的电机极对数是11,而这个每转一个区间需要走过六个扇区,因此,从下面的控制程序可以看出来,电机旋转一圈一共有66个区间。

#include <SimpleFOC.h>
 
#define sl 500
#define pi 3.1415926
#define f 30


#define enable_pinA 12
#define enable_pinB 13
#define enable_pinC 14

#define piA 27
#define piB 26
#define piC 25

MagneticSensorI2C sensor0 = MagneticSensorI2C(AS5600_I2C);
TwoWire I2Cone = TwoWire(0);
void setup() {
  Serial.begin(115200);
  _delay(750);
  I2Cone.begin(18, 5, 400000); 
  sensor0.init(&I2Cone);
  pinMode(enable_pinA,OUTPUT);
  digitalWrite(enable_pinA,HIGH);
  pinMode(enable_pinB,OUTPUT);
  digitalWrite(enable_pinB,HIGH);
  pinMode(enable_pinC,OUTPUT);
  digitalWrite(enable_pinC,HIGH);
  
  pinMode(piA,OUTPUT);
  pinMode(piB,OUTPUT);
  pinMode(piC,OUTPUT);
}
 
void loop() {
  //U0:000
  //U1:001
  //U2:010
  //U3:011
  //U4:100
  //U5:101
  //U6:110
  //U7:111
  //顺序:U0,U1,U3,U2,U6,U4,U5,U7
  digitalWrite(piA,0);
  digitalWrite(piB,0);
  digitalWrite(piC,0);
  delay(sl);
  
  digitalWrite(piA,0);
  digitalWrite(piB,0);
  digitalWrite(piC,1);
  delay(sl);
 
  digitalWrite(piA,0);
  digitalWrite(piB,1);
  digitalWrite(piC,1);
  delay(sl);
 
  digitalWrite(piA,0);
  digitalWrite(piB,1);
  digitalWrite(piC,0);
  delay(sl);
 
  digitalWrite(piA,1);
  digitalWrite(piB,1);
  digitalWrite(piC,0);
  delay(sl);
 
  digitalWrite(piA,1);
  digitalWrite(piB,0);
  digitalWrite(piC,0);
  delay(sl);
 
  digitalWrite(piA,1);
  digitalWrite(piB,0);
  digitalWrite(piC,1);
  delay(sl);
  
  digitalWrite(piA,1);
  digitalWrite(piB,1);
  digitalWrite(piC,1);
  delay(sl);
 
}

例程6:驱动电机平滑转圈(模拟正弦波)

为了更好的控制电机,我们这里模拟三路正弦波信号输入到电机里面,频率为10Hz。

#define sl 500
#define pi 3.1415926
#define f 10

#define enable_pinA 12
#define enable_pinB 13
#define enable_pinC 14
 
#define piA 27
#define piB 26
#define piC 25

void setup() {
  Serial.begin(115200);
  pinMode(enable_pinA,OUTPUT);
  digitalWrite(enable_pinA,HIGH);
  pinMode(enable_pinB,OUTPUT);
  digitalWrite(enable_pinB,HIGH);
  pinMode(enable_pinC,OUTPUT);
  digitalWrite(enable_pinC,HIGH);
  
  pinMode(piA,OUTPUT);
  pinMode(piB,OUTPUT);
  pinMode(piC,OUTPUT);
  ledcSetup(0,50000,8);//频道0,5000Hz,8位分辨率
  ledcAttachPin(32,0);
  ledcSetup(1,50000,8);//频道0,5000Hz,8位分辨率
  ledcAttachPin(33,1);
  ledcSetup(2,50000,8);//频道0,5000Hz,8位分辨率
  ledcAttachPin(25,2);
}
 
void loop() {
  long t;
  int a,b,c;
  double ts;
  t=millis();
  //Serial.println(t);
  ts=double(t)/1000.0;
  //Serial.println(ts);
  a=127+127*sin(2.0*pi*f*ts);
  b=127+127*sin(2.0*pi*f*ts+pi*2/3);
  c=127+127*sin(2.0*pi*f*ts+pi*4/3);
  
  Serial.print(a);
  Serial.print(",");
  Serial.print(b);
  Serial.print(",");
  Serial.println(c);
  ledcWrite(0,a);
  ledcWrite(1,b);
  ledcWrite(2,c);
  delay(10);
}

通过arduino的串口绘图器,我们可以看到我们的三路正弦波信号,由于频率太高,我们可能看不清楚。

那就把频率调低一些,把频率调成2Hz,这样更方便看。从下图我们已经看一清楚的看到三路正弦波信号了。

然后看电机的控制效果,这里重新调回10Hz的频率。

控制效果:

无刷电机4

例程7:通过编码器读取电机位置

simplefoc库函数代码:

#include <SimpleFOC.h>

MagneticSensorI2C sensor0 = MagneticSensorI2C(AS5600_I2C);
TwoWire I2Cone = TwoWire(0);
void setup() {
  Serial.begin(115200);
  _delay(750);
  I2Cone.begin(18, 5, 400000); 
  sensor0.init(&I2Cone);
}

void loop() {
  sensor0.update();
  Serial.println(sensor0.getAngle()); 
}

效果(下图为串口输出的数据,我一边用手去转动电机,一边看串口数据,可以看到数据在动态变化):

也可以将上面的例程4和这个程序一起结合,让电机一边自己转圈的同时,编码器一边动态输出当前位置数据:

代码:

#include <SimpleFOC.h>

#define sl 500
#define pi 3.1415926
#define f 30


MagneticSensorI2C sensor0 = MagneticSensorI2C(AS5600_I2C);
TwoWire I2Cone = TwoWire(0);
void setup() {
  Serial.begin(115200);
  _delay(750);
  I2Cone.begin(18, 5, 400000); 
  sensor0.init(&I2Cone);
  pinMode(22,OUTPUT);
  digitalWrite(22,HIGH);
  pinMode(32,OUTPUT);
  pinMode(33,OUTPUT);
  pinMode(25,OUTPUT);
  ledcSetup(0,50000,8);//频道0,5000Hz,8位分辨率
  ledcAttachPin(32,0);
  ledcSetup(1,50000,8);//频道0,5000Hz,8位分辨率
  ledcAttachPin(33,1);
  ledcSetup(2,50000,8);//频道0,5000Hz,8位分辨率
  ledcAttachPin(25,2);
}

void loop() {
  
  long t;
  int a,b,c;
  double ts;
  t=millis();
  ts=double(t)/1000.0;
  a=127+127*sin(2.0*pi*f*ts);
  b=127+127*sin(2.0*pi*f*ts+pi*2/3);
  c=127+127*sin(2.0*pi*f*ts+pi*4/3);

  ledcWrite(0,a);
  ledcWrite(1,b);
  ledcWrite(2,c);
  delay(10);
  sensor0.update();
  Serial.println(sensor0.getAngle()); 
}

效果:

例程8:通过IIC通信发现IIC总线上的AS5600设备

如果使用的是灯哥simplefoc v1.0+esp32开发板,那就用下面这个代码就可以。

#include <SimpleFOC.h>
TwoWire I2Cone = TwoWire(0);

void setup(){
  Serial.begin(115200); 
  I2Cone.begin(18, 5, 100000); 
  for(int i=0;i<255;i++)
  {
    I2Cone.beginTransmission(i);
    if(I2Cone.endTransmission()==0)
    {
      Serial.print("0x");
      Serial.println(i,HEX);
    }
  }
}
 
void loop(){}

 如果是使用的arduino uno+官方的simplefoc v0.2的硬件的话,用下面这个代码就可以:

#include <Wire.h>

void setup()
{
  Wire.begin();
  Serial.begin(115200);
}

void loop()
{
  byte error, address;
  int nDevices;
  Serial.println("Scanning...");

  nDevices = 0;
  for(address = 1; address < 127; address++ ) 
  {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error==4) 
    {
      Serial.print("Unknown error at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");
  delay(5000);
}

例程9:通过IIC通信读取AS5600的原始数据

#include "Wire.h"
#include <SimpleFOC.h>

TwoWire I2Cone = TwoWire(0);
byte readArray[2];

void setup(){
  Serial.begin(115200); 
  I2Cone.begin(18, 5, 400000); 
//  I2Cone.beginTransmission(0x36);
  
  for(int i=0;i<255;i++)
  {
    I2Cone.beginTransmission(i);
    if(I2Cone.endTransmission()==0)
    {
      Serial.println();
      Serial.print(i,HEX);
      Serial.println("successful");
    }
  }
  
//    I2Cone.write(0x0C);
//    I2Cone.endTransmission(false);
}

void loop(){
//  int readValue=0
//  I2Cone.requestFrom(0x36, (uint8_t)2);
//  for (byte i=0; i < 2; i++) {
//    readArray[i] = I2Cone.read();
//  }
//  readValue = ( readArray[1] &  lsb_mask );
//  readValue += ( ( readArray[0] & msb_mask ) << lsb_used );
//  Serial.println(readValue);
}

例程10:通过iic通讯读取AS5600位置数据(用simplefoc库函数)

如果是用的esp32开发板+simplefoc v0.2,则用以下代码就可以

/**
 * 使用电压控制回路的扭矩控制示例。
 * 
 * 大多数低端无刷电机驱动器没有电流测量功能,因此SimpleFOC为您提供了一种通过设置电机电压而不是电流来控制电机扭矩的方法。 
 * 
 * 这使无刷直流电机有效地成为直流电机,您可以以相同的方式使用它。
 */
#include <SimpleFOC.h>
 
MagneticSensorI2C sensor0 = MagneticSensorI2C(AS5600_I2C);
TwoWire I2Cone = TwoWire(0);
 
void setup() {
  Serial.begin(115200);
  I2Cone.begin(18,5,400000); 
  sensor0.init(&I2Cone);
}
void loop() {
  sensor0.update();
 
  Serial.println(sensor0.getAngle()); 
}

如果是用的esp32开发板+灯哥foc v3.0,则用以下代码就可以

如果用的是arduino uno+官方simplefoc v0.2,则用一下代码就可以

#include <SimpleFOC.h>

MagneticSensorI2C sensor0 = MagneticSensorI2C(AS5600_I2C);
TwoWire I2Cone = TwoWire();
 
void setup() {
  Serial.begin(115200);
  I2Cone.begin(); 
  sensor0.init(&I2Cone);
}
void loop() {
  sensor0.update();
 
  Serial.println(sensor0.getAngle()); 
}

例程11:开环速度控制

如果用的是esp32开发板+官方simplefoc v0.2,则可以用以下代码

// Deng's FOC 开环速度控制例程 测试库:SimpleFOC 2.1.1 测试硬件:灯哥开源FOC V1.0
// 串口中输入"T+数字"设定两个电机的转速,如设置电机以 10rad/s 转动,输入 "T10",电机上电时默认会以 5rad/s 转动
// 在使用自己的电机时,请一定记得修改默认极对数,即 BLDCMotor(7) 中的值,设置为自己的极对数数字
// 程序默认设置的供电电压为 7.4V,用其他电压供电请记得修改 voltage_power_supply , voltage_limit 变量中的值

#include <SimpleFOC.h>

BLDCMotor motor = BLDCMotor(11);
BLDCDriver3PWM driver = BLDCDriver3PWM(27, 26, 25, 12, 13, 14);

//目标变量
float target_velocity = 5.0;

//串口指令设置
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&target_velocity, cmd); }

void setup() {
  driver.voltage_power_supply = 12.0;
  driver.init();
  motor.linkDriver(&driver);
  motor.voltage_limit = 12.0;   // [V]
  motor.velocity_limit = 15; // [rad/s]
  
  //开环控制模式设置
  motor.controller = MotionControlType::velocity_openloop;

  //初始化硬件
  motor.init();

  //增加 T 指令
  command.add('T', doTarget, "target velocity");

  Serial.begin(115200);
  Serial.println("Motor ready!");
  Serial.println("Set target velocity [rad/s]");
  _delay(1000);
}

void loop() {
  motor.move(target_velocity);

  //用户通讯
  command.run();
}

例程12:闭环速度控制

如果硬件用的是esp32开发板和灯哥foc v1.0或2.0或3.0的话,可以用以下代码

如果硬件用的是esp32开发板和simplefoc v0.2的话,可以用以下代码

/**
Deng's FOC 闭环速度控制例程 测试库:SimpleFOC 2.1.1 测试硬件:灯哥开源FOC V1.0
在串口窗口中输入:T+速度,就可以使得两个电机闭环转动
比如让两个电机都以 10rad/s 的速度转动,则输入:T10
在使用自己的电机时,请一定记得修改默认极对数,即 BLDCMotor(7) 中的值,设置为自己的极对数数字
程序默认设置的供电电压为 7.4V,用其他电压供电请记得修改 voltage_power_supply , voltage_limit 变量中的值
默认PID针对的电机是 Ipower 4008 ,使用自己的电机需要修改PID参数,才能实现更好效果
 */
#include <SimpleFOC.h>
 
MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);
TwoWire I2Cone = TwoWire(0);
 
//电机参数
BLDCMotor motor = BLDCMotor(11);
BLDCDriver3PWM driver = BLDCDriver3PWM(27, 26, 25, 12, 13, 14);
 
//命令设置
float target_velocity = 0;
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&target_velocity, cmd); }
 
void setup() {
 
  I2Cone.begin(18, 5, 400000); 
  sensor.init(&I2Cone);
  //连接motor对象与传感器对象
  motor.linkSensor(&sensor);
 
  //供电电压设置 [V]
  driver.voltage_power_supply = 12.0;
  driver.init();
 
  //连接电机和driver对象
  motor.linkDriver(&driver);
 
  //FOC模型选择
  motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
  //运动控制模式设置
  motor.controller = MotionControlType::velocity;
 
  //速度PI环设置
  motor.PID_velocity.P = 0.2;
  motor.PID_velocity.I = 20;
  //最大电机限制电机
  motor.voltage_limit = 12.0;
  
  //速度低通滤波时间常数
  motor.LPF_velocity.Tf = 0.01;
 
  //设置最大速度限制
  motor.velocity_limit = 40;
 
  Serial.begin(115200);
  motor.useMonitoring(Serial);
  
  //初始化电机
  motor.init();
  //初始化 FOC
  motor.initFOC();
  command.add('T', doTarget, "target velocity");
 
  Serial.println(F("Motor ready."));
  Serial.println(F("Set the target velocity using serial terminal:"));
}
 
void loop() {
  motor.loopFOC();
  motor.move(target_velocity);
  command.run();
}

例程13:开环位置控制

如果你用的是esp32开发板+官方simplefoc v0.2,则可以用以下代码

// Deng's FOC 开环位置控制例程 测试库:SimpleFOC 2.1.1 测试硬件:灯哥开源FOC V1.0
// 串口中输入"T+数字"设定两个电机的位置,如设置电机转到到180度,输入 "T3.14"(弧度制的180度)
// 在使用自己的电机时,请一定记得修改默认极对数,即 BLDCMotor(7) 中的值,设置为自己的极对数数字
// 程序默认设置的供电电压为 7.4V,用其他电压供电请记得修改 voltage_power_supply , voltage_limit 变量中的值
 
#include <SimpleFOC.h>
 
BLDCMotor motor = BLDCMotor(11);
BLDCDriver3PWM driver = BLDCDriver3PWM(27, 26, 25, 12, 13, 14);
 
//目标变量
float target_velocity = 0;
 
//串口指令设置
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&target_velocity, cmd); }
 
void setup() {
 
  driver.voltage_power_supply = 12.0;
  driver.init();
  motor.linkDriver(&driver);
  motor.voltage_limit = 12.0;   // [V]
  motor.velocity_limit = 15; // [rad/s]
  
  //开环控制模式设置
  motor.controller = MotionControlType::angle_openloop;
 
  //初始化硬件
  motor.init();
 
  //增加 T 指令
  command.add('T', doTarget, "target velocity");
 
  Serial.begin(115200);
  Serial.println("Motor ready!");
  Serial.println("Set target position [rad/s]");
  _delay(1000);
}
 
void loop() {
  motor.move(target_velocity);
 
  //用户通讯
  command.run();
}

例程14:闭环位置控制

/**
Deng's FOC 闭环位置控制例程 测试库:SimpleFOC 2.1.1 测试硬件:灯哥开源FOC V1.0
在串口窗口中输入:T+位置,就可以使得两个电机闭环转动
比如让两个电机都转动180°,则输入其弧度制:T3.14
在使用自己的电机时,请一定记得修改默认极对数,即 BLDCMotor(7) 中的值,设置为自己的极对数数字
程序默认设置的供电电压为 7.4V,用其他电压供电请记得修改 voltage_power_supply , voltage_limit 变量中的值
默认PID针对的电机是 Ipower 4008 ,使用自己的电机需要修改PID参数,才能实现更好效果
*/

#include <SimpleFOC.h>

MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);
TwoWire I2Cone = TwoWire(0);

//电机参数
BLDCMotor motor = BLDCMotor(11);
BLDCDriver3PWM driver = BLDCDriver3PWM(27, 26, 25, 12, 13, 14);

//命令设置
float target_velocity = 0;
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&target_velocity, cmd); }

void setup() {
  I2Cone.begin(18, 5, 400000); 
  sensor.init(&I2Cone);
  //连接motor对象与传感器对象
  motor.linkSensor(&sensor);

  //供电电压设置 [V]
  driver.voltage_power_supply = 7.4;
  driver.init();

  //连接电机和driver对象
  motor.linkDriver(&driver);
  
  //FOC模型选择
  motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
  //运动控制模式设置
  motor.controller = MotionControlType::angle;

  //速度PI环设置
  motor.PID_velocity.P = 0.2;
  motor.PID_velocity.I = 20;
  //角度P环设置 
  motor.P_angle.P = 20;
  //最大电机限制电机
  motor.voltage_limit = 7.4;
  
  //速度低通滤波时间常数
  motor.LPF_velocity.Tf = 0.01;

  //设置最大速度限制
  motor.velocity_limit = 40;

  Serial.begin(115200);
  motor.useMonitoring(Serial);
  
  //初始化电机
  motor.init();
  //初始化 FOC
  motor.initFOC();
  command.add('T', doTarget, "target velocity");

  Serial.println(F("Motor ready."));
  Serial.println(F("Set the target velocity using serial terminal:"));
  
}

void loop() {
  motor.loopFOC();

  motor.move(target_velocity);

  command.run();
}

例程15:电压模式的开环扭矩控制

如果你使用的是esp32开发板+官方的simplefoc v0.2,那么以下代码可以运行

/**
 * 使用电压控制回路的扭矩控制示例。
 * 
 * 大多数低端无刷电机驱动器没有电流测量功能,因此SimpleFOC为您提供了一种通过设置电机电压而不是电流来控制电机扭矩的方法。 
 * 
 * 这使无刷直流电机有效地成为直流电机,您可以以相同的方式使用它。
 */
// 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/AC34

#include <SimpleFOC.h>
//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);
 
// voltage set point variable
float target_voltage = 2;
// 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);
}
 
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);
  
  // user communication
  command.run();
}

 如果出现如下错误:

例程16:电流模式的闭环力矩控制

如果你用的是arduino uno+官方simplefoc v0.2,那么可以用以下代码:

/**
 *
 * Torque control example using current control loop.
 *
 */
#include <SimpleFOC.h>


// BLDC motor & driver instance
BLDCMotor motor = BLDCMotor(11);
BLDCDriver3PWM driver = BLDCDriver3PWM(9, 5, 6, 8);

MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);
TwoWire I2Cone = TwoWire();

// current sensor
InlineCurrentSense current_sense = InlineCurrentSense(0.01, 50.0, A0, A2);

// current set point variable
float target_current = 0;
// instantiate the commander
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&target_current, cmd); }

void setup() {
  pinMode(8,OUTPUT);
  digitalWrite(8,HIGH);
  pinMode(7,OUTPUT);
  digitalWrite(7,HIGH);
  pinMode(4,OUTPUT);
  digitalWrite(4,HIGH);

  // initialize encoder sensor hardware
  // link the motor to the sensor
  I2Cone.begin(); 
  sensor.init(&I2Cone);
  motor.linkSensor(&sensor);

  // driver config
  // power supply voltage [V]
  driver.voltage_power_supply = 12;
  driver.init();
  // link driver
  motor.linkDriver(&driver);

  // current sense init hardware
  current_sense.init();
  // link the current sense to the motor
  motor.linkCurrentSense(&current_sense);

  // set torque mode:
  // TorqueControlType::dc_current
  // TorqueControlType::voltage
  // TorqueControlType::foc_current
  motor.torque_controller = TorqueControlType::foc_current;
  // set motion control loop to be used
  motor.controller = MotionControlType::torque;

  // foc currnet control parameters (Arduino UNO/Mega)
  motor.PID_current_q.P = 5;
  motor.PID_current_q.I= 300;
  motor.PID_current_d.P= 5;
  motor.PID_current_d.I = 300;
  motor.LPF_current_q.Tf = 0.01f;
  motor.LPF_current_d.Tf = 0.01f;
  // foc currnet control parameters (stm/esp/due/teensy)
  // motor.PID_current_q.P = 5;
  // motor.PID_current_q.I= 1000;
  // motor.PID_current_d.P= 5;
  // motor.PID_current_d.I = 1000;
  // motor.LPF_current_q.Tf = 0.002f; // 1ms default
  // motor.LPF_current_d.Tf = 0.002f; // 1ms default

  // 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 current");

  Serial.println(F("Motor ready."));
  Serial.println(F("Set the target current using serial terminal:"));
  _delay(1000);
}

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 torque (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_current);

  // user communication
  command.run();
}

参考文献:

1.【自制FOC驱动器】深入浅出讲解FOC算法与SVPWM技术 - 知乎

2.《ESP32 学习笔记》 之Arduino环境下 如何优雅的输出 频率占空比可调 的PWM波_慕容流年的博客-CSDN博客

3.电机极对数是啥?今天给大家普及一下技术贴

版权声明:本文为CSDN博主「Allen953」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qqliuzhitong/article/details/121268665

生成海报
点赞 0

Allen953

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

esp32用mcpwm驱动电机

目录 前言 目录 配置 操作 例程1 例程1解析 本篇为乐鑫官方文档,地址:Motor Control Pulse Width Modulator (MCPWM) - ESP32 - — ESP-IDF 编

Arduino 水滴检测

实物连接图: 电路图: 代码: void setup() {pinMode(3, OUTPUT);pinMode(2, INPUT); }void loop() {bool va2 digitalR

在Arduino上搭建ESP32开发环境

ESP32开发板可以通过官方的工具链、编译工具、ESP-IDF配合文本编辑器进行编程,但这样的方式有时比较麻烦,而且对新手极其不友好,因此经过简单配置,可使用Arduino对ESP32开发