让我们开始吧
当你的 SimpleFOClibrary 安装 完成和准备好必要的 硬件 之后,我们就可以开始有趣的部分了,编写代码让电机动起来!
步骤1 测试传感器
一切都连接良好的第一个信号是传感器读数良好。要测试传感器,请浏览库实例 examples/utils/sensor_test
,并找到你的传感器实例。这个实例的结构是这样的:
#include <SimpleFOC.h>
Encoder encoder = Encoder(2, 3, 500);
// 初始化中断例程
void doA(){encoder.handleA();}
void doB(){encoder.handleB();}
void setup() {
// 监视点
Serial.begin(115200);
// 初始化编码器硬件
sensor.init();
// 启用硬件中断
encoder.enableInterrupts(doA, doB);
Serial.println("Encoder ready");
_delay(1000);
}
void loop() {
// 在终端显示角度和角速度
Serial.print(sensor.getAngle());
Serial.print("\t");
Serial.println(sensor.getVelocity());
}
请确保更改传感器参数来适应你的应用程序,如引脚编号、每转的脉冲、总线地址等。如果不确定某些参数,请务必查看 传感器文档 。
如果你的传感器连接良好并且一切正常运行,那么你的串行终端应该有传感器角度和速度的输出。
☑️ 简单的测试
确保测试电机时,电机的一个旋转输出的传感器角度是 6.28 弧度。
步骤2 测试驱动程序
当传感器在运行时,你可以继续进行测试。测试驱动程序的最简单方法是使用库的实例。如果你有充裕的时间,你可以使用 examples/utils/driver_standalone_test
文件夹中的实例来测试驱动程序。这些实例将驱动程序作为一个独立的模块进行测试,你可以将任何电压值设置到驱动器的任何相位。
#include <SimpleFOC.h>
// 无刷直流电机驱动器实例
BLDCDriver3PWM driver = BLDCDriver3PWM(9, 5, 6, 8);
void setup() {
// PWM 频率 [Hz]
driver.pwm_frequency = 20000;
// 电源电压 [V]
driver.voltage_power_supply = 12;
// 允许最大直流电压 - 默认为电源电压
driver.voltage_limit = 12;
// 初始化驱动器
driver.init();
// 启用驱动器
driver.enable();
_delay(1000);
}
void loop() {
// 设置PWM (A: 3V, B: 1V, C: 5V)
driver.setPwm(3,1,5);
}
☑️ 简单的测试
确保所有相位输出的是 PWM 信号,可以尝试在每个相位和地之间连接一个小的led 灯或者使用万用表测量它。
步骤2 测试驱动器+电机组合-开环
如果你已经连接了电机,而且驱动器工作良好,我们建议你使用实例 examples/motion_control/open_loop_motion_control
中的开环控制实例来测试电机+驱动器组合。如果你的驱动程序与实例中提供的不一样,请浏览 驱动程序文档 ,并查找你需要的驱动程序和代码。此外,你可以浏览在 examples/utils/driver_standalone_test
文件夹中的实例,并查看如何使用。
下面是 BLDCDriver3PWM
开环速度控制的一个实例:
// 开环电机控制实例
#include <SimpleFOC.h>
// 无刷直流电机及驱动器实例
// BLDCMotor motor = BLDCMotor(pole pair number极对数, phase resistance相电阻(可选的));
BLDCMotor motor = BLDCMotor(11);
// BLDCDriver3PWM driver = BLDCDriver3PWM(pwmA, pwmB, pwmC, 使能引脚(可选的));
BLDCDriver3PWM driver = BLDCDriver3PWM(9, 5, 6, 8);
// commander实例化
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&motor.target, cmd); }
void setup() {
// 配置驱动器
// 电源电压 [V]
driver.voltage_power_supply = 12;
driver.init();
// 连接电机和驱动器
motor.linkDriver(&driver);
// 限制电机运动
// motor.phase_resistance = 3.52 // [Ohm]
// motor.current_limit = 2; // [Amps] - 如果相电阻有被定义
motor.voltage_limit = 3; // [V] - 如果相电阻没有定义
motor.velocity_limit = 5; // [rad/s] cca 50rpm
// 配置开环控制
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();
// 用户通信
command.run();
}
这个实例代码有一些非常重要的规则。
- 确保你使用正确的驱动的类和正确的 pwm 引脚,这个通常是很简单的,你可以在我们的 驱动文档 中找到很多关于这个方面的的文档。如果你不确定,也不能正常运行,请毫不犹豫地到我们的 社区论坛 上提问。
- 确保使用适当的电压限制。
motor.voltage_limit
将直接确定通过电机的电流:current = phase_resistance*motor.voltage_limit
。所以,为了避免过高的电流,请设法找到你电机的相位电阻。设置motor.voltage_limit
使电流不超过 2 Amps ,例如:motor.voltage_limit = 2*phase_resistance
。最好的选择是通过设置参数motor.phase_resistance
来提供电机的相位电阻值,然后你可以用motor.current_limit
而不是motor.voltage_limit
使这个问题变得简单。 如果你找不到你的电机的相位电阻,当他开始变小的时候motor.voltage_limit < 1;
也不能用你的万用表测量它。 - 确保正确输入极对数。很多数据表中找到极对数,如果你不确定,不要担心这一步就是为了准确地测出这个值。 😄
☑️ 简单的测试
1. 在速度模式下,将你的目标速度设置为 6.28 rad/s,这应该正好是每秒旋转一周。
2. 在位置模式下,设置目标位置为 6.28 rad,应该正好旋转一周。
如果不是,这意味着你的极对数可能不是很对,试着改变它,直到你恰好旋转一周(或在速度模式下每秒旋转一周)
步骤3 闭环控制 - 使用电压控制力矩
当你有一个工作传感器、工作电机和驱动器的时候,你就可以继续进行闭环控制测试。第一个要测试的是使用电压控制力矩控制的模式,这是 SimpleFOClibrary 中闭环控制的最简单形式。你可以在库实例的文件夹中找到不同传感器的该模式实例: examples/motion_control/torque_control
。 下面是 BLDCMotor3PWM
驱动器和 Encoder
作为位置传感器的一个实例:
#include <SimpleFOC.h>
// 无刷直流电机及驱动器实例
BLDCMotor motor = BLDCMotor(11);
BLDCDriver3PWM driver = BLDCDriver3PWM(9, 5, 6, 8);
// 编码器实例
Encoder encoder = Encoder(2, 3, 500);
// 回调通道A和B
void doA(){encoder.handleA();}
void doB(){encoder.handleB();}
// commander实例化
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&motor.target, cmd); }
void setup() {
// 初始化编码传感器硬件
encoder.init();
encoder.enableInterrupts(doA, doB);
// 连接电机和传感器
motor.linkSensor(&encoder);
// 配置驱动器
// 电源电压 [V]
driver.voltage_power_supply = 12;
driver.init();
// 连接驱动器
motor.linkDriver(&driver);
// 校准电压
motor.voltage_sensor_align = 5;
// 设置运动控制环
motor.torque_controller = TorqueControlType::voltage;
motor.controller = MotionControlType::torque;
// 增加电流限制
// motor.phase_resistance = 3.52 // [Ohm]
// motor.current_limit = 2; // [Amps] - 如果相电阻有被定义
// 使用串口监视
Serial.begin(115200);
// 如果不需要,可以注释掉此行
motor.useMonitoring(Serial);
// 初始化电机
motor.init();
// 校准编码器,启用FOC
motor.initFOC();
// 设置电机初始目标
// motor.target = 0.2; // Amps - 如果相电阻有被定义
motor.target = 2; // Volts
// 增加目标命令T
// command.add('T', doTarget, "target current"); // - 如果相电阻有被定义
command.add('T', doTarget, "target voltage");
Serial.println(F("Motor ready."));
Serial.println(F("Set the target using serial terminal:"));
_delay(1000);
}
void loop() {
// FOC算法主函数
motor.loopFOC();
// 运动控制函数
motor.move();
// 用户通信
command.run();
}
到目前为止,你已经知道了传感器、驱动器和电机如何配置好。如果之前的运行都是正常的,那这一步也不会有太大的问题。
这里要采取两个重要的步骤,确保你的电机没有使用过高的 motor.voltage_sensor_align
值,以防止电流过大。这条规则和开环的 motor.voltage_limit
是一样的。如果你不确定你的相位电阻是多少,从小的值开始测: motor.voltage_sensor_align < 1
。此外,你还可以定义电机的相位电阻,然后使用 motor.current_limit
值,这个变量将限制 motor.voltage_sensor_align
所以你不用再为它担心了。但如果你指定了相位电阻值,你就不用为电机设置电压命令,但要设置电流命令,更多信息请参阅 力矩控制文件 。
第二个重要的技巧是使用 监控 功能。这将帮助你调试可能出现的问题,在初始化和校准时会输出电机的状态。如果初始化失败,电机将被禁用,你可以用手毫无阻力地转动电机,如果代码可以运行,你的电机会开始旋转,你就可以通过串行终端设置电压(/电流,如果设置了motor.phase_resistance
set)。
☑️ 简单的测试
确保电机的初始化完成得很好。监控会输出你传感器的偏移,方向,极对数的检查,它会告诉你它是成功的或者是失败的。
步骤5 测试电流传感器 - 如果可用
如果你的设置里具有 SimpleFOClibrary 支持的电流传感器,那么我们建议在执行此步骤之前,确保你至少可以使用电压控制闭环力矩(第3步)。
最好的开始方式是使用电压将电流传感器添加到力矩控制代码中(第3步)。并通过监控将d、q电流输出到串行终端。
下面是一个代码实例:
#include <SimpleFOC.h>
// 无刷直流电机及驱动器实例
BLDCMotor motor = BLDCMotor(11);
BLDCDriver3PWM driver = BLDCDriver3PWM(9, 5, 6, 8);
// 编码器实例
Encoder encoder = Encoder(2, 3, 500);
// 回调通道A和B
void doA(){encoder.handleA();}
void doB(){encoder.handleB();}
// 电流检测
InlineCurrentSense current_sense = InlineCurrentSense(0.01, 50.0, A0, A2);
// commander实例化
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&motor.target, cmd); }
void setup() {
// 初始化编码传感器硬件
encoder.init();
encoder.enableInterrupts(doA, doB);
// 连接电机和传感器
motor.linkSensor(&encoder);
// 配置驱动器
// 电源电压 [V]
driver.voltage_power_supply = 12;
driver.init();
// 连接驱动器
motor.linkDriver(&driver);
// 电流检测初始化硬件
current_sense.init();
// 连接电流检测器和电机
motor.linkCurrentSense(¤t_sense);
// 校准电压
motor.voltage_sensor_align = 5;
// 设置运动控制环
motor.torque_controller = TorqueControlType::voltage;
motor.controller = MotionControlType::torque;
// 增加电流限制
// motor.phase_resistance = 3.52 // [Ohm]
// motor.current_limit = 2; // [Amps] - 如果相电阻有被定义
// 监视串口
Serial.begin(115200);
// 如果不需要,可以注释掉此行
motor.useMonitoring(Serial);
motor.monitor_downsampling = 100; // 设置下采样,可以大于100
motor.monitor_variables = _MON_CURR_Q | _MON_CURR_D; // 设置d和q电流监视
// 初始化电机
motor.init();
// 校准编码器,启用FOC
motor.initFOC();
// 设置电机初始目标
// motor.target = 0.2; // Amps - 如果相电阻有被定义
motor.target = 2; // Volts
// 添加目标命令T
// command.add('T', doTarget, "target current"); // - 如果相电阻有被定义
command.add('T', doTarget, "target voltage");
command.verbose = VerboseMode::nothing; // 禁止 commander输出至串口
Serial.println(F("Motor ready."));
Serial.println(F("Set the target using serial terminal:"));
_delay(1000);
}
void loop() {
// FOC算法主函数
motor.loopFOC();
// 运动控制函数
motor.move();
// 显示电流
motor.monitor();
// 用户通信
command.run();
}
这个实例的代码几乎与第3步的代码完全相同。所以你配置电机,传感器和驱动器的时候应该没有太大的问题。在这一步,将测试你的电流传感器是否工作良好。在调用这个实例的代码几乎与第3步的代码完全相同。所以你配置电机,传感器和驱动器的时候应该没有太大的问题。在这一步,将测试你的电流传感器是否工作良好。在调用 motor.monitor()
函数时,将读取电流传感器,并将当前的 d 和 q 电流输出到串行终端。你可以打开串口绘图仪来可视化它们。
☑️ 简单的测试
1. 用手握住电机,改变不同的目标电压/电流值。确保电机静止时电流 d 非常接近0。确保电流 q 与你设置的电机电压成比例。
2. 让电机旋转。注意你的电流 d 和 q 下降到一个较低的水平,然后是静止电机。观察一下在低速时电流 d 几乎为0,之后就与电机速度成比例上升。
请浏览 电流传感器文档 ,查看支持的传感器和所有配置参数。
步骤6 使用电流传感器实现完整的 FOC -如果可用
当你配置和测试好你的电机、位置传感器、驱动器和电流传感器之后,你就可以进行真正的 FOC 控制。
#include <SimpleFOC.h>
// 无刷直流电机及驱动器实例
BLDCMotor motor = BLDCMotor(11);
BLDCDriver3PWM driver = BLDCDriver3PWM(5, 10, 6, 8);
// 编码器实例
Encoder encoder = Encoder(2, 3, 500);
// 回调通道A和B
void doA(){encoder.handleA();}
void doB(){encoder.handleB();}
// 在线电流检测实例
InlineCurrentSense current_sense = InlineCurrentSense(0.01, 50.0, A0, A2);
// commander通信实例
Commander command = Commander(Serial);
void doMotor(char* cmd){ command.motor(&motor, cmd); }
void setup() {
// 初始化编码传感器硬件
encoder.init();
encoder.enableInterrupts(doA, doB);
// 连接电机和传感器
motor.linkSensor(&encoder);
// 配置驱动器
// 电源电压 [V]
driver.voltage_power_supply = 12;
driver.init();
// 连接驱动器
motor.linkDriver(&driver);
// 设置控制环类型
motor.torque_controller = TorqueControlType::foc_current;
motor.controller = MotionControlType::torque;
// 基于控制环类型配置控制器
motor.PID_velocity.P = 0.05;
motor.PID_velocity.I = 1;
motor.PID_velocity.D = 0;
// 默认为电源电压
motor.voltage_limit = 12;
// 速度低通滤波时间常数
motor.LPF_velocity.Tf = 0.01;
// 角度环控制器
motor.P_angle.P = 20;
// 角度环速度限制
motor.velocity_limit = 20;
// 使用串口监视电机初始化
// 监视点
Serial.begin(115200);
// 如果不需要,可以注释掉此行
motor.useMonitoring(Serial);
motor.monitor_downsampling = 0; // 初始禁用实时监视器
// 电流检测初始化和连接
current_sense.init();
motor.linkCurrentSense(¤t_sense);
// 初始化电机
motor.init();
// 校准编码器,启用FOC
motor.initFOC();
// 设置初始目标值
motor.target = 2;
// 订阅电机至commander
command.add('M', doMotor, "motor");
// 运行用户命令配置电机(完整命令列表见docs.simplefoc.com)
Serial.println(F("Motor commands sketch | Initial motion control > torque/current : target 0Amps."));
_delay(1000);
}
void loop() {
// 迭代设置FOC相电压
motor.loopFOC();
// 设置外部环目标的迭代函数
motor.move();
// 电机监视
motor.monitor();
// 用户通信
command.run();
}
要查看所有的 FOC 力矩控制参数,请访问 力矩控制文档。在第4步中,如果你在调整速度和位置的过程中设置了相位电阻。你很可能不需要再重新调整它们。
然而,最重要的事情还是使用 命令接口 来调整力矩控制的 PID 控制器和低通滤波器的参数,通过这种方式,你将能够快速测试,实时更改控制器的参数,并且看到结果。一旦达到你满意的情况,你就可以在代码中写入这些值,然后停止使用命令。
☑️ 简单的测试
将目标电流设置为 0Amps ,并尝试用手移动电机,确保像电机失灵一样地没有任何阻力。然后尝试设置小的电流值 (<0.5A) ,看看你是否能感觉到电机的力量作用在你的手上。如果你能感觉到,那么这一步就成功了!