Python连接Arduino初始化串口/dev/ttyACM0报设备占用错误求助
Python连接Arduino串口报[Errno 16]设备忙故障排查
故障现象
无法实现Python与Arduino的串口通信,每次尝试初始化连接时返回如下错误信息:
Traceback (most recent call last): File "/usr/lib/python3/dist-packages/serial/serialposix.py", line 322, in open self.fd = os.open(self.portstr, os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK) OSError: [Errno 16] Device or resource busy: '/dev/ttyACM0' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "<pyshell#2>", line 1, in <module> ser1 = serial.Serial('/dev/ttyACM0', 9600) File "/usr/lib/python3/dist-packages/serial/serialutil.py", line 244, in __init__ self.open() File "/usr/lib/python3/dist-packages/serial/serialposix.py", line 325, in open raise SerialException(msg.errno, "could not open port {}: {}".format(self._port, msg)) serial.serialutil.SerialException: [Errno 16] could not open port /dev/ttyACM0: [Errno 16] Device or resource busy: '/dev/ttyACM0'
报错指向代码行:
ser1 = serial.Serial('/dev/ttyACM0', 9600)
异常发生在串口初始化阶段,两端原始代码如下:
Python端原始代码
import serial import time s = serial.Serial('/dev/ttyACM0', 9600) s.close() s.open() time.sleep(5) s.write("test") try: while True: response = s.readline() print (response) except KeyboardInterrupt: s.close()
Arduino端原始代码
void setup() { Serial.begin(9600); Serial.println("running"); } void loop() { if(Serial.available()){ byte recieved = Serial.read(); Serial.print("recieved:"); Serial.println(recieved, DEC); } }
故障原因
- 核心报错
[Errno 16] Device or resource busy代表/dev/ttyACM0串口已经被其他进程占用,常见占用源包括:Arduino IDE自带的串口监视器、系统串口调试工具(minicom/gtkterm等)、Linux发行版默认预装的brltty盲文支持服务(该服务会自动抢占所有ttyACM类设备,是此类问题最高发诱因)。 - Python代码存在逻辑错误:
serial.Serial()实例化时会默认自动打开串口,后续手动调用close()再open()属于冗余操作,若初始化阶段就因端口占用抛错,这两行代码根本不会执行。 - Python3下串口写入要求传入字节类型数据,原始代码直接传入字符串
"test"会触发类型错误,哪怕端口占用问题解决也会运行失败。
解决步骤
- 释放被占用的串口
终端执行sudo fuser /dev/ttyACM0查询占用该端口的进程ID,执行kill <查询到的进程ID>终止占用进程即可。如果占用进程是brltty,直接执行sudo apt remove brltty卸载该服务即可永久解决抢占问题;如果是Arduino IDE开了串口监视器,直接关闭监视器窗口再运行脚本。 - 修正Python端代码
移除冗余的关开串口操作,给串口加超时参数避免读阻塞,写入数据时转成字节类型,修正后代码如下:
import serial import time # 实例化时自动建立串口连接,加timeout参数避免readline永久阻塞 s = serial.Serial('/dev/ttyACM0', 9600, timeout=1) # Arduino每次串口连接会自动重启,等待2秒让设备完成初始化 time.sleep(2) # 写入内容前加b转成字节类型 s.write(b"test") try: while True: response = s.readline() if response: # 字节转字符串输出,去掉首尾空白符 print(response.decode('utf-8').strip()) except KeyboardInterrupt: s.close()
- 确认串口操作权限
若释放端口后仍报错,执行sudo usermod -aG dialout <当前系统用户名>将当前用户加入串口操作权限组,执行完成后注销用户重新登录即可生效。
注:Arduino端代码不存在功能性问题,仅变量名
recieved为拼写笔误,不影响正常通信。
内容的提问来源于stack exchange,提问作者Miller
相关产品推荐
相关产品推荐

