feat: developing.........

This commit is contained in:
li-shihao-code
2026-03-10 13:26:14 +08:00
parent 01960271f7
commit efc644a77d
46 changed files with 16331 additions and 748 deletions
@@ -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 @@
# =========================================================
# 文件作用:统一错误码定义
# 对应 protoErrorCode
# 说明:
# 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 @@
# =========================================================
# 文件作用:文件摘要
# 对应 protoFileDigest
# 作用:用于参数包、URDF、数据文件校验
# =========================================================
string checksum_type # 摘要算法,例如 sha256
string checksum_value # 摘要值
@@ -0,0 +1,11 @@
# =========================================================
# 文件作用:文件引用
# 对应 protoFileReference
# 作用:用于报告、参数包、数据集、日志包等产物追溯
# =========================================================
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 @@
# =========================================================
# 文件作用:长任务受理响应
# 对应 protoJobAccepted
# 作用:耗时任务先返回 job_id,后续再查询状态
# 发送方:服务端
# 接收方:Ubuntu 车间电脑
# =========================================================
bool accepted # 是否受理成功
uint16 error_code # 未受理时的错误码,取值参考 ErrorCode.msg
string message # 说明
string job_id # 长任务 ID
@@ -0,0 +1,10 @@
# =========================================================
# 文件作用:长任务查询请求
# 对应 protoJobQuery
# 作用:通过 job_id 查询执行状态
# 发送方:Ubuntu 车间电脑
# 接收方:Linux 服务 或 Windows 车端代理
# =========================================================
RequestHeader header # 请求头
string job_id # 任务 ID
@@ -0,0 +1,19 @@
# =========================================================
# 文件作用:长任务状态定义
# 对应 protoJobState
# 说明:
# 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 @@
# =========================================================
# 文件作用:长任务状态响应
# 对应 protoJobStatus
# 作用:返回任务执行状态、进度、错误信息
# 发送方:服务端
# 接收方: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 @@
# =========================================================
# 文件作用:键值对
# 对应 protoKeyValuePair
# 作用:用于扩展元数据,避免每次新增少量字段都改协议
# =========================================================
string key # 键
string value # 值
@@ -0,0 +1,16 @@
# =========================================================
# 文件作用:六自由度位姿
# 对应 protoPose3D
# 作用:
# 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 @@
# =========================================================
# 文件作用:通用请求头
# 对应 protoRequestHeader
# 作用:带齐一次会话、任务、车辆、请求追踪信息
# 发送方:通常为 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 @@
# =========================================================
# 文件作用:通用短响应
# 对应 protoStandardResponse
# 作用:用于同步服务调用的标准响应
# 发送方:服务端
# 接收方:调用方
# 说明:
# 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 @@
# =========================================================
# 文件作用:三维向量
# 对应 protoVector3D
# 作用:用于表达三轴偏置、平移量、加速度等三维数据
# =========================================================
float64 x # X 轴分量
float64 y # Y 轴分量
float64 z # Z 轴分量
@@ -0,0 +1,949 @@
# 自动化标定车间 Proto 协同工作说明
[![Protocol](https://img.shields.io/badge/Protocol-Protocol%20Buffers-blue)](https://developers.google.com/protocol-buffers)
[![Platform](https://img.shields.io/badge/Platform-Ubuntu%20%7C%20Linux%20%7C%20Windows-green)](https://ubuntu.com)
[![Status](https://img.shields.io/badge/Status-Design%20Phase-orange)](./)
> **核心定位**:面向自动化标定车间的分层协议设计,实现车间总控、专业域服务与车端代理的协同工作。
---
## 📋 目录
- [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
- PPPure 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 在一次完整会话中的协同时序
![自动化标定车间协同时序图](../docs/images/sequence_diagram.png)
---
## 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; // 车端里程计 Xm
double odom_y_m = 4; // 车端里程计 Ym
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 @@
# =========================================================
# 文件作用:心跳服务
# 对应 protoHeartbeatRequest + 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
File diff suppressed because it is too large Load Diff
+22 -74
View File
@@ -1,76 +1,24 @@
===================================================================================================
[?????????] (??????????) [???Ubuntu ???? (?)] [???Windows??] (????)
===================================================================================================
## 车间标定流程
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ?? ??????? ³ <--- main_pipeline.xml
³ BehaviorTree.CPP ?? ³ (???????????)
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
³
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ?? 1.???????? ³ ³ ?? BT ????? (C++) ³ ³ ?? AGV ???? ³
³ (?????????) ³<~~~~~³ - ?????? API ³------->³ (agv_calib_chassis) ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ API 1³ - ?????? API ³ gRPC 1 ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
(ROS 2 Action Server) ³ - ???????? API ³
³ ³
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ?? 2.???????? ³ ³ ³ ³ ?? AGV ???? ³
³ (?????? PID) ³<~~~~~³ ------------------------- ³------->³ (agv_calib_control) ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ API 2³ ³ gRPC 2 ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
(ROS 2 Action Server) ³ ??? ??????? (/tmp/) ³
³ - ??? .csv ???? ³
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ - ??? .png / .pcd ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ?? 3.???????? ³ ³ ³ ³ ?? AGV ????? ³
³ (Ceres ? 4x4 ??) ³<~~~~~³ ------------------------- ³------->³ (sensor_calibration) ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ API 3ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ gRPC 3 ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
(ROS 2 Action Server)
车辆画像建档
创建车间会话
生成执行计划
车间预检 / readiness
外部定位阶段(可选/前置)
底盘标定阶段
运控标定阶段
传感器标定阶段
阶段验证 / 人工审批
参数提交 / 必要时回滚
最终报告归档
===================================================================================================
=====================================================================================================
[??? ROS 2 ?? (?? & ???)] [??? ROS 2 ???? (??????)] [????? (gRPC)]
=====================================================================================================
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ?? ???????³ ³ ?? ChassisGatewayComponent ³ [Wi-Fi 6]
³ (?? ROS 2 Srv) ³<-- ROS Srv -->³ (?? agv_calib_chassis.proto) ³<--- gRPC ---> ?? ????
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ ?????????? gRPC ?? ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ?? ?????? ³<-- ROS Topic--³ ?? ControlGatewayComponent ³ [Wi-Fi 6]
³ (???? Topic) ³ ³ (?? agv_calib_control.proto) ³<--- gRPC ---> ?? ????
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ<-- ROS Action-³ ?????? gRPC ??? Topic ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ?? ?????? ³ ³ ?? SensorGatewayComponent ³ [Wi-Fi 6]
³ (???????) ³<-- ROS Action-³ (?? sensor_calibration.proto) ³<--- gRPC ---> ?? ???
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ ?????????Action????³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
=====================================================================================================
[?? Windows ????]
³
³ (C++ ?????? Ticks ? ??)
?
[?? Windows gRPC Server]
³
³ (? Wi-Fi 6 ? 50Hz Stream ???????)
?
==================== ?????? ====================
³
[?? Linux ChassisGatewayNode (???????)]
³ (?? gRPC Client ?? reader->Read() ???)
³
³ (1:1 ?????? ROS 2 ? msg ???)
?
[?? Linux ChassisGatewayNode (ROS 2 Publisher)]
³
³ (?? pub_telemetry_->publish() ? ROS 2 ????)
?
================= ROS 2 ?????? =================
³
ÃÄ? [?? ????????] (?? Subscriber ?????????)
ÃÄ? [?? ????????] (?? Subscriber ??????? > 20A ????)
ÃÄ? [?? ???????] (?? Subscriber ?????????)
ÀÄ? [?? ROS Bag ???] (????????? 50Hz ????????)