Link

位置控制环

此控制环允许您实时将电机移动到所需角度。通过以下方式启用此模式:

// set angle/position motion control loop
motor.controller = MotionControlType::angle;

您可以通过运行 motion_control/position_motion_control/ 文件夹中的示例来测试此算法。

工作原理

无刷直流电机 步进电机

角度 / 位置控制环围绕速度控制环形成闭环控制。而无论采用哪种扭矩控制方式,速度控制环都围绕扭矩控制形成闭环。如果是未设置相电阻的电压模式,速度运动控制将使用电压 Uq 来设置扭矩指令:

如果是任何一种电流扭矩控制模式(FOC 或直流电流)或提供了相电阻的电压模式,角度运动控制将为扭矩控制器设置目标电流 iq

因此,角度控制环是通过在 速度控制环 上额外添加一个级联的控制环而形成的,如上图所示。该环通过使用额外的 PID 控制器和一个可选的低通滤波器来实现闭环。控制器从电机读取角度 a(可选进行滤波),并确定电机为达到用户设置的期望角度 ad 应达到的速度 vd。然后,速度控制器读取电机的当前滤波速度 vf,并为扭矩控制环设置达到由角度环设定的速度 vd 所需的扭矩目标(uq 电压或 iq 电流)。

控制器参数

要调整此控制环,您可以先设置速度 PID 控制器、低通滤波器和限制参数,

// velocity PID controller parameters
// default P=0.5 I = 10 D =0
motor.PID_velocity.P = 0.2;
motor.PID_velocity.I = 20;
motor.PID_velocity.D = 0.001;
// jerk control using voltage voltage ramp
// default value is 300 volts per sec  ~ 0.3V per millisecond
motor.PID_velocity.output_ramp = 1000;

// velocity low pass filtering
// default 5ms - try different values to see what is the best. 
// the lower the less filtered
motor.LPF_velocity.Tf = 0.01;

// setting the limits
// either voltage
motor.voltage_limit = 10; // Volts - default driver.voltage_limit
// of current 
motor.current_limit = 2; // Amps - default 0.2Amps

然后设置角度 PID 控制器、低通滤波器和限制参数:

// angle PID controller 
// default P=20
motor.P_angle.P = 20; 
motor.P_angle.I = 0;  // usually only P controller is enough 
motor.P_angle.D = 0;  // usually only P controller is enough 
// acceleration control using output ramp
// this variable is in rad/s^2 and sets the limit of acceleration
motor.P_angle.output_ramp = 10000; // default 1e6 rad/s^2

// angle low pass filtering
// default 0 - disabled  
// use only for very noisy position sensors - try to avoid and keep the values very small
motor.LPF_angle.Tf = 0; // default 0

// setting the limits
//  maximal velocity of the position control
motor.velocity_limit = 4; // rad/s - default 20

为获得最佳性能,同时参数化速度 PID 和角度 PID 控制器非常重要。 可以通过更新 motor.PID_velocity 结构来参数化速度 PID 控制器,如 速度控制环 中所述。

  • 大致规则是降低比例增益 P 以减少振动。
  • 您可能无需调整 I 或 D 值。

可以通过更改 motor.P_angle 结构来更新角度 PID 控制器。

  • 在大多数应用中,简单的 P 控制器就足够了(I=D=0)
  • 比例增益 P 会使其响应更迅速,但值过高会导致不稳定和振动。
  • output_ramp 值相当于加速度限制 - 默认值接近无穷大,必要时降低它。

对于角度控制,您也能看到速度 LPF 滤波器的影响。

  • 从速度控制到角度控制,LPF_velocity.Tf 值不应有太大变化。因此,一旦为速度环调整好,就可以保持不变。
  • 在大多数情况下,LPF_angle.Tf 将保持为 0,即禁用状态。

此外,您可以配置控制器的 velocity_limit 值。此值可防止控制器为电机设置过高的速度 vd

  • 如果将 velocity_limit 设置得很低,您的电机将以恰好此速度在期望位置之间移动。如果设置得较高,您甚至不会注意到这个变量的存在。😃

最后,每个应用都略有不同,您很可能需要稍微调整控制器值以达到期望的行为。

有关此方法的更多理论和源代码文档,请查看 深入探究部分。

位置控制示例代码

无刷直流电机 步进电机

这是一个非常基本的位置运动控制程序示例,基于电压扭矩控制,并包含完整配置。运行此代码时,电机将每 1 秒 在 -1 弧度 和 1 弧度 之间移动。

#include <SimpleFOC.h>

// motor instance
BLDCMotor motor = BLDCMotor(11);
// driver instance
BLDCDriver3PWM driver = BLDCDriver3PWM(9, 10, 11, 8);

// encoder instance
Encoder encoder = Encoder(2, 3, 500);
// channel A and B callbacks
void doA(){encoder.handleA();}
void doB(){encoder.handleB();}

void setup() {
  
  // initialize encoder sensor hardware
  encoder.init();
  encoder.enableInterrupts(doA, doB); 
  // link the motor to the sensor
  motor.linkSensor(&encoder);

  // driver config
  driver.init();
  motor.linkDriver(&driver);

  // set motion control loop to be used
  motor.controller = MotionControlType::angle;

  // controller configuration 
  // default parameters in defaults.h

  // controller configuration based on the control type 
  // velocity PID controller parameters
  // default P=0.5 I = 10 D =0
  motor.PID_velocity.P = 0.2;
  motor.PID_velocity.I = 20;
  motor.PID_velocity.D = 0.001;
  // jerk control using voltage voltage ramp
  // default value is 300 volts per sec  ~ 0.3V per millisecond
  motor.PID_velocity.output_ramp = 1000;

  // velocity low pass filtering
  // default 5ms - try different values to see what is the best. 
  // the lower the less filtered
  motor.LPF_velocity.Tf = 0.01;

  // angle P controller -  default P=20
  motor.P_angle.P = 20;

  //  maximal velocity of the position control
  // default 20
  motor.velocity_limit = 4;
  // default voltage_power_supply
  motor.voltage_limit = 10;

  // use monitoring with serial 
  Serial.begin(115200);
  // comment out if not needed
  motor.useMonitoring(Serial);
  
  // initialize motor
  motor.init();
  // align encoder and start FOC
  motor.initFOC();


  Serial.println("Motor ready.");
  _delay(1000);
}

// angle set point variable
float target_angle = 1;
// timestamp for changing direction
long timestamp_us = _micros();

void loop() {

  // each one second
  if(_micros() - timestamp_us > 1e6) {
      timestamp_us = _micros();
      // inverse angle
      target_angle = -target_angle;   
  }

  // main FOC algorithm function
  motor.loopFOC();

  // Motion control function
  motor.move(target_angle);
}
#include <SimpleFOC.h>

// motor instance
StepperMotor motor = StepperMotor(50);
// driver instance
StepperDriver2PWM driver = StepperDriver2PWM(9, 10, 11, 8);

// encoder instance
Encoder encoder = Encoder(2, 3, 500);
// channel A and B callbacks
void doA(){encoder.handleA();}
void doB(){encoder.handleB();}

void setup() {
  
  // initialize encoder sensor hardware
  encoder.init();
  encoder.enableInterrupts(doA, doB); 
  // link the motor to the sensor
  motor.linkSensor(&encoder);

  // driver config
  driver.init();
  motor.linkDriver(&driver);

  // set motion control loop to be used
  motor.controller = MotionControlType::angle;

  // controller configuration 
  // default parameters in defaults.h

  // controller configuration based on the control type 
  // velocity PID controller parameters
  // default P=0.5 I = 10 D =0
  motor.PID_velocity.P = 0.2;
  motor.PID_velocity.I = 20;
  motor.PID_velocity.D = 0.001;
  // jerk control using voltage voltage ramp
  // default value is 300 volts per sec  ~ 0.3V per millisecond
  motor.PID_velocity.output_ramp = 1000;

  // velocity low pass filtering
  // default 5ms - try different values to see what is the best. 
  // the lower the less filtered
  motor.LPF_velocity.Tf = 0.01;

  // angle P controller -  default P=20
  motor.P_angle.P = 20;

  //  maximal velocity of the position control
  // default 20
  motor.velocity_limit = 4;
  // default voltage_power_supply
  motor.voltage_limit = 10;

  // use monitoring with serial 
  Serial.begin(115200);
  // comment out if not needed
  motor.useMonitoring(Serial);
  
  // initialize motor
  motor.init();
  // align encoder and start FOC
  motor.initFOC();


  Serial.println("Motor ready.");
  _delay(1000);
}

// angle set point variable
float target_angle = 1;
// timestamp for changing direction
long timestamp_us = _micros();

void loop() {

  // each one second
  if(_micros() - timestamp_us > 1e6) {
      timestamp_us = _micros();
      // inverse angle
      target_angle = -target_angle;   
  }

  // main FOC algorithm function
  motor.loopFOC();

  // Motion control function
  motor.move(target_angle);
}

项目示例

这里有一个使用位置控制的项目示例,描述了所需的完整硬件 + 软件设置。

示例项目 部分中找到更多项目。