如何通过zb_control.py停止adxl345test.py并保持监听X-CTU指令?
解决Zigbee控制脚本启停子进程的问题
你的核心问题在于使用subprocess.call()启动adxl345test.py时,该方法是阻塞式的——它会一直等待子进程执行完毕才会继续运行zb_control.py的后续代码。这就导致当你发送"stop"指令时,zb_control.py根本没在监听串口,自然无法响应停止命令。
下面是修正后的可行方案,主要做了两点关键改动:
- 使用
subprocess.Popen()替代call(),让子进程后台运行,不阻塞主脚本 - 保存子进程实例,方便后续精准终止,避免误杀其他进程
修改后的完整代码
import serial, time, sys, os, subprocess # 把串口初始化移到循环外,避免重复打开端口引发冲突 ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=2) # 初始化子进程变量,用于保存adxl345test的进程实例 data_collector = None while True: # 串口读取的是字节串,解码为字符串才能和指令正确匹配 inc = ser.readline().strip().decode('utf-8') if inc == 'run': # 检查子进程是否已在运行,避免重复启动 if data_collector is None or data_collector.poll() is not None: print("---------------") print("Collecting data") print("---------------") # 用Popen启动后台进程,直接返回进程对象,不阻塞主脚本 data_collector = subprocess.Popen(["python", "adxl345test.py"]) else: print("Data collector is already running!") elif inc == 'stop': # 检查子进程是否存在且正在运行 if data_collector is not None and data_collector.poll() is None: # 先尝试优雅终止,若进程无响应再考虑用kill()强制杀死 data_collector.terminate() # 等待进程彻底结束(可选) data_collector.wait() print("-----------------------") print("Script has been stopped") print("-----------------------") # 重置子进程变量,方便下次启动 data_collector = None else: print("Data collector is not running!") # 加小延迟降低CPU占用率 time.sleep(0.1)
关键改动解释
- 串口初始化移到循环外:你之前每次循环都重新打开串口,容易引发端口占用冲突,移到外部只初始化一次更稳定。
- 使用
Popen()启动进程:这个方法会立即返回子进程对象,主脚本可以持续监听串口指令,不会被子进程阻塞。 - 保存子进程实例:通过
data_collector变量保存进程对象,后续直接调用terminate()就能精准停止目标脚本,比pkill更安全,不会误杀其他同名进程。 - 进程状态检查:启动前判断进程是否已在运行、停止前判断进程是否存在,避免重复启动或无效停止的报错。
- 字节串解码:串口读取的内容是字节串,必须解码为字符串才能和"run"/"stop"指令正确匹配,这也是你可能遇到的隐性匹配失败问题。
关于你之前尝试方法的问题
你注释的pkill/killall方法之所以没生效,本质是call()阻塞了主脚本,elif 'stop'分支根本没机会执行。另外,代码里adxl345test.py没加引号,写成check_call(["pkill", "-9", "-f", adxl345test.py])会直接报错,正确写法应该是check_call(["pkill", "-9", "-f", "adxl345test.py"])——但即使修正了引号,主脚本被阻塞的核心问题不解决,这些代码也执行不到。
内容的提问来源于stack exchange,提问作者user75374
相关产品推荐
相关产品推荐

