基于Python与中断实现树莓派机器人直线行驶的问题排查
解决树莓派电机同步跑偏问题:中断逻辑优化方案
嘿,我来帮你排查下这个同步问题!你的思路方向是对的——用光电传感器的中断来对齐左右轮的转动步数,但目前的代码逻辑和中断处理有几个关键点需要调整,咱们一步步来梳理:
问题分析
从你的中断触发情况和代码来看,核心问题出在这几点:
- 中断函数的状态赋值逻辑混乱:比如右侧中断触发时,你直接把
zaehler_l设为2(强制左轮前进),左侧中断时把zaehler_r设为2(强制右轮前进)。这会导致一个轮子刚触发中断停下,另一个轮子就被强制启动,完全打乱了“等慢轮追上”的同步逻辑。 - 缺少防抖处理:光电传感器检测轮子孔洞时,很容易因为机械抖动或信号波动触发多次中断,从日志里的重复触发就能看出来,这会让计数和状态完全错乱。
- 状态变量设计不合理:用1/2的二元状态无法准确记录轮子的转动步数,应该用计数器来跟踪每个轮子转过的孔洞数量,这样才能精准对比两个轮子的进度。
优化方案
1. 调整中断逻辑:只做计数,不修改对方状态
中断函数要尽量简洁,只负责给对应轮子的计数器加1,不要做其他状态修改,避免干扰主循环的同步判断。同时添加防抖参数,过滤抖动触发。
2. 主循环:基于计数器的同步控制
主循环里对比左右轮的计数器,让进度快的轮子暂停,直到慢的轮子追上,再一起继续前进。这样就能保证两个轮子始终保持相同的转动步数,解决跑偏问题。
修改后的代码示例
import RPi.GPIO as GPIO # 全局计数器,记录左右轮转过的孔洞数 count_r = 0 count_l = 0 def interrupt_routinerechts(channel): global count_r # 中断里尽量避免print,影响实时性,调试时可以保留 # print("Interrupt Rechts") count_r += 1 def interrupt_routinelinks(channel): global count_l # print("Interrupt Links") count_l += 1 # GPIO初始化,添加防抖(bouncetime单位:毫秒,根据你的轮子转速调整) GPIO.setmode(GPIO.BCM) GPIO.setup(4, GPIO.IN, pull_up_down=GPIO.PUD_UP) GPIO.setup(6, GPIO.IN, pull_up_down=GPIO.PUD_UP) GPIO.add_event_detect(4, GPIO.FALLING, callback=interrupt_routinerechts, bouncetime=200) GPIO.add_event_detect(6, GPIO.FALLING, callback=interrupt_routinelinks, bouncetime=200) # 假设你的forward()、stoppr()、forwardr()、stoppl()、forwardl()已经正确实现 print("Los Geht's") runProgram = True try: while runProgram: # 对比计数器,同步左右轮 if count_r > count_l: # 右轮快了,停右轮,左轮继续 stoppr() forwardl() elif count_l > count_r: # 左轮快了,停左轮,右轮继续 stoppl() forwardr() else: # 进度一致,双轮前进 forward() except KeyboardInterrupt: print("Exception thrown -> Abort") finally: GPIO.cleanup()
额外注意事项
- 传感器安装校准:确保左右轮的塑料轮孔洞数量完全一致,且传感器对准孔洞的位置相同,这样每次中断对应的转动角度才一致。
- 防抖时间调整:
bouncetime的数值可以根据你的轮子转速调整,比如转速快就调小一点,转速慢就调大一点,避免漏触发或多触发。 - 中断函数轻量化:中断函数里不要执行耗时操作(比如
print),否则会影响中断响应速度,导致计数不准。
内容的提问来源于stack exchange,提问作者Daniel M
相关产品推荐
相关产品推荐

