COM5串口访问被拒:Arduino雷达可视化Python脚本故障求助
串口权限错误:无法打开COM5端口(PermissionError 13)
我正在编写Python脚本,通过COM5端口读取搭载舵机和超声波传感器的Arduino设备串口数据,用来绘制雷达样式图表。已经尝试以下排查步骤:
- 关闭Arduino IDE串口监视器,确认无程序占用端口
- 以管理员权限运行脚本
- 重启电脑
- 卸载并重装pyserial库
但始终触发如下错误:
serial.serialutil.SerialException: could not open port 'COM5': PermissionError(13, 'Access is denied.', None, 5)
我的Python代码:
from matplotlib import pyplot as plt import matplotlib matplotlib.use('TkAgg') import numpy as np import time import serial import keyboard ser = serial.Serial('COM5', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=2) # setup the basic display window fig = plt.figure(facecolor='k') fig.canvas.toolbar.pack_forget() fig.canvas.manager.set_window_title('Radar') mng = plt.get_current_fig_manager() mng.window.state('zoomed') #setup the sub plot (the radar screen) ax = fig.add_subplot(1,1,1, polar=True, facecolor='green') ax.tick_params(axis='both', colors='white' ) ax.xaxis.grid(True, color='grey', linestyle='--') ax.yaxis.grid(True, color='grey', linestyle='--') rmax = 100 ax.set_ylim([0.0, rmax]) ax.set_xlim([0.0, np.pi]) ax.set_position([0.1, 0.1, 0.8, 0.8 ]) ax.set_rticks(np.linspace(0.0, rmax, 5)) ax.set_rlabel_position(0) ax.set_thetagrids(np.linspace(0.0, 360, 17)) angles = np.arange(0, 360, 1) #convert angles to radians theta = angles * (np.pi / 180) pols = ax.plot([], linestyle='', marker='o', markerfacecolor='r', markeredgecolor='w', markeredgewidth=1.0, markersize=3.0, alpha=0.5) line1 = ax.plot([], color='w', linewidth=3.0) fig.canvas.draw() dists = np.ones((len(angles),)) axbbackground = fig.canvas.copy_from_bbox(ax.bbox) while True: try: data = ser.readline() decoded = data.decode() data = (decoded.replace('\r','')).replace('\n','') #split data values (one distance, one angle) where there is a comma vals = [float(ii) for ii in data.split(',')] #check that there is in fact 2 values and it doesnt try plot an incomplete graph if len(vals) < 2: continue angle, dist = vals # can test working by adding #print(angle, dist) #Create all angles into a list to plot all at once dists[int(angle)] = dist pols.set_data(theta, dists) #plot background fig.canvas.restore_region(axbbackground) ax.draw_artist(pols) #create sweeping line line1.set_data(np.repeat((angle*(np.pi/180)), 2),np.linspace(0.0, rmax, 2)) ax.draw_artist(line1) fig.canvas.blit(ax.bbox) fig.canvas.flush_events() if keyboard.is_pressed('q'): plt.close('all') print('User to quit the application') break except KeyboardInterrupt: plt.close('all') ser.close() # Always close the port after usage print("Keyboard interrupt") break exit
我的Arduino代码:
#include <Servo.h> Servo micro_servo; int pos = 0; const int servo_pin = 7; const int trig_echo_pin = 3; float duration, distance; void setup() { pinMode (servo_pin, OUTPUT); pinMode (trig_echo_pin, OUTPUT); Serial.begin(9600); micro_servo.attach(servo_pin); } void loop() { // Sweep the servo from 0 to 180 degrees for (pos = 0; pos <= 180; pos++) { micro_servo.write(pos); delay(50); read_ultrasonic_distance(pos); } // Sweep the servo back from 180 to 0 degrees for (pos = 180;pos>=180; pos--) { micro_servo.write(pos); delay(50); read_ultrasonic_distance(pos); } delay(200); } void read_ultrasonic_distance(int angle) { pinMode(trig_echo_pin, OUTPUT); digitalWrite(trig_echo_pin, LOW); delayMicroseconds(2); digitalWrite(trig_echo_pin, HIGH); delayMicroseconds(10); digitalWrite(trig_echo_pin, LOW); // Set the pin to input mode to receive the echo pinMode(trig_echo_pin, INPUT); duration = pulseIn(trig_echo_pin, HIGH); // Measure the duration of the echo pulse // Calculate the distance based on the duration distance = (duration * 0.0343) / 2; // Send the angle and distance to the Python program via serial Serial.print(angle); Serial.print(","); Serial.println(distance); }
解决建议
1. 清理隐蔽的端口占用进程
Arduino IDE关闭后,后台可能残留java.exe进程占用串口。打开任务管理器,结束所有与Arduino、Python相关的进程,再重新运行脚本。
2. 优化串口初始化与关闭逻辑
给串口初始化加重试机制,同时确保所有退出路径都能正确关闭端口:
import serial.tools.list_ports # 先验证端口存在性 ports = [port.device for port in serial.tools.list_ports.comports()] if 'COM5' not in ports: print("COM5端口不存在,请检查设备连接") exit() # 带重试的串口初始化 ser = None for _ in range(3): try: ser = serial.Serial('COM5', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=2) break except serial.SerialException as e: print(f"尝试打开端口失败:{e}") time.sleep(1) if not ser: print("多次尝试后仍无法打开端口") exit() # 原循环逻辑... # 确保程序退出时关闭串口 try: while True: # 原循环代码 pass finally: if ser and ser.is_open: ser.close() print("串口已关闭")
3. 修复Arduino的舵机回扫逻辑
你的Arduino代码中,舵机回扫的循环条件错误,导致只会执行一次:
// 错误代码 for (pos = 180;pos>=180; pos--) // 修正为 for (pos = 180; pos >= 0; pos--)
错误的循环会导致数据发送异常,间接影响串口连接稳定性。
4. 排查硬件与驱动问题
- 更换USB接口重新连接Arduino,排除接触不良
- 卸载并重新安装Arduino官方USB串口驱动
- 检查设备管理器中COM5端口是否有黄色感叹号,若有则修复驱动
内容的提问来源于stack exchange,提问作者Loft
相关产品推荐
相关产品推荐

