树莓派多进程控制风速计与伺服平台异常问题求助
树莓派多进程GPIO与伺服控制问题排查
问题背景
在树莓派项目中使用multiprocess模块实现两项核心功能:风速计风速计算、基于伺服电机的光伏板平台转动控制。主进程初始化硬件对象并启动三个子进程,其中calculate_power_p运行正常,但另外两个进程出现异常。
主函数代码:
def main(): ane = Anemometer(pin=38, radius=65, anamometer_factor=1, action_time=5, measurment_fraquency=0.01, max_wind_speed=40, mesurment_time=30) prb = PhotoresistorBase(TR=1, TL=3, BR=0, BL=2, signifficant_diff=40) BS = Servo(pin=12, min_val=10, max_val=50) US = Servo(pin=18, min_val=29, max_val=43) pv_based = Pv(6) pv_servo = Pv(5) ... calculate_wind_vel_p = Process(target=calculate_wind_vel, args=(ane, BS, US)) calculate_power_p = Process(target=calculate_power, args=(pv_based, pv_servo)) turn_platform_p = Process(target=turn_platform, args=(prb, BS, US)) calculate_wind_vel_p.start() calculate_power_p.start() turn_platform_p.start() calculate_wind_vel_p.join() calculate_power_p.join() turn_platform_p.join()
异常1:风速计进程calculate_wind_vel_p
目标函数代码:
def calculate_wind_vel(ane, BS, US): while True: wind_speed = ane.calculate_mean_wind_velocity() ... data = (datetime.datetime.now(), wind_speed) insert_vel_data(conn, data) time.sleep(1)
- 多进程模式下,
Anemometer类的calculate_wind_velocity方法中,count仅在第一次GPIO.event_detected触发时递增一次,后续事件触发不再计数;循环再次执行时count完全不递增。 - 单独在主进程运行风速计代码时功能完全正常:
ane = Anemometer(pin=38, radius=65, anamometer_factor=1, action_time=5, measurment_fraquency=0.01, max_wind_speed=40, mesurment_time=30) while True: ret = ane.calculate_mean_wind_velocity() print(ret) time.sleep(2)
异常2:伺服平台进程turn_platform_p
进程执行伺服类函数,但伺服电机无动作,函数未正确计算或改变状态。
问题根源
树莓派multiprocess采用fork机制创建子进程,子进程会复制主进程内存空间,但硬件资源存在独占性,导致两个核心问题:
- GPIO事件监听失效:主进程初始化的GPIO事件检测是内核级资源,不会被子进程复制,子进程无法捕获后续GPIO触发事件。
- 硬件对象跨进程无效:
Anemometer、Servo等对象依赖的GPIO底层句柄在子进程中无效,无法正确操作硬件;同时多进程操作同一GPIO引脚会引发资源竞争,导致指令冲突。
解决方案
1. 改用多线程替代多进程(优先方案)
硬件控制场景下,多线程共享进程内存与硬件资源句柄,不会出现资源复制失效问题:
from threading import Thread import time def main(): # 初始化所有硬件对象 ane = Anemometer(pin=38, radius=65, anamometer_factor=1, action_time=5, measurment_fraquency=0.01, max_wind_speed=40, mesurment_time=30) prb = PhotoresistorBase(TR=1, TL=3, BR=0, BL=2, signifficant_diff=40) BS = Servo(pin=12, min_val=10, max_val=50) US = Servo(pin=18, min_val=29, max_val=43) pv_based = Pv(6) pv_servo = Pv(5) # 创建线程 calculate_wind_vel_t = Thread(target=calculate_wind_vel, args=(ane, BS, US)) calculate_power_t = Thread(target=calculate_power, args=(pv_based, pv_servo)) turn_platform_t = Thread(target=turn_platform, args=(prb, BS, US)) # 设置守护线程,随主进程退出 calculate_wind_vel_t.daemon = True calculate_power_t.daemon = True turn_platform_t.daemon = True calculate_wind_vel_t.start() calculate_power_t.start() turn_platform_t.start() # 保持主进程运行 while True: time.sleep(1)
2. 进程间队列传递指令(必须用多进程时)
通过multiprocessing.Queue实现主进程统一处理硬件操作,子进程仅负责计算逻辑:
from multiprocessing import Process, Queue import datetime def calculate_wind_vel(queue): while True: # 此处需从主进程获取GPIO计数或在子进程内独立初始化风速计(避免跨进程传递对象) wind_speed = ... queue.put(('wind_data', wind_speed)) time.sleep(1) def turn_platform(queue): while True: # 计算平台转动角度指令 angle_cmd = ... queue.put(('servo_cmd', 'BS', angle_cmd)) time.sleep(0.5) def main(): queue = Queue() # 主进程初始化所有硬件对象 ane = Anemometer(...) BS = Servo(...) US = Servo(...) pv_based = Pv(6) pv_servo = Pv(5) # 创建进程 p1 = Process(target=calculate_wind_vel, args=(queue,)) p2 = Process(target=turn_platform, args=(queue,)) p3 = Process(target=calculate_power, args=(pv_based, pv_servo)) p1.start() p2.start() p3.start() # 主进程监听队列,执行硬件操作 while True: if not queue.empty(): cmd_type, *args = queue.get() if cmd_type == 'wind_data': wind_speed = args[0] insert_vel_data(conn, (datetime.datetime.now(), wind_speed)) elif cmd_type == 'servo_cmd': servo_name, angle = args if servo_name == 'BS': BS.set_angle(angle) time.sleep(0.01)
3. 子进程内独立初始化硬件(避免资源冲突)
若坚持使用多进程,每个子进程需独立初始化对应硬件对象,禁止跨进程传递主进程创建的硬件实例:
def calculate_wind_vel(): # 子进程内独立初始化风速计 ane = Anemometer(pin=38, radius=65, anamometer_factor=1, action_time=5, measurment_fraquency=0.01, max_wind_speed=40, mesurment_time=30) while True: wind_speed = ane.calculate_mean_wind_velocity() data = (datetime.datetime.now(), wind_speed) insert_vel_data(conn, data) time.sleep(1) def turn_platform(): # 子进程内独立初始化光敏电阻与伺服电机 prb = PhotoresistorBase(TR=1, TL=3, BR=0, BL=2, signifficant_diff=40) BS = Servo(pin=12, min_val=10, max_val=50) while True: # 执行平台转动逻辑 ... def main(): calculate_wind_vel_p = Process(target=calculate_wind_vel) turn_platform_p = Process(target=turn_platform) calculate_power_p = Process(target=calculate_power, args=(pv_based, pv_servo)) calculate_wind_vel_p.start() calculate_power_p.start() turn_platform_p.start() calculate_wind_vel_p.join() calculate_power_p.join() turn_platform_p.join()
注意:此方案需确保不同子进程不操作同一GPIO引脚,避免资源竞争。
内容的提问来源于stack exchange,提问作者Lezakk
相关产品推荐
相关产品推荐

