新增pod_bridge吊舱桥接中间件(树莓派4B部署)
- pod_bridge: 协议G版编解码/地理位置引导律/PX4网关/串口链路/闭环主循环 - 含三项安全修复: position_time_ms拆分、表2-2锁定门控、run()异常护栏 - 测试92条全绿; 附树莓派4B(Ubuntu 24.04)部署注意事项与最小依赖清单
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
"""pod_serial.py —— 吊舱串口链路(pyserial 8N1 + FrameParser 分帧)。
|
||||
|
||||
文档:波特率 115200、无校验、8N1。本模块只做字节搬运与分帧,不理解帧语义:
|
||||
* poll() —— 非阻塞读取已到达字节(timeout=0 + in_waiting),喂 FrameParser,
|
||||
返回本次解析出的帧列表(粘包/半帧由 FrameParser 处理);
|
||||
* send() —— 写入一帧已编码字节;
|
||||
* close() —— 关闭串口。
|
||||
|
||||
非阻塞轮询设计便于与 asyncio 桥接主循环单线程协作(无需读线程)。PodLink 为
|
||||
duck-typed 接口,桥接层据此工作,测试可注入内存 FakePod,无需硬件。
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List, Protocol, runtime_checkable
|
||||
|
||||
from .protocol import FrameParser
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@runtime_checkable
|
||||
class PodLink(Protocol):
|
||||
"""吊舱链路接口(PodSerial 实机实现 / 测试 FakePod 均满足)。"""
|
||||
|
||||
def poll(self) -> List[object]:
|
||||
"""返回本次解析出的帧列表(Telemetry / TargetGeo 等)。"""
|
||||
...
|
||||
|
||||
def send(self, data: bytes) -> None:
|
||||
"""写入一帧已编码字节。"""
|
||||
...
|
||||
|
||||
def close(self) -> None:
|
||||
...
|
||||
|
||||
|
||||
class PodSerial:
|
||||
"""实机串口实现。pyserial 惰性导入:未装 pyserial 也能 import 本模块并用 mock。"""
|
||||
|
||||
def __init__(self, port: str, baudrate: int = 115200,
|
||||
parser: FrameParser | None = None) -> None:
|
||||
if not port:
|
||||
raise ValueError("吊舱串口未配置: pod_serial.port 为空")
|
||||
import serial # 惰性导入
|
||||
self._ser = serial.Serial(
|
||||
port=port, baudrate=baudrate,
|
||||
bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE,
|
||||
stopbits=serial.STOPBITS_ONE,
|
||||
timeout=0, write_timeout=1.0,
|
||||
)
|
||||
self._parser = parser or FrameParser()
|
||||
logger.info("[PodSerial] 打开 %s @%d 8N1", port, baudrate)
|
||||
|
||||
def poll(self) -> List[object]:
|
||||
waiting = self._ser.in_waiting
|
||||
if waiting <= 0:
|
||||
return []
|
||||
return self._parser.feed(self._ser.read(waiting))
|
||||
|
||||
def send(self, data: bytes) -> None:
|
||||
self._ser.write(data)
|
||||
|
||||
def close(self) -> None:
|
||||
try:
|
||||
self._ser.close()
|
||||
logger.info("[PodSerial] 串口已关闭")
|
||||
except Exception as exc:
|
||||
logger.warning("[PodSerial] 关闭异常: %s", exc)
|
||||
Reference in New Issue
Block a user