ODrive应用 #8 平衡车轮毂电机和遥控器设置指南

平衡车轮毂电机和遥控器设置指南

应大家的要求,这里提供了有关如何设置ODrive以使用RC PWM输入来驱动平衡车轮毂电机的详细说明。
每个步骤都附带说明,因此希望您可以顺利的完成配置。此视频演示了最终运行效果。

电机接线

电机具有三个较粗的电机相位线(通常为黄色,蓝色,绿色),以及一组5条较细的线,用于霍尔传感器反馈(通常为红色,黄色,蓝色,绿色,黑色)。
您可以以任何顺序将电机的相线连接到ODrive的电机连接器中,因为稍后我们仍将对其校准。 将霍尔反馈连接到ODrive J4连接器(确保和电机通道号匹配),如下所示:

霍尔反馈线J4 连接器
Red5V
YellowA
BlueB
GreenZ
BlackGND

注意:为了与编码器输入兼容,ODrive在霍尔传感器连接的引脚上没有任何滤波电容器。 因此,为了获得可靠的霍尔信号,建议在这些引脚上添加一些滤波电容。

电机配置

标准6.5英寸轮毂电动机有30个永磁极,因此极对数为15。 如果您使用的是它电机,则需要数一下磁铁个数或通过数据表以获取此信息。

odrv0.axis0.motor.config.pole_pairs = 15

平衡车轮毂电机与普通的电机相比具有更高的相电阻,因此我们使用更高的电压进行电机校准,并将电流感应设置的更敏感。同时,电机的电感也相当高,因此我们需要将电流控制器的带宽从默认值减小以保持其稳定。

odrv0.axis0.motor.config.resistance_calib_max_voltage = 4
odrv0.axis0.motor.config.requested_current_range = 25 #需要重启以使此项参数生效
odrv0.axis0.motor.config.current_control_bandwidth = 100

将编码器设置为霍尔模式(而不是编码器增量模式)
霍尔反馈对于电动机中的每个极对都有6种状态。 由于我们有15个极对,因此将cpr设置为15 * 6 = 90。

odrv0.axis0.encoder.config.mode = ENCODER_MODE_HALL
odrv0.axis0.encoder.config.cpr = 90

由于霍尔反馈每转仅具有90个计数,因此我们希望减少速度跟踪带宽以获得更平滑的速度估计。
我们还可以适当的调低一些控制器的增益,使系统反应不那么激进,当然也应该能够适合您的应用。
因为可能想要控制轮式机器人,所以我们选择速度控制模式。 请注意,在速度模式下不使用pos_gain,但我还是给了您一个推荐值,以防您想运行位置控制模式。

odrv0.axis0.encoder.config.bandwidth = 100
odrv0.axis0.controller.config.pos_gain = 1
odrv0.axis0.controller.config.vel_gain = 0.02
odrv0.axis0.controller.config.vel_integrator_gain = 0.1
odrv0.axis0.controller.config.vel_limit = 1000
odrv0.axis0.controller.config.control_mode = CTRL_MODE_VELOCITY_CONTROL

在下一步中,我们将开始为电机供电,因此我们要确保首先保存配置,然后需要重启ODrive。

odrv0.save_configuration()
odrv0.reboot()

确保电动机可以自由转动,然后执行电机校准。

odrv0.axis0.requested_state = AXIS_STATE_MOTOR_CALIBRATION

您可以通过以下指令读取与电机有关的所有数据:

odrv0.axis0.motor

检查是否出现错误,并且相电阻和电感值是合理的。 以下是我得到的结果:

  error = 0x0000 (int)
  phase_inductance = 0.00033594953129068017 (float)
  phase_resistance = 0.1793474406003952 (float)

如果一切看起来都正常,那么您可以执行以下指令命令ODrive将校准的结果保存:

odrv0.axis0.motor.config.pre_calibrated = True

下一步是检查电机和霍尔传感器之间的校准情况。
由于先前接线步骤,您可以按随机顺序连接电机相线,并且霍尔信号也是随机的。 所以校准后不要再更改它。
确保电动机可以自由旋转:

odrv0.axis0.requested_state = AXIS_STATE_ENCODER_OFFSET_CALIBRATION

检查校准后的状态:

odrv0.axis0.encoder

检查是否有错误出现。 如果您的霍尔传感器安装角度还算标准,则offset_float应接近0.5。

  error = 0x0000 (int)
  offset_float = 0.5126956701278687 (float)

如果一切看起来都正常,那么您可以执行以下指令,这样在下次启动后就不用再次进行编码器校准了:

odrv0.axis0.encoder.config.pre_calibrated = True

好的,我们现在完成了电机配置! 是时候保存,重新启动然后进行测试了。
ODrive启动后会进入空闲状态(我们将在稍后进行切换),我们之后可以启动闭环控制。

odrv0.save_configuration()
odrv0.reboot()
odrv0.axis0.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL
odrv0.axis0.controller.vel_setpoint = 120
# Your motor should spin here
odrv0.axis0.controller.vel_setpoint = 0
odrv0.axis0.requested_state = AXIS_STATE_IDLE

希望您的电机能正常旋转! 如果不正常,请仔细核对上述所有操作。

PWM 信号输入

如果要使用RC遥控器来控制电机,则可以使用PWM输入
让我们使用GPIO 3/4作为速度控制信号的输入,这样我们就不必禁用UART。
然后,将这些摇杆输入范围映射到某个合适的速度设定范围。
我们还必须重新启动以使PWM输入生效。

odrv0.config.gpio3_pwm_mapping.min = -200
odrv0.config.gpio3_pwm_mapping.max = 200
odrv0.config.gpio3_pwm_mapping.endpoint = odrv0.axis0.controller._remote_attributes['vel_setpoint']

odrv0.config.gpio4_pwm_mapping.min = -200
odrv0.config.gpio4_pwm_mapping.max = 200
odrv0.config.gpio4_pwm_mapping.endpoint = odrv0.axis1.controller._remote_attributes['vel_setpoint']

odrv0.save_configuration()
odrv0.reboot()

现在我们可以检查摇杆是否正确控制电机转速了。 移动遥控器摇杆,打印vel_setpoint,移动到其他位置,然后再次检查。

In [1]: odrv0.axis1.controller.vel_setpoint
Out[1]: 0.1904754638671875

In [2]: odrv0.axis1.controller.vel_setpoint
Out[2]: 0.1904754638671875

In [3]: odrv0.axis1.controller.vel_setpoint
Out[3]: 28.152389526367188

In [4]: odrv0.axis1.controller.vel_setpoint
Out[4]: 61.21905517578125

In [5]: odrv0.axis1.controller.vel_setpoint
Out[5]: -52.990474700927734

好的,现在我们应该能够使用遥控器来控制电机的转速了!

odrv0.axis0.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL
odrv0.axis1.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL

安全提醒

确保在RC接收器上设置故障保护功能,以便在遥控器和接收器之间失去连接时,接收器将为两个轴的速度设定值输出0(或对您的设备来说安全的设定)。 另请注意,如果接收器关闭(电源丢失等),或者从接收器到ODrive的信号丢失(电线拔出等),则ODrive将继续执行上一个命令的速度设定值。 ODrive中的PWM输入当前没有超时保护功能。

启动后自动进入闭环控制模式

尝试重新启动,然后在两个轴上激活AXIS_STATE_CLOSED_LOOP_CONTROL。 检查一切正常,并按预期工作。
现在可以使ODrive启动后自动进入闭环控制模式。 这样在没有PC或其它控制主机的情况下运行ODrive将会很方便。

odrv0.axis0.config.startup_closed_loop_control = True
odrv0.axis1.config.startup_closed_loop_control = True
odrv0.save_configuration()
odrv0.reboot()

如果您有任何问题或疑问,欢迎您加入ODrive社区或QQ群 851421965 进行交流。

  • 3
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
当然可以!下面是一个简单的示例代码,用于测试STM32F103C8T6控制的二轮平衡的编码器和电机。 ```c #include "stm32f10x.h" // 定义引脚 #define ENCODER_1_A_PIN GPIO_Pin_0 #define ENCODER_1_B_PIN GPIO_Pin_1 #define ENCODER_2_A_PIN GPIO_Pin_2 #define ENCODER_2_B_PIN GPIO_Pin_3 // 编码器计数 volatile int32_t encoder_1_count = 0; volatile int32_t encoder_2_count = 0; // 初始化编码器 void encoder_init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 编码器1引脚配置 GPIO_InitStructure.GPIO_Pin = ENCODER_1_A_PIN | ENCODER_1_B_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 设置为上拉输入 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 编码器2引脚配置 GPIO_InitStructure.GPIO_Pin = ENCODER_2_A_PIN | ENCODER_2_B_PIN; GPIO_Init(GPIOA, &GPIO_InitStructure); // 连接编码器中断 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource2); EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; EXTI_ClearITPendingBit(EXTI_Line0); EXTI_ClearITPendingBit(EXTI_Line2); // 设置中断线和触发方式 EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line2; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); // 中断配置 NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; NVIC_Init(&NVIC_InitStructure); } // 中断处理函数 void EXTI0_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line0) != RESET) { // 编码器1计数 if (GPIO_ReadInputDataBit(GPIOA, ENCODER_1_B_PIN) == 1) { encoder_1_count++; } else { encoder_1_count--; } EXTI_ClearITPendingBit(EXTI_Line0); } } void EXTI2_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line2) != RESET) { // 编码器2计数 if (GPIO_ReadInputDataBit(GPIOA, ENCODER_2_B_PIN) == 1) { encoder_2_count++; } else { encoder_2_count--; } EXTI_ClearITPendingBit(EXTI_Line2); } } int main(void) { encoder_init(); while (1) { // 在这里可以进行电机控制和编码器读取的操作 } } ``` 这只是一个示例代码,你可以在其中添加电机控制的逻辑和其他功能。同时,注意根据你实际的硬件连接进行引脚配置和中断处理函数的修改。希望对你有所帮助!如果有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值