目录
- 一、硬件接线
- 二、官方代码操作
- 2.1、力矩模式
- 2.2、速度模式
- 2.3、位置模式
- 三、移植后的代码操作
- 3.1、力矩模式
- 3.2、速度模式
- 3.3、位置模式
- 3.4、跳过上电校准
- 3.4.1、手动输入参数
- 3.4.2、flash保存参数
- 3.5、测试云台电机
- 四、代码说明
- 五、定点运算和浮点运算
ODrive、VESC和SimpleFOC 教程链接汇总:请点击
一、硬件接线
用编码器的SPI接口,可以跳过上电检测。ABZ接口必须每次上电校准,
驱动板 购买链接:某宝购买
电机 购买链接:某宝购买
二、官方代码操作
用官方代码操作,验证控制效果,获取配置参数,
本小节演示用v0.5.1版本固件,因为v0.5.1的教程最丰富。当然也可以用v0.5.6版本。
2.1、力矩模式
odrv0.axis0.controller.config.vel_limit 限制最大速度,当超过最大速度时力矩变小,电机速度在限速附近波动会导致电动振动。
//力矩模式
odrv0.erase_configuration()
odrv0.config.dc_max_positive_current = 30
odrv0.config.dc_max_negative_current = -5.0
odrv0.axis0.motor.config.motor_type = MOTOR_TYPE_HIGH_CURRENT
odrv0.axis0.motor.config.pole_pairs = 7
odrv0.axis0.motor.config.calibration_current = 5
odrv0.axis0.encoder.config.mode = ENCODER_MODE_SPI_ABS_AMS
odrv0.axis0.encoder.config.abs_spi_cs_gpio_pin = 1
odrv0.axis0.encoder.config.cpr = 2**14
odrv0.axis0.controller.config.control_mode = CONTROL_MODE_TORQUE_CONTROL
odrv0.axis0.controller.config.vel_limit = 20 //超过限制速度,力矩变小
odrv0.axis0.controller.config.input_mode = INPUT_MODE_TORQUE_RAMP
odrv0.axis0.controller.config.torque_ramp_rate = 0.1
odrv0.save_configuration() //v0.5.6保存后重启,不用再 reboot
odrv0.reboot()
odrv0.axis0.requested_state = AXIS_STATE_FULL_CALIBRATION_SEQUENCE
odrv0.axis0.error
odrv0.axis0.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL
odrv0.axis0.controller.input_torque = 0.1
2.2、速度模式
//速度模式
odrv0.erase_configuration()
odrv0.config.dc_max_positive_current = 30
odrv0.config.dc_max_negative_current = -5.0
odrv0.axis0.motor.config.motor_type = MOTOR_TYPE_HIGH_CURRENT
odrv0.axis0.motor.config.pole_pairs = 7
odrv0.axis0.motor.config.calibration_current = 5
odrv0.axis0.encoder.config.mode = ENCODER_MODE_SPI_ABS_AMS
odrv0.axis0.encoder.config.abs_spi_cs_gpio_pin = 1
odrv0.axis0.encoder.config.cpr = 2**14
odrv0.axis0.controller.config.control_mode = CONTROL_MODE_VELOCITY_CONTROL
odrv0.axis0.controller.config.vel_gain = 0.02
odrv0.axis0.controller.config.vel_integrator_gain = 0.2
odrv0.axis0.controller.config.vel_limit = 50 //12V电源,5008电机的最大转速大概50
odrv0.axis0.controller.config.input_mode = INPUT_MODE_VEL_RAMP
odrv0.axis0.controller.config.vel_ramp_rate = 50
odrv0.save_configuration() //v0.5.6保存后重启,不用再 reboot
odrv0.reboot()
odrv0.axis0.requested_state = AXIS_STATE_FULL_CALIBRATION_SEQUENCE
odrv0.axis0.error
odrv0.axis0.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL
odrv0.axis0.controller.input_vel = 5
2.3、位置模式
如果电机停止的位置刚好是磁阻最大,会被齿槽力拉到磁阻最小位置,然后PID算法又把它转到磁阻最大位置,如此反复拉扯。
这个问题需要在下一节抗齿槽算法来解决,
//位置模式
odrv0.erase_configuration()
odrv0.config.dc_max_positive_current = 30
odrv0.config.dc_max_negative_current = -5.0
odrv0.axis0.motor.config.motor_type = MOTOR_TYPE_HIGH_CURRENT
odrv0.axis0.motor.config.pole_pairs = 7
odrv0.axis0.motor.config.calibration_current = 5
odrv0.axis0.encoder.config.mode = ENCODER_MODE_SPI_ABS_AMS
odrv0.axis0.encoder.config.abs_spi_cs_gpio_pin = 1
odrv0.axis0.encoder.config.cpr = 2**14
odrv0.axis0.controller.config.control_mode = CONTROL_MODE_POSITION_CONTROL
odrv0.axis0.controller.config.vel_limit = 50
odrv0.axis0.controller.config.pos_gain = 20
odrv0.axis0.controller.config.vel_gain = 0.04 //位置模式下的速度环PI参数比速度模式下的要大一点
odrv0.axis0.controller.config.vel_integrator_gain = 0.5
odrv0.axis0.controller.config.input_mode = INPUT_MODE_TRAP_TRAJ
odrv0.axis0.trap_traj.config.vel_limit = 10
odrv0.axis0.trap_traj.config.accel_limit = 10
odrv0.axis0.trap_traj.config.decel_limit = 10
odrv0.save_configuration()
odrv0.reboot()
odrv0.axis0.requested_state = AXIS_STATE_FULL_CALIBRATION_SEQUENCE
odrv0.axis0.error
odrv0.axis0.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL
odrv0.axis0.controller.input_pos = 0
odrv0.axis0.controller.input_pos = 1
三、移植后的代码操作
使用本节提供的第一个代码,下图:
3.1、力矩模式
-
在MyProject.h文件中设置参数,下图:
-
编译烧写,
-
发送指令“C”,3秒钟后电机“嘀”一声,然后正转8个电角度,反转8个电角度,同时串口打印校准参数。
-
再发送指令“G”,电机闭环,
-
再发送指令“S0.1”,电机开始转动,如果空载电机会达到最大转速。如果限速,电机只能达到限制转速。
视频:稍后上传
3.2、速度模式
-
在MyProject.h文件中设置参数,下图:
-
编译烧写,
-
发送指令“C”,3秒钟后电机“嘀”一声,然后正转8个电角度,反转8个电角度,同时串口打印校准参数。
-
再发送指令“G”,电机闭环,
-
再发送指令“T10”,电机转动。读取实时速度,指令为“V”。
视频:稍后上传
3.3、位置模式
-
在MyProject.h文件中设置参数,下图:
-
编译烧写,
-
发送指令“C”,3秒钟后电机“嘀”一声,然后正转8个电角度,反转8个电角度,同时串口打印校准参数。
-
再发送指令“G”,电机闭环,
-
再发送指令“K1”,电机转到指定位置。读取当前位置指令为“P”。
视频:稍后上传
3.4、跳过上电校准
-
官方ODrive每次上电都要校准一下才能进入闭环,否则会报错(只有无感模式可以直接进入闭环),据说在代码中配置也可以跳过校准,我没找到配置的方法。
-
SimpleFOC中,把校准参数写入代码可以跳过检测,我按照SimpleFOC的方法做了类似设计:
3.4.1、手动输入参数
1、第一次设置为0,编译烧下载,下图:
2、发送指令“C”校准电机,获取校准参数,下图:
电机起始位置不同,校准的偏置角度可能不一样,填写其中任一次的校准值即可(原理在上一篇教程中讲过了)。
3、把获取的五个参数写入代码,编译下载,下图:
4、重新上电,可以不用再校准,直接发送指令“G”进入闭环。
5、ABZ编码器为增量编码器,需要每次上电都检测,不能跳过。
3.4.2、flash保存参数
手动输入参数比较麻烦,功能升级,增加了flash保存功能,并且可以开机进入闭环,请看第二个代码,
1、上电后发送指令“C”校准电机,
2、发送指令“A1”配置已经校准,相当于官方指令:odrv0.axis0.motor.config.pre_calibrated = True,
3、如果需要开机进入闭环,发送指令“B1”,相当于官方指令:odrv0.axis0.config.startup_closed_loop_control = True,
4、发送指令“F”保存参数到flash,
5、发送指令“R”重启。
6、初始化时设置好目标值,闭环后可直接运行到设定值。
保存在flash的参数,重新烧写代码不会被删除,代码更新时记得发送指令删除,以免影响新代码的执行。
3.5、测试云台电机
ODrive也可以控制云台电机,参数更容易调试,因为有梯形轨迹算法,所以位置模式的效果也比SimpleFOC好,
1、硬件接线,下图:
驱动板 购买链接:某宝购买
电机 购买链接:某宝购买
2、在MyProject.h文件中设置参数,下图:
3、操作与上面的相同,不再赘述,
视频:稍后上传
四、代码说明
以这个代码为例,简单捋下流程:
1、while(1) 的工作量很小,下图
2、定时器更新中断是核心,下图:
3、大部分功能处理在 上图的control_loop_cb() 函数中,
4、在axis.c文件中进入闭环,下图:
5、在controller.c文件中根据输出模式,处理位置、速度和力矩变量,
然后是位置环PID和速度环PID运算,下图:
所有的输入模式,运算后最终生成这个输出,下图:
6、在motor,c中生成 Id/Iq,下图:
7、接下来就是你们喜欢的FOC变换,主要由 pwm_update_cb() 函数实现,
代码流程就是这样,别问我细节,我不可能自毁形象告诉你我不会!
五、定点运算和浮点运算
-
定点运算,通过放大程序运行中的变量的方式,把浮点数转化为定点数,提高了计算效率,使得低性能的单片机也可以实现高性能的算法。
-
去年(2022年)初的时候我还曾计划过把SimpleFOC的代码转换为定点运算,好在没空做。
-
定点运算早就存在,但是ST采用定点运算配合它的电机库,极大的推广了这一技术,我觉得目前市面上只要是定点运算的电机驱动器,应该都会受到ST的影响,或者直接就师承ST。
-
定点运算的标幺化太过复杂,繁琐,既要防止溢出又怕精度不够,对于新手非常不友好。
浮点运算则简单、直观、高精度,除了单片机成本高,但是随着国产单片机的崛起,成本门槛已经不存在了。 -
并且随着ODrive和VESC等开源技术影响的逐渐扩大,浮点运算一定会成为主流。
-
看到一些国产单片机厂家在推定点运算的驱动器,我觉得这些厂家应该是没把握住技术发展方向,要么就是技术不够成熟。请大家根据自己的能力和需要选择技术路线。
(完)