串口通信的核心是 pyserial 库,这是 Python 中最常用、最强大的串口操作库。

核心函数详解 (基于 pyserial)
在 pyserial 库中,所有操作都围绕 serial.Serial 这个类对象展开。
初始化与打开串口 (serial.Serial)
这是第一步,用于创建一个串口对象,并设置好所有必要的参数。
import serial
# --- 构造函数 ---
# ser = serial.Serial(port, baudrate, bytesize, parity, stopbits, timeout, xonxoff, rtscts, dsrdtr)
# 参数说明:
# port: 串口设备名,例如在 Windows 上是 'COM3',在 Linux 上是 '/dev/ttyUSB0' 或 '/dev/ttyACM0'
# baudrate: 波特率,必须与机器人端设置的波特率一致,9600, 115200
# bytesize: 数据位,通常是 8 (serial.EIGHTBITS)
# parity: 校验位,通常是 'N' (无校验 serial.PARITY_NONE)
# stopbits: 停止位,通常是 1 (serial.STOPBITS_ONE)
# timeout: 超时时间(秒),非常重要!
# - None: 阻塞模式,read() 会一直等待直到读到数据
# - 0: 非阻塞模式,read() 立即返回,读到多少是多少
# - x.x: 超时模式,read() 最多等待 x.x 秒
# xonxoff: 是否启用软件流控 (默认 False)
# rtscts: 是否启用硬件流控 (默认 False)
# dsrdtr: 是否启用硬件流控 (默认 False)
# --- 常用简化写法 ---
ser = serial.Serial(
port='/dev/ttyUSB0',
baudrate=115200,
timeout=1 # 设置超时为1秒,防止程序卡死
)
# --- 其他常用方法 ---
ser.baudrate = 9600 # 动态修改波特率
ser.port = 'COM4' # 动态修改串口
ser.open() # 手动打开串口(如果构造函数中 auto_open=False)
ser.is_open # 检查串口是否已打开,返回 True 或 False
写数据 (write)
向机器人发送指令。
# ser.write(data)
# 参数说明:
# data: 必须是 bytes 类型,不能是字符串
# --- 示例 ---
# 发送字符串 "START",需要先编码成 bytes
command = "START\n" # 很多机器人协议以换行符作为命令结束
ser.write(command.encode('utf-8')) # 或者 command.encode('ascii')
# 发送一个字节数据
ser.write(b'\x01') # 发送十六进制 0x01
读数据 (read, readline, readlines)
从机器人读取返回的数据或状态。

# --- read(size=1) ---
# 读取指定大小的字节,如果超时时间内没读到足够字节,则返回已读到的部分。
# size: 要读取的字节数
data = ser.read(10) # 读取10个字节,如果1秒内没读到10个,则返回已读到的
# --- readline() ---
# 读取一行,以换行符 '\n' 或 '\r' 为结束标志,非常适用于读取文本协议。
# 如果超时时间内没读到换行符,则返回已读到的内容。
response = ser.readline() # 读取一行,返回 bytes 类型
print(response.decode('utf-8').strip()) # 解码并去除首尾空白字符
# --- readlines() ---
# 读取多行,直到超时,返回一个包含多行 bytes 的列表。
# 注意:如果数据流很慢,这个函数可能会阻塞很长时间,一般不推荐使用。
# lines = ser.readlines()
关闭串口 (close)
在程序结束或不再需要通信时,必须关闭串口以释放资源。
ser.close()
完整示例:控制一个假设的机器人
假设我们的机器人通过串口接收指令,格式为 命令+参数\n,MOVE 100\n 表示向前移动100cm,机器人返回 OK\n 表示成功。
import serial
import time
def connect_to_robot(port, baudrate=115200, timeout=1):
"""
连接到机器人串口
:param port: 串口号
:param baudrate: 波特率
:param timeout: 超时时间
:return: serial.Serial 对象 或 None
"""
try:
ser = serial.Serial(
port=port,
baudrate=baudrate,
timeout=timeout
)
print(f"成功连接到串口 {port}")
return ser
except serial.SerialException as e:
print(f"连接串口 {port} 失败: {e}")
return None
def send_command(ser, command):
"""
发送命令并等待响应
:param ser: 串口对象
:param command: 要发送的命令字符串
"""
if not ser or not ser.is_open:
print("串口未打开,无法发送命令。")
return
# 发送命令
ser.write(command.encode('utf-8'))
print(f"已发送命令: {command.strip()}")
# 等待并读取响应
response = ser.readline()
if response:
print(f"机器人响应: {response.decode('utf-8').strip()}")
else:
print("超时,未收到机器人响应。")
def main():
# --- 配置参数 ---
# !!! 请根据你的实际情况修改这些参数 !!!
ROBOT_PORT = '/dev/ttyUSB0' # Linux 或 macOS
# ROBOT_PORT = 'COM3' # Windows
ROBOT_BAUDRATE = 115200
# 1. 连接机器人
robot_serial = connect_to_robot(ROBOT_PORT, ROBOT_BAUDRATE)
if robot_serial:
try:
# 给机器人一点时间启动和准备
time.sleep(2)
# 2. 发送一系列命令
send_command(robot_serial, "START\n") # 启动机器人
time.sleep(0.5)
send_command(robot_serial, "MOVE 100\n") # 移动100cm
time.sleep(0.5)
send_command(robot_serial, "TURN 90\n") # 转向90度
time.sleep(0.5)
send_command(robot_serial, "STOP\n") # 停止
except KeyboardInterrupt:
print("\n用户中断程序,正在关闭串口...")
finally:
# 3. 关闭串口 (非常重要!)
robot_serial.close()
print("串口已关闭。")
if __name__ == '__main__':
main()
进阶主题与最佳实践
使用 with 语句 (推荐)
with 语句可以确保串口在使用完毕后被自动关闭,即使发生错误也不会忘记关闭,是更安全、更 Pythonic 的写法。
import serial
# with 语句会自动处理 ser.close()
with serial.Serial('/dev/ttyUSB0', 115200, timeout=1) as ser:
ser.write(b'HELLO\n')
response = ser.readline()
print(f"Response: {response.decode('utf-8').strip()}")
# ser 已经被自动关闭了
多线程/异步串口通信
机器人的数据接收往往是持续不断的(不断上报传感器数据),而发送命令是事件驱动的,如果使用单线程,在 readline() 等待数据时,程序就无法发送新的命令。
解决方法是使用多线程:
- 主线程:负责发送命令和用户交互。
- 数据读取线程:在一个循环中持续读取串口数据,并放入队列或进行其他处理。
import threading
import queue
import serial
# 创建一个队列用于线程间通信
data_queue = queue.Queue()
def read_from_port(ser):
"""一个持续从串口读取数据的线程函数"""
while True:
if ser.in_waiting > 0:
line = ser.readline()
data_queue.put(line) # 将读到的数据放入队列
print(f"收到数据: {line.decode('utf-8').strip()}")
time.sleep(0.01) # 短暂休眠,避免CPU占用过高
# --- 主程序 ---
ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=1)
# 启动数据读取线程
read_thread = threading.Thread(target=read_from_port, args=(ser,), daemon=True)
read_thread.start()
# 主线程可以继续执行其他任务,比如发送命令
ser.write(b'START\n')
time.sleep(2)
ser.write(b'READ_SENSOR\n')
# 让主线程保持运行,以便观察子线程的输出
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print("程序退出")
ser.close()
跨平台串口名
不同操作系统的串口命名规则不同:
- Windows:
COM1,COM2, ... - Linux:
/dev/ttyS0,/dev/ttyUSB0,/dev/ttyACM0, ... - macOS:
/dev/tty.serialname
在编写跨平台程序时,需要根据操作系统选择正确的串口名,可以使用 platform 模块来判断。
import platform
import serial
def find_robot_port():
system = platform.system()
if system == 'Windows':
# 可以尝试常见的 COM 端口
for i in range(1, 10):
port = f'COM{i}'
try:
ser = serial.Serial(port, 115200, timeout=0.1)
ser.close()
return port
except:
continue
elif system == 'Linux':
# 可以尝试常见的 USB 串口设备
for port in ['/dev/ttyUSB0', '/dev/ttyACM0']:
try:
ser = serial.Serial(port, 115200, timeout=0.1)
ser.close()
return port
except:
continue
# ... 其他系统处理
return None
robot_port = find_robot_port()
if robot_port:
print(f"找到机器人串口: {robot_port}")
else:
print("未找到可用的机器人串口。")
希望这份详细的指南能帮助你实现机器人的串口连接!
标签: 机器人串口通信函数 Python机器人串口连接函数 STM32机器人串口控制函数