树莓派4B多进程控制小车电机动力不足问题求助
问题分析与解决方案
核心原因
multiprocessing创建的子进程会复制父进程的内存空间,但GPIO和PWM对象是和硬件寄存器绑定的专属资源,子进程里的power_a、power_b只是父进程对象的空副本,并没有真正和硬件建立有效连接。调用ChangeDutyCycle时,这些副本无法正确控制电机的占空比,最终导致电机功率不足。
线程版正常是因为所有线程共享同一进程的资源,GPIO/PWM对象从始至终都是有效的。
解决方案
方案1:在Flask服务进程内重新初始化GPIO和PWM
把GPIO配置、PWM初始化逻辑移到start_server函数里,让子进程自己创建有效的硬件连接,不要复用父进程的资源:
def start_server(shared_allowed_movement): global local_allowed_movement, power_a, power_b, in1, in2, en_a, in3, in4, en_b local_allowed_movement = shared_allowed_movement # 子进程内单独初始化GPIO与PWM in1 = 23 in2 = 24 en_a = 25 in3 = 17 in4 = 27 en_b = 22 GPIO.setmode(GPIO.BCM) GPIO.setup(in1,GPIO.OUT) GPIO.setup(in2,GPIO.OUT) GPIO.setup(en_a,GPIO.OUT) GPIO.output(in1,GPIO.LOW) GPIO.output(in2,GPIO.LOW) GPIO.setup(in3,GPIO.OUT) GPIO.setup(in4,GPIO.OUT) GPIO.setup(en_b,GPIO.OUT) GPIO.output(in3,GPIO.LOW) GPIO.output(in4,GPIO.LOW) power_a = GPIO.PWM(en_a,1000) power_b = GPIO.PWM(en_b,1000) power_a.start(1) power_b.start(1) app.run(host='192.168.100.36', port=8000, threaded=True)
同时删除主进程里的GPIO/PWM初始化代码,避免父进程提前占用硬件资源。
方案2:用进程间通信委托专门进程处理电机控制
创建独立的电机控制进程,Flask进程只负责接收请求并通过队列发送指令,由控制进程执行实际的GPIO操作:
def motor_control_process(command_queue): # 初始化GPIO和PWM in1 = 23 in2 = 24 en_a = 25 in3 = 17 in4 = 27 en_b = 22 GPIO.setmode(GPIO.BCM) GPIO.setup(in1,GPIO.OUT) GPIO.setup(in2,GPIO.OUT) GPIO.setup(en_a,GPIO.OUT) GPIO.output(in1,GPIO.LOW) GPIO.output(in2,GPIO.LOW) GPIO.setup(in3,GPIO.OUT) GPIO.setup(in4,GPIO.OUT) GPIO.setup(en_b,GPIO.OUT) GPIO.output(in3,GPIO.LOW) GPIO.output(in4,GPIO.LOW) power_a = GPIO.PWM(en_a,1000) power_b = GPIO.PWM(en_b,1000) power_a.start(1) power_b.start(1) while True: command = command_queue.get() if command == 'forward': power_a.ChangeDutyCycle(50) power_b.ChangeDutyCycle(50) GPIO.output(in1,GPIO.LOW) GPIO.output(in2,GPIO.HIGH) GPIO.output(in3,GPIO.LOW) GPIO.output(in4,GPIO.HIGH) elif command == 'backward': power_a.ChangeDutyCycle(50) power_b.ChangeDutyCycle(50) GPIO.output(in1,GPIO.HIGH) GPIO.output(in2,GPIO.LOW) GPIO.output(in3,GPIO.HIGH) GPIO.output(in4,GPIO.LOW) # 其他指令(右转、左转、停止)同理处理 # 主函数调整 if __name__ == '__main__': manager = multiprocessing.Manager() shared_allowed_movement = manager.Value("c", "no restriction") command_queue = manager.Queue() server_process = multiprocessing.Process(target=start_server, args=(shared_allowed_movement, command_queue)) motor_process = multiprocessing.Process(target=motor_control_process, args=(command_queue,)) boundary_detection_process = multiprocessing.Process(target=boundary_detection, args=(shared_allowed_movement,)) motor_process.start() server_process.start() boundary_detection_process.start() server_process.join() boundary_detection_process.join() motor_process.join()
然后修改Flask路由函数,不再直接操作GPIO,而是往队列里发送指令:
@app.route('/move_forward', methods=['POST']) def move_forward(): global local_allowed_movement if local_allowed_movement.value == 'no restriction': command_queue.put('forward') return jsonify({"message": "Car moving forward"})
额外修复点
move_stop函数里的power_a.start(1)是错误用法,start()只需要调用一次,调整占空比应该用ChangeDutyCycle:
@app.route('/move_stop', methods=['POST']) def move_stop(): power_a.ChangeDutyCycle(1) power_b.ChangeDutyCycle(1) GPIO.output(in1,GPIO.LOW) GPIO.output(in2,GPIO.LOW) GPIO.output(in3,GPIO.LOW) GPIO.output(in4,GPIO.LOW) return jsonify({"message": "Car stopped"})
验证步骤
- 优先测试方案1,去掉主进程的GPIO初始化逻辑,在Flask进程内重新初始化,观察电机功率是否恢复。
- 如果问题仍存在,检查树莓派电源供应:多进程运行会增加功耗,确保电源能提供5V 3A以上的稳定电流。
内容的提问来源于stack exchange,提问作者PotustPl
相关产品推荐
相关产品推荐

