feat: developing.........
This commit is contained in:
@@ -0,0 +1,414 @@
|
||||
import sys
|
||||
import math
|
||||
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
|
||||
QHBoxLayout, QPushButton, QLabel, QGroupBox,
|
||||
QTextEdit, QLineEdit, QCheckBox, QStackedWidget,
|
||||
QListWidget, QListWidgetItem, QProgressBar, QComboBox, QGridLayout, QFormLayout)
|
||||
from PyQt5.QtCore import Qt, QTimer, QSize, QPointF
|
||||
from PyQt5.QtGui import QFont, QTextCursor, QPainter, QColor, QPen, QBrush, QPolygonF
|
||||
|
||||
# =================================================================
|
||||
# 🗺️ 共享组件:车间 2D 数字孪生沙盘 (高对比白底版)
|
||||
# =================================================================
|
||||
class WorkshopMapWidget(QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setMinimumSize(400, 300)
|
||||
self.setStyleSheet("background-color: #FFFFFF; border: 1px solid #D1D5DB; border-radius: 6px;")
|
||||
self.agv_x, self.agv_y, self.agv_yaw = 0.0, 0.0, 0.0
|
||||
self.scale = 35.0
|
||||
|
||||
def update_pose(self, x, y, yaw):
|
||||
self.agv_x, self.agv_y, self.agv_yaw = x, y, yaw
|
||||
self.update()
|
||||
|
||||
def paintEvent(self, event):
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHint(QPainter.Antialiasing)
|
||||
w, h = self.width(), self.height()
|
||||
cx, cy = w / 2, h / 2
|
||||
|
||||
# 浅灰网格
|
||||
painter.setPen(QPen(QColor("#E5E7EB"), 1, Qt.DashLine))
|
||||
for i in range(-20, 21):
|
||||
px = cx + i * self.scale
|
||||
painter.drawLine(int(px), 0, int(px), h)
|
||||
py = cy - i * self.scale
|
||||
painter.drawLine(0, int(py), w, int(py))
|
||||
|
||||
# 绝对坐标系原点
|
||||
painter.setPen(QPen(QColor(220, 38, 38, 200), 2))
|
||||
painter.drawLine(int(cx), int(cy), int(cx + 50), int(cy))
|
||||
painter.setPen(QPen(QColor(22, 163, 74, 200), 2))
|
||||
painter.drawLine(int(cx), int(cy), int(cx), int(cy - 50))
|
||||
|
||||
# 绘制 AGV (宝蓝色高亮)
|
||||
pixel_x = cx + (self.agv_x * self.scale)
|
||||
pixel_y = cy - (self.agv_y * self.scale)
|
||||
painter.translate(pixel_x, pixel_y)
|
||||
painter.rotate(-math.degrees(self.agv_yaw))
|
||||
|
||||
car_l, car_w = 1.2 * self.scale, 0.7 * self.scale
|
||||
painter.setBrush(QBrush(QColor(37, 99, 235, 80)))
|
||||
painter.setPen(QPen(QColor(37, 99, 235), 2))
|
||||
|
||||
poly = QPolygonF([QPointF(car_l/2, 0), QPointF(-car_l/2, -car_w/2), QPointF(-car_l/4, 0), QPointF(-car_l/2, car_w/2)])
|
||||
painter.drawPolygon(poly)
|
||||
|
||||
# =================================================================
|
||||
# 🖥️ 主控台:侧边栏 + 多页面栈架构
|
||||
# =================================================================
|
||||
class CalibrationDashboard(QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setWindowTitle("🚀 L4 AGV 自动化车间调度总控台 (v3.0 工业侧边栏版)")
|
||||
self.resize(1350, 850)
|
||||
|
||||
# 🚨 全局样式:深色侧边栏 + 明亮工作区
|
||||
self.setStyleSheet("""
|
||||
QMainWindow { background-color: #F3F4F6; color: #1F2937; font-family: 'Microsoft YaHei', sans-serif; }
|
||||
|
||||
/* 侧边栏样式 */
|
||||
QListWidget { background-color: #1E293B; color: #9CA3AF; border: none; font-size: 15px; font-weight: bold; outline: 0; padding-top: 10px;}
|
||||
QListWidget::item { padding: 15px 20px; border-bottom: 1px solid #334155; }
|
||||
QListWidget::item:hover { background-color: #334155; color: #F8FAFC; }
|
||||
QListWidget::item:selected { background-color: #2563EB; color: #FFFFFF; border-left: 4px solid #60A5FA; }
|
||||
|
||||
/* 业务面板样式 */
|
||||
QGroupBox { font-weight: bold; color: #1D4ED8; font-size: 14px; border: 1px solid #D1D5DB; border-radius: 6px; margin-top: 15px; background-color: #FFFFFF; }
|
||||
QGroupBox::title { subcontrol-origin: margin; left: 10px; padding: 0 5px; color: #1D4ED8;}
|
||||
QLabel { color: #1F2937; font-weight: bold; background: transparent; }
|
||||
QLineEdit, QComboBox { background-color: #F9FAFB; border: 1px solid #D1D5DB; padding: 6px; border-radius: 4px; font-weight: bold;}
|
||||
QPushButton { font-weight: bold; font-size: 14px; border-radius: 5px; padding: 10px; border: none; background-color: #E5E7EB; color: #1F2937;}
|
||||
QPushButton:hover { background-color: #D1D5DB; }
|
||||
QPushButton:disabled { background-color: #E5E7EB; color: #9CA3AF; }
|
||||
QCheckBox { font-weight: bold; font-size: 13px; }
|
||||
""")
|
||||
|
||||
self.sim_time = 0.0
|
||||
self.is_connected = False
|
||||
|
||||
self.init_ui()
|
||||
|
||||
# 模拟外部真值发送高频坐标
|
||||
self.sim_timer = QTimer(self)
|
||||
self.sim_timer.timeout.connect(self.simulate_ground_truth)
|
||||
|
||||
def init_ui(self):
|
||||
main_widget = QWidget()
|
||||
self.setCentralWidget(main_widget)
|
||||
main_layout = QHBoxLayout(main_widget)
|
||||
main_layout.setContentsMargins(0, 0, 0, 0)
|
||||
main_layout.setSpacing(0)
|
||||
|
||||
# ==========================================
|
||||
# 🗂️ 1. 左侧导航栏 (Sidebar)
|
||||
# ==========================================
|
||||
sidebar_container = QWidget()
|
||||
sidebar_container.setFixedWidth(240)
|
||||
sidebar_container.setStyleSheet("background-color: #1E293B;")
|
||||
sidebar_layout = QVBoxLayout(sidebar_container)
|
||||
sidebar_layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
# 侧边栏顶部 Logo
|
||||
lbl_logo = QLabel("🚀 AGV Calib Studio")
|
||||
lbl_logo.setStyleSheet("color: #60A5FA; font-size: 18px; font-weight: bold; padding: 20px 10px; background-color: #0F172A;")
|
||||
lbl_logo.setAlignment(Qt.AlignCenter)
|
||||
sidebar_layout.addWidget(lbl_logo)
|
||||
|
||||
self.nav_list = QListWidget()
|
||||
nav_items = [
|
||||
"🏠 首页: 车辆会话与画像",
|
||||
"⚙️ 阶段一: 底盘能力标定",
|
||||
"🧠 阶段二: 运控参数寻优",
|
||||
"📷 阶段三: 传感器走停拍"
|
||||
]
|
||||
for text in nav_items:
|
||||
item = QListWidgetItem(text)
|
||||
self.nav_list.addItem(item)
|
||||
|
||||
self.nav_list.currentRowChanged.connect(self.switch_page)
|
||||
sidebar_layout.addWidget(self.nav_list)
|
||||
|
||||
# ==========================================
|
||||
# 📑 2. 右侧工作区 (上: 堆叠页面, 下: 全局日志)
|
||||
# ==========================================
|
||||
right_container = QWidget()
|
||||
right_layout = QVBoxLayout(right_container)
|
||||
right_layout.setContentsMargins(15, 15, 15, 15)
|
||||
|
||||
self.stacked_widget = QStackedWidget()
|
||||
|
||||
# 实例化四个功能页面
|
||||
self.page_home = self.create_page_home()
|
||||
self.page_chassis = self.create_page_chassis()
|
||||
self.page_control = self.create_page_control()
|
||||
self.page_sensor = self.create_page_sensor()
|
||||
|
||||
self.stacked_widget.addWidget(self.page_home)
|
||||
self.stacked_widget.addWidget(self.page_chassis)
|
||||
self.stacked_widget.addWidget(self.page_control)
|
||||
self.stacked_widget.addWidget(self.page_sensor)
|
||||
|
||||
# 💻 底部全局系统日志 (无论切到哪页,日志永远可见!)
|
||||
grp_log = QGroupBox("💻 全局调度中心日志 (Session Console)")
|
||||
lyt_log = QVBoxLayout(grp_log)
|
||||
self.txt_log = QTextEdit()
|
||||
self.txt_log.setReadOnly(True)
|
||||
self.txt_log.setFont(QFont("Consolas", 11, QFont.Bold))
|
||||
self.txt_log.setStyleSheet("background-color: #F8FAFC; color: #15803D; border: 1px solid #D1D5DB; padding: 5px;")
|
||||
self.txt_log.setFixedHeight(150)
|
||||
lyt_log.addWidget(self.txt_log)
|
||||
|
||||
right_layout.addWidget(self.stacked_widget, 1)
|
||||
right_layout.addWidget(grp_log)
|
||||
|
||||
main_layout.addWidget(sidebar_container)
|
||||
main_layout.addWidget(right_container)
|
||||
|
||||
self.nav_list.setCurrentRow(0)
|
||||
self.append_log("✅ 自动化车间多页签 UI 挂载成功!")
|
||||
self.append_log("📌 请在 [首页] 完成 Session 握手,并下发 Vehicle Profile。")
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# 📄 页面 1: 首页 (对应 vehicle_profile.proto)
|
||||
# ---------------------------------------------------------
|
||||
def create_page_home(self):
|
||||
page = QWidget()
|
||||
layout = QHBoxLayout(page)
|
||||
|
||||
left_lyt = QVBoxLayout()
|
||||
grp_net = QGroupBox("🌐 1. 车端节点寻址与心跳")
|
||||
lyt_net = QFormLayout(grp_net)
|
||||
self.in_ip = QLineEdit("192.168.31.105")
|
||||
lyt_net.addRow("车端 Agent IP:", self.in_ip)
|
||||
btn_conn = QPushButton("📡 发送 HeartbeatRequest")
|
||||
btn_conn.setStyleSheet("background-color: #16A34A; color: white;")
|
||||
btn_conn.clicked.connect(self.mock_connect)
|
||||
lyt_net.addRow("", btn_conn)
|
||||
|
||||
grp_prof = QGroupBox("📋 2. 车辆画像配置 (Vehicle Profile)")
|
||||
lyt_prof = QFormLayout(grp_prof)
|
||||
lyt_prof.addRow("Session ID:", QLineEdit("SES-20260308-01"))
|
||||
lyt_prof.addRow("车辆唯一 ID:", QLineEdit("AGV-T01-Pro"))
|
||||
|
||||
cb_chassis = QComboBox()
|
||||
cb_chassis.addItems(["DIFFERENTIAL (差速)", "ACKERMANN (阿克曼)", "MULTI_STEER (多舵轮)"])
|
||||
lyt_prof.addRow("底盘构型:", cb_chassis)
|
||||
|
||||
cb_algo = QComboBox()
|
||||
cb_algo.addItems(["PID + 纯追踪 (PP)", "MPC", "LQR"])
|
||||
lyt_prof.addRow("运控算法:", cb_algo)
|
||||
|
||||
btn_recipe = QPushButton("📝 提交画像生成 Recipe 任务树")
|
||||
btn_recipe.setStyleSheet("background-color: #2563EB; color: white; padding: 15px;")
|
||||
btn_recipe.clicked.connect(lambda: self.append_log("✅ 车辆画像下发成功!标定配方 (Recipe) 已激活,请按序流转。"))
|
||||
|
||||
left_lyt.addWidget(grp_net)
|
||||
left_lyt.addWidget(grp_prof)
|
||||
left_lyt.addWidget(btn_recipe)
|
||||
left_lyt.addStretch()
|
||||
|
||||
right_lyt = QVBoxLayout()
|
||||
grp_map = QGroupBox("📡 外部真值绝对地图 (Ground Truth)")
|
||||
lyt_map = QVBoxLayout(grp_map)
|
||||
self.lbl_pose_home = QLabel("📍 绝对位姿 -> X: 0.00 | Y: 0.00 | Yaw: 0°")
|
||||
self.lbl_pose_home.setStyleSheet("color: #0369A1; font-size: 14px;")
|
||||
self.map_widget_home = WorkshopMapWidget()
|
||||
lyt_map.addWidget(self.lbl_pose_home)
|
||||
lyt_map.addWidget(self.map_widget_home)
|
||||
right_lyt.addWidget(grp_map)
|
||||
|
||||
layout.addLayout(left_lyt, 1)
|
||||
layout.addLayout(right_lyt, 1)
|
||||
return page
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# 📄 页面 2: 底盘标定 (对应 agv_calib_chassis.proto)
|
||||
# ---------------------------------------------------------
|
||||
def create_page_chassis(self):
|
||||
page = QWidget()
|
||||
layout = QHBoxLayout(page)
|
||||
|
||||
left_lyt = QVBoxLayout()
|
||||
grp_act = QGroupBox("⚙️ 动作原语长任务 (StartMotionPrimitive)")
|
||||
lyt_act = QVBoxLayout(grp_act)
|
||||
|
||||
actions = ["⬆️ 测距: 直线行驶 5 米", "🔄 测角: 原地自转 360°", "〰️ 测死区: 舵角扫频测试"]
|
||||
for act in actions:
|
||||
b = QPushButton(act)
|
||||
b.setStyleSheet("background-color: #4F46E5; color: white;")
|
||||
b.clicked.connect(lambda checked, t=act: self.append_log(f"🚀 提交底盘长任务: {t}。获得 JobID: JOB-CH-991"))
|
||||
lyt_act.addWidget(b)
|
||||
|
||||
lyt_act.addStretch()
|
||||
btn_estop = QPushButton("🛑 触发系统级急停 (Emergency Brake)")
|
||||
btn_estop.setStyleSheet("background-color: #DC2626; color: white; padding: 15px;")
|
||||
lyt_act.addWidget(btn_estop)
|
||||
left_lyt.addWidget(grp_act)
|
||||
|
||||
right_lyt = QVBoxLayout()
|
||||
grp_tel = QGroupBox("🌊 底盘 50Hz 遥测流 (StreamChassisTelemetry)")
|
||||
lyt_tel = QVBoxLayout(grp_tel)
|
||||
self.lbl_fl = QLabel("FL 模块: RPM: 0.0 | 脉冲: 0")
|
||||
self.lbl_fr = QLabel("FR 模块: RPM: 0.0 | 脉冲: 0")
|
||||
for lbl in [self.lbl_fl, self.lbl_fr]:
|
||||
lbl.setFont(QFont("Consolas", 14, QFont.Bold))
|
||||
lyt_tel.addWidget(lbl)
|
||||
|
||||
self.map_widget_chas = WorkshopMapWidget()
|
||||
lyt_tel.addWidget(self.map_widget_chas)
|
||||
right_lyt.addWidget(grp_tel)
|
||||
|
||||
layout.addLayout(left_lyt, 1)
|
||||
layout.addLayout(right_lyt, 1)
|
||||
return page
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# 📄 页面 3: 运控寻优 (对应 agv_calib_control.proto)
|
||||
# ---------------------------------------------------------
|
||||
def create_page_control(self):
|
||||
page = QWidget()
|
||||
layout = QHBoxLayout(page)
|
||||
|
||||
left_lyt = QVBoxLayout()
|
||||
grp_inj = QGroupBox("🧠 控制参数热注入 (InjectControllerParameters)")
|
||||
lyt_inj = QFormLayout(grp_inj)
|
||||
lyt_inj.addRow("横向 Kp:", QLineEdit("1.5"))
|
||||
lyt_inj.addRow("横向 Ki:", QLineEdit("0.0"))
|
||||
lyt_inj.addRow("前瞻距离 (Ld):", QLineEdit("1.2"))
|
||||
btn_inj = QPushButton("💉 热注入车端内存")
|
||||
btn_inj.setStyleSheet("background-color: #D97706; color: white;")
|
||||
btn_inj.clicked.connect(lambda: self.append_log("💉 参数已注入车端,当前版本: Ver-1.0.2"))
|
||||
lyt_inj.addRow(btn_inj)
|
||||
|
||||
grp_eval = QGroupBox("🏎️ 闭环考题评估 (StartControllerEvaluation)")
|
||||
lyt_eval = QVBoxLayout(grp_eval)
|
||||
btn_eval = QPushButton("🚗 跑 S 型测试轨迹测 RMSE")
|
||||
btn_eval.setStyleSheet("background-color: #059669; color: white;")
|
||||
btn_eval.clicked.connect(lambda: self.append_log("🚗 轨迹跟踪 Job 已创建,正在收集 ControlTelemetry..."))
|
||||
lyt_eval.addWidget(btn_eval)
|
||||
|
||||
left_lyt.addWidget(grp_inj)
|
||||
left_lyt.addWidget(grp_eval)
|
||||
left_lyt.addStretch()
|
||||
|
||||
right_lyt = QVBoxLayout()
|
||||
grp_map = QGroupBox("📉 实时闭环循迹监控")
|
||||
lyt_map = QVBoxLayout(grp_map)
|
||||
self.map_widget_ctrl = WorkshopMapWidget()
|
||||
lyt_map.addWidget(self.map_widget_ctrl)
|
||||
right_lyt.addWidget(grp_map)
|
||||
|
||||
layout.addLayout(left_lyt, 1)
|
||||
layout.addLayout(right_lyt, 1)
|
||||
return page
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# 📄 页面 4: 传感器标定 (对应 agv_calib_sensor.proto)
|
||||
# ---------------------------------------------------------
|
||||
def create_page_sensor(self):
|
||||
page = QWidget()
|
||||
layout = QVBoxLayout(page)
|
||||
|
||||
grp_cap = QGroupBox("📷 走停拍与同步锁存 (SynchronizedCapture)")
|
||||
lyt_cap = QVBoxLayout(grp_cap)
|
||||
|
||||
h_checks = QHBoxLayout()
|
||||
h_checks.addWidget(QCheckBox("前视相机 (cam_front)"))
|
||||
h_checks.addWidget(QCheckBox("机械臂相机 (arm_cam)"))
|
||||
h_checks.addWidget(QCheckBox("3D激光雷达 (lidar_top)"))
|
||||
lyt_cap.addLayout(h_checks)
|
||||
|
||||
h_btns = QHBoxLayout()
|
||||
btn_move = QPushButton("🚙 1. 移动至底盘/机械臂标定位")
|
||||
btn_move.setStyleSheet("background-color: #2563EB; color: white;")
|
||||
btn_move.clicked.connect(lambda: self.append_log("🚙 调度 Job 已发: 底盘与机械臂正在前往联合观测点..."))
|
||||
|
||||
btn_trig = QPushButton("📸 2. 发起硬同步锁存")
|
||||
btn_trig.setStyleSheet("background-color: #DB2777; color: white;")
|
||||
btn_trig.clicked.connect(lambda: self.append_log("📸 锁存成功!CaptureID: CAP-778899"))
|
||||
h_btns.addWidget(btn_move)
|
||||
h_btns.addWidget(btn_trig)
|
||||
lyt_cap.addLayout(h_btns)
|
||||
|
||||
grp_down = QGroupBox("📥 流式文件切块下载 (DownloadCapturedArtifact)")
|
||||
lyt_down = QVBoxLayout(grp_down)
|
||||
lyt_down.addWidget(QLabel("Job 状态:轮询拉取 LiDAR 压缩包..."))
|
||||
self.prog_bar = QProgressBar()
|
||||
self.prog_bar.setValue(0)
|
||||
btn_dl = QPushButton("⬇️ 根据 CaptureID 启动文件流传输")
|
||||
btn_dl.setStyleSheet("background-color: #7C3AED; color: white;")
|
||||
btn_dl.clicked.connect(self.mock_download)
|
||||
lyt_down.addWidget(self.prog_bar)
|
||||
lyt_down.addWidget(btn_dl)
|
||||
|
||||
layout.addWidget(grp_cap)
|
||||
layout.addWidget(grp_down)
|
||||
layout.addStretch()
|
||||
return page
|
||||
|
||||
# =========================================================
|
||||
# 🔄 UI 交互与动画逻辑
|
||||
# =========================================================
|
||||
def switch_page(self, index):
|
||||
self.stacked_widget.setCurrentIndex(index)
|
||||
page_names = ["[首页: 画像配置]", "[P1: 底盘运动学]", "[P2: 运控闭环]", "[P3: 传感器外参]"]
|
||||
self.append_log(f"👁️ UI 视图已切换至: {page_names[index]}")
|
||||
|
||||
def mock_connect(self):
|
||||
if not self.is_connected:
|
||||
self.append_log(f"🔄 发送 HeartbeatRequest -> {self.in_ip.text()} ...")
|
||||
self.append_log("✅ 收到 HeartbeatResponse: 车辆正常,vehicle_ready = True")
|
||||
self.is_connected = True
|
||||
self.sim_timer.start(33)
|
||||
else:
|
||||
self.append_log("⚠️ 会话连接已物理断开。")
|
||||
self.is_connected = False
|
||||
self.sim_timer.stop()
|
||||
|
||||
def mock_download(self):
|
||||
self.append_log("📥 创建 LRO 异步下载任务,后台轮询 JobStatus...")
|
||||
self.prog_bar.setValue(0)
|
||||
self.dl_timer = QTimer()
|
||||
self.dl_timer.timeout.connect(self._step_dl)
|
||||
self.dl_timer.start(50)
|
||||
|
||||
def _step_dl(self):
|
||||
val = self.prog_bar.value() + 4
|
||||
self.prog_bar.setValue(val)
|
||||
if val >= 100:
|
||||
self.dl_timer.stop()
|
||||
self.append_log("✅ JobStatus = SUCCEEDED, 数据文件安全落盘,Digest校验通过!")
|
||||
|
||||
def append_log(self, text):
|
||||
self.txt_log.append(text)
|
||||
self.txt_log.moveCursor(QTextCursor.End)
|
||||
|
||||
def simulate_ground_truth(self):
|
||||
# 假真值发生器:让小车跑一个平滑的 8 字形
|
||||
self.sim_time += 0.05
|
||||
x = 4.0 * math.sin(self.sim_time * 0.5)
|
||||
y = 2.0 * math.sin(self.sim_time)
|
||||
dx, dy = 2.0 * math.cos(self.sim_time * 0.5), 2.0 * math.cos(self.sim_time)
|
||||
yaw = math.atan2(dy, dx)
|
||||
|
||||
pose_str = f"📍 绝对位姿 -> X: {x:+.2f}m | Y: {y:+.2f}m | Yaw: {math.degrees(yaw):+05.1f}°"
|
||||
self.lbl_pose_home.setText(pose_str)
|
||||
|
||||
# 🚨 魔法:同步更新所有页面的地图实例!
|
||||
self.map_widget_home.update_pose(x, y, yaw)
|
||||
self.map_widget_chas.update_pose(x, y, yaw)
|
||||
self.map_widget_ctrl.update_pose(x, y, yaw)
|
||||
|
||||
# 模拟底盘页面的高频遥测数字
|
||||
if self.stacked_widget.currentIndex() == 1:
|
||||
rpm = abs(80 * math.cos(self.sim_time))
|
||||
self.lbl_fl.setText(f"FL 模块: RPM: {rpm:.1f} | 脉冲: {int(self.sim_time*1000)}")
|
||||
self.lbl_fr.setText(f"FR 模块: RPM: {rpm:.1f} | 脉冲: {int(self.sim_time*1000)}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QApplication(sys.argv)
|
||||
window = CalibrationDashboard()
|
||||
window.show()
|
||||
sys.exit(app.exec_())
|
||||
@@ -1,15 +0,0 @@
|
||||
# === [Goal] 行为树给网关下发的下载任务 ===
|
||||
int64 capture_timestamp_us # 刚才拿到的取件码
|
||||
string sensor_id # 例如 "cam_front"
|
||||
uint8 DATA_TYPE_IMAGE = 0
|
||||
uint8 DATA_TYPE_POINTCLOUD = 1
|
||||
uint8 data_type # 告诉网关下图片还是下点云
|
||||
string save_directory # 保存的 Ubuntu 目录,如 "/tmp/calib_data"
|
||||
---
|
||||
# === [Result] 网关下完后返回给行为树的结果 ===
|
||||
bool success
|
||||
string saved_file_path # 🚨 终极目的:返回存好的绝对路径 (如 /tmp/calib_data/cam_front_167888.png)
|
||||
string error_message
|
||||
---
|
||||
# === [Feedback] 网关实时汇报的下载进度 ===
|
||||
uint64 downloaded_bytes # 已下载的字节数 (供行为树监控是否卡死)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 148 KiB |
@@ -1,6 +0,0 @@
|
||||
string camera_id
|
||||
float64 fx
|
||||
float64 fy
|
||||
float64 cx
|
||||
float64 cy
|
||||
float64[] dist_coeffs
|
||||
@@ -1,10 +0,0 @@
|
||||
int64 hardware_timestamp_us
|
||||
float64 odom_x_m
|
||||
float64 odom_y_m
|
||||
float64 odom_yaw_rad
|
||||
float64 feedback_linear_vel_ms
|
||||
float64 feedback_angular_vel_rads
|
||||
float64 left_motor_current_amp
|
||||
float64 right_motor_current_amp
|
||||
float64 steering_motor_current_amp
|
||||
float64 cmd_steering_output
|
||||
@@ -0,0 +1,31 @@
|
||||
# =========================================================
|
||||
# 文件作用:统一错误码定义
|
||||
# 对应 proto:ErrorCode
|
||||
# 说明:
|
||||
# 1) ROS2 msg 不支持 proto 的 enum 语法
|
||||
# 2) 因此这里使用 常量 + code 字段 的方式表达
|
||||
# 3) 其他 msg / srv 中的 error_code 字段统一使用 uint16
|
||||
# =========================================================
|
||||
|
||||
uint16 ERROR_CODE_UNSPECIFIED=0
|
||||
uint16 OK=1
|
||||
uint16 INVALID_ARGUMENT=2
|
||||
uint16 INVALID_STATE=3
|
||||
uint16 VEHICLE_BUSY=4
|
||||
uint16 NOT_READY=5
|
||||
uint16 TIMEOUT=6
|
||||
uint16 NETWORK_LOSS=7
|
||||
uint16 SAFETY_TRIGGERED=8
|
||||
uint16 HARDWARE_FAULT=9
|
||||
uint16 FILE_NOT_FOUND=10
|
||||
uint16 CHECKSUM_MISMATCH=11
|
||||
uint16 INTERNAL_ERROR=12
|
||||
uint16 UNSUPPORTED_CAPABILITY=13
|
||||
uint16 RESOURCE_LOCKED=14
|
||||
uint16 MANUAL_CONFIRM_REQUIRED=15
|
||||
uint16 APPROVAL_REQUIRED=16
|
||||
uint16 VALIDATION_FAILED=17
|
||||
uint16 ROLLBACK_REQUIRED=18
|
||||
uint16 DATA_QUALITY_INSUFFICIENT=19
|
||||
|
||||
uint16 code # 当前错误码值
|
||||
@@ -0,0 +1,8 @@
|
||||
# =========================================================
|
||||
# 文件作用:文件摘要
|
||||
# 对应 proto:FileDigest
|
||||
# 作用:用于参数包、URDF、数据文件校验
|
||||
# =========================================================
|
||||
|
||||
string checksum_type # 摘要算法,例如 sha256
|
||||
string checksum_value # 摘要值
|
||||
@@ -0,0 +1,11 @@
|
||||
# =========================================================
|
||||
# 文件作用:文件引用
|
||||
# 对应 proto:FileReference
|
||||
# 作用:用于报告、参数包、数据集、日志包等产物追溯
|
||||
# =========================================================
|
||||
|
||||
string file_name # 文件名
|
||||
string file_uri # 文件路径 / URI
|
||||
int64 size_bytes # 文件大小(字节)
|
||||
string description # 文件说明
|
||||
FileDigest digest # 文件摘要
|
||||
@@ -1,13 +0,0 @@
|
||||
int64 hardware_timestamp_us
|
||||
int64 encoder_ticks_fl
|
||||
int64 encoder_ticks_fr
|
||||
int64 encoder_ticks_rl
|
||||
int64 encoder_ticks_rr
|
||||
float64 actual_steer_angle_front_deg
|
||||
float64 actual_steer_angle_rear_deg
|
||||
float64 current_fl_amp
|
||||
float64 current_fr_amp
|
||||
float64 current_rl_amp
|
||||
float64 current_rr_amp
|
||||
float64 current_steer_front_amp
|
||||
uint32 driver_error_code
|
||||
@@ -0,0 +1,12 @@
|
||||
# =========================================================
|
||||
# 文件作用:长任务受理响应
|
||||
# 对应 proto:JobAccepted
|
||||
# 作用:耗时任务先返回 job_id,后续再查询状态
|
||||
# 发送方:服务端
|
||||
# 接收方:Ubuntu 车间电脑
|
||||
# =========================================================
|
||||
|
||||
bool accepted # 是否受理成功
|
||||
uint16 error_code # 未受理时的错误码,取值参考 ErrorCode.msg
|
||||
string message # 说明
|
||||
string job_id # 长任务 ID
|
||||
@@ -0,0 +1,10 @@
|
||||
# =========================================================
|
||||
# 文件作用:长任务查询请求
|
||||
# 对应 proto:JobQuery
|
||||
# 作用:通过 job_id 查询执行状态
|
||||
# 发送方:Ubuntu 车间电脑
|
||||
# 接收方:Linux 服务 或 Windows 车端代理
|
||||
# =========================================================
|
||||
|
||||
RequestHeader header # 请求头
|
||||
string job_id # 任务 ID
|
||||
@@ -0,0 +1,19 @@
|
||||
# =========================================================
|
||||
# 文件作用:长任务状态定义
|
||||
# 对应 proto:JobState
|
||||
# 说明:
|
||||
# 1) ROS2 msg 不支持 proto 的 enum 语法
|
||||
# 2) 因此这里使用 常量 + state 字段 的方式表达
|
||||
# =========================================================
|
||||
|
||||
uint8 JOB_STATE_UNSPECIFIED=0
|
||||
uint8 PENDING=1
|
||||
uint8 RUNNING=2
|
||||
uint8 WAITING_MANUAL=3
|
||||
uint8 WAITING_APPROVAL=4
|
||||
uint8 SUCCEEDED=5
|
||||
uint8 FAILED=6
|
||||
uint8 CANCELED=7
|
||||
uint8 ROLLED_BACK=8
|
||||
|
||||
uint8 state # 当前任务状态值
|
||||
@@ -0,0 +1,15 @@
|
||||
# =========================================================
|
||||
# 文件作用:长任务状态响应
|
||||
# 对应 proto:JobStatus
|
||||
# 作用:返回任务执行状态、进度、错误信息
|
||||
# 发送方:服务端
|
||||
# 接收方:Ubuntu 车间电脑
|
||||
# =========================================================
|
||||
|
||||
string job_id # 任务 ID
|
||||
uint8 state # 当前状态,取值参考 JobState.msg
|
||||
float64 progress # 进度,建议范围 0.0 ~ 1.0
|
||||
uint16 error_code # 当前错误码,取值参考 ErrorCode.msg
|
||||
string message # 状态说明
|
||||
int64 server_timestamp_us # 服务端时间戳
|
||||
bool safe_to_retry # 是否适合自动重试
|
||||
@@ -0,0 +1,8 @@
|
||||
# =========================================================
|
||||
# 文件作用:键值对
|
||||
# 对应 proto:KeyValuePair
|
||||
# 作用:用于扩展元数据,避免每次新增少量字段都改协议
|
||||
# =========================================================
|
||||
|
||||
string key # 键
|
||||
string value # 值
|
||||
@@ -0,0 +1,16 @@
|
||||
# =========================================================
|
||||
# 文件作用:六自由度位姿
|
||||
# 对应 proto:Pose3D
|
||||
# 作用:
|
||||
# 1) 用于表达 base_link、传感器、外部定位坐标系之间的位姿关系
|
||||
# 2) 平移单位为米
|
||||
# 3) 旋转单位为弧度
|
||||
# 4) 采用 xyz + rpy 表达
|
||||
# =========================================================
|
||||
|
||||
float64 x_m # X 方向平移(m)
|
||||
float64 y_m # Y 方向平移(m)
|
||||
float64 z_m # Z 方向平移(m)
|
||||
float64 roll_rad # 绕 X 轴旋转(rad)
|
||||
float64 pitch_rad # 绕 Y 轴旋转(rad)
|
||||
float64 yaw_rad # 绕 Z 轴旋转(rad)
|
||||
@@ -0,0 +1,15 @@
|
||||
# =========================================================
|
||||
# 文件作用:通用请求头
|
||||
# 对应 proto:RequestHeader
|
||||
# 作用:带齐一次会话、任务、车辆、请求追踪信息
|
||||
# 发送方:通常为 Ubuntu 车间电脑
|
||||
# 接收方:Linux 内部服务 或 Windows 车端代理
|
||||
# =========================================================
|
||||
|
||||
string session_id # 本次整车标定会话 ID
|
||||
string task_id # 当前任务 ID / 阶段 ID
|
||||
string vehicle_id # 车辆 ID
|
||||
string request_id # 本次请求唯一 ID
|
||||
int64 client_send_timestamp_us # 请求发送时间戳(微秒)
|
||||
string operator_id # 操作员工号 / 工位号
|
||||
string workshop_host # Ubuntu 车间电脑主机名
|
||||
@@ -1,8 +0,0 @@
|
||||
string source_frame
|
||||
string target_frame
|
||||
float64 trans_x_mm
|
||||
float64 trans_y_mm
|
||||
float64 trans_z_mm
|
||||
float64 roll_deg
|
||||
float64 pitch_deg
|
||||
float64 yaw_deg
|
||||
@@ -0,0 +1,14 @@
|
||||
# =========================================================
|
||||
# 文件作用:通用短响应
|
||||
# 对应 proto:StandardResponse
|
||||
# 作用:用于同步服务调用的标准响应
|
||||
# 发送方:服务端
|
||||
# 接收方:调用方
|
||||
# 说明:
|
||||
# 1) error_code 使用 uint16
|
||||
# 2) 取值参考 ErrorCode.msg 中定义的常量
|
||||
# =========================================================
|
||||
|
||||
bool success # 是否成功
|
||||
uint16 error_code # 错误码,取值参考 ErrorCode.msg
|
||||
string message # 说明文字
|
||||
@@ -1,5 +0,0 @@
|
||||
float64 x_m
|
||||
float64 y_m
|
||||
float64 yaw_rad
|
||||
float64 target_speed_ms
|
||||
float64 curvature
|
||||
@@ -0,0 +1,9 @@
|
||||
# =========================================================
|
||||
# 文件作用:三维向量
|
||||
# 对应 proto:Vector3D
|
||||
# 作用:用于表达三轴偏置、平移量、加速度等三维数据
|
||||
# =========================================================
|
||||
|
||||
float64 x # X 轴分量
|
||||
float64 y # Y 轴分量
|
||||
float64 z # Z 轴分量
|
||||
@@ -0,0 +1,949 @@
|
||||
# 自动化标定车间 Proto 协同工作说明
|
||||
|
||||
[](https://developers.google.com/protocol-buffers)
|
||||
[](https://ubuntu.com)
|
||||
[](./)
|
||||
|
||||
> **核心定位**:面向自动化标定车间的分层协议设计,实现车间总控、专业域服务与车端代理的协同工作。
|
||||
|
||||
---
|
||||
|
||||
## 📋 目录
|
||||
|
||||
- [1. 项目目标](#1-项目目标)
|
||||
- [2. 七个 Proto 文件的职责划分](#2-七个-proto-文件的职责划分)
|
||||
- [2.1 calibration_common.proto](#21-calibration_commonproto)
|
||||
- [2.2 vehicle_profile.proto](#22-vehicle_profileproto)
|
||||
- [2.3 external_localization.proto](#23-external_localizationproto)
|
||||
- [2.4 chassis_calibration.proto](#24-chassis_calibrationproto)
|
||||
- [2.5 sensor_calibration.proto](#25-sensor_calibrationproto)
|
||||
- [2.6 control_calibration.proto](#26-control_calibrationproto)
|
||||
- [2.7 workshop_orchestration.proto](#27-workshop_orchestrationproto)
|
||||
- [3. 七个 Proto 的依赖关系](#3-七个-proto-的依赖关系)
|
||||
- [4. 协同架构图](#4-协同架构图)
|
||||
- [5. 自动化标定车间的完整逻辑流程](#5-自动化标定车间的完整逻辑流程)
|
||||
- [6. 为什么一定要拆成这 7 个 Proto](#6-为什么一定要拆成这-7-个-proto)
|
||||
- [7. 从通信形态角度看,这 7 个 Proto 如何使用](#7-从通信形态角度看这-7-个-proto-如何使用)
|
||||
- [8. 七个 Proto 在一次完整会话中的协同时序](#8-七个-proto-在一次完整会话中的协同时序)
|
||||
- [9. 七个 Proto 的工程分层建议](#9-七个-proto-的工程分层建议)
|
||||
- [10. 当前这套 Proto 的核心协同原则](#10-当前这套-proto-的核心协同原则)
|
||||
- [11. 落地实现时还必须注意的点](#11-落地实现时还必须注意的点)
|
||||
- [12. 推荐的理解方式](#12-推荐的理解方式)
|
||||
- [13. 总结](#13-总结)
|
||||
- [14. 后续建议](#14-后续建议)
|
||||
|
||||
---
|
||||
|
||||
## 1. 项目目标
|
||||
|
||||
本项目面向**自动化标定车间**场景,目标是通过一组分层设计的 `.proto` 协议文件,定义:
|
||||
|
||||
- 车间上位机(Ubuntu / Linux)内部各服务之间的通信接口
|
||||
- 车间上位机与车端执行代理(Windows)之间的通信接口
|
||||
- 自动化调度、车辆建模、外部定位、底盘标定、传感器标定、运控参数标定等模块之间的职责边界
|
||||
- 整车自动化标定流程的统一任务组织方式、状态表达方式、结果归档方式
|
||||
|
||||
这一套协议的核心设计思想不是"把所有逻辑塞到一个服务里",而是:
|
||||
|
||||
1. **车间总控负责流程编排**
|
||||
2. **各标定域服务负责专业能力**
|
||||
3. **车端代理只负责动作执行、数据采集、参数落盘**
|
||||
4. **所有流程都围绕统一的会话、任务、车辆画像、作业状态进行协同**
|
||||
|
||||
---
|
||||
|
||||
## 2. 七个 Proto 文件的职责划分
|
||||
|
||||
本工程共包含 **7** 个核心 `.proto` 文件,它们共同构成自动化标定车间的通信协议层。
|
||||
|
||||
---
|
||||
|
||||
### 2.1 calibration_common.proto
|
||||
|
||||
**作用:公共基础协议定义**
|
||||
|
||||
这是整个系统的底层公共协议文件,所有其他 proto 都会依赖它。
|
||||
|
||||
**主要定义内容:**
|
||||
|
||||
- 通用请求头 `RequestHeader`
|
||||
- 空消息、标准响应、错误码
|
||||
- 长任务状态表达 `JobAccepted` / `JobQuery` / `JobStatus`
|
||||
- 心跳请求与响应 `HeartbeatRequest` / `HeartbeatResponse`
|
||||
- 文件摘要 `FileDigest`
|
||||
- 统一错误码 `ErrorCode`
|
||||
- 统一任务状态 `JobState`
|
||||
|
||||
**解决的共性问题:**
|
||||
|
||||
- 一次请求是谁发起的
|
||||
- 属于哪个标定会话
|
||||
- 当前针对哪台车
|
||||
- 这个任务现在处于什么状态
|
||||
- 返回的是不是成功
|
||||
- 错误是否可重试
|
||||
- 文件、参数包如何做摘要校验
|
||||
|
||||
> **一句话理解**:`calibration_common.proto` 是整个自动化标定车间协议体系的"地基"。
|
||||
|
||||
---
|
||||
|
||||
### 2.2 vehicle_profile.proto
|
||||
|
||||
**作用:车辆画像与能力建模**
|
||||
|
||||
这个文件负责表达"待标定对象到底是什么"。
|
||||
|
||||
**主要定义内容:**
|
||||
|
||||
- 车辆底盘类型
|
||||
- 是否带机械臂
|
||||
- 传感器配置类型
|
||||
- 控制器算法配置
|
||||
- 车辆基础几何与命名信息
|
||||
- URDF 导入关联信息
|
||||
- 车辆能力声明
|
||||
|
||||
**解决的对象建模问题:**
|
||||
|
||||
- 当前进站的是哪种车
|
||||
- 是阿克曼、差速、单舵轮还是多舵轮
|
||||
- 车上有哪些传感器
|
||||
- 机械臂有没有
|
||||
- 需要做哪些标定任务
|
||||
- 底盘标定该走哪套动作原语
|
||||
- 运控参数标定应该面向哪些控制器
|
||||
|
||||
> **一句话理解**:`vehicle_profile.proto` 负责回答"这台车是谁、长什么样、具备什么能力"。
|
||||
|
||||
---
|
||||
|
||||
### 2.3 external_localization.proto
|
||||
|
||||
**作用:外部定位能力与测量结果接口**
|
||||
|
||||
这个文件负责定义自动化车间中"外部定位系统"相关的协议。
|
||||
|
||||
这里的外部定位通常不是车上自带定位,而是车间里的外部测量系统,例如:
|
||||
|
||||
- 动捕系统
|
||||
- 激光跟踪仪
|
||||
- 高精度全站仪
|
||||
- 外部相机阵列
|
||||
- 标定工装测量系统
|
||||
|
||||
**主要职责:**
|
||||
|
||||
- 请求外部定位系统开始测量
|
||||
- 获取目标位姿 / 轨迹
|
||||
- 获取参考基准坐标
|
||||
- 记录测量结果质量
|
||||
- 提供给底盘、传感器、运控标定使用的真值参考
|
||||
|
||||
它在整个车间流程中是一个非常关键的"**真值来源模块**"。
|
||||
|
||||
> **一句话理解**:`external_localization.proto` 负责给整个自动化标定车间提供高精度外部参考。
|
||||
|
||||
---
|
||||
|
||||
### 2.4 chassis_calibration.proto
|
||||
|
||||
**作用:底盘标定执行代理协议**
|
||||
|
||||
这个文件主要描述**车间上位机 → Windows 车端代理**之间,底盘标定相关的执行接口。
|
||||
|
||||
**主要内容:**
|
||||
|
||||
- 底盘工作模式切换
|
||||
- 车端底盘能力查询
|
||||
- 动作原语执行请求
|
||||
- 底盘遥测流
|
||||
- 底盘参数写入
|
||||
- 当前生效参数查询
|
||||
- 紧急刹停
|
||||
|
||||
**典型动作原语:**
|
||||
|
||||
- 直线行驶
|
||||
- 圆弧行驶
|
||||
- 原地旋转
|
||||
- 舵角扫动
|
||||
|
||||
**典型遥测:**
|
||||
|
||||
- 里程计
|
||||
- 轮速
|
||||
- 编码器
|
||||
- 舵角
|
||||
- 驱动器状态
|
||||
- 急停状态
|
||||
|
||||
这个文件本质上不是"求解底盘参数",而是定义:
|
||||
|
||||
> Linux 上位机如何命令车端去做底盘动作,并拿回原始数据,再由 Linux 进行参数求解。
|
||||
|
||||
> **一句话理解**:`chassis_calibration.proto` 是底盘标定的"执行与数据回传协议"。
|
||||
|
||||
---
|
||||
|
||||
### 2.5 sensor_calibration.proto
|
||||
|
||||
**作用:传感器标定任务与结果接口**
|
||||
|
||||
这个文件负责定义传感器标定域相关协议。
|
||||
|
||||
**覆盖范围:**
|
||||
|
||||
- 下视相机
|
||||
- 前视相机
|
||||
- 机械臂相机(眼在手上 / 眼在手外)
|
||||
- 2D 激光雷达
|
||||
- 3D 激光雷达
|
||||
- IMU
|
||||
|
||||
**典型标定内容:**
|
||||
|
||||
- 相机内参
|
||||
- IMU 内参(如 `accel_bias` / `gyro_bias`)
|
||||
- 传感器外参(相对于 `base_link`)
|
||||
- 标定数据采集任务
|
||||
- 标定结果质量评估
|
||||
- 标定结果写入与查询
|
||||
|
||||
这个文件通常会与 `vehicle_profile.proto`、`external_localization.proto`、`workshop_orchestration.proto` 有很强协作关系。
|
||||
|
||||
因为是否要做某种传感器标定、该使用哪种工装、是否需要机械臂配合、外部真值从哪里来,都取决于车辆画像和整体流程编排。
|
||||
|
||||
> **一句话理解**:`sensor_calibration.proto` 负责定义传感器标定的任务、数据和结果。
|
||||
|
||||
---
|
||||
|
||||
### 2.6 control_calibration.proto
|
||||
|
||||
**作用:运控参数调优标定执行代理协议**
|
||||
|
||||
这个文件负责定义车辆控制参数调优相关接口。
|
||||
|
||||
这里的"运控参数标定"一般不是底盘几何标定,而是:
|
||||
|
||||
- 横向控制器参数标定
|
||||
- 纵向控制器参数标定
|
||||
|
||||
**典型控制算法:**
|
||||
|
||||
- PID
|
||||
- MPC
|
||||
- LQR
|
||||
- PP(Pure Pursuit)
|
||||
|
||||
并且要明确拆分为:
|
||||
|
||||
- **横向控制器**
|
||||
- **纵向控制器**
|
||||
|
||||
因为这两类控制目标不同,参数含义不同,评估指标也不同。
|
||||
|
||||
**主要功能:**
|
||||
|
||||
- 控制工作模式切换
|
||||
- 参数热加载
|
||||
- 控制评估任务启动
|
||||
- 遥测流回传
|
||||
- 参数固化
|
||||
- 当前参数查询
|
||||
- 紧急停车
|
||||
|
||||
**常见评估任务:**
|
||||
|
||||
- 轨迹跟踪任务
|
||||
- 速度阶跃任务
|
||||
|
||||
**常见回传指标:**
|
||||
|
||||
- 横向误差
|
||||
- 航向误差
|
||||
- 速度误差
|
||||
- 转向输出
|
||||
- 油门 / 驱动输出
|
||||
- 饱和状态
|
||||
|
||||
> **一句话理解**:`control_calibration.proto` 负责让 Linux 调参服务可以驱动车端执行控制测试并闭环评估。
|
||||
|
||||
---
|
||||
|
||||
### 2.7 workshop_orchestration.proto
|
||||
|
||||
**作用:车间总控编排协议**
|
||||
|
||||
这是整个自动化标定车间里最核心的"总控协议"。
|
||||
|
||||
它不是具体做底盘求解,也不是具体做传感器求解,而是负责编排整条流程:
|
||||
|
||||
- 创建整车标定会话
|
||||
- 加载车辆画像
|
||||
- 校验前置条件
|
||||
- 决定本次需要执行哪些任务
|
||||
- 按阶段推进流程
|
||||
- 跟踪每个子任务状态
|
||||
- 统一处理失败、重试、跳过、中止
|
||||
- 归档全部标定结果
|
||||
- 输出最终标定报告
|
||||
|
||||
它会与其余 6 个 proto 对应的服务产生协作关系。
|
||||
|
||||
你可以把它理解成:
|
||||
|
||||
> 自动化标定车间的"总导演"和"状态机主控器"
|
||||
|
||||
> **一句话理解**:`workshop_orchestration.proto` 决定"先做什么、后做什么、谁调用谁、失败了怎么办"。
|
||||
|
||||
---
|
||||
|
||||
## 3. 七个 Proto 的依赖关系
|
||||
|
||||
整体依赖关系可以概括为:
|
||||
|
||||
| Proto 文件 | 被依赖方 | 作用 |
|
||||
|:-----------|:---------|:-----|
|
||||
| `calibration_common.proto` | 所有其他 proto | 公共基础能力 |
|
||||
| `vehicle_profile.proto` | orchestration、底盘、传感器、运控标定 | 车辆建模依据 |
|
||||
| `external_localization.proto` | 底盘、传感器、运控标定 | 外部真值/参考测量 |
|
||||
| `chassis_calibration.proto` | `workshop_orchestration.proto` | 被总控调度 |
|
||||
| `sensor_calibration.proto` | `workshop_orchestration.proto` | 被总控调度 |
|
||||
| `control_calibration.proto` | `workshop_orchestration.proto` | 被总控调度 |
|
||||
| `workshop_orchestration.proto` | - | 作为总控层,组织全部流程 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 协同架构图
|
||||
|
||||
下面是一个推荐的逻辑协同图:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[工作人员在 Ubuntu 车间电脑配置车辆信息] --> B[vehicle_profile.proto
|
||||
生成车辆画像]
|
||||
B --> C[workshop_orchestration.proto
|
||||
创建整车标定会话]
|
||||
C --> D[前置检查 / 能力校验 / 安全检查]
|
||||
|
||||
D --> E[external_localization.proto
|
||||
初始化外部定位系统]
|
||||
E --> F[chassis_calibration.proto
|
||||
执行底盘动作与回传遥测]
|
||||
E --> G[sensor_calibration.proto
|
||||
执行传感器采集与求解]
|
||||
E --> H[control_calibration.proto
|
||||
执行轨迹/速度测试并评估]
|
||||
|
||||
F --> C
|
||||
G --> C
|
||||
H --> C
|
||||
|
||||
C --> I[统一汇总结果]
|
||||
I --> J[参数写入 / 版本归档 / 生成报告]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 自动化标定车间的完整逻辑流程
|
||||
|
||||
下面从工程落地角度梳理一遍完整的自动化流程。
|
||||
|
||||
---
|
||||
|
||||
### 阶段 1:车辆入站与基础配置
|
||||
|
||||
工作人员在 Ubuntu 车间电脑上完成基础配置:
|
||||
|
||||
- 输入车辆 ID
|
||||
- 选择底盘类型
|
||||
- 选择是否带机械臂
|
||||
- 选择搭载的传感器类型
|
||||
- 选择控制器类型(横向 / 纵向)
|
||||
- 导入 URDF(可选但强烈建议)
|
||||
- 选择本次需要执行的标定项目
|
||||
|
||||
此时由 `vehicle_profile.proto` 完成车辆画像建模。
|
||||
|
||||
**输出结果:**
|
||||
|
||||
- 一个完整的车辆画像对象
|
||||
- 当前标定会话的基础上下文
|
||||
|
||||
---
|
||||
|
||||
### 阶段 2:创建整车标定会话
|
||||
|
||||
由 `workshop_orchestration.proto` 创建一轮完整的标定会话。
|
||||
|
||||
这里通常会生成:
|
||||
|
||||
- `session_id`
|
||||
- 标定计划
|
||||
- 子任务列表
|
||||
- 初始状态机节点
|
||||
|
||||
同时将统一的 `RequestHeader` 注入后续所有子任务请求。
|
||||
|
||||
**输出结果:**
|
||||
|
||||
- 一次完整的整车标定上下文
|
||||
- 后续所有模块共享同一会话 ID
|
||||
|
||||
---
|
||||
|
||||
### 阶段 3:前置检查
|
||||
|
||||
总控模块调用各子服务检查前置条件:
|
||||
|
||||
- 车辆是否在线
|
||||
- 车端代理是否在线
|
||||
- 外部定位系统是否在线
|
||||
- 传感器是否可通信
|
||||
- 驱动器是否健康
|
||||
- 急停状态是否释放
|
||||
- 当前车辆能力是否满足目标任务
|
||||
|
||||
这里会大量使用:
|
||||
|
||||
- `Heartbeat`
|
||||
- `StandardResponse`
|
||||
- `JobStatus`
|
||||
- 车辆能力查询
|
||||
- 外部定位能力查询
|
||||
|
||||
若前置检查失败,则流程不能继续。
|
||||
|
||||
---
|
||||
|
||||
### 阶段 4:外部定位系统建立参考
|
||||
|
||||
由 `external_localization.proto` 驱动外部定位系统建立参考坐标框架。
|
||||
|
||||
例如:
|
||||
|
||||
- 建立车间世界坐标系
|
||||
- 识别待标定车辆
|
||||
- 获取基准工装位姿
|
||||
- 连续输出外部真值位姿
|
||||
- 检查测量质量是否达标
|
||||
|
||||
这一阶段输出的是后续标定需要依赖的"真值"或"参考值"。
|
||||
|
||||
---
|
||||
|
||||
### 阶段 5:底盘标定
|
||||
|
||||
由 `workshop_orchestration.proto` 调度 `chassis_calibration.proto` 所对应的服务进行底盘标定。
|
||||
|
||||
**基本流程:**
|
||||
|
||||
1. 切换到底盘标定模式
|
||||
2. 查询底盘能力
|
||||
3. 按底盘类型下发动作原语
|
||||
4. 车端执行动作
|
||||
5. 车端持续回传遥测
|
||||
6. Linux 求解底盘参数
|
||||
7. 参数写入车端
|
||||
8. 查询写入后的生效结果
|
||||
|
||||
**不同底盘类型的动作组合:**
|
||||
|
||||
| 底盘类型 | 动作组合 |
|
||||
|:---------|:---------|
|
||||
| 阿克曼 | 直线、圆弧、舵角扫动 |
|
||||
| 差速 | 直线、原地旋转、圆弧 |
|
||||
| 单舵轮 | 直线、圆弧、舵角扫动 |
|
||||
| 多舵轮 | 直线、旋转、单模块扫动或联动测试 |
|
||||
|
||||
**底盘标定解决的问题:**
|
||||
|
||||
- 直线跑偏
|
||||
- 曲率误差
|
||||
- 轮径补偿
|
||||
- 轴距/轮距有效值
|
||||
- 编码器比例
|
||||
- 舵角零偏
|
||||
- 模块安装误差
|
||||
|
||||
---
|
||||
|
||||
### 阶段 6:传感器标定
|
||||
|
||||
由 `workshop_orchestration.proto` 调度 `sensor_calibration.proto` 进行传感器标定。
|
||||
|
||||
**常见流程:**
|
||||
|
||||
1. 根据车辆画像,识别本车有哪些传感器需要标定
|
||||
2. 检查工装和采集条件
|
||||
3. 触发采集任务
|
||||
4. 回传采集状态和原始数据引用
|
||||
5. Linux 侧完成求解
|
||||
6. 输出标定参数
|
||||
7. 参数写入配置系统
|
||||
8. 校验结果质量是否达标
|
||||
|
||||
**两大类参数:**
|
||||
|
||||
#### 6.1 内参
|
||||
|
||||
例如:
|
||||
|
||||
- 相机内参矩阵
|
||||
- 畸变参数
|
||||
- IMU 的 `accel_bias`
|
||||
- IMU 的 `gyro_bias`
|
||||
|
||||
#### 6.2 外参
|
||||
|
||||
例如:
|
||||
|
||||
- 各传感器相对 `base_link` 的位姿
|
||||
- 手眼关系
|
||||
- 机械臂末端与相机的位姿关系
|
||||
- 外部定位参考坐标系到车体系的关系
|
||||
|
||||
---
|
||||
|
||||
### 阶段 7:运控参数标定
|
||||
|
||||
由 `workshop_orchestration.proto` 调度 `control_calibration.proto` 进行运控参数调优。
|
||||
|
||||
> **注意**:控制器必须拆成横向与纵向两大类来表达。
|
||||
|
||||
#### 横向控制器
|
||||
|
||||
例如:
|
||||
|
||||
- PID(横向误差 / 航向误差)
|
||||
- MPC
|
||||
- LQR
|
||||
- Pure Pursuit
|
||||
|
||||
#### 纵向控制器
|
||||
|
||||
例如:
|
||||
|
||||
- PID(速度环)
|
||||
- MPC 速度规划控制
|
||||
- 其他速度控制算法
|
||||
|
||||
**典型流程:**
|
||||
|
||||
1. 切换到调参模式
|
||||
2. 下发一版候选参数
|
||||
3. 启动车端评估任务
|
||||
4. 执行轨迹跟踪或速度阶跃测试
|
||||
5. 回传遥测数据
|
||||
6. Linux 计算性能指标
|
||||
7. 决定继续迭代还是固化参数
|
||||
8. 固化最终参数版本
|
||||
|
||||
**评估指标:**
|
||||
|
||||
- 横向误差
|
||||
- 航向误差
|
||||
- 速度误差
|
||||
- 超调量
|
||||
- 稳态误差
|
||||
- 控制量抖动
|
||||
- 饱和比例
|
||||
- 收敛时间
|
||||
|
||||
---
|
||||
|
||||
### 阶段 8:统一收敛判定与结果归档
|
||||
|
||||
当底盘标定、传感器标定、运控标定都完成后,由总控模块统一判定:
|
||||
|
||||
- 是否全部成功
|
||||
- 是否存在部分成功
|
||||
- 是否允许跳过某项后完成整体会话
|
||||
- 是否需要人工复核
|
||||
- 是否需要重试某一子项
|
||||
|
||||
然后进行:
|
||||
|
||||
- 参数版本归档
|
||||
- 文件摘要记录
|
||||
- 标定结果持久化
|
||||
- 会话状态闭环
|
||||
- 生成最终报告
|
||||
|
||||
---
|
||||
|
||||
## 6. 为什么一定要拆成这 7 个 Proto
|
||||
|
||||
从自动化标定车间落地的角度,这样拆分有几个核心优点。
|
||||
|
||||
---
|
||||
|
||||
### 6.1 降低耦合
|
||||
|
||||
如果把所有内容塞到一个 proto 或一个服务里,会导致:
|
||||
|
||||
- 车辆建模与执行耦合
|
||||
- 专业算法与流程编排耦合
|
||||
- 车端执行与求解逻辑耦合
|
||||
- 协议难维护
|
||||
- 后续扩展困难
|
||||
|
||||
拆分后,每个 proto 只负责一个明确领域。
|
||||
|
||||
---
|
||||
|
||||
### 6.2 便于多人协作开发
|
||||
|
||||
你这个项目本身就已经是多人分工场景:
|
||||
|
||||
- 你负责自动化车间运行逻辑
|
||||
- 别人负责外部定位
|
||||
- 别人负责底盘标定算法
|
||||
- 别人负责运控调参算法
|
||||
- 别人负责传感器标定算法
|
||||
|
||||
在这种情况下,proto 分层能让每个人在清晰边界内开发。
|
||||
|
||||
---
|
||||
|
||||
### 6.3 便于后续接 ROS2
|
||||
|
||||
你后面明确希望把 proto 内容进一步映射为:
|
||||
|
||||
- ROS2 msg
|
||||
- ROS2 srv
|
||||
- ROS2 action
|
||||
|
||||
如果 proto 设计本身就已经分层清晰,那么后续转换到 ROS2 的结构也会更自然:
|
||||
|
||||
- 公共消息 → 基础 msg
|
||||
- 短请求/响应 → srv
|
||||
- 长任务 → action
|
||||
- 流式遥测 → topic
|
||||
|
||||
---
|
||||
|
||||
### 6.4 更符合真实车间运行逻辑
|
||||
|
||||
真实车间不是"一个函数跑到底",而是:
|
||||
|
||||
- 一个总控状态机
|
||||
- 多个专业子服务
|
||||
- 一个或多个车端执行代理
|
||||
- 多个外部设备
|
||||
- 多阶段流程推进
|
||||
- 随时可能失败、重试、中断、恢复
|
||||
|
||||
所以协议设计也必须体现真实的系统边界。
|
||||
|
||||
---
|
||||
|
||||
## 7. 从通信形态角度看,这 7 个 Proto 如何使用
|
||||
|
||||
自动化标定车间里并不是所有消息都属于同一种通信形式。
|
||||
|
||||
---
|
||||
|
||||
### 7.1 适合短同步调用的内容
|
||||
|
||||
典型如:
|
||||
|
||||
- 工作模式切换
|
||||
- 能力查询
|
||||
- 当前参数查询
|
||||
- 心跳
|
||||
- 参数写入确认
|
||||
|
||||
这类内容通常是**请求-响应式**的。
|
||||
|
||||
---
|
||||
|
||||
### 7.2 适合长任务异步处理的内容
|
||||
|
||||
典型如:
|
||||
|
||||
- 启动底盘测试任务
|
||||
- 启动传感器采集任务
|
||||
- 启动控制评估任务
|
||||
- 启动外部定位测量任务
|
||||
|
||||
这些任务通常不会立刻完成,因此需要:
|
||||
|
||||
- 先返回 `JobAccepted`
|
||||
- 后续通过 `JobQuery` / `JobStatus` 查询
|
||||
- 或进一步映射为 action
|
||||
|
||||
---
|
||||
|
||||
### 7.3 适合流式数据输出的内容
|
||||
|
||||
典型如:
|
||||
|
||||
- 底盘遥测
|
||||
- 控制遥测
|
||||
- 外部定位连续位姿流
|
||||
- 传感器采集状态流
|
||||
|
||||
这类数据天然是持续输出的,更适合 topic / stream。
|
||||
|
||||
---
|
||||
|
||||
## 8. 七个 Proto 在一次完整会话中的协同时序
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## 9. 七个 Proto 的工程分层建议
|
||||
|
||||
为了后续工程实现更清晰,建议代码目录也按这 7 个 proto 的职责进行分层。
|
||||
|
||||
**参考结构:**
|
||||
|
||||
```text
|
||||
proto/
|
||||
├── calibration_common.proto
|
||||
├── vehicle_profile.proto
|
||||
├── external_localization.proto
|
||||
├── chassis_calibration.proto
|
||||
├── sensor_calibration.proto
|
||||
├── control_calibration.proto
|
||||
└── workshop_orchestration.proto
|
||||
|
||||
services/
|
||||
├── workshop_orchestrator/
|
||||
├── vehicle_profile_manager/
|
||||
├── external_localization_service/
|
||||
├── chassis_calibration_service/
|
||||
├── sensor_calibration_service/
|
||||
├── control_calibration_service/
|
||||
└── vehicle_agent_windows/
|
||||
|
||||
algorithms/
|
||||
├── chassis_solver/
|
||||
├── sensor_solver/
|
||||
├── control_tuner/
|
||||
└── external_localization_backend/
|
||||
|
||||
configs/
|
||||
├── vehicles/
|
||||
├── sensors/
|
||||
├── controllers/
|
||||
└── workshop/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 当前这套 Proto 的核心协同原则
|
||||
|
||||
这 7 个 proto 在设计上应始终遵循以下原则。
|
||||
|
||||
---
|
||||
|
||||
### 原则 1:总控只编排,不求解
|
||||
|
||||
`workshop_orchestration.proto` 负责:
|
||||
|
||||
- 编排
|
||||
- 状态推进
|
||||
- 失败处理
|
||||
- 结果汇总
|
||||
|
||||
但不要在总控里塞入底盘求解、传感器求解、控制调参等专业算法细节。
|
||||
|
||||
---
|
||||
|
||||
### 原则 2:车端只执行,不决策
|
||||
|
||||
Windows 车端代理负责:
|
||||
|
||||
- 接收命令
|
||||
- 执行动作
|
||||
- 采集遥测
|
||||
- 写入参数
|
||||
- 回传状态
|
||||
|
||||
它不应该承载复杂的标定求解逻辑。
|
||||
|
||||
---
|
||||
|
||||
### 原则 3:参数求解在 Linux 侧完成
|
||||
|
||||
不论是:
|
||||
|
||||
- 底盘参数求解
|
||||
- 传感器参数求解
|
||||
- 运控参数优化
|
||||
|
||||
都应优先放在 Ubuntu / Linux 车间电脑侧完成。
|
||||
|
||||
这与你之前确定的原则完全一致。
|
||||
|
||||
---
|
||||
|
||||
### 原则 4:车辆画像先行
|
||||
|
||||
任何标定任务开始之前,都必须先有完整的车辆画像。
|
||||
|
||||
否则:
|
||||
|
||||
- 不知道该做哪些任务
|
||||
- 不知道该下发哪些动作
|
||||
- 不知道哪些传感器存在
|
||||
- 不知道是否涉及机械臂
|
||||
- 不知道使用哪套控制参数模板
|
||||
|
||||
---
|
||||
|
||||
### 原则 5:统一任务状态表达
|
||||
|
||||
所有耗时任务都应尽量统一为:
|
||||
|
||||
- 受理
|
||||
- 执行中
|
||||
- 成功
|
||||
- 失败
|
||||
- 取消
|
||||
|
||||
并配合统一错误码和统一重试语义。
|
||||
|
||||
这样总控状态机才容易实现。
|
||||
|
||||
---
|
||||
|
||||
## 11. 落地实现时还必须注意的点
|
||||
|
||||
虽然这 7 个 proto 已经能覆盖主干流程,但真正落地时,还必须继续注意以下内容。
|
||||
|
||||
---
|
||||
|
||||
### 11.1 安全状态一定要贯穿所有流程
|
||||
|
||||
例如:
|
||||
|
||||
- 急停是否触发
|
||||
- 防撞区域是否占用
|
||||
- 机械臂是否处于安全姿态
|
||||
- 外部定位工装是否到位
|
||||
- 当前车速是否允许切模式
|
||||
- 参数写入时是否禁止车辆运动
|
||||
|
||||
这些要么在公共协议中补状态字段,要么在各业务协议中明确体现。
|
||||
|
||||
---
|
||||
|
||||
### 11.2 所有结果都要有版本和摘要
|
||||
|
||||
尤其是:
|
||||
|
||||
- 底盘参数
|
||||
- 传感器外参
|
||||
- 相机内参
|
||||
- IMU 偏置
|
||||
- 运控参数
|
||||
- URDF 引用版本
|
||||
|
||||
都建议具备:
|
||||
|
||||
- `parameter_version`
|
||||
- `digest`
|
||||
- `applied_timestamp`
|
||||
- `source_session_id`
|
||||
|
||||
---
|
||||
|
||||
### 11.3 所有长任务最好支持中止与恢复
|
||||
|
||||
真实车间里很常见:
|
||||
|
||||
- 人员临时介入
|
||||
- 车辆断电
|
||||
- 网络闪断
|
||||
- 外部定位丢失
|
||||
- 工装被碰撞
|
||||
- 某个子任务失败
|
||||
|
||||
所以流程设计最好支持:
|
||||
|
||||
- 取消任务
|
||||
- 安全中止
|
||||
- 从阶段恢复
|
||||
- 局部重跑
|
||||
|
||||
---
|
||||
|
||||
### 11.4 结果质量不能只给成功/失败
|
||||
|
||||
例如:
|
||||
|
||||
- 传感器标定应给重投影误差、残差、覆盖率
|
||||
- 底盘标定应给直线误差、角度误差、曲率误差
|
||||
- 运控调参应给超调、稳态误差、收敛时间
|
||||
- 外部定位应给测量质量等级、可见性状态
|
||||
|
||||
也就是说,最终不应该只有 `success=true/false`,而应该尽可能有"质量指标"。
|
||||
|
||||
---
|
||||
|
||||
## 12. 推荐的理解方式
|
||||
|
||||
如果把整个自动化标定车间看成一个工厂流水线,那么:
|
||||
|
||||
| Proto 文件 | 类比角色 |
|
||||
|:-----------|:---------|
|
||||
| `calibration_common.proto` | 通用工单格式、错误码、状态码、追踪信息 |
|
||||
| `vehicle_profile.proto` | 产品型号定义表 |
|
||||
| `external_localization.proto` | 高精度测量工位 |
|
||||
| `chassis_calibration.proto` | 底盘调校工位 |
|
||||
| `sensor_calibration.proto` | 传感器标定工位 |
|
||||
| `control_calibration.proto` | 运控调参工位 |
|
||||
| `workshop_orchestration.proto` | 整条产线的总调度系统 |
|
||||
|
||||
---
|
||||
|
||||
## 13. 总结
|
||||
|
||||
这 7 个 proto 不是彼此独立的零散文件,而是共同组成了自动化标定车间的完整协议体系:
|
||||
|
||||
- `calibration_common.proto` 提供统一基础能力
|
||||
- `vehicle_profile.proto` 描述待标定车辆对象
|
||||
- `external_localization.proto` 提供外部真值参考
|
||||
- `chassis_calibration.proto` 负责底盘标定执行与数据回传
|
||||
- `sensor_calibration.proto` 负责传感器标定任务与结果表达
|
||||
- `control_calibration.proto` 负责横纵向控制参数调优执行链路
|
||||
- `workshop_orchestration.proto` 负责全流程编排、状态推进与结果汇总
|
||||
|
||||
它们共同支撑起一条完整的自动化标定车间流程:
|
||||
|
||||
**车辆入站 → 车辆画像 → 会话创建 → 前置检查 → 外部定位建立参考 → 底盘标定 → 传感器标定 → 运控调参 → 参数写入 → 结果归档 → 会话闭环**
|
||||
|
||||
这也是后续继续落地到:
|
||||
|
||||
- ROS2 接口映射
|
||||
- C++ 服务实现
|
||||
- 状态机编排
|
||||
- 车端代理实现
|
||||
- 参数管理系统
|
||||
- 标定报告系统
|
||||
|
||||
的协议基础。
|
||||
|
||||
---
|
||||
|
||||
## 📄 附录
|
||||
|
||||
### 相关文档
|
||||
|
||||
- [Protocol Buffers 官方文档](https://developers.google.com/protocol-buffers)
|
||||
- [ROS2 接口设计指南](https://docs.ros.org/)
|
||||
|
||||
### 修订记录
|
||||
|
||||
| 版本 | 日期 | 说明 |
|
||||
|:-----|:-----|:-----|
|
||||
| v1.0 | 2026-03-10 | 初始版本,定义 7 个核心 proto 职责 |
|
||||
|
||||
---
|
||||
|
||||
*本文档遵循 [Markdown 最佳实践](https://www.markdownguide.org/basic-syntax/) 编写。*
|
||||
@@ -1,165 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
// 规范包名:agv.calibration.chassis
|
||||
// 设计原则:专门负责底盘最底层机械物理特征的开环标定与体检
|
||||
package agv.calibration.chassis;
|
||||
|
||||
// =========================================================
|
||||
// 核心服务:AGV 底盘底层硬件自诊与物理运动学标定代理服务
|
||||
// [部署端 Server]:Windows 车端 (只负责听口令、转电机、报裸数据)
|
||||
// [调用端 Client]:Linux 车间服务器 (负责发口令、看雷达真值、算误差)
|
||||
// =========================================================
|
||||
service AgvCalibChassisService {
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 第一步:权限接管与安全熔断 (剥夺车端算法大脑)
|
||||
// ---------------------------------------------------------
|
||||
// 💻 [Linux 发送 -> Windows]:要求切断底盘运动学逆解,进入纯物理开环直驱模式
|
||||
// 🚙 [Windows 返回 -> Linux]:返回接管是否成功的回执
|
||||
rpc SetDiagnosticMode(DiagnosticModeRequest) returns (StandardResponse);
|
||||
|
||||
// 💻 [Linux 发送 -> Windows]:无视一切状态立刻抱死电机的紧急急停指令
|
||||
// 🚙 [Windows 返回 -> Linux]:返回急停执行状态
|
||||
rpc HardwareEmergencyBrake(Empty) returns (StandardResponse);
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 第二步:打开体征监控水龙头 (数字孪生健康诊断)
|
||||
// ---------------------------------------------------------
|
||||
// 💻 [Linux 发送 -> Windows]:发送空请求,触发高频推流开关
|
||||
// 🚙 [Windows 持续流式返回 -> Linux]:以 50Hz 频率持续不断地回传原始脉冲与电流
|
||||
rpc StreamHardwareTelemetry(Empty) returns (stream HardwareState);
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 第三步:原始物理开环考题下发 (逼迫底盘暴露机械缺陷)
|
||||
// ---------------------------------------------------------
|
||||
// 💻 [Linux 发送 -> Windows]:绕过算法,直接命令指定驱动轮以固定 RPM 盲跑
|
||||
// 🚙 [Windows 返回 -> Linux]:返回电机是否已成功按给定 RPM 运转
|
||||
rpc ExecuteRawDriveCommand(RawDriveRequest) returns (StandardResponse);
|
||||
|
||||
// 💻 [Linux 发送 -> Windows]:直接对转向机构下发绝对物理角度 (测机械装歪的角度)
|
||||
// 🚙 [Windows 返回 -> Linux]:返回舵机是否已开始执行角度指令
|
||||
rpc ExecuteRawSteerCommand(RawSteerRequest) returns (StandardResponse);
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 第四步:物理本底参数定稿写值 (标定闭环结束)
|
||||
// ---------------------------------------------------------
|
||||
// 💻 [Linux 发送 -> Windows]:下发 Linux 结合外部真值算出的绝对物理修正系数
|
||||
// 🚙 [Windows 返回 -> Linux]:将系数覆写到本地硬盘/驱动板后,返回成功回执
|
||||
rpc CommitKinematicParameters(KinematicParams) returns (StandardResponse);
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 基础通用消息结构
|
||||
// =========================================================
|
||||
|
||||
// 空消息,通常作为触发类请求发送
|
||||
// 💻 [流向]:Linux 发送 -> Windows
|
||||
message Empty {}
|
||||
|
||||
// 通用应答载荷
|
||||
// 🚙 [流向]:Windows 返回 -> Linux
|
||||
message StandardResponse {
|
||||
bool success = 1;
|
||||
string message = 2; // 若失败,返回驱动器底层报错详情 (如 "ERR_MOTOR_OVERCURRENT")
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 1. 权限模式请求载荷
|
||||
// =========================================================
|
||||
// 💻 [流向]:Linux 发送 -> Windows
|
||||
message DiagnosticModeRequest {
|
||||
enum Mode {
|
||||
NORMAL_KINEMATICS = 0; // 正常模式 (底盘接收 V_x, Omega,由车端执行逆解分配)
|
||||
DIRECT_RAW_DRIVE = 1; // 直驱模式 (切断逆解,允许 Linux 直接独立下发左/右轮转速)
|
||||
}
|
||||
Mode target_mode = 1;
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 2. 硬件底层遥测推流载荷 (裸数据)
|
||||
// =========================================================
|
||||
// 🚙 [流向]:Windows 疯狂上报 -> Linux (50Hz)
|
||||
message HardwareState {
|
||||
// 底层获取到脉冲那一瞬间的高精度单调系统时钟 (绝对微秒数)
|
||||
int64 hardware_timestamp_us = 1;
|
||||
|
||||
// --- A. 原始编码器反馈 (Linux 拿它与雷达真值做除法,算真实物理位移与滑移率) ---
|
||||
// 🚨 严禁返回平滑后的速度(m/s),必须返回最原始的累计脉冲 Ticks!
|
||||
int64 encoder_ticks_fl = 2; // 左前轮累计脉冲
|
||||
int64 encoder_ticks_fr = 3; // 右前轮累计脉冲
|
||||
int64 encoder_ticks_rl = 4;
|
||||
int64 encoder_ticks_rr = 5;
|
||||
|
||||
// --- B. 物理舵角反馈 (Linux 拿它比对指令响应时间,测定机械死区) ---
|
||||
double actual_steer_angle_front_deg = 6;
|
||||
double actual_steer_angle_rear_deg = 7;
|
||||
|
||||
// --- C. 动力与负载健康状态 (Linux 防烧毁熔断的判断依据) ---
|
||||
// 若维持匀速所需的电流异常激增,说明减速机干涉或刹车未放,Linux 会立刻触发急停
|
||||
double current_fl_amp = 8; // 左前电机实际相电流 (安培)
|
||||
double current_fr_amp = 9;
|
||||
double current_rl_amp = 10;
|
||||
double current_rr_amp = 11;
|
||||
double current_steer_front_amp = 12;// 前转向舵机实际电流 (安培)
|
||||
|
||||
// --- D. 驱动器硬件报警位 ---
|
||||
uint32 driver_error_code = 13; // 0x00=健康, 0x01=过压, 0x02=堵转过流等
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 3. 原始动作指令请求载荷
|
||||
// =========================================================
|
||||
// 💻 [流向]:Linux 发送 -> Windows
|
||||
message RawDriveRequest {
|
||||
string test_case_id = 1; // 测试流水号 (如 "Slip_Test_0.5m")
|
||||
|
||||
// 直接下发给电机的原始指令 (若是两驱车,后轮填 0 即可)
|
||||
double fl_motor_rpm = 2; // 左前轮目标物理转速 (RPM)
|
||||
double fr_motor_rpm = 3; // 右前轮目标物理转速 (RPM)
|
||||
double rl_motor_rpm = 4;
|
||||
double rr_motor_rpm = 5;
|
||||
|
||||
// 🚨 断网防飞车底线:若超过该时间未收到新指令,车端底层必须自动刹车
|
||||
double duration_sec = 6;
|
||||
}
|
||||
|
||||
// 💻 [流向]:Linux 发送 -> Windows
|
||||
message RawSteerRequest {
|
||||
string test_case_id = 1; // 测试流水号 (如 "Deadzone_Sweep_5deg")
|
||||
|
||||
// 针对舵机/转向推杆的绝对物理角度指令 (度)
|
||||
double front_steer_angle_deg = 2;
|
||||
double rear_steer_angle_deg = 3;
|
||||
|
||||
// 扫频测试参数 (用于测定机械往复间隙 Backlash)
|
||||
optional double sweep_amplitude_deg = 4; // 往复抖动幅度 (度)
|
||||
optional double sweep_frequency_hz = 5; // 抖动频率 (Hz)
|
||||
|
||||
double duration_sec = 6;
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 4. 物理运动学本底参数定稿载荷
|
||||
// =========================================================
|
||||
// 💻 [流向]:Linux 发送 -> Windows
|
||||
message KinematicParams {
|
||||
// (注:全字段使用 optional,Linux 测了哪一项就只下发哪一项要求车端覆盖,未发的不作修改)
|
||||
|
||||
// --- 1. 真实有效物理轮径 (纠正“开环跑偏”与里程计位移误差) ---
|
||||
optional double wheel_radius_fl_m = 1;
|
||||
optional double wheel_radius_fr_m = 2;
|
||||
optional double wheel_radius_rl_m = 3;
|
||||
optional double wheel_radius_rr_m = 4;
|
||||
|
||||
// --- 2. 机械零位绝对偏差补偿 (纠正“指令0度但车子斜着走”) ---
|
||||
optional double steer_zero_offset_front_deg = 5;
|
||||
optional double steer_zero_offset_rear_deg = 6;
|
||||
|
||||
// --- 3. 旋转几何协同参数 (纠正“原地打转时车体甩尾晃动”) ---
|
||||
optional double effective_track_width_m = 7; // 左右轮真实物理有效轮距 (m)
|
||||
optional double effective_wheel_base_m = 8; // 前后轮真实物理有效轴距 (m)
|
||||
|
||||
// 针对多舵轮底盘:瞬时旋转中心(ICR)的物理几何偏移
|
||||
optional double icr_offset_x_m = 9;
|
||||
optional double icr_offset_y_m = 10;
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
// 规范包名,确保与传感器外参标定业务(agv.calibration.sensor)严格物理与逻辑隔离
|
||||
package agv.calibration.control;
|
||||
|
||||
// =========================================================
|
||||
// 核心服务:AGV 运控大脑(PID/MPC)参数自动化寻优调教代理
|
||||
// [部署端 Server]:Windows车端 (满血保留自身算法,负责执行闭环追踪与高频汇报)
|
||||
// [调用端 Client]:Linux标定服务器 (上帝视角,负责发轨迹、看误差、AI打分与发新参数)
|
||||
// =========================================================
|
||||
service AgvCalibControlService {
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 第一步:权限接管与生命周期安全管控
|
||||
// ---------------------------------------------------------
|
||||
// 💻 [Linux 发送 -> Windows]:要求切断避障,但保留底层 PID/MPC 算法就绪
|
||||
// 🚙 [Windows 返回 -> Linux]:回复模式切换成功,准备好接考题
|
||||
rpc SetControlMode(ModeRequest) returns (StandardResponse);
|
||||
|
||||
// 💻 [Linux 发送 -> Windows]:断网或飞车时的最高级别急停,无视一切直接刹车
|
||||
// 🚙 [Windows 返回 -> Linux]:返回底层抱死结果
|
||||
rpc EmergencyStop(Empty) returns (StandardResponse);
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 第二步:运动考题下发 (开环排雷 / 闭环寻优 / 波峰对齐)
|
||||
// ---------------------------------------------------------
|
||||
// 【场景A: 纯物理开环备用】
|
||||
// 💻 [Linux 发送 -> Windows]:要求切断算法盲跑,多用于摸底或辅助验证
|
||||
// 🚙 [Windows 返回 -> Linux]:确认已按指定 RPM/PWM 运转
|
||||
rpc ExecuteOpenLoopCmd(OpenLoopRequest) returns (StandardResponse);
|
||||
|
||||
// 【场景B: 算法闭环调优】
|
||||
// 💻 [Linux 发送 -> Windows]:下发一条由几百个点组成的测试轨迹(如 S型贝塞尔曲线)
|
||||
// 🚙 [Windows 返回 -> Linux]:收到轨迹后,车端立刻使用它自带的 PID/MPC 算法努力贴合轨迹跑圈
|
||||
rpc FollowTestTrajectory(TrajectoryRequest) returns (StandardResponse);
|
||||
|
||||
// 【场景C: 波峰时序对齐】
|
||||
// 💻 [Linux 发送 -> Windows]:下发极短促的阶跃加速指令,人为制造绝对速度波峰
|
||||
// 🚙 [Windows 返回 -> Linux]:确认加速。(Linux 借此波峰算出网络的绝对 Time Offset)
|
||||
rpc ExecuteStepResponse(StepResponseRequest) returns (StandardResponse);
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 第三步:运控参数 AI 寻优:动态热注入与最终固化
|
||||
// ---------------------------------------------------------
|
||||
// 💻 [Linux 发送 -> Windows]:Linux 发现上一圈跑得差,AI算出了新的 PID/前瞻距离,要求立即热注入
|
||||
// 🚙 [Windows 返回 -> Linux]:车端将新参数瞬间覆写进运行内存(不重启系统),随时准备用新参数重跑
|
||||
rpc InjectTuningParameters(ControlParams) returns (StandardResponse);
|
||||
|
||||
// 💻 [Linux 发送 -> Windows]:Linux 判定误差极小,调优结束,命令固化目前内存里的最高分参数
|
||||
// 🚙 [Windows 返回 -> Linux]:车端将这组完美参数永久覆写进硬盘的 config.yaml 或系统注册表
|
||||
rpc CommitControlParameters(Empty) returns (StandardResponse);
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 第四步:高频数字孪生体感上报 (50Hz)
|
||||
// ---------------------------------------------------------
|
||||
// 💻 [Linux 发送 -> Windows]:空包触发,命令车端开始疯狂推流
|
||||
// 🚙 [Windows 持续流式返回 -> Linux]:以 50Hz 频率,持续上报自己的里程计坐标、速度和单调时间戳
|
||||
rpc StreamTelemetry(Empty) returns (stream TelemetryData);
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 基础通用消息结构
|
||||
// =========================================================
|
||||
|
||||
// 💻 [流向]:Linux 发送 -> Windows (通常用作触发信号)
|
||||
message Empty {}
|
||||
|
||||
// 🚙 [流向]:Windows 返回 -> Linux (通用应答)
|
||||
message StandardResponse {
|
||||
bool success = 1;
|
||||
string message = 2; // 包含执行成功的回执,或底盘卡死/驱动器报错等异常原因
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 1. 模式控制结构体
|
||||
// =========================================================
|
||||
|
||||
// 💻 [流向]:Linux 发送 -> Windows
|
||||
message ModeRequest {
|
||||
enum Mode {
|
||||
NORMAL_MODE = 0; // 正常业务模式(打开避障和导航,出厂默认状态)
|
||||
OPEN_LOOP_MODE = 1; // 物理开环标定模式(切断所有算法纠偏,提线木偶状态)
|
||||
TUNING_MODE = 2; // 闭环调优模式(切断环境避障,但必须保留原生 PID/MPC 追踪算法)
|
||||
}
|
||||
Mode target_mode = 1;
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 2. 动作指令请求载荷
|
||||
// =========================================================
|
||||
|
||||
// 💻 [流向]:Linux 发送 -> Windows
|
||||
message OpenLoopRequest {
|
||||
double left_motor_cmd = 1; // 左驱动轮目标转速 (RPM) 或占空比
|
||||
double right_motor_cmd = 2; // 右驱动轮目标转速 (RPM) 或占空比
|
||||
double steering_angle = 3; // 针对单/多舵轮底盘的绝对舵角指令 (度,差速轮忽略)
|
||||
|
||||
// 🚨 极度关键的安全设计:指令超时时间
|
||||
// 业务潜台词:车端若失去网络连接,超时后必须由底层代码强制将速度归零,严防撞墙!
|
||||
double duration_sec = 4;
|
||||
}
|
||||
|
||||
// 💻 [流向]:Linux 发送 -> Windows (组成考卷的一小步)
|
||||
message TrajectoryPoint {
|
||||
double x_m = 1; // 目标点 X 坐标 (米)
|
||||
double y_m = 2; // 目标点 Y 坐标 (米)
|
||||
double yaw_rad = 3; // 目标点 偏航角 (弧度)
|
||||
double target_speed_ms = 4; // 到达该点时的期望线速度 (米/秒)
|
||||
double curvature = 5; // 该点处的轨迹曲率 (可选项,用于辅助前瞻距离映射)
|
||||
}
|
||||
|
||||
// 💻 [流向]:Linux 发送 -> Windows (下发整张考卷)
|
||||
message TrajectoryRequest {
|
||||
string test_case_id = 1; // 考题名称,如 "Bezier_Curve_S_Speed_1.2"
|
||||
repeated TrajectoryPoint path = 2; // 组成考题曲线的稠密坐标点阵列
|
||||
}
|
||||
|
||||
// 💻 [流向]:Linux 发送 -> Windows (制造波峰)
|
||||
message StepResponseRequest {
|
||||
double target_velocity_ms = 1; // 极速阶跃的目标线速度 (如猛烈加速到 1.5 m/s)
|
||||
double duration_sec = 2; // 阶跃维持时间 (极短,如 1~2 秒即可,用于产生绝对波峰)
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 3. 待调优运控参数载荷 (支持增量式热更新)
|
||||
// =========================================================
|
||||
|
||||
// 💻 [流向]:Linux 发送 -> Windows
|
||||
message ControlParams {
|
||||
// 🚨 业务潜台词:采用 optional 关键字,允许 Linux 每次只下发需要修改的个别参数。
|
||||
// 没下发的参数,Windows 必须保持内存中的原样,千万不能清零!
|
||||
|
||||
// --- 底盘物理运动学修正系数 (由第一阶段开环算得) ---
|
||||
optional double wheel_radius_left_ratio = 1; // 左侧真实有效轮径补偿乘数 (如 1.002)
|
||||
optional double wheel_radius_right_ratio = 2; // 右侧真实有效轮径补偿乘数 (如 0.998)
|
||||
optional double effective_track_width_m = 3; // 有效轮距 (m)
|
||||
optional double steering_zero_offset_deg = 4; // 舵角机械零位静态偏差 (度)
|
||||
|
||||
// --- 经典 PID 控制增益 ---
|
||||
optional double pid_kp_lateral = 5;
|
||||
optional double pid_ki_lateral = 6;
|
||||
optional double pid_kd_lateral = 7; // 用于提供阻尼,抑制高频画龙震荡
|
||||
|
||||
optional double pid_kp_heading = 8;
|
||||
optional double pid_ki_heading = 9;
|
||||
optional double pid_kd_heading = 10;
|
||||
|
||||
// --- 先进算法核心参数 ---
|
||||
optional double pure_pursuit_lookahead_m = 11; // 纯追踪前瞻距离 Ld (m)
|
||||
optional double mpc_weight_q_lateral = 12; // MPC Q矩阵:对横向误差的惩罚权重
|
||||
optional double mpc_weight_r_steering = 13; // MPC R矩阵:对转向电机发力剧烈度的惩罚权重 (控制平顺性)
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 4. 高频遥测推流载荷 (数字孪生状态汇报)
|
||||
// =========================================================
|
||||
|
||||
// 🚙 [流向]:Windows 疯狂上报 -> Linux (50Hz)
|
||||
message TelemetryData {
|
||||
// 🚨 互相关对齐的核心依据:
|
||||
// 必须使用 Windows 底层高精度单调时钟 (如 QueryPerformanceCounter) 的绝对微秒数。
|
||||
// 绝对禁止在车端人为做时序平滑或使用受 NTP 影响的系统时间!
|
||||
int64 hardware_timestamp_us = 1;
|
||||
|
||||
// --- A. 车端推算的内部里程计位姿 (Odom) ---
|
||||
// 业务潜台词:Linux 拿这个跟外面上帝视角的雷达真值相减,就算出了算法的实际追踪误差(RMSE)
|
||||
double odom_x_m = 2;
|
||||
double odom_y_m = 3;
|
||||
double odom_yaw_rad = 4;
|
||||
|
||||
// --- B. 底层执行器真实物理反馈 (用于提取波峰) ---
|
||||
// 业务潜台词:用于跟指令速度比对,提取波峰,并计算 Jerk (加加速度/平顺性)
|
||||
double feedback_linear_vel_ms = 5; // 编码器解算的真实线速度 (m/s)
|
||||
double feedback_angular_vel_rads = 6;// 陀螺仪或编码器解算的真实角速度 (rad/s)
|
||||
|
||||
// --- C. 硬件健康与功耗监控 (用于 Linux 诊断干涉卡死) ---
|
||||
// 业务潜台词:如果遇到急弯时电流长期满载,Linux 判定该考题超出了这台车的物理极限。
|
||||
double left_motor_current_amp = 7; // 左驱动电机实时电流 (A)
|
||||
double right_motor_current_amp = 8; // 右驱动电机实时电流 (A)
|
||||
double steering_motor_current_amp = 9; // 转向舵机实时电流 (A)
|
||||
|
||||
// --- D. 算法控制输出量 (用于 Linux 识别死区或物理饱和) ---
|
||||
// 业务潜台词:观察 PID 算出的期望舵角,看是否长期顶在软件限幅上 (如打满死舵)
|
||||
double cmd_steering_output = 10; // 控制算法计算出的期望底层舵角指令 (度/弧度)
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
// 规范包名,防止与其他业务(如底盘 chassis 或 运控 control)的接口冲突
|
||||
// 设计原则:严格遵循“走-停-拍”防延迟策略与大文件分块流式传输
|
||||
package agv.calibration.sensor;
|
||||
|
||||
// =========================================================
|
||||
// 核心服务:多传感器自动化外参标定代理服务
|
||||
// [部署端 Server]:Windows车端 (充当带轮子的三脚架与文件下载服务器)
|
||||
// [调用端 Client]:Linux标定服务器 (掌控状态机、拉取大文件、算 Ceres 矩阵)
|
||||
// =========================================================
|
||||
service SensorCalibrationService {
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 第一步:物理走位 (走)
|
||||
// ---------------------------------------------------------
|
||||
// 💻 [Linux 发送 -> Windows]:调度车辆开到指定的标定观测点,到达后【绝对刹车静止】
|
||||
// 🚙 [Windows 返回 -> Linux]:物理到位抱死刹车后,返回成功回执
|
||||
// 🚨 业务潜台词:Linux 收到回执后,必须在代码里强制 sleep(0.5s) 等待避震悬挂平息,冻结物理空间!
|
||||
rpc MoveToObservationPose (PoseRequest) returns (StandardResponse);
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 第二步:防延迟同步锁存 (停与拍)
|
||||
// ---------------------------------------------------------
|
||||
// 💻 [Linux 发送 -> Windows]:命令车辆瞬间将底层相机的显存和雷达的点云冻结到后备内存池
|
||||
// 🚙 [Windows 返回 -> Linux]:立刻锁存,并返回高精度硬件时间戳,作为后续拉取大文件的唯一“取件码”
|
||||
rpc TriggerSyncCapture (CaptureRequest) returns (CaptureResponse);
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 第三步:大文件流式下载 (传 —— 破解 Windows 网络延迟的绝杀)
|
||||
// ---------------------------------------------------------
|
||||
// 💻 [Linux 发送 -> Windows]:凭“取件码”请求下载巨大的图片/点云原文件
|
||||
// 🚙 [Windows 持续流式返回 -> Linux]:将 5MB+ 的无损文件切成小块,像流水一样源源不断传回 Linux
|
||||
// 🚨 业务潜台词:必须使用 stream 关键字!否则 gRPC 会因为单包超过 4MB 瞬间崩溃!
|
||||
rpc DownloadImage (DataFetchRequest) returns (stream FileChunk);
|
||||
rpc DownloadPointCloud (DataFetchRequest) returns (stream FileChunk);
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 第四步:标定闭环定稿 (写)
|
||||
// ---------------------------------------------------------
|
||||
// 💻 [Linux 发送 -> Windows]:Linux 攒够数据算完复杂的 4x4 外参矩阵后,下发给车端持久化保存
|
||||
// 🚙 [Windows 返回 -> Linux]:车端收到后直接覆写 sensor_config.yaml 或注册表,返回成功
|
||||
rpc CommitCalibrationResults (CalibrationPayload) returns (StandardResponse);
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 基础响应
|
||||
// =========================================================
|
||||
|
||||
// 🚙 [流向]:Windows 返回 -> Linux (通用应答)
|
||||
message StandardResponse {
|
||||
bool success = 1;
|
||||
string message = 2; // 成功提示或具体的报错原因(如:标定点坐标越界导致碰撞防线触发)
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 1. 物理走位请求 (走)
|
||||
// =========================================================
|
||||
|
||||
// 💻 [流向]:Linux 发送 -> Windows
|
||||
message PoseRequest {
|
||||
double target_x_m = 1; // 目标 X 坐标 (米)
|
||||
double target_y_m = 2; // 目标 Y 坐标 (米)
|
||||
double target_yaw_deg = 3; // 目标偏航角 (度)
|
||||
bool is_relative = 4; // true: 相对当前位置移动; false: 绝对世界坐标
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 2. 触发同步抓拍请求与响应 (停与拍)
|
||||
// =========================================================
|
||||
|
||||
// 💻 [流向]:Linux 发送 -> Windows
|
||||
message CaptureRequest {
|
||||
// 业务潜台词:告诉车端这次要同时拍哪些传感器,例如 ["cam_front", "lidar_top"]
|
||||
// 收到指令的这一微秒,车端底层必须同时将名单里传感器的数据 copy 冻结出来!未点名的不管,节约内存。
|
||||
repeated string sensor_ids = 1;
|
||||
}
|
||||
|
||||
// 🚙 [流向]:Windows 返回 -> Linux
|
||||
message CaptureResponse {
|
||||
bool success = 1;
|
||||
// 🚨 极度关键:“取件码”!车端打上的高精度硬件时间戳(微秒)。
|
||||
// 业务潜台词:这是提取大文件的唯一凭证,无论一会儿 Wi-Fi 传得有多慢,只要凭证一致,保证拿回来的图片和点云在物理空间上是绝对严丝合缝对齐的!
|
||||
int64 capture_timestamp_us = 2;
|
||||
string error_message = 3;
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 3. 大文件下载请求与文件流块 (传)
|
||||
// =========================================================
|
||||
|
||||
// 💻 [流向]:Linux 发送 -> Windows (凭码提货)
|
||||
message DataFetchRequest {
|
||||
int64 capture_timestamp_us = 1; // 阶段2拿到的唯一“取件码”
|
||||
string sensor_id = 2; // 具体要拉取哪个传感器的数据,例如 "cam_front"
|
||||
}
|
||||
|
||||
// 🚙 [流向]:Windows 持续流式返回 -> Linux (流水线发货)
|
||||
message FileChunk {
|
||||
// 业务潜台词:规避 gRPC 单条消息默认 4MB 的内存限制,防止传大图片时程序崩溃。
|
||||
bytes chunk_data = 1; // 文件的二进制分块(建议车端 C++ 每次切 512KB - 1MB 发送)
|
||||
bool is_last_chunk = 2; // 标记是否为最后一块,告诉 Linux 停止拼接并保存文件
|
||||
|
||||
// 🚨 致命防坑潜台词:绝对禁止传 "jpg" 或 "jpeg"!
|
||||
// 有损压缩的伪影会导致亚像素角点提取出现好几个像素的偏差,毁掉整个 3D 标定精度。
|
||||
// 必须是 "png", "bmp", "raw" 或 "pcd"!
|
||||
string format_ext = 3;
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 4. 标定结果载荷(支持内参、外参灵活组合发回车端) (写)
|
||||
// =========================================================
|
||||
|
||||
// 💻 [流向]:Linux 发送 -> Windows (下发算好的内参,多为离线预标定备用)
|
||||
message CameraIntrinsics {
|
||||
string camera_id = 1;
|
||||
double fx = 2; double fy = 3;
|
||||
double cx = 4; double cy = 5;
|
||||
repeated double dist_coeffs = 6; // 畸变系数阵列 [k1, k2, p1, p2, k3]
|
||||
}
|
||||
|
||||
// 💻 [流向]:Linux 发送 -> Windows (下发算好的 6-DOF 外参矩阵)
|
||||
message SensorExtrinsics {
|
||||
// 业务潜台词:告诉车端,source 坐标系 相对 target 坐标系,平移和旋转了多少。
|
||||
string source_frame = 1; // 源坐标系,如 "lidar_top" 或 "cam_left"
|
||||
string target_frame = 2; // 目标坐标系,如 "cam_front" 或 "base_link" (底盘质心)
|
||||
|
||||
// 平移向量 (强制规定工业制式单位为毫米 mm,消除浮点数歧义)
|
||||
double trans_x_mm = 3;
|
||||
double trans_y_mm = 4;
|
||||
double trans_z_mm = 5;
|
||||
|
||||
// 空间旋转姿态 (强制规定工业制式单位为度 degrees,方便人工排错,绝不混用弧度)
|
||||
double roll_deg = 6;
|
||||
double pitch_deg = 7;
|
||||
double yaw_deg = 8;
|
||||
}
|
||||
|
||||
// 💻 [流向]:Linux 发送 -> Windows (出厂全量包)
|
||||
message CalibrationPayload {
|
||||
string task_id = 1; // 标定任务流水号,用于 MES 系统的云端溯源
|
||||
|
||||
// 业务潜台词:采用 repeated 数组,Linux 可以一次性把全车所有的内参、外参一股脑发过去。
|
||||
// 车端只需一个 for 循环,把这些矩阵依次写进硬盘即可。
|
||||
repeated CameraIntrinsics updated_intrinsics = 2;
|
||||
repeated SensorExtrinsics updated_extrinsics = 3;
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package agv.calibration.common;
|
||||
|
||||
// =========================================================
|
||||
// 文件作用:自动化标定车间公共协议定义
|
||||
// 使用范围:
|
||||
// 1) Ubuntu 车间电脑内部服务之间
|
||||
// 2) Ubuntu 车间电脑 与 Windows 车端代理服务之间
|
||||
// 3) 所有专项标定服务的公共基础消息
|
||||
// =========================================================
|
||||
|
||||
// =========================================================
|
||||
// 空消息
|
||||
// 作用:无参数 RPC 使用
|
||||
// =========================================================
|
||||
message Empty {}
|
||||
|
||||
// =========================================================
|
||||
// 三维向量
|
||||
// 作用:用于表达三轴偏置、平移量、加速度等三维数据
|
||||
// =========================================================
|
||||
message Vector3D {
|
||||
double x = 1; // X 轴分量
|
||||
double y = 2; // Y 轴分量
|
||||
double z = 3; // Z 轴分量
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 六自由度位姿
|
||||
// 作用:用于表达 base_link、传感器、外部定位坐标系之间的位姿关系
|
||||
// 说明:
|
||||
// 1) 平移单位为米
|
||||
// 2) 旋转单位为弧度
|
||||
// 3) 采用 xyz + rpy 表达,便于工程实现与人工检查
|
||||
// =========================================================
|
||||
message Pose3D {
|
||||
double x_m = 1; // X 方向平移(m)
|
||||
double y_m = 2; // Y 方向平移(m)
|
||||
double z_m = 3; // Z 方向平移(m)
|
||||
double roll_rad = 4; // 绕 X 轴旋转(rad)
|
||||
double pitch_rad = 5; // 绕 Y 轴旋转(rad)
|
||||
double yaw_rad = 6; // 绕 Z 轴旋转(rad)
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 通用请求头
|
||||
// 作用:带齐一次会话、任务、车辆、请求追踪信息
|
||||
// 发送方:通常为 Ubuntu 车间电脑
|
||||
// 接收方:Linux 内部服务 或 Windows 车端代理
|
||||
// =========================================================
|
||||
message RequestHeader {
|
||||
string session_id = 1; // 本次整车标定会话 ID
|
||||
string task_id = 2; // 当前任务 ID / 阶段 ID
|
||||
string vehicle_id = 3; // 车辆 ID
|
||||
string request_id = 4; // 本次请求唯一 ID
|
||||
int64 client_send_timestamp_us = 5; // 请求发送时间戳(微秒)
|
||||
string operator_id = 6; // 操作员工号 / 工位号
|
||||
string workshop_host = 7; // Ubuntu 车间电脑主机名
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 统一错误码
|
||||
// 作用:所有服务统一返回,便于编排器与状态机处理
|
||||
// =========================================================
|
||||
enum ErrorCode {
|
||||
ERROR_CODE_UNSPECIFIED = 0; // 未指定
|
||||
OK = 1; // 正常
|
||||
INVALID_ARGUMENT = 2; // 参数非法
|
||||
INVALID_STATE = 3; // 当前状态不允许执行
|
||||
VEHICLE_BUSY = 4; // 车辆当前忙
|
||||
NOT_READY = 5; // 未准备好
|
||||
TIMEOUT = 6; // 超时
|
||||
NETWORK_LOSS = 7; // 网络异常
|
||||
SAFETY_TRIGGERED = 8; // 安全保护触发
|
||||
HARDWARE_FAULT = 9; // 硬件故障
|
||||
FILE_NOT_FOUND = 10; // 文件不存在
|
||||
CHECKSUM_MISMATCH = 11; // 校验失败
|
||||
INTERNAL_ERROR = 12; // 内部错误
|
||||
UNSUPPORTED_CAPABILITY = 13; // 当前车辆不支持该能力
|
||||
RESOURCE_LOCKED = 14; // 资源已被其他会话占用
|
||||
MANUAL_CONFIRM_REQUIRED = 15;// 需要人工确认后继续
|
||||
APPROVAL_REQUIRED = 16; // 需要人工审批后继续
|
||||
VALIDATION_FAILED = 17; // 验证未通过
|
||||
ROLLBACK_REQUIRED = 18; // 需要参数回滚
|
||||
DATA_QUALITY_INSUFFICIENT = 19; // 数据质量不足
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 通用短响应
|
||||
// 作用:用于同步 RPC 的标准响应
|
||||
// 发送方:服务端
|
||||
// 接收方:调用方
|
||||
// =========================================================
|
||||
message StandardResponse {
|
||||
bool success = 1; // 是否成功
|
||||
ErrorCode error_code = 2; // 错误码
|
||||
string message = 3; // 说明文字
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 长任务状态
|
||||
// 作用:用于异步任务状态表达
|
||||
// =========================================================
|
||||
enum JobState {
|
||||
JOB_STATE_UNSPECIFIED = 0; // 未指定
|
||||
PENDING = 1; // 已受理,等待执行
|
||||
RUNNING = 2; // 执行中
|
||||
WAITING_MANUAL = 3; // 等待人工操作 / 确认
|
||||
WAITING_APPROVAL = 4; // 等待审批
|
||||
SUCCEEDED = 5; // 成功
|
||||
FAILED = 6; // 失败
|
||||
CANCELED = 7; // 已取消
|
||||
ROLLED_BACK = 8; // 已回滚
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 长任务受理响应
|
||||
// 作用:耗时任务先返回 job_id,后续轮询状态
|
||||
// 发送方:服务端
|
||||
// 接收方:Ubuntu 车间电脑
|
||||
// =========================================================
|
||||
message JobAccepted {
|
||||
bool accepted = 1; // 是否受理成功
|
||||
ErrorCode error_code = 2; // 未受理时的错误码
|
||||
string message = 3; // 说明
|
||||
string job_id = 4; // 长任务 ID
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 长任务查询请求
|
||||
// 作用:通过 job_id 查询执行状态
|
||||
// 发送方:Ubuntu 车间电脑
|
||||
// 接收方:Linux 服务 或 Windows 车端代理
|
||||
// =========================================================
|
||||
message JobQuery {
|
||||
RequestHeader header = 1; // 请求头
|
||||
string job_id = 2; // 任务 ID
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 长任务状态响应
|
||||
// 作用:返回任务执行状态、进度、错误信息
|
||||
// 发送方:服务端
|
||||
// 接收方:Ubuntu 车间电脑
|
||||
// =========================================================
|
||||
message JobStatus {
|
||||
string job_id = 1; // 任务 ID
|
||||
JobState state = 2; // 当前状态
|
||||
double progress = 3; // 进度,建议范围 0.0 ~ 1.0
|
||||
ErrorCode error_code = 4; // 当前错误码
|
||||
string message = 5; // 状态说明
|
||||
int64 server_timestamp_us = 6; // 服务端时间戳
|
||||
bool safe_to_retry = 7; // 是否适合自动重试
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 心跳请求
|
||||
// 作用:保持 Linux 与 Windows 车端之间的在线状态
|
||||
// 发送方:Ubuntu 车间电脑
|
||||
// 接收方:Windows 车端代理 / Linux 子服务
|
||||
// =========================================================
|
||||
message HeartbeatRequest {
|
||||
RequestHeader header = 1; // 请求头
|
||||
string agent_name = 2; // 服务名 / 代理名
|
||||
int32 expect_next_heartbeat_ms = 3; // 下次期望心跳间隔(ms)
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 心跳响应
|
||||
// 作用:反馈当前是否在线、是否可接任务
|
||||
// 发送方:服务端
|
||||
// 接收方:调用方
|
||||
// =========================================================
|
||||
message HeartbeatResponse {
|
||||
bool success = 1; // 是否正常
|
||||
ErrorCode error_code = 2; // 错误码
|
||||
string message = 3; // 说明文字
|
||||
int64 server_timestamp_us = 4; // 响应时间戳
|
||||
bool vehicle_ready = 5; // 车辆 / 服务是否准备好接任务
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 文件摘要
|
||||
// 作用:用于参数包、URDF、数据文件校验
|
||||
// =========================================================
|
||||
message FileDigest {
|
||||
string checksum_type = 1; // 摘要算法,例如 sha256
|
||||
string checksum_value = 2; // 摘要值
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 文件引用
|
||||
// 作用:用于报告、参数包、数据集、日志包等产物追溯
|
||||
// =========================================================
|
||||
message FileReference {
|
||||
string file_name = 1; // 文件名
|
||||
string file_uri = 2; // 文件路径 / URI
|
||||
int64 size_bytes = 3; // 文件大小(字节)
|
||||
string description = 4; // 文件说明
|
||||
FileDigest digest = 5; // 文件摘要
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 键值对
|
||||
// 作用:用于扩展元数据,避免每次新增少量字段都改协议
|
||||
// =========================================================
|
||||
message KeyValuePair {
|
||||
string key = 1; // 键
|
||||
string value = 2; // 值
|
||||
}
|
||||
@@ -0,0 +1,359 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package agv.calibration.chassis;
|
||||
|
||||
import "calibration_common.proto";
|
||||
import "vehicle_profile.proto";
|
||||
|
||||
// =========================================================
|
||||
// 文件作用:底盘标定执行代理协议
|
||||
// 运行关系:
|
||||
// Ubuntu 车间电脑(Linux) -> Windows 车端代理
|
||||
// 说明:
|
||||
// 1) Linux 负责底盘参数求解、误差分析、验证判断
|
||||
// 2) Windows 车端只负责执行动作、回传原始状态、写入参数
|
||||
// =========================================================
|
||||
|
||||
// =========================================================
|
||||
// 服务:底盘标定服务
|
||||
// 运行位置:Windows 车端电脑
|
||||
// 调用方:Ubuntu 车间电脑
|
||||
// =========================================================
|
||||
service AgvCalibChassisService {
|
||||
// 心跳保活
|
||||
rpc Heartbeat(.agv.calibration.common.HeartbeatRequest)
|
||||
returns (.agv.calibration.common.HeartbeatResponse);
|
||||
|
||||
// 设置底盘标定工作模式
|
||||
rpc SetChassisWorkMode(ChassisWorkModeRequest)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
|
||||
// 查询车端底盘能力
|
||||
rpc GetChassisCapability(ChassisCapabilityRequest)
|
||||
returns (ChassisCapabilityResponse);
|
||||
|
||||
// 启动一个底盘动作原语任务
|
||||
rpc StartMotionPrimitive(MotionPrimitiveRequest)
|
||||
returns (.agv.calibration.common.JobAccepted);
|
||||
|
||||
// 查询底盘任务状态
|
||||
rpc GetChassisJobStatus(.agv.calibration.common.JobQuery)
|
||||
returns (.agv.calibration.common.JobStatus);
|
||||
|
||||
// 查询底盘任务结果
|
||||
rpc GetChassisJobResult(.agv.calibration.common.JobQuery)
|
||||
returns (ChassisJobResult);
|
||||
|
||||
// 取消底盘任务
|
||||
rpc CancelChassisJob(.agv.calibration.common.JobQuery)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
|
||||
// 打开底盘遥测流
|
||||
rpc StreamChassisTelemetry(StreamChassisTelemetryRequest)
|
||||
returns (stream ChassisTelemetry);
|
||||
|
||||
// 写入底盘标定结果
|
||||
rpc CommitChassisCalibrationParameters(CommitChassisCalibrationParametersRequest)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
|
||||
// 查询当前已生效底盘标定参数
|
||||
rpc GetAppliedChassisCalibrationParameters(GetAppliedChassisCalibrationParametersRequest)
|
||||
returns (AppliedChassisCalibrationParametersResponse);
|
||||
|
||||
// 紧急刹停
|
||||
rpc EmergencyBrake(.agv.calibration.common.Empty)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 底盘工作模式
|
||||
// 作用:切换底盘到标定准备、直接执行等模式
|
||||
// =========================================================
|
||||
message ChassisWorkModeRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
|
||||
enum Mode {
|
||||
CHASSIS_MODE_UNSPECIFIED = 0; // 未指定
|
||||
NORMAL_MODE = 1; // 正常业务模式
|
||||
CALIBRATION_READY_MODE = 2; // 标定准备模式
|
||||
DIRECT_EXECUTION_MODE = 3; // 允许直接执行原始动作命令
|
||||
VALIDATION_MODE = 4; // 底盘参数验证模式
|
||||
}
|
||||
|
||||
Mode target_mode = 2; // 目标模式
|
||||
string reason = 3; // 切换原因
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 查询底盘能力请求
|
||||
// 作用:运行前确认当前车辆支持哪些动作
|
||||
// =========================================================
|
||||
message ChassisCapabilityRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 查询底盘能力响应
|
||||
// 作用:返回当前车辆底盘形式和支持的动作原语
|
||||
// =========================================================
|
||||
message ChassisCapabilityResponse {
|
||||
bool success = 1; // 是否成功
|
||||
.agv.calibration.common.ErrorCode error_code = 2; // 错误码
|
||||
string message = 3; // 说明
|
||||
.agv.calibration.vehicle.profile.ChassisType chassis_type = 4; // 底盘类型
|
||||
bool supports_straight_line = 5; // 是否支持直线动作
|
||||
bool supports_arc = 6; // 是否支持圆弧动作
|
||||
bool supports_in_place_rotation = 7; // 是否支持原地旋转
|
||||
bool supports_steer_sweep = 8; // 是否支持舵角扫动
|
||||
bool supports_reverse_motion = 9; // 是否支持倒车动作
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 直线动作命令
|
||||
// 作用:用于验证直线行驶能力和线速度误差
|
||||
// =========================================================
|
||||
message StraightLineCommand {
|
||||
double target_speed_ms = 1; // 目标线速度(m/s)
|
||||
double target_distance_m = 2; // 目标距离(m)
|
||||
bool reverse = 3; // 是否倒车
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 圆弧动作命令
|
||||
// 作用:用于验证曲线行驶能力和曲率误差
|
||||
// =========================================================
|
||||
message ArcCommand {
|
||||
double target_speed_ms = 1; // 目标线速度(m/s)
|
||||
double radius_m = 2; // 目标半径(m)
|
||||
double sweep_angle_deg = 3; // 圆弧扫角(度)
|
||||
bool clockwise = 4; // 是否顺时针
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 原地旋转动作命令
|
||||
// 作用:用于差速、多舵轮等底盘的旋转能力测试
|
||||
// =========================================================
|
||||
message InPlaceRotationCommand {
|
||||
double target_yaw_deg = 1; // 目标旋转角(度)
|
||||
double target_angular_vel_deg_s = 2; // 目标角速度(度/秒)
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 舵角扫动命令
|
||||
// 作用:用于阿克曼、单舵轮、多舵轮的转向零位和转向响应测试
|
||||
// =========================================================
|
||||
message SteeringSweepCommand {
|
||||
double target_angle_deg = 1; // 目标舵角(度)
|
||||
double sweep_amplitude_deg = 2; // 扫动幅值(度)
|
||||
double sweep_frequency_hz = 3; // 扫动频率(Hz)
|
||||
double duration_sec = 4; // 持续时长(秒)
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 底盘动作原语请求
|
||||
// 作用:让车端执行一个标准化动作
|
||||
// 发送方:Ubuntu 车间电脑
|
||||
// 接收方:Windows 车端代理
|
||||
// =========================================================
|
||||
message MotionPrimitiveRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
string test_case_id = 2; // 测试用例 ID
|
||||
|
||||
enum TaskPurpose {
|
||||
CHASSIS_TASK_PURPOSE_UNSPECIFIED = 0; // 未指定
|
||||
DATA_COLLECTION = 1; // 数据采集
|
||||
VALIDATION = 2; // 参数验证
|
||||
DIRECT_CHECK = 3; // 直接检查
|
||||
}
|
||||
|
||||
TaskPurpose task_purpose = 3; // 任务目的
|
||||
|
||||
oneof primitive {
|
||||
StraightLineCommand straight_line = 4; // 直线动作
|
||||
ArcCommand arc = 5; // 圆弧动作
|
||||
InPlaceRotationCommand in_place_rotation = 6;// 原地旋转
|
||||
SteeringSweepCommand steering_sweep = 7; // 舵角扫动
|
||||
}
|
||||
|
||||
bool brake_when_finished = 8; // 结束后是否刹停
|
||||
double timeout_sec = 9; // 任务超时时间
|
||||
string source_iteration_id = 10; // 来源迭代号
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 底盘遥测流请求
|
||||
// 作用:指定底盘遥测内容和频率
|
||||
// =========================================================
|
||||
message StreamChassisTelemetryRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
uint32 expected_hz = 2; // 期望上报频率
|
||||
bool include_odom = 3; // 是否包含里程计
|
||||
bool include_wheel_state = 4; // 是否包含轮组状态
|
||||
bool include_driver_state = 5; // 是否包含驱动器状态
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 单个轮 / 舵模块状态
|
||||
// 作用:兼容差速、单舵轮、多舵轮、阿克曼等形式
|
||||
// =========================================================
|
||||
message WheelModuleState {
|
||||
string module_id = 1; // 模块 ID,例如 fl / fr / drive_center
|
||||
int64 encoder_ticks = 2; // 编码器累计脉冲
|
||||
double wheel_speed_rpm = 3; // 当前轮速(RPM)
|
||||
double steer_angle_deg = 4; // 当前舵角(度),无舵角则可置 0
|
||||
double motor_current_amp = 5; // 电机电流(A)
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 底盘遥测数据
|
||||
// 作用:回传原始底盘状态供 Linux 做误差分析
|
||||
// 发送方:Windows 车端代理
|
||||
// 接收方:Ubuntu 车间电脑
|
||||
// =========================================================
|
||||
message ChassisTelemetry {
|
||||
int64 hardware_timestamp_us = 1; // 硬件时间戳
|
||||
.agv.calibration.vehicle.profile.ChassisType chassis_type = 2; // 当前底盘类型
|
||||
double odom_x_m = 3; // 车端里程计 X(m)
|
||||
double odom_y_m = 4; // 车端里程计 Y(m)
|
||||
double odom_yaw_rad = 5; // 车端里程计偏航角(rad)
|
||||
double linear_velocity_ms = 6; // 实际线速度(m/s)
|
||||
double angular_velocity_rads = 7; // 实际角速度(rad/s)
|
||||
repeated WheelModuleState modules = 8; // 所有轮 / 舵模块状态
|
||||
bool estop_engaged = 9; // 是否急停
|
||||
uint32 driver_error_code = 10; // 驱动器错误码
|
||||
string active_job_id = 11; // 当前任务 ID
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 通用底盘参数
|
||||
// 作用:不同底盘形式都可能共用的几何 / 补偿参数
|
||||
// =========================================================
|
||||
message CommonChassisCalibrationParams {
|
||||
optional double effective_wheel_base_m = 1; // 有效轴距(m)
|
||||
optional double effective_track_width_m = 2; // 有效轮距(m)
|
||||
optional double longitudinal_scale = 3; // 纵向里程比例补偿
|
||||
optional double lateral_scale = 4; // 横向里程比例补偿
|
||||
optional double yaw_scale = 5; // 航向比例补偿
|
||||
optional double straight_line_bias = 6; // 直线跑偏补偿
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 阿克曼专属参数
|
||||
// 作用:适用于阿克曼车
|
||||
// =========================================================
|
||||
message AckermannCalibrationParams {
|
||||
optional double front_left_steer_zero_offset_deg = 1; // 左前舵角零偏
|
||||
optional double front_right_steer_zero_offset_deg = 2; // 右前舵角零偏
|
||||
optional double rear_left_wheel_radius_m = 3; // 左后轮有效半径
|
||||
optional double rear_right_wheel_radius_m = 4; // 右后轮有效半径
|
||||
optional double steering_ratio = 5; // 转向传动比
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 差速专属参数
|
||||
// 作用:适用于差速 AGV
|
||||
// =========================================================
|
||||
message DifferentialCalibrationParams {
|
||||
optional double left_wheel_radius_m = 1; // 左轮有效半径
|
||||
optional double right_wheel_radius_m = 2; // 右轮有效半径
|
||||
optional double axle_track_width_m = 3; // 驱动轮间距
|
||||
optional double left_encoder_scale = 4; // 左编码器比例系数
|
||||
optional double right_encoder_scale = 5; // 右编码器比例系数
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 单舵轮专属参数
|
||||
// 作用:适用于单舵轮 AGV
|
||||
// =========================================================
|
||||
message SingleSteerWheelCalibrationParams {
|
||||
optional double drive_wheel_radius_m = 1; // 驱动轮有效半径
|
||||
optional double steer_zero_offset_deg = 2; // 舵角零偏
|
||||
optional double steering_ratio = 3; // 转向比
|
||||
optional double drive_encoder_scale = 4; // 驱动编码器比例
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 多舵轮单模块参数
|
||||
// 作用:用于多舵轮车每个模块的独立参数
|
||||
// =========================================================
|
||||
message SteeringModuleCalibrationParam {
|
||||
string module_id = 1; // 模块 ID
|
||||
optional double wheel_radius_m = 2; // 模块轮半径
|
||||
optional double steer_zero_offset_deg = 3; // 模块舵角零偏
|
||||
optional double module_pos_x_m = 4; // 模块在 base_link 下的 X
|
||||
optional double module_pos_y_m = 5; // 模块在 base_link 下的 Y
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 多舵轮专属参数
|
||||
// 作用:适用于多舵轮 AGV
|
||||
// =========================================================
|
||||
message MultiSteerWheelCalibrationParams {
|
||||
repeated SteeringModuleCalibrationParam modules = 1; // 各舵轮模块参数
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 底盘标定参数总包
|
||||
// 作用:统一表达不同底盘类型的标定结果
|
||||
// =========================================================
|
||||
message ChassisCalibrationParameterSet {
|
||||
.agv.calibration.vehicle.profile.ChassisType chassis_type = 1; // 底盘类型
|
||||
CommonChassisCalibrationParams common = 2; // 通用参数
|
||||
|
||||
oneof specific_params {
|
||||
AckermannCalibrationParams ackermann = 3; // 阿克曼参数
|
||||
DifferentialCalibrationParams differential = 4;// 差速参数
|
||||
SingleSteerWheelCalibrationParams single_steer = 5; // 单舵轮参数
|
||||
MultiSteerWheelCalibrationParams multi_steer = 6; // 多舵轮参数
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 写入底盘标定参数请求
|
||||
// 作用:将 Linux 求解结果写入车端
|
||||
// =========================================================
|
||||
message CommitChassisCalibrationParametersRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
string parameter_version = 2; // 参数版本号
|
||||
ChassisCalibrationParameterSet params = 3; // 参数总包
|
||||
string commit_reason = 4; // 写入原因
|
||||
.agv.calibration.common.FileDigest digest = 5; // 参数摘要
|
||||
bool persistent_write = 6; // 是否持久化
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 查询当前已生效底盘参数请求
|
||||
// =========================================================
|
||||
message GetAppliedChassisCalibrationParametersRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 查询当前已生效底盘参数响应
|
||||
// =========================================================
|
||||
message AppliedChassisCalibrationParametersResponse {
|
||||
bool success = 1; // 是否成功
|
||||
.agv.calibration.common.ErrorCode error_code = 2; // 错误码
|
||||
string message = 3; // 说明
|
||||
string parameter_version = 4; // 当前版本
|
||||
ChassisCalibrationParameterSet params = 5; // 当前生效参数
|
||||
int64 applied_timestamp_us = 6; // 生效时间
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 底盘任务结果
|
||||
// 作用:返回底盘动作执行后的分析摘要,供编排器判断是否可进入下一步
|
||||
// =========================================================
|
||||
message ChassisJobResult {
|
||||
bool success = 1; // 是否成功
|
||||
.agv.calibration.common.ErrorCode error_code = 2; // 错误码
|
||||
string message = 3; // 说明
|
||||
string job_id = 4; // 任务 ID
|
||||
bool data_quality_passed = 5; // 数据质量是否达标
|
||||
bool suitable_for_commit = 6; // 是否适合写入参数
|
||||
string recommended_parameter_version = 7; // 推荐参数版本
|
||||
double max_lateral_error_m = 8; // 最大横向误差
|
||||
double max_yaw_error_rad = 9; // 最大航向误差
|
||||
double estimated_straight_line_bias = 10; // 估计的直线跑偏
|
||||
repeated .agv.calibration.common.FileReference artifacts = 11; // 关联产物
|
||||
}
|
||||
@@ -0,0 +1,325 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package agv.calibration.control;
|
||||
|
||||
import "calibration_common.proto";
|
||||
import "vehicle_profile.proto";
|
||||
|
||||
// =========================================================
|
||||
// 文件作用:运控参数调优执行代理协议
|
||||
// 运行关系:
|
||||
// Ubuntu 车间电脑(Linux) -> Windows 车端代理
|
||||
// 说明:
|
||||
// 1) Linux 负责控制参数搜索、收敛判断、验证分析
|
||||
// 2) Windows 负责执行轨迹 / 速度测试并回传遥测
|
||||
// 3) 控制器明确区分为“横向控制器”和“纵向控制器”
|
||||
// =========================================================
|
||||
|
||||
// =========================================================
|
||||
// 服务:运控调参服务
|
||||
// 运行位置:Windows 车端电脑
|
||||
// 调用方:Ubuntu 车间电脑
|
||||
// =========================================================
|
||||
service AgvCalibControlService {
|
||||
// 心跳保活
|
||||
rpc Heartbeat(.agv.calibration.common.HeartbeatRequest)
|
||||
returns (.agv.calibration.common.HeartbeatResponse);
|
||||
|
||||
// 设置调参工作模式
|
||||
rpc SetControlWorkMode(ControlWorkModeRequest)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
|
||||
// 热加载一版控制参数
|
||||
rpc InjectControllerParameters(InjectControllerParametersRequest)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
|
||||
// 启动一个控制评估任务
|
||||
rpc StartControllerEvaluation(ControllerEvaluationRequest)
|
||||
returns (.agv.calibration.common.JobAccepted);
|
||||
|
||||
// 查询控制评估任务状态
|
||||
rpc GetControlJobStatus(.agv.calibration.common.JobQuery)
|
||||
returns (.agv.calibration.common.JobStatus);
|
||||
|
||||
// 查询控制评估任务结果
|
||||
rpc GetControlJobResult(.agv.calibration.common.JobQuery)
|
||||
returns (ControlJobResult);
|
||||
|
||||
// 取消控制评估任务
|
||||
rpc CancelControlJob(.agv.calibration.common.JobQuery)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
|
||||
// 打开控制遥测流
|
||||
rpc StreamControlTelemetry(StreamControlTelemetryRequest)
|
||||
returns (stream ControlTelemetry);
|
||||
|
||||
// 固化最终控制参数
|
||||
rpc CommitControllerParameters(CommitControllerParametersRequest)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
|
||||
// 查询当前已生效控制参数
|
||||
rpc GetActiveControllerParameters(GetActiveControllerParametersRequest)
|
||||
returns (ActiveControllerParametersResponse);
|
||||
|
||||
// 紧急停车
|
||||
rpc EmergencyStop(.agv.calibration.common.Empty)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 运控工作模式
|
||||
// 作用:切换控制系统到调试、评估等状态
|
||||
// =========================================================
|
||||
message ControlWorkModeRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
|
||||
enum Mode {
|
||||
CONTROL_MODE_UNSPECIFIED = 0; // 未指定
|
||||
NORMAL_MODE = 1; // 正常模式
|
||||
TUNING_READY_MODE = 2; // 调参准备模式
|
||||
EVALUATION_MODE = 3; // 参数评估模式
|
||||
VALIDATION_MODE = 4; // 参数验证模式
|
||||
}
|
||||
|
||||
Mode target_mode = 2; // 目标模式
|
||||
string reason = 3; // 切换原因
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// PID 参数
|
||||
// 作用:PID 控制器参数
|
||||
// =========================================================
|
||||
message PIDParams {
|
||||
string loop_name = 1; // 回路名,例如 lateral / heading / speed
|
||||
double kp = 2; // 比例系数
|
||||
double ki = 3; // 积分系数
|
||||
double kd = 4; // 微分系数
|
||||
optional double integral_limit = 5; // 积分限幅
|
||||
optional double output_limit = 6; // 输出限幅
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// MPC 参数
|
||||
// 作用:MPC 控制器参数
|
||||
// =========================================================
|
||||
message MPCParams {
|
||||
uint32 prediction_horizon = 1; // 预测步长
|
||||
uint32 control_horizon = 2; // 控制步长
|
||||
double model_dt_s = 3; // 离散时间步长
|
||||
double q_lateral = 4; // 横向误差权重
|
||||
double q_heading = 5; // 航向误差权重
|
||||
double q_speed = 6; // 速度误差权重
|
||||
double r_control = 7; // 控制输出权重
|
||||
double r_control_rate = 8; // 控制变化率权重
|
||||
optional double output_limit = 9; // 输出限幅
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// LQR 参数
|
||||
// 作用:LQR 控制器参数
|
||||
// =========================================================
|
||||
message LQRParams {
|
||||
repeated double q_state_weights = 1; // 状态权重向量 Q
|
||||
repeated double r_input_weights = 2; // 输入权重向量 R
|
||||
optional double preview_time_s = 3; // 前视时间
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// Pure Pursuit 参数
|
||||
// 作用:Pure Pursuit 控制器参数
|
||||
// =========================================================
|
||||
message PurePursuitParams {
|
||||
double lookahead_m = 1; // 前瞻距离
|
||||
optional double min_lookahead_m = 2; // 最小前瞻距离
|
||||
optional double max_lookahead_m = 3; // 最大前瞻距离
|
||||
optional double curvature_gain = 4; // 曲率增益
|
||||
optional double steering_limit_deg = 5; // 转向限幅
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 单个控制器参数包
|
||||
// 作用:统一表达“某个控制轴上的某个控制器”的参数
|
||||
// 说明:
|
||||
// 1) control_axis 用来明确这是横向控制器还是纵向控制器
|
||||
// 2) algorithm_type 用来明确该控制器采用哪类算法
|
||||
// =========================================================
|
||||
message ControllerParameterPack {
|
||||
.agv.calibration.vehicle.profile.ControlAxisType control_axis = 1; // 控制轴类型
|
||||
.agv.calibration.vehicle.profile.ControllerAlgorithmType algorithm_type = 2; // 算法类型
|
||||
|
||||
oneof params {
|
||||
PIDParams pid = 3; // PID 参数
|
||||
MPCParams mpc = 4; // MPC 参数
|
||||
LQRParams lqr = 5; // LQR 参数
|
||||
PurePursuitParams pure_pursuit = 6; // Pure Pursuit 参数
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 控制参数集合
|
||||
// 作用:一版参数里可以同时包含多个控制器参数
|
||||
// 说明:
|
||||
// 1) 例如可同时包含“横向 MPC + 纵向 PID”
|
||||
// 2) 也可包含“横向 PP + 纵向 PID”
|
||||
// =========================================================
|
||||
message ControllerParameterSet {
|
||||
repeated ControllerParameterPack items = 1; // 参数项列表
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 热注入参数请求
|
||||
// 作用:将 Linux 计算出的一版参数加载到车端运行内存
|
||||
// =========================================================
|
||||
message InjectControllerParametersRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
string parameter_version = 2; // 参数版本号
|
||||
ControllerParameterSet parameter_set = 3; // 参数集合
|
||||
bool apply_immediately = 4; // 是否立即生效
|
||||
string source_iteration_id = 5; // 来源迭代号
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 轨迹点
|
||||
// 作用:控制评估任务中使用的测试轨迹点
|
||||
// =========================================================
|
||||
message TrajectoryPoint {
|
||||
double x_m = 1; // 目标 X
|
||||
double y_m = 2; // 目标 Y
|
||||
double yaw_rad = 3; // 目标偏航角
|
||||
double target_speed_ms = 4; // 目标速度
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 轨迹跟踪评估任务
|
||||
// 作用:让车端按当前控制参数跑一条测试轨迹
|
||||
// =========================================================
|
||||
message TrajectoryTrackingTask {
|
||||
repeated TrajectoryPoint path = 1; // 轨迹点序列
|
||||
bool stop_at_end = 2; // 结束后是否停车
|
||||
double timeout_sec = 3; // 超时时间
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 速度阶跃任务
|
||||
// 作用:用于评估纵向动态响应
|
||||
// =========================================================
|
||||
message VelocityStepTask {
|
||||
double target_velocity_ms = 1; // 目标速度
|
||||
double hold_time_sec = 2; // 保持时长
|
||||
double settle_before_step_sec = 3; // 阶跃前静稳时间
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 控制评估任务请求
|
||||
// 作用:启动一次参数评估任务
|
||||
// 发送方:Ubuntu 车间电脑
|
||||
// 接收方:Windows 车端代理
|
||||
// =========================================================
|
||||
message ControllerEvaluationRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
string test_case_id = 2; // 测试用例 ID
|
||||
|
||||
enum TaskPurpose {
|
||||
CONTROL_TASK_PURPOSE_UNSPECIFIED = 0; // 未指定
|
||||
DATA_COLLECTION = 1; // 数据采集
|
||||
TUNING_EVALUATION = 2; // 调参评估
|
||||
VALIDATION = 3; // 最终验证
|
||||
}
|
||||
|
||||
TaskPurpose task_purpose = 3; // 任务目的
|
||||
|
||||
oneof task {
|
||||
TrajectoryTrackingTask trajectory_tracking = 4; // 轨迹跟踪任务
|
||||
VelocityStepTask velocity_step = 5; // 速度阶跃任务
|
||||
}
|
||||
|
||||
string source_iteration_id = 6; // 来源迭代号
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 控制遥测流请求
|
||||
// 作用:配置遥测频率和内容
|
||||
// =========================================================
|
||||
message StreamControlTelemetryRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
uint32 expected_hz = 2; // 上报频率
|
||||
bool include_tracking_error = 3; // 是否包含跟踪误差
|
||||
bool include_control_output = 4; // 是否包含控制器输出
|
||||
bool include_vehicle_feedback = 5; // 是否包含车辆反馈
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 控制遥测
|
||||
// 作用:回传调参评估时的关键数据
|
||||
// 发送方:Windows 车端代理
|
||||
// 接收方:Ubuntu 车间电脑
|
||||
// =========================================================
|
||||
message ControlTelemetry {
|
||||
int64 hardware_timestamp_us = 1; // 时间戳
|
||||
double odom_x_m = 2; // 位置 X
|
||||
double odom_y_m = 3; // 位置 Y
|
||||
double odom_yaw_rad = 4; // 偏航角
|
||||
double linear_velocity_ms = 5; // 实际线速度
|
||||
double angular_velocity_rads = 6; // 实际角速度
|
||||
|
||||
double lateral_error_m = 7; // 横向误差
|
||||
double heading_error_rad = 8; // 航向误差
|
||||
double speed_error_ms = 9; // 速度误差
|
||||
|
||||
double steering_output = 10; // 横向控制输出
|
||||
double throttle_output = 11; // 纵向驱动输出
|
||||
bool saturation_flag = 12; // 是否发生饱和
|
||||
string active_job_id = 13; // 当前任务 ID
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 固化控制参数请求
|
||||
// 作用:将最终收敛的一版参数写入车端
|
||||
// =========================================================
|
||||
message CommitControllerParametersRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
string parameter_version = 2; // 参数版本号
|
||||
ControllerParameterSet parameter_set = 3; // 参数集合
|
||||
string commit_reason = 4; // 写入原因
|
||||
.agv.calibration.common.FileDigest digest = 5; // 摘要
|
||||
bool persistent_write = 6; // 是否持久化
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 查询当前控制参数请求
|
||||
// =========================================================
|
||||
message GetActiveControllerParametersRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 查询当前控制参数响应
|
||||
// =========================================================
|
||||
message ActiveControllerParametersResponse {
|
||||
bool success = 1; // 是否成功
|
||||
.agv.calibration.common.ErrorCode error_code = 2; // 错误码
|
||||
string message = 3; // 说明
|
||||
string parameter_version = 4; // 当前参数版本
|
||||
ControllerParameterSet parameter_set = 5; // 当前生效参数
|
||||
int64 applied_timestamp_us = 6; // 生效时间
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 控制任务结果
|
||||
// 作用:返回一次调参评估 / 验证后的结果摘要
|
||||
// =========================================================
|
||||
message ControlJobResult {
|
||||
bool success = 1; // 是否成功
|
||||
.agv.calibration.common.ErrorCode error_code = 2; // 错误码
|
||||
string message = 3; // 说明
|
||||
string job_id = 4; // 任务 ID
|
||||
bool data_quality_passed = 5; // 数据质量是否达标
|
||||
bool suitable_for_commit = 6; // 是否适合写入
|
||||
string recommended_parameter_version = 7; // 推荐参数版本
|
||||
double rms_lateral_error_m = 8; // 横向误差均方根
|
||||
double rms_heading_error_rad = 9; // 航向误差均方根
|
||||
double rms_speed_error_ms = 10; // 速度误差均方根
|
||||
double overshoot_ratio = 11; // 超调比例
|
||||
double settle_time_sec = 12; // 收敛时间
|
||||
repeated .agv.calibration.common.FileReference artifacts = 13; // 关联产物
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package agv.calibration.localization.external;
|
||||
|
||||
import "calibration_common.proto";
|
||||
|
||||
// =========================================================
|
||||
// 文件作用:外部定位 / 基准建立执行代理协议
|
||||
// 运行关系:
|
||||
// Ubuntu 车间电脑(Linux) -> Windows 车端代理 / 外部定位桥接服务
|
||||
// 说明:
|
||||
// 1) Linux 负责外部定位基准求解、重复性分析、验证判断
|
||||
// 2) 车端 / 桥接服务只负责采集数据、提供位姿流、执行必要动作
|
||||
// =========================================================
|
||||
|
||||
// =========================================================
|
||||
// 服务:外部定位标定服务
|
||||
// 运行位置:Windows 车端代理 或 Linux 外部定位桥接服务
|
||||
// 调用方:Ubuntu 车间电脑
|
||||
// =========================================================
|
||||
service AgvCalibExternalLocalizationService {
|
||||
// 心跳保活
|
||||
rpc Heartbeat(.agv.calibration.common.HeartbeatRequest)
|
||||
returns (.agv.calibration.common.HeartbeatResponse);
|
||||
|
||||
// 设置外部定位工作模式
|
||||
rpc SetExternalLocalizationWorkMode(ExternalLocalizationWorkModeRequest)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
|
||||
// 查询外部定位能力
|
||||
rpc GetExternalLocalizationCapability(ExternalLocalizationCapabilityRequest)
|
||||
returns (ExternalLocalizationCapabilityResponse);
|
||||
|
||||
// 启动一个外部定位任务
|
||||
rpc StartExternalLocalizationTask(ExternalLocalizationTaskRequest)
|
||||
returns (.agv.calibration.common.JobAccepted);
|
||||
|
||||
// 查询外部定位任务状态
|
||||
rpc GetExternalLocalizationJobStatus(.agv.calibration.common.JobQuery)
|
||||
returns (.agv.calibration.common.JobStatus);
|
||||
|
||||
// 查询外部定位任务结果
|
||||
rpc GetExternalLocalizationJobResult(.agv.calibration.common.JobQuery)
|
||||
returns (ExternalLocalizationJobResult);
|
||||
|
||||
// 取消外部定位任务
|
||||
rpc CancelExternalLocalizationJob(.agv.calibration.common.JobQuery)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
|
||||
// 打开外部定位遥测流
|
||||
rpc StreamExternalLocalizationTelemetry(StreamExternalLocalizationTelemetryRequest)
|
||||
returns (stream ExternalLocalizationTelemetry);
|
||||
|
||||
// 写入外部定位标定结果
|
||||
rpc CommitExternalLocalizationResult(CommitExternalLocalizationResultRequest)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
|
||||
// 查询当前已生效外部定位结果
|
||||
rpc GetAppliedExternalLocalizationResult(GetAppliedExternalLocalizationResultRequest)
|
||||
returns (AppliedExternalLocalizationResultResponse);
|
||||
|
||||
// 紧急停止
|
||||
rpc EmergencyStop(.agv.calibration.common.Empty)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 外部定位工作模式请求
|
||||
// 作用:切换外部定位桥接服务到不同模式
|
||||
// =========================================================
|
||||
message ExternalLocalizationWorkModeRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
|
||||
enum Mode {
|
||||
EXTERNAL_LOCALIZATION_MODE_UNSPECIFIED = 0; // 未指定
|
||||
NORMAL_MODE = 1; // 正常模式
|
||||
CALIBRATION_READY_MODE = 2; // 标定准备模式
|
||||
REFERENCE_COLLECTION_MODE = 3; // 参考数据采集模式
|
||||
VALIDATION_MODE = 4; // 验证模式
|
||||
}
|
||||
|
||||
Mode target_mode = 2; // 目标模式
|
||||
string reason = 3; // 切换原因
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 查询外部定位能力请求
|
||||
// 作用:查询当前工位 / 服务支持的外部定位能力
|
||||
// =========================================================
|
||||
message ExternalLocalizationCapabilityRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 查询外部定位能力响应
|
||||
// 作用:返回当前支持的数据源与功能
|
||||
// =========================================================
|
||||
message ExternalLocalizationCapabilityResponse {
|
||||
bool success = 1; // 是否成功
|
||||
.agv.calibration.common.ErrorCode error_code = 2; // 错误码
|
||||
string message = 3; // 说明
|
||||
bool supports_marker_alignment = 4; // 是否支持基于标靶对齐
|
||||
bool supports_reference_pose_collection = 5; // 是否支持参考位姿采集
|
||||
bool supports_repeatability_validation = 6; // 是否支持重复性验证
|
||||
string localization_source_name = 7; // 外部定位源名称
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 参考位姿采集任务
|
||||
// 作用:采集一批车辆静止位姿用于重复性分析或基准建立
|
||||
// =========================================================
|
||||
message ReferencePoseCollectionTask {
|
||||
uint32 sample_count = 1; // 需要采集的样本数
|
||||
bool require_vehicle_static = 2; // 是否要求车辆静止
|
||||
double timeout_sec = 3; // 超时时间
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 标靶对齐任务
|
||||
// 作用:通过标靶 / 标定板建立外部参考坐标关系
|
||||
// =========================================================
|
||||
message MarkerAlignmentTask {
|
||||
string target_board_id = 1; // 标靶 / 标定板 ID
|
||||
uint32 min_valid_observation_count = 2; // 最少有效观测数
|
||||
double timeout_sec = 3; // 超时时间
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 一致性验证任务
|
||||
// 作用:验证外部定位输出的重复性与稳定性
|
||||
// =========================================================
|
||||
message ConsistencyValidationTask {
|
||||
uint32 sample_count = 1; // 样本数
|
||||
double max_position_stddev_m = 2; // 允许的最大位置标准差
|
||||
double max_yaw_stddev_rad = 3; // 允许的最大航向标准差
|
||||
double timeout_sec = 4; // 超时时间
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 外部定位任务请求
|
||||
// 作用:启动一类外部定位任务
|
||||
// 发送方:Ubuntu 车间电脑
|
||||
// 接收方:Windows 车端代理 / Linux 桥接服务
|
||||
// =========================================================
|
||||
message ExternalLocalizationTaskRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
string test_case_id = 2; // 测试用例 ID
|
||||
|
||||
enum TaskPurpose {
|
||||
EXTERNAL_LOCALIZATION_TASK_PURPOSE_UNSPECIFIED = 0; // 未指定
|
||||
DATA_COLLECTION = 1; // 数据采集
|
||||
SOLVING = 2; // 求解
|
||||
VALIDATION = 3; // 验证
|
||||
}
|
||||
|
||||
TaskPurpose task_purpose = 3; // 任务目的
|
||||
|
||||
oneof task {
|
||||
ReferencePoseCollectionTask reference_pose_collection = 4; // 参考位姿采集
|
||||
MarkerAlignmentTask marker_alignment = 5; // 标靶对齐
|
||||
ConsistencyValidationTask consistency_validation = 6; // 一致性验证
|
||||
}
|
||||
|
||||
string source_iteration_id = 7; // 来源迭代号
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 外部定位遥测流请求
|
||||
// 作用:指定外部定位数据上报内容
|
||||
// =========================================================
|
||||
message StreamExternalLocalizationTelemetryRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
uint32 expected_hz = 2; // 期望上报频率
|
||||
bool include_pose = 3; // 是否包含位姿
|
||||
bool include_quality_metrics = 4; // 是否包含质量指标
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 外部定位遥测
|
||||
// 作用:回传外部定位实时观测结果
|
||||
// 发送方:Windows 车端代理 / Linux 桥接服务
|
||||
// 接收方:Ubuntu 车间电脑
|
||||
// =========================================================
|
||||
message ExternalLocalizationTelemetry {
|
||||
int64 hardware_timestamp_us = 1; // 硬件时间戳
|
||||
bool pose_valid = 2; // 位姿是否有效
|
||||
.agv.calibration.common.Pose3D workshop_pose = 3; // 在车间参考系下的位姿
|
||||
double position_stddev_m = 4; // 位置标准差
|
||||
double yaw_stddev_rad = 5; // 航向标准差
|
||||
uint32 observed_target_count = 6; // 当前观测到的目标数量
|
||||
string reference_source_name = 7; // 外部定位源名称
|
||||
string active_job_id = 8; // 当前任务 ID
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 外部定位标定结果
|
||||
// 作用:表达车间参考系与外部定位参考系之间的结果关系
|
||||
// =========================================================
|
||||
message ExternalLocalizationCalibrationResult {
|
||||
string workshop_frame_id = 1; // 车间参考坐标系 ID
|
||||
string localization_frame_id = 2; // 外部定位坐标系 ID
|
||||
.agv.calibration.common.Pose3D workshop_to_localization = 3; // 车间系到定位系的位姿
|
||||
double position_repeatability_m = 4; // 位置重复性
|
||||
double yaw_repeatability_rad = 5; // 航向重复性
|
||||
double residual_error_m = 6; // 残差位置误差
|
||||
double residual_error_rad = 7; // 残差姿态误差
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 外部定位结果写入请求
|
||||
// 作用:将 Linux 求解出的外部定位结果写入系统
|
||||
// =========================================================
|
||||
message CommitExternalLocalizationResultRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
string parameter_version = 2; // 结果版本号
|
||||
ExternalLocalizationCalibrationResult result = 3; // 外部定位结果
|
||||
string commit_reason = 4; // 写入原因
|
||||
.agv.calibration.common.FileDigest digest = 5; // 摘要
|
||||
bool persistent_write = 6; // 是否持久化
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 查询当前已生效外部定位结果请求
|
||||
// =========================================================
|
||||
message GetAppliedExternalLocalizationResultRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 查询当前已生效外部定位结果响应
|
||||
// =========================================================
|
||||
message AppliedExternalLocalizationResultResponse {
|
||||
bool success = 1; // 是否成功
|
||||
.agv.calibration.common.ErrorCode error_code = 2; // 错误码
|
||||
string message = 3; // 说明
|
||||
string parameter_version = 4; // 当前版本
|
||||
ExternalLocalizationCalibrationResult result = 5; // 当前生效结果
|
||||
int64 applied_timestamp_us = 6; // 生效时间
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 外部定位任务结果
|
||||
// 作用:返回求解 / 验证后的结果摘要,供编排器判断是否进入下一阶段
|
||||
// =========================================================
|
||||
message ExternalLocalizationJobResult {
|
||||
bool success = 1; // 是否成功
|
||||
.agv.calibration.common.ErrorCode error_code = 2; // 错误码
|
||||
string message = 3; // 说明
|
||||
string job_id = 4; // 任务 ID
|
||||
bool data_quality_passed = 5; // 数据质量是否达标
|
||||
bool suitable_for_commit = 6; // 是否适合写入
|
||||
string recommended_parameter_version = 7; // 推荐结果版本号
|
||||
ExternalLocalizationCalibrationResult result = 8; // 结果内容
|
||||
repeated .agv.calibration.common.FileReference artifacts = 9; // 关联产物
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package agv.calibration.sensor;
|
||||
|
||||
import "calibration_common.proto";
|
||||
import "vehicle_profile.proto";
|
||||
|
||||
// =========================================================
|
||||
// 文件作用:传感器标定执行代理协议
|
||||
// 运行关系:
|
||||
// Ubuntu 车间电脑(Linux) -> Windows 车端代理 / 采集服务
|
||||
// 说明:
|
||||
// 1) Linux 负责图像 / 点云 / IMU 数据分析与参数求解
|
||||
// 2) 车端 / 采集服务只负责组织采集、回传观测状态、写入结果
|
||||
// 3) 支持相机内参、IMU 内参、传感器外参、手眼标定
|
||||
// =========================================================
|
||||
|
||||
// =========================================================
|
||||
// 服务:传感器标定服务
|
||||
// 运行位置:Windows 车端代理 或 Linux 采集桥接服务
|
||||
// 调用方:Ubuntu 车间电脑
|
||||
// =========================================================
|
||||
service AgvCalibSensorService {
|
||||
// 心跳保活
|
||||
rpc Heartbeat(.agv.calibration.common.HeartbeatRequest)
|
||||
returns (.agv.calibration.common.HeartbeatResponse);
|
||||
|
||||
// 设置传感器标定工作模式
|
||||
rpc SetSensorCalibrationWorkMode(SensorCalibrationWorkModeRequest)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
|
||||
// 查询传感器标定能力
|
||||
rpc GetSensorCalibrationCapability(SensorCalibrationCapabilityRequest)
|
||||
returns (SensorCalibrationCapabilityResponse);
|
||||
|
||||
// 启动一个传感器标定任务
|
||||
rpc StartSensorCalibrationTask(SensorCalibrationTaskRequest)
|
||||
returns (.agv.calibration.common.JobAccepted);
|
||||
|
||||
// 查询传感器标定任务状态
|
||||
rpc GetSensorCalibrationJobStatus(.agv.calibration.common.JobQuery)
|
||||
returns (.agv.calibration.common.JobStatus);
|
||||
|
||||
// 查询传感器标定任务结果
|
||||
rpc GetSensorCalibrationJobResult(.agv.calibration.common.JobQuery)
|
||||
returns (SensorCalibrationJobResult);
|
||||
|
||||
// 取消传感器标定任务
|
||||
rpc CancelSensorCalibrationJob(.agv.calibration.common.JobQuery)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
|
||||
// 打开传感器标定遥测流
|
||||
rpc StreamSensorCalibrationTelemetry(StreamSensorCalibrationTelemetryRequest)
|
||||
returns (stream SensorCalibrationTelemetry);
|
||||
|
||||
// 写入传感器标定参数
|
||||
rpc CommitSensorCalibrationParameters(CommitSensorCalibrationParametersRequest)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
|
||||
// 查询当前已生效传感器参数
|
||||
rpc GetAppliedSensorCalibrationParameters(GetAppliedSensorCalibrationParametersRequest)
|
||||
returns (AppliedSensorCalibrationParametersResponse);
|
||||
|
||||
// 紧急停止
|
||||
rpc EmergencyStop(.agv.calibration.common.Empty)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 传感器标定工作模式
|
||||
// 作用:切换采集服务到不同模式
|
||||
// =========================================================
|
||||
message SensorCalibrationWorkModeRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
|
||||
enum Mode {
|
||||
SENSOR_CALIBRATION_MODE_UNSPECIFIED = 0; // 未指定
|
||||
NORMAL_MODE = 1; // 正常模式
|
||||
CALIBRATION_READY_MODE = 2; // 标定准备模式
|
||||
DATA_CAPTURE_MODE = 3; // 采集模式
|
||||
VALIDATION_MODE = 4; // 验证模式
|
||||
}
|
||||
|
||||
Mode target_mode = 2; // 目标模式
|
||||
string reason = 3; // 切换原因
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 查询传感器标定能力请求
|
||||
// 作用:查询当前车辆和工位支持的传感器标定能力
|
||||
// =========================================================
|
||||
message SensorCalibrationCapabilityRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 查询传感器标定能力响应
|
||||
// 作用:返回支持的传感器标定类型
|
||||
// =========================================================
|
||||
message SensorCalibrationCapabilityResponse {
|
||||
bool success = 1; // 是否成功
|
||||
.agv.calibration.common.ErrorCode error_code = 2; // 错误码
|
||||
string message = 3; // 说明
|
||||
bool supports_camera_intrinsic = 4; // 是否支持相机内参标定
|
||||
bool supports_imu_intrinsic = 5; // 是否支持 IMU 内参标定
|
||||
bool supports_sensor_to_base_extrinsic = 6; // 是否支持传感器到 base_link 外参
|
||||
bool supports_hand_eye = 7; // 是否支持手眼标定
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 相机内参标定任务
|
||||
// 作用:采集图像并求解相机内参
|
||||
// =========================================================
|
||||
message CameraIntrinsicCalibrationTask {
|
||||
string sensor_id = 1; // 目标相机 ID
|
||||
uint32 required_image_count = 2;// 所需图像数
|
||||
double timeout_sec = 3; // 超时时间
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// IMU 内参标定任务
|
||||
// 作用:采集 IMU 静态 / 动态数据并求解偏置等参数
|
||||
// =========================================================
|
||||
message IMUIntrinsicCalibrationTask {
|
||||
string sensor_id = 1; // 目标 IMU ID
|
||||
uint32 required_static_segment_count = 2; // 静止段数量
|
||||
uint32 required_motion_segment_count = 3; // 运动段数量
|
||||
double timeout_sec = 4; // 超时时间
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 传感器到 base_link 外参标定任务
|
||||
// 作用:求解单个传感器与车辆 base_link 的位姿关系
|
||||
// =========================================================
|
||||
message SensorToBaseExtrinsicCalibrationTask {
|
||||
string sensor_id = 1; // 目标传感器 ID
|
||||
string base_frame_id = 2; // 车辆 base_link / 基准 frame
|
||||
uint32 required_sample_count = 3;// 所需样本数
|
||||
double timeout_sec = 4; // 超时时间
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 手眼标定模式
|
||||
// 作用:区分眼在手上与眼在手外
|
||||
// =========================================================
|
||||
enum HandEyeCalibrationMode {
|
||||
HAND_EYE_CALIBRATION_MODE_UNSPECIFIED = 0; // 未指定
|
||||
EYE_IN_HAND = 1; // 眼在手上
|
||||
EYE_TO_HAND = 2; // 眼在手外
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 手眼标定任务
|
||||
// 作用:求解机械臂相机与机械臂 / 车体的关系
|
||||
// =========================================================
|
||||
message HandEyeCalibrationTask {
|
||||
string sensor_id = 1; // 目标相机 ID
|
||||
string arm_id = 2; // 机械臂 ID
|
||||
HandEyeCalibrationMode mode = 3; // 手眼模式
|
||||
uint32 required_pose_count = 4; // 所需位姿数
|
||||
double timeout_sec = 5; // 超时时间
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 传感器标定任务请求
|
||||
// 作用:启动一次传感器标定任务
|
||||
// 发送方:Ubuntu 车间电脑
|
||||
// 接收方:Windows 车端代理 / Linux 采集服务
|
||||
// =========================================================
|
||||
message SensorCalibrationTaskRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
string test_case_id = 2; // 测试用例 ID
|
||||
|
||||
enum TaskPurpose {
|
||||
SENSOR_TASK_PURPOSE_UNSPECIFIED = 0; // 未指定
|
||||
DATA_COLLECTION = 1; // 数据采集
|
||||
SOLVING = 2; // 求解
|
||||
VALIDATION = 3; // 验证
|
||||
}
|
||||
|
||||
TaskPurpose task_purpose = 3; // 任务目的
|
||||
|
||||
oneof task {
|
||||
CameraIntrinsicCalibrationTask camera_intrinsic = 4; // 相机内参
|
||||
IMUIntrinsicCalibrationTask imu_intrinsic = 5; // IMU 内参
|
||||
SensorToBaseExtrinsicCalibrationTask sensor_to_base_extrinsic = 6; // 外参
|
||||
HandEyeCalibrationTask hand_eye = 7; // 手眼标定
|
||||
}
|
||||
|
||||
string source_iteration_id = 8; // 来源迭代号
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 传感器遥测流请求
|
||||
// 作用:配置传感器标定过程中的状态上报
|
||||
// =========================================================
|
||||
message StreamSensorCalibrationTelemetryRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
uint32 expected_hz = 2; // 期望上报频率
|
||||
bool include_observation_progress = 3; // 是否包含采集进度
|
||||
bool include_quality_metrics = 4; // 是否包含质量指标
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 传感器标定遥测
|
||||
// 作用:回传采集进度、观测质量和任务执行状态
|
||||
// =========================================================
|
||||
message SensorCalibrationTelemetry {
|
||||
int64 hardware_timestamp_us = 1; // 硬件时间戳
|
||||
string sensor_id = 2; // 传感器 ID
|
||||
.agv.calibration.vehicle.profile.SensorType sensor_type = 3; // 传感器类型
|
||||
uint32 collected_sample_count = 4; // 已采集样本数
|
||||
uint32 target_sample_count = 5; // 目标样本数
|
||||
bool target_detected = 6; // 当前是否检测到标定目标
|
||||
double quality_score = 7; // 当前观测质量评分
|
||||
string active_job_id = 8; // 当前任务 ID
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 相机内参
|
||||
// 作用:表达相机标定后的内参结果
|
||||
// =========================================================
|
||||
message CameraIntrinsics {
|
||||
uint32 image_width = 1; // 图像宽度
|
||||
uint32 image_height = 2; // 图像高度
|
||||
double fx = 3; // 焦距 fx
|
||||
double fy = 4; // 焦距 fy
|
||||
double cx = 5; // 主点 cx
|
||||
double cy = 6; // 主点 cy
|
||||
repeated double distortion_coeffs = 7; // 畸变系数
|
||||
string distortion_model = 8; // 畸变模型名称
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// IMU 内参
|
||||
// 作用:表达 IMU 偏置等内参结果
|
||||
// 说明:
|
||||
// 1) accel_bias 为加速度计三轴偏置
|
||||
// 2) gyro_bias 为陀螺仪三轴偏置
|
||||
// =========================================================
|
||||
message IMUIntrinsics {
|
||||
.agv.calibration.common.Vector3D accel_bias = 1; // 加速度计偏置
|
||||
.agv.calibration.common.Vector3D gyro_bias = 2; // 陀螺仪偏置
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 传感器外参
|
||||
// 作用:表达传感器与车辆 base_link 的位姿关系
|
||||
// =========================================================
|
||||
message SensorExtrinsics {
|
||||
string parent_frame_id = 1; // 父坐标系,一般为 base_link
|
||||
string child_frame_id = 2; // 子坐标系,一般为 sensor frame
|
||||
.agv.calibration.common.Pose3D parent_to_child = 3; // 父到子的位姿
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 单个传感器标定参数
|
||||
// 作用:统一表达一个传感器的内参和 / 或外参
|
||||
// =========================================================
|
||||
message SensorCalibrationParameter {
|
||||
string sensor_id = 1; // 传感器 ID
|
||||
.agv.calibration.vehicle.profile.SensorType sensor_type = 2; // 传感器类型
|
||||
CameraIntrinsics camera_intrinsics = 3; // 相机内参;仅相机适用
|
||||
IMUIntrinsics imu_intrinsics = 4; // IMU 内参;仅 IMU 适用
|
||||
SensorExtrinsics extrinsics = 5; // 传感器外参
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 传感器标定参数总包
|
||||
// 作用:统一表达整车所有传感器的标定结果
|
||||
// =========================================================
|
||||
message SensorCalibrationParameterSet {
|
||||
repeated SensorCalibrationParameter items = 1; // 参数项列表
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 写入传感器标定参数请求
|
||||
// 作用:将 Linux 求解出的传感器参数写入系统
|
||||
// =========================================================
|
||||
message CommitSensorCalibrationParametersRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
string parameter_version = 2; // 参数版本号
|
||||
SensorCalibrationParameterSet params = 3; // 参数总包
|
||||
string commit_reason = 4; // 写入原因
|
||||
.agv.calibration.common.FileDigest digest = 5; // 摘要
|
||||
bool persistent_write = 6; // 是否持久化
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 查询当前已生效传感器参数请求
|
||||
// =========================================================
|
||||
message GetAppliedSensorCalibrationParametersRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 查询当前已生效传感器参数响应
|
||||
// =========================================================
|
||||
message AppliedSensorCalibrationParametersResponse {
|
||||
bool success = 1; // 是否成功
|
||||
.agv.calibration.common.ErrorCode error_code = 2; // 错误码
|
||||
string message = 3; // 说明
|
||||
string parameter_version = 4; // 当前版本
|
||||
SensorCalibrationParameterSet params = 5; // 当前生效参数
|
||||
int64 applied_timestamp_us = 6; // 生效时间
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 传感器标定任务结果
|
||||
// 作用:返回某次传感器标定 / 验证的结果摘要
|
||||
// =========================================================
|
||||
message SensorCalibrationJobResult {
|
||||
bool success = 1; // 是否成功
|
||||
.agv.calibration.common.ErrorCode error_code = 2; // 错误码
|
||||
string message = 3; // 说明
|
||||
string job_id = 4; // 任务 ID
|
||||
bool data_quality_passed = 5; // 数据质量是否达标
|
||||
bool suitable_for_commit = 6; // 是否适合写入
|
||||
string recommended_parameter_version = 7; // 推荐参数版本
|
||||
double reprojection_error_px = 8; // 相机类任务的重投影误差
|
||||
double translation_residual_m = 9; // 外参平移残差
|
||||
double rotation_residual_deg = 10; // 外参旋转残差
|
||||
repeated .agv.calibration.common.FileReference artifacts = 11; // 关联产物
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package agv.calibration.vehicle.profile;
|
||||
|
||||
import "calibration_common.proto";
|
||||
|
||||
// =========================================================
|
||||
// 文件作用:车辆画像与能力描述协议
|
||||
// 使用范围:
|
||||
// 1) 车间在开始整车标定前,先描述“要标定的到底是什么车”
|
||||
// 2) 供车间编排器根据车辆画像自动生成执行计划
|
||||
// =========================================================
|
||||
|
||||
// =========================================================
|
||||
// 服务:车辆画像服务
|
||||
// 运行位置:Ubuntu 车间电脑
|
||||
// 调用方:车间编排器、配置界面、专项服务
|
||||
// =========================================================
|
||||
service VehicleProfileService {
|
||||
// 心跳保活
|
||||
rpc Heartbeat(.agv.calibration.common.HeartbeatRequest)
|
||||
returns (.agv.calibration.common.HeartbeatResponse);
|
||||
|
||||
// 注册 / 更新一份车辆画像
|
||||
rpc RegisterOrUpdateVehicleProfile(RegisterOrUpdateVehicleProfileRequest)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
|
||||
// 查询车辆画像
|
||||
rpc GetVehicleProfile(VehicleProfileQuery)
|
||||
returns (VehicleProfileResponse);
|
||||
|
||||
// 评估当前车辆画像支持哪些标定能力
|
||||
rpc EvaluateVehicleCalibrationApplicability(
|
||||
EvaluateVehicleCalibrationApplicabilityRequest)
|
||||
returns (VehicleCalibrationApplicabilityResponse);
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 底盘类型
|
||||
// 作用:描述车辆底盘运动学形式
|
||||
// =========================================================
|
||||
enum ChassisType {
|
||||
CHASSIS_TYPE_UNSPECIFIED = 0; // 未指定
|
||||
ACKERMANN = 1; // 阿克曼
|
||||
DIFFERENTIAL = 2; // 差速
|
||||
SINGLE_STEER_WHEEL = 3; // 单舵轮
|
||||
MULTI_STEER_WHEEL = 4; // 多舵轮
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 传感器类型
|
||||
// 作用:描述车辆上挂载的传感器种类
|
||||
// =========================================================
|
||||
enum SensorType {
|
||||
SENSOR_TYPE_UNSPECIFIED = 0; // 未指定
|
||||
DOWNWARD_CAMERA = 1; // 下视相机
|
||||
FRONT_CAMERA = 2; // 前视相机
|
||||
ARM_CAMERA = 3; // 机械臂相机
|
||||
LIDAR_3D = 4; // 3D 激光雷达
|
||||
LIDAR_2D = 5; // 2D 激光雷达
|
||||
IMU = 6; // IMU
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 相机安装形式
|
||||
// 作用:描述相机与车体 / 机械臂的安装关系
|
||||
// =========================================================
|
||||
enum CameraMountType {
|
||||
CAMERA_MOUNT_TYPE_UNSPECIFIED = 0; // 未指定
|
||||
FIXED_ON_BASE = 1; // 固定在车体上
|
||||
DOWNWARD_MOUNTED = 2; // 下视安装
|
||||
FRONT_MOUNTED = 3; // 前视安装
|
||||
EYE_IN_HAND = 4; // 眼在手上
|
||||
EYE_TO_HAND = 5; // 眼在手外
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 控制器类型
|
||||
// 作用:将控制器分成横向控制器与纵向控制器
|
||||
// =========================================================
|
||||
enum ControlAxisType {
|
||||
CONTROL_AXIS_UNSPECIFIED = 0; // 未指定
|
||||
LATERAL_CONTROL = 1; // 横向控制
|
||||
LONGITUDINAL_CONTROL = 2; // 纵向控制
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 控制算法类型
|
||||
// 作用:描述车辆当前支持的控制算法
|
||||
// =========================================================
|
||||
enum ControllerAlgorithmType {
|
||||
CONTROLLER_ALGORITHM_UNSPECIFIED = 0; // 未指定
|
||||
PID = 1; // PID
|
||||
MPC = 2; // MPC
|
||||
LQR = 3; // LQR
|
||||
PURE_PURSUIT = 4; // Pure Pursuit
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 标定能力类型
|
||||
// 作用:用于编排器判断某个专项是否适用于当前车辆
|
||||
// =========================================================
|
||||
enum CalibrationAbilityType {
|
||||
CALIBRATION_ABILITY_UNSPECIFIED = 0; // 未指定
|
||||
EXTERNAL_LOCALIZATION_CALIBRATION = 1; // 外部定位 / 基准建立
|
||||
CHASSIS_CALIBRATION = 2; // 底盘标定
|
||||
CONTROL_CALIBRATION = 3; // 运控参数标定
|
||||
SENSOR_CALIBRATION = 4; // 传感器标定
|
||||
HAND_EYE_CALIBRATION = 5; // 手眼标定
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 车辆基础信息
|
||||
// 作用:表达车辆身份信息
|
||||
// =========================================================
|
||||
message VehicleBaseInfo {
|
||||
string vehicle_id = 1; // 车辆唯一 ID
|
||||
string vehicle_name = 2; // 车辆显示名
|
||||
string model_name = 3; // 车型 / 型号
|
||||
string serial_number = 4; // 出厂序列号
|
||||
string manufacturer = 5; // 厂商
|
||||
string description = 6; // 备注说明
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 机械臂画像
|
||||
// 作用:描述车辆是否带机械臂以及机械臂的基本信息
|
||||
// =========================================================
|
||||
message MechanicalArmProfile {
|
||||
bool has_mechanical_arm = 1; // 是否带机械臂
|
||||
string arm_id = 2; // 机械臂 ID
|
||||
string arm_model = 3; // 机械臂型号
|
||||
uint32 dof = 4; // 自由度
|
||||
string arm_base_frame = 5; // 机械臂基座坐标系
|
||||
string tool_frame = 6; // 末端工具坐标系
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 传感器画像
|
||||
// 作用:描述单个传感器的安装与参与标定属性
|
||||
// =========================================================
|
||||
message SensorProfile {
|
||||
string sensor_id = 1; // 传感器 ID
|
||||
SensorType sensor_type = 2; // 传感器类型
|
||||
string sensor_name = 3; // 传感器显示名
|
||||
string frame_id = 4; // 传感器 frame_id
|
||||
CameraMountType camera_mount_type = 5;// 相机安装形式;非相机可忽略
|
||||
bool enabled = 6; // 当前是否启用
|
||||
bool needs_intrinsic_calibration = 7; // 是否需要做内参标定
|
||||
bool needs_extrinsic_calibration = 8; // 是否需要做外参标定
|
||||
string device_hint = 9; // 设备名 / topic / IP / 端口等提示信息
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 控制器画像
|
||||
// 作用:描述某一控制轴支持的算法集合
|
||||
// =========================================================
|
||||
message ControllerProfile {
|
||||
ControlAxisType control_axis = 1; // 控制轴类型
|
||||
repeated ControllerAlgorithmType supported_algorithms = 2; // 支持的算法列表
|
||||
ControllerAlgorithmType default_algorithm = 3; // 默认算法
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 标定能力项
|
||||
// 作用:表达当前车辆是否支持某项标定
|
||||
// =========================================================
|
||||
message CalibrationCapability {
|
||||
CalibrationAbilityType ability_type = 1; // 标定能力类型
|
||||
bool supported = 2; // 是否支持
|
||||
string message = 3; // 说明文字
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 车辆画像总包
|
||||
// 作用:统一表达待标定车辆的全部静态配置
|
||||
// 发送方:配置界面 / 车间系统
|
||||
// 接收方:车间编排器 / 各专项服务
|
||||
// =========================================================
|
||||
message VehicleProfile {
|
||||
VehicleBaseInfo base_info = 1; // 车辆基础信息
|
||||
ChassisType chassis_type = 2; // 底盘类型
|
||||
MechanicalArmProfile arm_profile = 3; // 机械臂画像
|
||||
repeated SensorProfile sensors = 4; // 所有传感器画像
|
||||
repeated ControllerProfile controllers = 5; // 控制器画像
|
||||
.agv.calibration.common.FileReference urdf_file = 6; // 车辆 URDF 文件引用
|
||||
string base_link_frame = 7; // 车辆 base_link 名称
|
||||
repeated CalibrationCapability capabilities = 8; // 标定能力清单
|
||||
repeated .agv.calibration.common.KeyValuePair metadata = 9; // 扩展元数据
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 注册 / 更新车辆画像请求
|
||||
// 作用:向系统写入一份车辆画像
|
||||
// =========================================================
|
||||
message RegisterOrUpdateVehicleProfileRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
VehicleProfile profile = 2; // 车辆画像
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 车辆画像查询请求
|
||||
// 作用:按 vehicle_id 查询车辆画像
|
||||
// =========================================================
|
||||
message VehicleProfileQuery {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
string vehicle_id = 2; // 车辆 ID
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 车辆画像查询响应
|
||||
// 作用:返回完整车辆画像
|
||||
// =========================================================
|
||||
message VehicleProfileResponse {
|
||||
bool success = 1; // 是否成功
|
||||
.agv.calibration.common.ErrorCode error_code = 2; // 错误码
|
||||
string message = 3; // 说明
|
||||
VehicleProfile profile = 4; // 车辆画像
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 标定适用性评估请求
|
||||
// 作用:根据车辆画像分析能否执行各项标定
|
||||
// =========================================================
|
||||
message EvaluateVehicleCalibrationApplicabilityRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
VehicleProfile profile_snapshot = 2; // 车辆画像快照
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 适用性问题
|
||||
// 作用:描述不支持 / 风险 / 缺失项
|
||||
// =========================================================
|
||||
message ApplicabilityIssue {
|
||||
CalibrationAbilityType ability_type = 1; // 对应能力
|
||||
bool blocking = 2; // 是否为阻塞问题
|
||||
string message = 3; // 问题说明
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 标定适用性评估响应
|
||||
// 作用:返回支持项与阻塞项,供编排器生成计划
|
||||
// =========================================================
|
||||
message VehicleCalibrationApplicabilityResponse {
|
||||
bool success = 1; // 是否成功
|
||||
.agv.calibration.common.ErrorCode error_code = 2; // 错误码
|
||||
string message = 3; // 说明
|
||||
repeated CalibrationCapability capabilities = 4; // 支持能力列表
|
||||
repeated ApplicabilityIssue issues = 5; // 问题列表
|
||||
bool overall_supported = 6; // 是否总体可开展标定
|
||||
}
|
||||
@@ -0,0 +1,475 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package agv.calibration.workshop;
|
||||
|
||||
import "calibration_common.proto";
|
||||
import "vehicle_profile.proto";
|
||||
|
||||
// =========================================================
|
||||
// 文件作用:自动化标定车间总编排协议
|
||||
// 使用范围:
|
||||
// 1) 负责整车标定会话的创建、规划、执行、暂停、恢复、取消
|
||||
// 2) 负责人工确认节点、审批节点、回滚、报告归档
|
||||
// 3) 负责把外部定位 / 底盘 / 运控 / 传感器标定串成完整闭环
|
||||
// =========================================================
|
||||
|
||||
// =========================================================
|
||||
// 服务:车间总编排服务
|
||||
// 运行位置:Ubuntu 车间电脑
|
||||
// 调用方:上位机界面、自动化车间入口程序
|
||||
// =========================================================
|
||||
service WorkshopOrchestrationService {
|
||||
// 心跳保活
|
||||
rpc Heartbeat(.agv.calibration.common.HeartbeatRequest)
|
||||
returns (.agv.calibration.common.HeartbeatResponse);
|
||||
|
||||
// 创建一场新的整车标定会话
|
||||
rpc CreateWorkshopSession(CreateWorkshopSessionRequest)
|
||||
returns (CreateWorkshopSessionResponse);
|
||||
|
||||
// 查询会话信息
|
||||
rpc GetWorkshopSession(WorkshopSessionQuery)
|
||||
returns (WorkshopSessionResponse);
|
||||
|
||||
// 生成本次会话的执行计划
|
||||
rpc BuildExecutionPlan(BuildExecutionPlanRequest)
|
||||
returns (BuildExecutionPlanResponse);
|
||||
|
||||
// 执行车间预检 / readiness 检查
|
||||
rpc RunWorkshopPrecheck(RunWorkshopPrecheckRequest)
|
||||
returns (.agv.calibration.common.JobAccepted);
|
||||
|
||||
// 查询最近一次预检结果
|
||||
rpc GetLastWorkshopPrecheckResult(WorkshopSessionQuery)
|
||||
returns (WorkshopPrecheckResponse);
|
||||
|
||||
// 启动整场自动化标定
|
||||
rpc StartWorkshopSession(StartWorkshopSessionRequest)
|
||||
returns (.agv.calibration.common.JobAccepted);
|
||||
|
||||
// 查询整场会话对应长任务状态
|
||||
rpc GetWorkshopJobStatus(.agv.calibration.common.JobQuery)
|
||||
returns (.agv.calibration.common.JobStatus);
|
||||
|
||||
// 暂停整场会话
|
||||
rpc PauseWorkshopSession(PauseWorkshopSessionRequest)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
|
||||
// 恢复整场会话
|
||||
rpc ResumeWorkshopSession(ResumeWorkshopSessionRequest)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
|
||||
// 取消整场会话
|
||||
rpc CancelWorkshopSession(CancelWorkshopSessionRequest)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
|
||||
// 打开会话事件流
|
||||
rpc StreamWorkshopEvent(WorkshopSessionQuery)
|
||||
returns (stream WorkshopEvent);
|
||||
|
||||
// 人工确认某个等待中的手动步骤
|
||||
rpc AcknowledgeManualStep(ManualStepAckRequest)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
|
||||
// 审批某个阶段的结果
|
||||
rpc ApproveStageResult(ApproveStageResultRequest)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
|
||||
// 对某阶段参数进行回滚
|
||||
rpc RollbackStageParameters(RollbackStageParametersRequest)
|
||||
returns (.agv.calibration.common.StandardResponse);
|
||||
|
||||
// 获取最终车间报告
|
||||
rpc GetWorkshopReport(WorkshopSessionQuery)
|
||||
returns (WorkshopReportResponse);
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 会话状态
|
||||
// 作用:描述整场整车标定会话当前所处阶段
|
||||
// =========================================================
|
||||
enum WorkshopSessionState {
|
||||
WORKSHOP_SESSION_STATE_UNSPECIFIED = 0; // 未指定
|
||||
DRAFT = 1; // 草稿,尚未规划
|
||||
PLANNING = 2; // 正在规划
|
||||
READY = 3; // 已规划完成,可启动
|
||||
RUNNING = 4; // 运行中
|
||||
PAUSED = 5; // 已暂停
|
||||
WAITING_MANUAL_ACTION = 6; // 等待人工动作
|
||||
WAITING_APPROVAL = 7; // 等待审批
|
||||
SUCCEEDED = 8; // 整场成功
|
||||
FAILED = 9; // 整场失败
|
||||
CANCELED = 10; // 已取消
|
||||
ROLLED_BACK = 11; // 已回滚
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 车间阶段类型
|
||||
// 作用:描述执行计划中的阶段类别
|
||||
// =========================================================
|
||||
enum WorkshopStageType {
|
||||
WORKSHOP_STAGE_TYPE_UNSPECIFIED = 0; // 未指定
|
||||
STAGE_EXTERNAL_LOCALIZATION = 1; // 外部定位 / 基准建立阶段
|
||||
STAGE_CHASSIS_CALIBRATION = 2; // 底盘标定阶段
|
||||
STAGE_CONTROL_CALIBRATION = 3; // 运控参数标定阶段
|
||||
STAGE_SENSOR_CALIBRATION = 4; // 传感器标定阶段
|
||||
STAGE_VALIDATION = 5; // 验证复测阶段
|
||||
STAGE_MANUAL_CHECK = 6; // 人工检查 / 人工放置 / 人工确认阶段
|
||||
STAGE_REPORT_FINALIZATION = 7; // 报告归档阶段
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 阶段执行策略
|
||||
// 作用:控制某个阶段失败时系统该如何处理
|
||||
// =========================================================
|
||||
enum StageExecutionPolicy {
|
||||
STAGE_EXECUTION_POLICY_UNSPECIFIED = 0; // 未指定
|
||||
REQUIRED = 1; // 必须执行,失败即整场失败
|
||||
OPTIONAL = 2; // 可选执行,失败后可继续
|
||||
SKIP_IF_UNSUPPORTED = 3; // 若车辆不支持则自动跳过
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 审批状态
|
||||
// 作用:描述某一阶段结果是否需要人工审核
|
||||
// =========================================================
|
||||
enum ApprovalState {
|
||||
APPROVAL_STATE_UNSPECIFIED = 0; // 未指定
|
||||
APPROVAL_NOT_REQUIRED = 1; // 不需要审批
|
||||
APPROVAL_PENDING = 2; // 待审批
|
||||
APPROVED = 3; // 已通过
|
||||
REJECTED = 4; // 已拒绝
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 人工动作类型
|
||||
// 作用:表达需要人工介入的节点类型
|
||||
// =========================================================
|
||||
enum ManualActionType {
|
||||
MANUAL_ACTION_TYPE_UNSPECIFIED = 0; // 未指定
|
||||
PLACE_TARGET_BOARD = 1; // 放置标靶 / 标定板
|
||||
CONFIRM_WORKCELL_CLEAR = 2; // 确认工位区域安全
|
||||
CONFIRM_VEHICLE_POSE = 3; // 确认车辆姿态已就位
|
||||
CONFIRM_ARM_HOME = 4; // 确认机械臂已回零
|
||||
CONFIRM_SENSOR_INSTALLATION = 5; // 确认传感器安装状态
|
||||
CONFIRM_READY_TO_CONTINUE = 6; // 确认可继续执行
|
||||
OTHER_MANUAL_ACTION = 7; // 其他人工动作
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 车间事件类型
|
||||
// 作用:用于异步通知界面 / 上层系统
|
||||
// =========================================================
|
||||
enum WorkshopEventType {
|
||||
WORKSHOP_EVENT_TYPE_UNSPECIFIED = 0; // 未指定
|
||||
SESSION_STATE_CHANGED = 1; // 会话状态变化
|
||||
STAGE_STARTED = 2; // 阶段开始
|
||||
STAGE_COMPLETED = 3; // 阶段完成
|
||||
STAGE_FAILED = 4; // 阶段失败
|
||||
MANUAL_ACTION_REQUIRED = 5; // 需要人工操作
|
||||
APPROVAL_REQUIRED = 6; // 需要审批
|
||||
SAFETY_TRIGGERED = 7; // 安全保护触发
|
||||
REPORT_READY = 8; // 报告已生成
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 操作员信息
|
||||
// 作用:记录本次会话的人工责任归属
|
||||
// =========================================================
|
||||
message WorkshopOperatorInfo {
|
||||
string operator_id = 1; // 操作员工号
|
||||
string operator_name = 2; // 操作员姓名
|
||||
string workstation_id = 3;// 工位 ID
|
||||
string shift_id = 4; // 班次 ID
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 单项标定任务配置
|
||||
// 作用:表达本次会话中某类专项是否启用
|
||||
// =========================================================
|
||||
message RequestedCalibrationTask {
|
||||
WorkshopStageType stage_type = 1; // 阶段类型
|
||||
bool enabled = 2; // 是否启用
|
||||
bool require_manual_approval = 3; // 是否要求人工审批
|
||||
string reason = 4; // 启用 / 禁用原因
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 会话配置
|
||||
// 作用:描述整场自动化标定运行策略
|
||||
// =========================================================
|
||||
message WorkshopSessionConfig {
|
||||
repeated RequestedCalibrationTask requested_tasks = 1; // 请求执行的专项列表
|
||||
bool auto_commit_parameters = 2; // 是否自动写入参数
|
||||
bool require_manual_approval_before_commit = 3; // 写入前是否要求审批
|
||||
bool run_validation_after_each_stage = 4; // 每阶段后是否自动复测
|
||||
bool stop_on_first_failure = 5; // 是否首错即停
|
||||
bool allow_optional_stage_skip = 6; // 是否允许可选阶段跳过
|
||||
bool enable_auto_rollback_on_validation_failure = 7; // 验证失败是否自动回滚
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 阶段计划
|
||||
// 作用:描述车间编排器生成的一步执行计划
|
||||
// =========================================================
|
||||
message StagePlan {
|
||||
string stage_id = 1; // 阶段 ID
|
||||
WorkshopStageType stage_type = 2; // 阶段类型
|
||||
string display_name = 3; // 阶段显示名
|
||||
uint32 order_index = 4; // 阶段顺序号
|
||||
StageExecutionPolicy execution_policy = 5; // 执行策略
|
||||
repeated string depends_on_stage_ids = 6; // 依赖的前置阶段 ID
|
||||
bool requires_manual_confirmation_before_start = 7; // 开始前是否要求人工确认
|
||||
bool requires_approval_before_commit = 8; // 参数提交前是否要求审批
|
||||
ManualActionType manual_action_type = 9; // 若为人工阶段,对应的人工动作类型
|
||||
string executor_service_name = 10; // 实际执行的服务名
|
||||
string description = 11; // 阶段说明
|
||||
uint32 retry_limit = 12; // 最大重试次数
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 车间会话
|
||||
// 作用:统一表达整场标定会话的核心状态
|
||||
// =========================================================
|
||||
message WorkshopSession {
|
||||
string session_id = 1; // 会话 ID
|
||||
WorkshopSessionState state = 2; // 会话状态
|
||||
.agv.calibration.vehicle.profile.VehicleProfile vehicle_profile_snapshot = 3; // 车辆画像快照
|
||||
WorkshopOperatorInfo operator_info = 4; // 操作员信息
|
||||
WorkshopSessionConfig config = 5; // 会话配置
|
||||
repeated StagePlan stage_plan = 6; // 阶段计划
|
||||
int64 created_timestamp_us = 7; // 创建时间
|
||||
int64 updated_timestamp_us = 8; // 最近更新时间
|
||||
string active_stage_id = 9; // 当前活跃阶段 ID
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 创建会话请求
|
||||
// 作用:创建一场新的整车标定会话
|
||||
// =========================================================
|
||||
message CreateWorkshopSessionRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
.agv.calibration.vehicle.profile.VehicleProfile vehicle_profile_snapshot = 2; // 车辆画像快照
|
||||
WorkshopOperatorInfo operator_info = 3; // 操作员信息
|
||||
WorkshopSessionConfig config = 4; // 会话配置
|
||||
string workshop_line_id = 5; // 产线 / 工位线 ID
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 创建会话响应
|
||||
// 作用:返回新建会话结果
|
||||
// =========================================================
|
||||
message CreateWorkshopSessionResponse {
|
||||
bool success = 1; // 是否成功
|
||||
.agv.calibration.common.ErrorCode error_code = 2; // 错误码
|
||||
string message = 3; // 说明
|
||||
string session_id = 4; // 新建会话 ID
|
||||
WorkshopSessionState state = 5; // 初始状态
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 会话查询请求
|
||||
// 作用:按 session_id 查询会话
|
||||
// =========================================================
|
||||
message WorkshopSessionQuery {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
string session_id = 2; // 会话 ID
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 会话查询响应
|
||||
// 作用:返回整场会话信息
|
||||
// =========================================================
|
||||
message WorkshopSessionResponse {
|
||||
bool success = 1; // 是否成功
|
||||
.agv.calibration.common.ErrorCode error_code = 2; // 错误码
|
||||
string message = 3; // 说明
|
||||
WorkshopSession session = 4; // 会话详情
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 生成执行计划请求
|
||||
// 作用:根据车辆画像与配置生成阶段计划
|
||||
// =========================================================
|
||||
message BuildExecutionPlanRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
string session_id = 2; // 会话 ID
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 生成执行计划响应
|
||||
// 作用:返回生成后的阶段计划
|
||||
// =========================================================
|
||||
message BuildExecutionPlanResponse {
|
||||
bool success = 1; // 是否成功
|
||||
.agv.calibration.common.ErrorCode error_code = 2; // 错误码
|
||||
string message = 3; // 说明
|
||||
repeated StagePlan stage_plan = 4; // 阶段计划
|
||||
repeated string warnings = 5; // 警告信息
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 车间预检请求
|
||||
// 作用:在正式启动前检查车辆、工位、服务、传感器、资源锁等是否就绪
|
||||
// =========================================================
|
||||
message RunWorkshopPrecheckRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
string session_id = 2; // 会话 ID
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 单个预检项
|
||||
// 作用:表达一条 readiness / 安全 / 资源检查结果
|
||||
// =========================================================
|
||||
message PrecheckItem {
|
||||
string item_code = 1; // 检查项编码
|
||||
string display_name = 2; // 检查项名称
|
||||
bool passed = 3; // 是否通过
|
||||
bool blocking = 4; // 是否为阻塞项
|
||||
.agv.calibration.common.ErrorCode error_code = 5; // 错误码
|
||||
string message = 6; // 结果说明
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 车间预检结果
|
||||
// 作用:返回最近一次预检详细结果
|
||||
// =========================================================
|
||||
message WorkshopPrecheckResponse {
|
||||
bool success = 1; // 是否成功
|
||||
.agv.calibration.common.ErrorCode error_code = 2; // 错误码
|
||||
string message = 3; // 说明
|
||||
bool all_passed = 4; // 是否全部通过
|
||||
repeated PrecheckItem items = 5; // 检查项明细
|
||||
int64 checked_timestamp_us = 6; // 检查时间
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 启动会话请求
|
||||
// 作用:正式启动整场自动化标定
|
||||
// =========================================================
|
||||
message StartWorkshopSessionRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
string session_id = 2; // 会话 ID
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 暂停会话请求
|
||||
// 作用:暂停整场标定
|
||||
// =========================================================
|
||||
message PauseWorkshopSessionRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
string session_id = 2; // 会话 ID
|
||||
string reason = 3; // 暂停原因
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 恢复会话请求
|
||||
// 作用:从暂停态恢复整场标定
|
||||
// =========================================================
|
||||
message ResumeWorkshopSessionRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
string session_id = 2; // 会话 ID
|
||||
string reason = 3; // 恢复原因
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 取消会话请求
|
||||
// 作用:终止整场标定
|
||||
// =========================================================
|
||||
message CancelWorkshopSessionRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
string session_id = 2; // 会话 ID
|
||||
string reason = 3; // 取消原因
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 车间事件
|
||||
// 作用:向界面 / 上层系统异步推送状态变化
|
||||
// =========================================================
|
||||
message WorkshopEvent {
|
||||
int64 server_timestamp_us = 1; // 服务端时间戳
|
||||
string session_id = 2; // 会话 ID
|
||||
string stage_id = 3; // 阶段 ID
|
||||
WorkshopEventType event_type = 4; // 事件类型
|
||||
WorkshopSessionState session_state = 5; // 当前会话状态
|
||||
.agv.calibration.common.JobState stage_job_state = 6; // 当前阶段任务状态
|
||||
bool requires_manual_ack = 7; // 是否需要人工确认
|
||||
string message = 8; // 事件说明
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 人工步骤确认请求
|
||||
// 作用:当系统停在人工步骤时,由操作员确认完成
|
||||
// =========================================================
|
||||
message ManualStepAckRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
string session_id = 2; // 会话 ID
|
||||
string stage_id = 3; // 阶段 ID
|
||||
bool confirmed = 4; // 是否确认完成
|
||||
string note = 5; // 备注
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 阶段结果审批请求
|
||||
// 作用:对某阶段结果进行通过 / 驳回
|
||||
// =========================================================
|
||||
message ApproveStageResultRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
string session_id = 2; // 会话 ID
|
||||
string stage_id = 3; // 阶段 ID
|
||||
ApprovalState decision = 4; // 审批结论
|
||||
string reviewer_id = 5; // 审批人 ID
|
||||
string comment = 6; // 审批说明
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 参数回滚请求
|
||||
// 作用:对某阶段参数回滚到指定版本
|
||||
// =========================================================
|
||||
message RollbackStageParametersRequest {
|
||||
.agv.calibration.common.RequestHeader header = 1; // 请求头
|
||||
string session_id = 2; // 会话 ID
|
||||
string stage_id = 3; // 阶段 ID
|
||||
string target_parameter_version = 4; // 回滚目标版本
|
||||
string reason = 5; // 回滚原因
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 阶段结果摘要
|
||||
// 作用:用于最终报告中概述每个阶段的结果
|
||||
// =========================================================
|
||||
message StageResultSummary {
|
||||
string stage_id = 1; // 阶段 ID
|
||||
WorkshopStageType stage_type = 2; // 阶段类型
|
||||
bool success = 3; // 是否成功
|
||||
.agv.calibration.common.JobState final_job_state = 4; // 最终任务状态
|
||||
ApprovalState approval_state = 5; // 审批状态
|
||||
string parameter_version = 6; // 该阶段产出的参数版本
|
||||
repeated .agv.calibration.common.FileReference artifacts = 7; // 关联产物
|
||||
string summary = 8; // 摘要说明
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 车间最终报告
|
||||
// 作用:归档整场会话的总体结果与所有阶段结果
|
||||
// =========================================================
|
||||
message WorkshopReport {
|
||||
string session_id = 1; // 会话 ID
|
||||
bool overall_success = 2; // 是否总体成功
|
||||
int64 started_timestamp_us = 3; // 开始时间
|
||||
int64 finished_timestamp_us = 4; // 结束时间
|
||||
repeated StageResultSummary stage_results = 5; // 各阶段结果
|
||||
repeated .agv.calibration.common.FileReference report_files = 6; // 报告文件
|
||||
string summary = 7; // 总结说明
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// 车间报告响应
|
||||
// 作用:返回最终归档报告
|
||||
// =========================================================
|
||||
message WorkshopReportResponse {
|
||||
bool success = 1; // 是否成功
|
||||
.agv.calibration.common.ErrorCode error_code = 2; // 错误码
|
||||
string message = 3; // 说明
|
||||
WorkshopReport report = 4; // 报告内容
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
string task_id
|
||||
win_ubuntu_bridge/CameraIntrinsic[] updated_intrinsics
|
||||
win_ubuntu_bridge/SensorExtrinsic[] updated_extrinsics
|
||||
---
|
||||
bool success
|
||||
string message
|
||||
@@ -1,26 +0,0 @@
|
||||
bool has_wheel_radius_fl
|
||||
float64 wheel_radius_fl_m
|
||||
bool has_wheel_radius_fr
|
||||
float64 wheel_radius_fr_m
|
||||
bool has_wheel_radius_rl
|
||||
float64 wheel_radius_rl_m
|
||||
bool has_wheel_radius_rr
|
||||
float64 wheel_radius_rr_m
|
||||
|
||||
bool has_steer_zero_offset_front
|
||||
float64 steer_zero_offset_front_deg
|
||||
bool has_steer_zero_offset_rear
|
||||
float64 steer_zero_offset_rear_deg
|
||||
|
||||
bool has_effective_track_width
|
||||
float64 effective_track_width_m
|
||||
bool has_effective_wheel_base
|
||||
float64 effective_wheel_base_m
|
||||
|
||||
bool has_icr_offset_x
|
||||
float64 icr_offset_x_m
|
||||
bool has_icr_offset_y
|
||||
float64 icr_offset_y_m
|
||||
---
|
||||
bool success
|
||||
string message
|
||||
@@ -1,7 +0,0 @@
|
||||
float64 left_motor_cmd
|
||||
float64 right_motor_cmd
|
||||
float64 steering_angle
|
||||
float64 duration_sec
|
||||
---
|
||||
bool success
|
||||
string message
|
||||
@@ -1,9 +0,0 @@
|
||||
string test_case_id
|
||||
float64 fl_motor_rpm
|
||||
float64 fr_motor_rpm
|
||||
float64 rl_motor_rpm
|
||||
float64 rr_motor_rpm
|
||||
float64 duration_sec
|
||||
---
|
||||
bool success
|
||||
string message
|
||||
@@ -1,10 +0,0 @@
|
||||
string test_case_id
|
||||
float64 front_steer_angle_deg
|
||||
float64 rear_steer_angle_deg
|
||||
bool has_sweep
|
||||
float64 sweep_amplitude_deg
|
||||
float64 sweep_frequency_hz
|
||||
float64 duration_sec
|
||||
---
|
||||
bool success
|
||||
string message
|
||||
@@ -1,5 +0,0 @@
|
||||
float64 target_velocity_ms
|
||||
float64 duration_sec
|
||||
---
|
||||
bool success
|
||||
string message
|
||||
@@ -1,5 +0,0 @@
|
||||
string test_case_id
|
||||
win_ubuntu_bridge/TrajectoryPoint[] path
|
||||
---
|
||||
bool success
|
||||
string message
|
||||
@@ -0,0 +1,24 @@
|
||||
# =========================================================
|
||||
# 文件作用:心跳服务
|
||||
# 对应 proto:HeartbeatRequest + HeartbeatResponse
|
||||
# 作用:保持 Linux 与 Windows 车端代理 / Linux 子服务之间的在线状态
|
||||
# 调用方:Ubuntu 车间电脑 或 上位服务
|
||||
# 服务方:Windows 车端代理 / Linux 子服务
|
||||
# =========================================================
|
||||
|
||||
# =========================
|
||||
# 请求部分
|
||||
# =========================
|
||||
RequestHeader header # 请求头
|
||||
string agent_name # 服务名 / 代理名
|
||||
int32 expect_next_heartbeat_ms # 下次期望心跳间隔(ms)
|
||||
|
||||
---
|
||||
# =========================
|
||||
# 响应部分
|
||||
# =========================
|
||||
bool success # 是否正常
|
||||
uint16 error_code # 错误码,取值参考 ErrorCode.msg
|
||||
string message # 说明文字
|
||||
int64 server_timestamp_us # 响应时间戳
|
||||
bool vehicle_ready # 车辆 / 服务是否准备好接任务
|
||||
@@ -1,32 +0,0 @@
|
||||
bool has_wheel_radius_left_ratio
|
||||
float64 wheel_radius_left_ratio
|
||||
bool has_wheel_radius_right_ratio
|
||||
float64 wheel_radius_right_ratio
|
||||
bool has_effective_track_width_m
|
||||
float64 effective_track_width_m
|
||||
bool has_steering_zero_offset_deg
|
||||
float64 steering_zero_offset_deg
|
||||
|
||||
bool has_pid_kp_lateral
|
||||
float64 pid_kp_lateral
|
||||
bool has_pid_ki_lateral
|
||||
float64 pid_ki_lateral
|
||||
bool has_pid_kd_lateral
|
||||
float64 pid_kd_lateral
|
||||
|
||||
bool has_pid_kp_heading
|
||||
float64 pid_kp_heading
|
||||
bool has_pid_ki_heading
|
||||
float64 pid_ki_heading
|
||||
bool has_pid_kd_heading
|
||||
float64 pid_kd_heading
|
||||
|
||||
bool has_pure_pursuit_lookahead_m
|
||||
float64 pure_pursuit_lookahead_m
|
||||
bool has_mpc_weight_q_lateral
|
||||
float64 mpc_weight_q_lateral
|
||||
bool has_mpc_weight_r_steering
|
||||
float64 mpc_weight_r_steering
|
||||
---
|
||||
bool success
|
||||
string message
|
||||
@@ -1,7 +0,0 @@
|
||||
float64 target_x_m
|
||||
float64 target_y_m
|
||||
float64 target_yaw_deg
|
||||
bool is_relative
|
||||
---
|
||||
bool success
|
||||
string message
|
||||
@@ -1,4 +0,0 @@
|
||||
uint8 target_mode # 0: NORMAL, 1: OPEN_LOOP, 2: TUNING_MODE
|
||||
---
|
||||
bool success
|
||||
string message
|
||||
@@ -1,4 +0,0 @@
|
||||
uint8 target_mode # 0: NORMAL_KINEMATICS, 1: DIRECT_RAW_DRIVE
|
||||
---
|
||||
bool success
|
||||
string message
|
||||
@@ -1,5 +0,0 @@
|
||||
string[] sensor_ids
|
||||
---
|
||||
bool success
|
||||
int64 capture_timestamp_us # 🚨 极其关键的“取件码”
|
||||
string error_message
|
||||
+12554
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user