You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派4开环系统下霍尔编码器无法绘制RPM曲线问题求助

树莓派4霍尔编码器X1解码开环系统故障排查&修复方案

我仔细梳理了你的问题和代码,你现在卡在X1解码的霍尔编码器在开环系统里没法正常运行,但PID模式却能正常工作这个点上,而且已经尝试了低通滤波还是没解决。结合你的代码细节,我从几个核心方向帮你排查问题,再给出修复后的完整方案:

核心问题拆解

  1. 编码器计数逻辑的致命问题

    • 你在循环里反复注册GPIO.add_event_detect,这会导致同一个引脚绑定N个回调函数,计数直接乱套——回调应该只注册一次!
    • 你的counterup回调里多了个if GPIO.input(channel) == 1的判断,完全没必要:既然是用GPIO.RISING触发的回调,触发时引脚肯定是高电平,这个判断纯粹是多余的,还可能导致计数丢步。
    • 最关键的:你代码里写的encoderCount = 55,但实际PPR是160!这直接导致转速计算完全错误,开环系统根本拿不到正确的转速反馈,自然没法按预期运行。
  2. 开环控制逻辑完全混乱

    • 你在循环里每次都重置count = 0,然后固定给50%的PWM占空比,这根本不是开环控制——开环的核心是根据目标转速输出对应的固定PWM值,而不是每次循环都重启PWM、固定占空比。
    • 时间处理部分的simulationTime = int(1000 / 24 * simulationTime)逻辑模糊,而且和后面np.linspace(0,20)的时间轴完全不匹配,采样和时间同步彻底乱了。
  3. 资源管理的低级错误

    • 你在循环里反复调用pwmOut.start(50),这会导致PWM模块多次重启,电机转速根本稳定不下来。

修复后的完整代码

下面是调整后的代码,修复了所有上述问题,适配X1解码逻辑、正确的PPR设置,还有合理的开环控制流程:

import RPi.GPIO as GPIO
import numpy as np
import time
import matplotlib.pyplot as plt
from time import sleep
import sensormotion as sm
from motor_model import motor
from scipy.integrate import odeint

# 定义GPIO引脚
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # 编码器A相输入(X1解码只需要A相)
GPIO.setup(18, GPIO.OUT)  # PWM输出引脚
GPIO.setup(27, GPIO.OUT)  # 电机左转方向引脚
GPIO.setup(22, GPIO.OUT)  # 电机右转方向引脚

# 系统核心参数(按实际硬件修改)
TARGET_RPM = 500  # 开环控制的目标转速
PPR = 160  # 编码器实际脉冲数/转(你之前写的55是错误的!)
SAMPLING_TIME = 0.01  # 采样间隔(10ms)
PWM_FREQ = 100  # PWM工作频率(树莓派推荐100Hz,避免高频干扰)
MAX_PWM = 100  # PWM最大占空比(0-100)

# 全局变量
encoder_count = 0  # 编码器脉冲计数
speed_history = np.array([])
time_history = np.array([])

# 编码器计数回调(X1解码:仅检测A相上升沿)
def count_encoder_pulse(channel):
    global encoder_count
    encoder_count += 1  # 上升沿触发时直接计数,无需额外判断

# 转速转换:脉冲计数转RPM
def count_to_rpm(count, sampling_time, ppr):
    # 每秒脉冲数 = 采样周期内计数 / 采样时间
    # RPM = (每秒脉冲数 * 60秒) / 每转脉冲数
    return (count / sampling_time) * 60 / ppr

# 电机方向控制函数
def set_motor_dir(direction):
    if direction == 'cw':  # 顺时针转动
        GPIO.output(27, 0)
        GPIO.output(22, 1)
    elif direction == 'ccw':  # 逆时针转动
        GPIO.output(27, 1)
        GPIO.output(22, 0)
    else:  # 停止电机
        GPIO.output(27, 0)
        GPIO.output(22, 0)

# 初始化PWM模块
pwm_out = GPIO.PWM(18, PWM_FREQ)
pwm_out.start(0)  # 先以0占空比启动,避免电机突然启动

try:
    # 仅注册一次编码器事件检测!
    GPIO.add_event_detect(17, GPIO.RISING, callback=count_encoder_pulse)
    set_motor_dir('cw')  # 设置电机顺时针转动

    # 开环控制核心:根据目标转速设置固定PWM占空比
    # 注意:这个PWM值需要你实际测试校准——不同电机的电压-转速特性不同
    # 比如你测试后发现60%占空比能达到500RPM,就填60
    OPEN_LOOP_PWM = 60
    pwm_out.ChangeDutyCycle(OPEN_LOOP_PWM)

    # 数据采样循环(运行20秒)
    start_time = time.perf_counter()  # 用高精度计时函数
    while time.perf_counter() - start_time < 20:
        current_time = time.perf_counter() - start_time
        encoder_count = 0  # 重置计数,准备下一次采样
        sleep(SAMPLING_TIME)
        # 计算当前转速
        current_rpm = count_to_rpm(encoder_count, SAMPLING_TIME, PPR)
        # 保存数据到历史数组
        speed_history = np.append(speed_history, current_rpm)
        time_history = np.append(time_history, current_time)
        print(f"当前转速: {current_rpm:.2f} RPM")

    # 停止电机并清理PWM
    set_motor_dir('stop')
    pwm_out.stop()

    # 绘制转速曲线
    plt.figure(figsize=(10, 6))
    plt.plot(time_history, speed_history, 'k-', linewidth=0.8, label='编码器实测转速')
    plt.axhline(y=TARGET_RPM, color='r', linestyle='--', label='目标转速')
    plt.title("开环控制下电机转速曲线")
    plt.xlabel('时间 [s]')
    plt.ylabel('转速 [RPM]')
    plt.legend(loc='upper right')
    plt.grid(True)
    plt.show()

except KeyboardInterrupt:
    print("程序被用户中断")
finally:
    GPIO.remove_event_detect(17)  # 移除编码器事件检测
    GPIO.cleanup()  # 清理所有GPIO资源

额外优化建议

  1. 开环PWM值校准:你必须实际测试你的电机,找到对应目标转速的PWM占空比——不同电机的KV值、负载情况不同,固定PWM值需要根据实际场景调整。
  2. 编码器硬件验证:先单独测试编码器计数,手动转动电机一圈,看计数是否刚好是160次,确保硬件连接(比如接线、上拉电阻)和计数逻辑正确。
  3. 噪声滤波优化:如果编码器信号有噪声,推荐用滑动平均滤波,比Butterworth滤波更简单适合嵌入式场景:
    # 滑动平均滤波示例(窗口大小为5)
    def moving_average(data, window_size=5):
        return np.convolve(data, np.ones(window_size)/window_size, mode='valid')
    
  4. 计时精度优化:用time.perf_counter()替代time.time(),能获得更高精度的计时,适合高速采样场景。

内容的提问来源于stack exchange,提问作者Nimra Ghazal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 11:43:14