Files
KDL_WORK/work/doc/KDL_WASM计算接口设计.md
2026-06-27 08:45:38 -04:00

1033 lines
29 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# KDL WASM 计算接口设计
版本0.1
适用范围GRL 通用机器人程序、虚拟控制器、离线编程、路径验证、轨迹回放
运行环境:浏览器 TypeScript + Web Worker + Orocos KDL WebAssembly
## 1. 目标
本文定义 KDL WASM 需要暴露给 TypeScript 虚拟控制器和通用机器人程序 GRL 使用的计算函数。接口设计从 GRL 语法反推,而不是简单暴露 KDL C++ 类。
GRL 中直接依赖 KDL WASM 的语义包括:
1. `joint_target``pose_target` 的目标点解析和可达性验证。
2. `tool``frame``offset``offset_in` 的位姿变换。
3. `movej` 关节角度差分运行。
4. `movel` TCP 直线运行。
5. `movec` TCP 圆弧运行。
6. `path``run_path``operation` 的批量轨迹生成和批量诊断。
7. 速度、加速度、zone、采样周期、节拍估算。
8. 虚拟控制器运行时的当前 TCP、当前关节、轨迹采样点、报警诊断。
KDL WASM 不负责:
1. GRL 词法和语法解析。
2. 程序流程控制、变量、IO、wait、子程序调用。
3. 碰撞检测和几何布尔运算。
4. 真实品牌控制器的完整 look-ahead 和伺服细节。
5. OPFS 项目文件管理。
这些由 TypeScript 层、虚拟控制器、碰撞模块和 OPFS Workspace 实现。
## 2. 总体架构
```text
GRL Source / OLP Model / Brand Import
|
TypeScript Parser + Semantic Analyzer
|
Executable IR / MotionSegmentRequest
|
KdlWorkerClient
|
kdl.worker.ts
|
KDL WASM C ABI / Embind Wrapper
|
Orocos KDL
```
设计原则:
1. KDL WASM 运行在 Worker 中,避免阻塞 UI 主线程。
2. TypeScript 业务层只使用稳定接口,不直接操作 KDL C++ 对象。
3. WASM 内部使用 `RobotHandle` 管理机器人链、求解器和缓存。
4. 机器人结构源数据为 URDFTypeScript 层负责解析 XML 并生成标准模型WASM 层负责构造 KDL `Tree/Chain`
5. 高频数据使用 `Float64Array`,结构化配置使用 JSON。
6. 所有计算函数返回统一诊断,不只返回成功/失败。
## 3. KDL 能力映射
| GRL/虚拟控制器能力 | KDL 或包装层能力 | 说明 |
| --- | --- | --- |
| URDF 串联链 | `Tree``Chain``Segment``Joint` | 包装层从标准模型构造 |
| `movej` 终点 FK | `ChainFkSolverPos_recursive` | 关节到法兰/TCP |
| `movel/movec` 逐点 IK | `ChainIkSolverPos_NR_JL``ChainIkSolverPos_LMA` | 带关节限位和诊断 |
| 雅可比和奇异性 | `ChainJntToJacSolver` | 输出 Jacobian 和指标 |
| TCP 直线路径 | `Path_Line` 或包装层等价实现 | MOVEL 采样 |
| TCP 圆弧路径 | `Path_Circle` 或包装层等价实现 | MOVEC 采样 |
| 梯形速度 | `VelocityProfile_Trap` | 生成 `s/sd/sdd` |
| 轨迹段 | `Trajectory_Segment` | 路径 + 速度曲线 |
| zone/blend | `Path_RoundedComposite` 或自研 blend | P1 阶段 |
## 4. TypeScript 顶层 API
建议对外提供一个异步客户端:
```ts
interface KdlWasmApi {
init(options?: KdlInitOptions): Promise<KdlRuntimeInfo>;
dispose(): Promise<void>;
loadRobotFromUrdf(urdfXml: string, options: UrdfLoadOptions): Promise<RobotHandle>;
createRobotFromModel(model: NormalizedRobotModel): Promise<RobotHandle>;
destroyRobot(handle: RobotHandle): Promise<void>;
getRobotInfo(handle: RobotHandle): Promise<RobotInfo>;
getJointLimits(handle: RobotHandle): Promise<JointLimits[]>;
normalizePose(input: PoseLike, options?: PoseNormalizeOptions): Promise<Pose>;
composePose(a: Pose, b: Pose): Promise<Pose>;
inversePose(pose: Pose): Promise<Pose>;
applyToolAndFrame(target: PoseTarget, tool: Pose, frame: Pose): Promise<Pose>;
applyOffset(target: PoseTarget, offset: OffsetSpec): Promise<PoseTarget>;
fk(handle: RobotHandle, joints: Float64Array, options?: FkOptions): Promise<FkResult>;
fkAllLinks(handle: RobotHandle, joints: Float64Array, options?: FkOptions): Promise<LinkPoseResult>;
jacobian(handle: RobotHandle, joints: Float64Array, options?: JacobianOptions): Promise<JacobianResult>;
ik(handle: RobotHandle, seed: Float64Array, target: Pose, options?: IkOptions): Promise<IkResult>;
ikBatch(handle: RobotHandle, seeds: Float64Array[], targets: Pose[], options?: IkOptions): Promise<IkResult[]>;
checkJointLimits(handle: RobotHandle, joints: Float64Array): Promise<LimitCheckResult>;
checkVelocityLimits(handle: RobotHandle, trajectory: TrajectoryResult): Promise<LimitCheckResult>;
checkSingularity(handle: RobotHandle, joints: Float64Array): Promise<SingularityResult>;
checkReachability(handle: RobotHandle, target: PoseTarget, options?: IkOptions): Promise<ReachabilityResult>;
checkReachabilityBatch(handle: RobotHandle, targets: PoseTarget[], options?: IkOptions): Promise<ReachabilityResult[]>;
makeTrapProfile(length: number, options: TrapProfileOptions): Promise<TrapProfileResult>;
sampleTrapProfile(length: number, options: TrapProfileOptions): Promise<TrapSample[]>;
planMoveJ(handle: RobotHandle, request: MoveJRequest): Promise<TrajectoryResult>;
planMoveL(handle: RobotHandle, request: MoveLRequest): Promise<TrajectoryResult>;
planMoveC(handle: RobotHandle, request: MoveCRequest): Promise<TrajectoryResult>;
planPath(handle: RobotHandle, request: PathPlanRequest): Promise<PathPlanResult>;
validatePath(handle: RobotHandle, request: PathPlanRequest): Promise<PathValidationResult>;
estimateCycleTime(input: TrajectoryResult | PathPlanResult): Promise<CycleTimeResult>;
resampleTrajectory(trajectory: TrajectoryResult, sampleTime: number): Promise<TrajectoryResult>;
}
```
API 命名使用 `planMoveJ/planMoveL/planMoveC`,避免与 GRL 语句名混淆。GRL 编译器把 `movej/movel/movec` 解析成 IR 后,由虚拟控制器调用这些函数。
## 5. 基础数据类型
### 5.1 句柄和运行信息
```ts
type RobotHandle = number;
interface KdlRuntimeInfo {
version: string;
kdlVersion?: string;
wasmBuild: string;
supportsThreads: boolean;
supportsWasmFs: boolean;
}
```
### 5.2 位姿
内部统一使用位置 + 四元数:
```ts
interface Pose {
position: [number, number, number]; // meter
quaternion: [number, number, number, number]; // x, y, z, w
}
type PoseLike =
| Pose
| { xyz: [number, number, number]; rpy: [number, number, number] }
| { xyz: [number, number, number]; quat: [number, number, number, number] };
```
GRL 中 `pose(x, y, z, rx, ry, rz)` 由 TypeScript 编译器规范化为 `Pose` 后传给 KDL WASM。
### 5.3 目标点
```ts
interface PoseTarget {
id?: string;
pose: Pose;
config?: RobotConfiguration;
tool?: Pose;
frame?: Pose;
extAxis?: number[];
sourceMap?: MotionSourceMap;
}
interface JointTarget {
id?: string;
joints: number[];
extAxis?: number[];
sourceMap?: MotionSourceMap;
}
interface RobotConfiguration {
shoulder?: -1 | 0 | 1;
elbow?: -1 | 0 | 1;
wrist?: -1 | 0 | 1;
turnNumbers?: number[];
}
```
### 5.4 速度和 zone
```ts
type SpeedSpec =
| { kind: "joint_percent"; value: number }
| { kind: "joint_abs"; velocity: number; acceleration?: number }
| { kind: "linear"; velocity: number; acceleration?: number; angularVelocity?: number };
type ZoneSpec =
| { kind: "fine" }
| { kind: "distance"; value: number }
| { kind: "cnt"; value: number }
| { kind: "continuous" };
```
首版 `zone` 可只用于诊断和后处理,运动规划先按 `fine` 到点执行。P1 阶段再实现连续 blend。
### 5.5 诊断
```ts
interface MotionDiagnostic {
severity: "info" | "warning" | "error";
code: string;
message: string;
time?: number;
pointIndex?: number;
segmentId?: string;
targetId?: string;
sourceMap?: MotionSourceMap;
data?: Record<string, unknown>;
}
interface MotionSourceMap {
file?: string;
line?: number;
column?: number;
module?: string;
proc?: string;
pathId?: string;
pathPointId?: string;
operationId?: string;
brandSource?: "abb" | "fanuc" | "kuka" | "grl";
}
```
诊断 code 建议固定:
| code | 含义 |
| --- | --- |
| `KDL_INVALID_MODEL` | 机器人模型非法 |
| `KDL_TARGET_UNREACHABLE` | 目标不可达 |
| `KDL_IK_FAILED` | IK 求解失败 |
| `KDL_JOINT_LIMIT` | 关节超限 |
| `KDL_VELOCITY_LIMIT` | 速度超限 |
| `KDL_ACCEL_LIMIT` | 加速度超限 |
| `KDL_SINGULARITY` | 接近奇异 |
| `KDL_ARC_DEGENERATE` | 圆弧退化 |
| `KDL_PATH_EMPTY` | 空路径 |
| `KDL_ZONE_APPROXIMATED` | zone 被近似处理 |
## 6. 机器人模型 API
### 6.1 URDF 加载
```ts
interface UrdfLoadOptions {
robotId: string;
baseLink: string;
tipLink: string;
tool?: Pose;
base?: Pose;
jointOrder?: string[];
overrideLimits?: JointLimitOverride[];
}
interface NormalizedRobotModel {
robotId: string;
name: string;
baseLink: string;
tipLink: string;
links: LinkModel[];
joints: JointModel[];
activeJointNames: string[];
limits: JointLimits[];
source: {
type: "urdf";
urdfHash: string;
};
}
```
推荐实现分工:
1. TypeScript 解析 URDF XML检查 link/joint 连通性和单位。
2. TypeScript 生成 `NormalizedRobotModel`
3. WASM 根据标准模型构造 KDL `Tree` 和从 `baseLink``tipLink``Chain`
4. WASM 创建 FK、IK、Jacobian 求解器并绑定到 `RobotHandle`
### 6.2 机器人信息
```ts
interface RobotInfo {
handle: RobotHandle;
robotId: string;
name: string;
baseLink: string;
tipLink: string;
jointNames: string[];
dof: number;
limits: JointLimits[];
}
interface JointLimits {
name: string;
lower: number;
upper: number;
velocity: number;
acceleration: number;
jerk?: number;
}
```
GRL 编译器在编译 `joint_target` 时应检查数组长度与 `dof` 一致。
## 7. 位姿和坐标变换 API
GRL 中 `tool``frame``offset``offset_in` 都需要位姿变换。虽然 TypeScript 也可实现这些基础变换,但建议 KDL WASM 提供一致的计算函数,避免数值约定不一致。
```ts
interface OffsetSpec {
mode: "frame" | "tool" | "world";
xyz?: [number, number, number];
rpy?: [number, number, number];
quaternion?: [number, number, number, number];
}
```
函数要求:
1. `normalizePose`:把欧拉角或四元数输入规范化。
2. `composePose`:计算 `a * b`
3. `inversePose`:计算位姿逆。
4. `applyToolAndFrame`:把目标点、工具、工件坐标转换为机器人基坐标下 TCP 目标。
5. `applyOffset`:实现 GRL `pick offset z 100 mm``offset_in tool z -50 mm`
## 8. FK、IK、Jacobian API
### 8.1 正解 FK
```ts
interface FkOptions {
tool?: Pose;
frame?: Pose;
includeFlange?: boolean;
}
interface FkResult {
ok: boolean;
flange: Pose;
tcp: Pose;
joints: number[];
diagnostics: MotionDiagnostic[];
}
```
用途:
1. 虚拟控制器显示当前 TCP。
2. `movel/movec` 计算当前 TCP 起点。
3. 轨迹采样点生成 TCP 位姿。
4. 3D 机器人 link 位姿显示。
### 8.2 全 link 正解
```ts
interface LinkPoseResult {
ok: boolean;
linkPoses: Array<{ link: string; pose: Pose }>;
diagnostics: MotionDiagnostic[];
}
```
用途:
1. 机器人模型显示。
2. 未来碰撞检测前置数据。
3. 轨迹回放时显示每个连杆。
### 8.3 逆解 IK
```ts
interface IkOptions {
tool?: Pose;
frame?: Pose;
qMin?: number[];
qMax?: number[];
maxIterations?: number;
positionTolerance?: number;
orientationTolerance?: number;
seeds?: number[][];
preferredConfig?: RobotConfiguration;
allowApproximate?: boolean;
}
interface IkResult {
ok: boolean;
joints?: number[];
iterations: number;
residualPosition?: number;
residualOrientation?: number;
configuration?: RobotConfiguration;
reason?: "unreachable" | "joint_limit" | "singularity" | "max_iteration" | "invalid_model";
diagnostics: MotionDiagnostic[];
}
```
IK 使用规则:
1. `movej pose_target` 需要 IK 一次,求终点关节。
2. `movel` 每个 TCP 采样点需要 IK。
3. `movec` 每个圆弧采样点需要 IK。
4. `ikBatch` 用于批量路径可达性检查。
5. 连续轨迹中每个采样点的 seed 使用上一采样点关节,减少姿态跳变。
### 8.4 Jacobian 和奇异性
```ts
interface JacobianResult {
ok: boolean;
rows: number;
cols: number;
data: Float64Array;
diagnostics: MotionDiagnostic[];
}
interface SingularityResult {
ok: boolean;
nearSingularity: boolean;
manipulability?: number;
conditionNumber?: number;
diagnostics: MotionDiagnostic[];
}
```
用途:
1. 运动前诊断。
2. MOVEL/MOVEC 采样点奇异性警告。
3. 可达性报告和路径优化提示。
## 9. 梯形速度 API
GRL 速度和加速度需要转换为轨迹采样的路径参数。P0 阶段实现梯形速度曲线。
```ts
interface TrapProfileOptions {
maxVelocity: number;
maxAcceleration: number;
sampleTime: number;
startVelocity?: number;
endVelocity?: number;
}
interface TrapSample {
index: number;
time: number;
s: number;
sd: number;
sdd: number;
}
interface TrapProfileResult {
ok: boolean;
type: "trapezoid" | "triangle";
length: number;
duration: number;
tAccel: number;
tConst: number;
tDecel: number;
vPeak: number;
samples: TrapSample[];
diagnostics: MotionDiagnostic[];
}
```
规则:
1. `length` 为路径长度,单位 meter、radian 或归一化长度,由调用方按运动类型决定。
2. 距离足够长时生成梯形速度曲线。
3. 距离不足时自动退化为三角速度曲线。
4. 首末采样点必须严格对应 `s=0``s=1`
5. 所有 `TrajectoryResult` 必须保留实际速度曲线采样,便于节拍报告。
## 10. 轨迹数据结构
```ts
interface TrajectoryPoint {
index: number;
time: number;
dt: number;
s: number;
sd: number;
sdd: number;
joints: number[];
jointVelocity: number[];
jointAcceleration: number[];
flange: Pose;
tcp: Pose;
tcpVelocity?: [number, number, number, number, number, number];
tcpAcceleration?: [number, number, number, number, number, number];
motion: "MOVEJ" | "MOVEL" | "MOVEC";
segmentId?: string;
targetId?: string;
sourceMap?: MotionSourceMap;
diagnostics: MotionDiagnostic[];
}
interface TrajectoryResult {
ok: boolean;
motion: "MOVEJ" | "MOVEL" | "MOVEC";
duration: number;
sampleTime: number;
points: TrajectoryPoint[];
events: TrajectoryEvent[];
diagnostics: MotionDiagnostic[];
meta?: Record<string, unknown>;
}
```
轨迹点用于:
1. 虚拟控制器 Motion Queue。
2. 3D 仿真回放。
3. 可达性报告。
4. 节拍报告。
5. 轨迹导出和 OPFS trace。
## 11. MOVEJ 计算函数
### 11.1 请求
```ts
interface MoveJRequest {
startJoints: number[];
target: JointTarget | PoseTarget;
speed: SpeedSpec;
zone: ZoneSpec;
tool?: Pose;
frame?: Pose;
sampleTime: number;
speedOverride?: number;
sourceMap?: MotionSourceMap;
}
```
### 11.2 计算语义
`planMoveJ` 对应 GRL
```text
movej TargetExpr [speed Speed] [zone Zone] [tool Tool] [frame Frame]
```
算法:
1. 校验 `startJoints` 长度和关节限位。
2. 如果 target 是 `joint_target`,直接得到 `qEnd`
3. 如果 target 是 `pose_target`,先调用 IK 得到 `qEnd`
4. 计算每个关节角度差 `dq[i] = qEnd[i] - qStart[i]`
5. 根据关节速度、加速度限制计算同步运动时长。
6. 生成梯形速度曲线。
7. 对每个采样点计算关节位置、速度、加速度。
8. 对每个采样点 FK输出 TCP。
9. 检查关节限位、速度、加速度和奇异性。
### 11.3 必须返回的诊断
1. 目标 IK 失败。
2. 起点或终点关节超限。
3. 采样点速度或加速度超限。
4. 接近奇异点。
5. `zone` 在 P0 阶段被近似为 fine。
## 12. MOVEL 计算函数
### 12.1 请求
```ts
interface MoveLRequest {
startJoints: number[];
target: PoseTarget;
speed: SpeedSpec;
zone: ZoneSpec;
tool?: Pose;
frame?: Pose;
sampleTime: number;
orientationMode?: "fixed" | "slerp" | "tool_z_lock";
ik?: IkOptions;
speedOverride?: number;
sourceMap?: MotionSourceMap;
}
```
### 12.2 计算语义
`planMoveL` 对应 GRL
```text
movel TargetExpr [speed Speed] [zone Zone] [tool Tool] [frame Frame]
```
算法:
1.`startJoints` 做 FK得到起点 TCP。
2. 将目标点应用 tool/frame/offset得到终点 TCP。
3. 计算直线长度。
4. 使用 `linear` 速度生成梯形速度曲线。
5. 对每个采样点计算直线位置和姿态插补。
6. 对每个采样点 IKseed 使用上一采样点关节。
7. 检查 IK 连续性、关节限位、速度、加速度、奇异性。
8. 输出轨迹和 TCP 直线误差。
### 12.3 必须返回的诊断
1. 目标不可达。
2. 某个采样点 IK 失败。
3. TCP 直线误差超过容差。
4. 姿态误差超过容差。
5. 关节配置突变。
6. 速度或加速度超限。
## 13. MOVEC 计算函数
### 13.1 请求
```ts
interface MoveCRequest {
startJoints: number[];
via: PoseTarget;
target: PoseTarget;
speed: SpeedSpec;
zone: ZoneSpec;
tool?: Pose;
frame?: Pose;
sampleTime: number;
orientationMode?: "fixed" | "slerp";
arcMode?: "via" | "center" | "radius";
circleDirection?: "short" | "long" | "cw" | "ccw";
ik?: IkOptions;
speedOverride?: number;
sourceMap?: MotionSourceMap;
}
```
### 13.2 计算语义
`planMoveC` 对应 GRL
```text
movec via ViaTargetExpr target EndTargetExpr [speed Speed] [zone Zone] [tool Tool] [frame Frame]
```
算法:
1.`startJoints` 做 FK得到起点 TCP。
2. 将 via 和 target 应用 tool/frame/offset。
3. 检查三点是否重合或共线。
4. 计算圆心、半径、法向量、圆弧角度和圆弧长度。
5. 使用 `linear` 速度按圆弧长度生成梯形速度曲线。
6. 对每个采样点计算圆弧 TCP 位姿。
7. 对每个采样点 IKseed 使用上一采样点关节。
8. 检查圆弧误差、IK 连续性、关节限位、速度、加速度、奇异性。
### 13.3 圆弧元数据
```ts
interface CirclePlanMeta {
center: [number, number, number];
radius: number;
normal: [number, number, number];
angle: number;
length: number;
direction: "cw" | "ccw";
maxArcError: number;
}
```
`TrajectoryResult.meta.circle` 必须包含 `CirclePlanMeta`
### 13.4 必须返回的诊断
1. via 或 target 不可达。
2. 三点重合、近似重合或近似共线。
3. 半径过小或圆弧长度过短。
4. 某个采样点 IK 失败。
5. 圆弧误差超过容差。
6. 速度或加速度超限。
## 14. Path 和 Operation 批量接口
### 14.1 Path 请求
```ts
interface MotionSegmentRequest {
id: string;
motion: "MOVEJ" | "MOVEL" | "MOVEC";
target?: JointTarget | PoseTarget;
via?: PoseTarget;
speed: SpeedSpec;
zone: ZoneSpec;
tool?: Pose;
frame?: Pose;
sourceMap?: MotionSourceMap;
}
interface PathPlanRequest {
startJoints: number[];
segments: MotionSegmentRequest[];
sampleTime: number;
speedOverride?: number;
stopOnError?: boolean;
}
```
### 14.2 `planPath`
`planPath` 用于 `run_path` 展开后的整条路径轨迹生成:
1. 按 segment 顺序调用 `planMoveJ/planMoveL/planMoveC`
2. 每段终点关节作为下一段起点。
3. 合并所有轨迹点,重新编号和更新时间。
4. 保留每段 `sourceMap`
5. 生成整条路径的总时长。
```ts
interface PathPlanResult {
ok: boolean;
duration: number;
segments: TrajectoryResult[];
points: TrajectoryPoint[];
diagnostics: MotionDiagnostic[];
}
```
### 14.3 `validatePath`
`validatePath` 用于离线编程路径验证,不要求必须返回完整轨迹点,可按配置只返回诊断:
```ts
interface PathValidationResult {
ok: boolean;
reachable: boolean;
cycleTime?: number;
segmentReports: SegmentValidationReport[];
diagnostics: MotionDiagnostic[];
}
interface SegmentValidationReport {
segmentId: string;
ok: boolean;
motion: "MOVEJ" | "MOVEL" | "MOVEC";
duration?: number;
maxJointVelocityRatio?: number;
maxJointAccelerationRatio?: number;
maxCartesianError?: number;
diagnostics: MotionDiagnostic[];
}
```
`run_operation` 不需要 KDL WASM 单独理解工艺,只需要 TypeScript 把 operation 展开为 start action、path、end action。KDL WASM 只处理其中的 motion segment。
## 15. 可达性和批量检查
### 15.1 单点可达性
```ts
interface ReachabilityResult {
ok: boolean;
reachable: boolean;
targetId?: string;
joints?: number[];
residualPosition?: number;
residualOrientation?: number;
nearestPose?: Pose;
diagnostics: MotionDiagnostic[];
}
```
### 15.2 批量可达性
`checkReachabilityBatch` 用于:
1. Path 编辑器批量目标点检查。
2. CAD 曲线采样点预检查。
3. 自动编程生成后快速诊断。
4. 品牌程序导入后的目标点检查。
批量函数必须保持输入顺序,返回结果与输入 target 一一对应。
## 16. 节拍估算
```ts
interface CycleTimeResult {
ok: boolean;
motionTime: number;
waitTime?: number;
ioTime?: number;
totalTime: number;
segmentTimes: Array<{
segmentId?: string;
motion: "MOVEJ" | "MOVEL" | "MOVEC";
duration: number;
}>;
diagnostics: MotionDiagnostic[];
}
```
KDL WASM 只估算运动时间。`waitTime`、IO 脚本延迟、工艺设备延迟由虚拟控制器补充。
## 17. Worker RPC 协议
主线程和 Worker 建议使用统一消息格式:
```ts
interface KdlRpcRequest<T = unknown> {
id: number;
method: keyof KdlWasmApi;
payload: T;
}
interface KdlRpcResponse<T = unknown> {
id: number;
ok: boolean;
result?: T;
error?: {
code: string;
message: string;
diagnostics?: MotionDiagnostic[];
};
}
```
要求:
1. 大数组使用 Transferable 或共享内存策略,避免频繁复制。
2. 每个请求必须有唯一 id。
3. Worker 崩溃或 WASM 初始化失败时,主线程能恢复并重新初始化。
4. 对长路径计算提供进度回调或分块计算,避免 Worker 长时间无响应。
## 18. C ABI / Embind 暴露建议
不建议把 KDL C++ 类完整暴露给 TypeScript。建议底层导出少量稳定函数
```cpp
extern "C" {
int kdl_init(const char* options_json);
int kdl_create_robot(const char* model_json);
int kdl_destroy_robot(int robot_handle);
int kdl_get_robot_info(int robot_handle, char* out_json, int out_len);
int kdl_fk(int robot_handle, const double* joints, int n, double* out_pose7);
int kdl_fk_all_links(int robot_handle, const double* joints, int n, char* out_json, int out_len);
int kdl_jacobian(int robot_handle, const double* joints, int n, double* out_matrix);
int kdl_ik(int robot_handle, const double* seed, int n, const double* target_pose7, const char* options_json, double* out_joints);
int kdl_plan_movej(int robot_handle, const char* request_json, char* out_json, int out_len);
int kdl_plan_movel(int robot_handle, const char* request_json, char* out_json, int out_len);
int kdl_plan_movec(int robot_handle, const char* request_json, char* out_json, int out_len);
int kdl_plan_path(int robot_handle, const char* request_json, char* out_json, int out_len);
int kdl_sample_trap(double length, const char* options_json, char* out_json, int out_len);
int kdl_last_error(char* out_json, int out_len);
}
```
说明:
1. P0 可用 JSON 输入输出实现,简单可靠。
2. 高频 FK/IK 批量计算可增加 TypedArray 版本,减少 JSON 开销。
3. TypeScript API 层负责把 C ABI 包装成 Promise。
4. 所有 C ABI 返回 `0` 表示成功,非 `0` 表示错误,错误详情通过 `kdl_last_error` 获取。
## 19. 内存和性能要求
首版目标:
1. 单机器人 6 轴模型初始化小于 1 秒。
2. 单次 FK 小于 1 ms。
3. 单次 IK 平均小于 10 ms复杂点允许更长但必须有超时。
4. 1000 个目标点批量可达性检查可在可接受交互时间内完成。
5. 10 秒轨迹按 4 ms 采样约 2500 点,必须能稳定生成和回放。
实现建议:
1. `RobotHandle` 内缓存 FK、IK、Jacobian solver。
2. `ikBatch` 中复用上一点结果作为 seed。
3. 对长路径分段计算,及时返回进度。
4. 避免每个采样点跨 Worker 往返,轨迹整段在 Worker 内完成。
5. 大轨迹 trace 写 OPFS 由 TypeScript 层完成WASM 不直接管理项目文件。
## 20. 错误处理
所有 API 不抛裸字符串错误,必须返回结构化错误:
```ts
interface KdlError {
code: string;
message: string;
diagnostics: MotionDiagnostic[];
}
```
错误分级:
1. `error`:不能生成可执行轨迹,例如 IK 失败、模型非法。
2. `warning`可生成轨迹但存在风险例如接近限位、zone 被近似。
3. `info`:辅助信息,例如使用了三角速度曲线。
虚拟控制器处理规则:
1. `error`:进入 alarm 或 hold。
2. `warning`:允许仿真继续,但报告中必须显示。
3. `info`:写入 trace 或调试面板。
## 21. 与 GRL 的调用关系
| GRL 语法 | TypeScript 编译结果 | KDL WASM 函数 |
| --- | --- | --- |
| `target home = joint_target` | `JointTarget` | `checkJointLimits` |
| `target pick = pose_target` | `PoseTarget` | `checkReachability` |
| `pick offset z 100 mm` | `OffsetSpec` | `applyOffset` |
| `movej home` | `MoveJRequest` | `planMoveJ` |
| `movel pick` | `MoveLRequest` | `planMoveL` |
| `movec via mid target end` | `MoveCRequest` | `planMoveC` |
| `run_path pick_path` | `PathPlanRequest` | `planPath` |
| Path 可达性检查 | `PathPlanRequest` | `validatePath` |
| 节拍报告 | `TrajectoryResult/PathPlanResult` | `estimateCycleTime` |
`if/for/switch/call/wait/io` 不直接调用 KDL WASM但它们会影响何时调用运动函数和当前运行上下文。
### 21.1 不应暴露给 KDL WASM 的 GRL 语义
以下 GRL 语义由 TypeScript 虚拟控制器执行,不进入 KDL WASM
| GRL 语义 | 执行位置 | 说明 |
| --- | --- | --- |
| `if/elseif/else` | 虚拟控制器 | 判断分支,决定是否执行后续运动 |
| `while/for/switch` | 虚拟控制器 | 控制程序流,可能多次触发运动函数 |
| `proc/func/call/return` | 虚拟控制器 | 调用栈、参数、作用域不属于 KDL |
| `io.do/di/ai/ao` | IO Service | KDL 不管理 IO 状态 |
| `wait/pulse/timer` | 虚拟控制器 + IO Service | KDL 不阻塞等待 IO |
| `alarm/raise/try/catch` | 虚拟控制器 | KDL 只返回诊断,不执行异常流程 |
| `operation.process` | 工艺模块 | KDL 只处理 operation 展开后的 motion segment |
边界原则KDL WASM 只接收已经解析好的运动请求,不读取 GRL 源码,不维护程序变量,不执行子程序。
## 22. P0 必须暴露的函数
P0 阶段必须完成以下函数:
1. `init`
2. `loadRobotFromUrdf`
3. `createRobotFromModel`
4. `destroyRobot`
5. `getRobotInfo`
6. `getJointLimits`
7. `normalizePose`
8. `composePose`
9. `inversePose`
10. `applyOffset`
11. `applyToolAndFrame`
12. `fk`
13. `fkAllLinks`
14. `jacobian`
15. `ik`
16. `ikBatch`
17. `checkJointLimits`
18. `checkSingularity`
19. `checkReachability`
20. `checkReachabilityBatch`
21. `makeTrapProfile`
22. `sampleTrapProfile`
23. `planMoveJ`
24. `planMoveL`
25. `planMoveC`
26. `planPath`
27. `validatePath`
28. `estimateCycleTime`
29. `resampleTrajectory`
P1 扩展:
1. `planBlendPath`
2. `planMoveSpline`
3. `checkCollisionInputPoses`,只提供 link poses不做碰撞本身。
4. `optimizeSeedSequence`
5. `compareTrajectory`
6. 外部轴协调相关函数。
## 23. 测试要求
### 23.1 单元测试
1. URDF 到 KDL Chain 的 joint 顺序测试。
2. FK 与原生 KDL 结果对比。
3. IK 后再 FK误差小于容差。
4. Jacobian 尺寸和数值测试。
5. 梯形速度曲线长距离/短距离测试。
6. `applyOffset` 在 frame/tool/world 三种模式下测试。
### 23.2 运动测试
1. `planMoveJ` 关节同起同停。
2. `planMoveL` TCP 直线误差小于容差。
3. `planMoveC` 圆心、半径、弧长和圆弧误差正确。
4. `planMoveC` 三点共线时返回 `KDL_ARC_DEGENERATE`
5. 每种运动都检查速度、加速度、限位和 source map。
### 23.3 集成测试
1. 从 GRL `movej/movel/movec` 编译为请求并生成轨迹。
2. 从 GRL `path` 编译为 `PathPlanRequest` 并生成整条路径。
3. 轨迹写入 OPFS 后重新加载回放。
4. 长路径批量验证性能测试。
5. Worker 初始化、崩溃恢复和取消请求测试。
## 24. 实施顺序
建议按以下顺序开发:
1. WASM 工程骨架和 Worker RPC。
2. `NormalizedRobotModel` 到 KDL Chain。
3. FK、fkAllLinks。
4. IK、ikBatch。
5. Jacobian 和奇异性。
6. 位姿变换和 offset。
7. 梯形速度曲线。
8. planMoveJ。
9. planMoveL。
10. planMoveC。
11. planPath、validatePath。
12. 节拍估算和诊断报告。
13. 性能优化和 TypedArray 批量接口。
## 25. 结论
KDL WASM 对 GRL 的定位是“运动学和轨迹计算内核”。它不解释完整机器人程序,也不处理 IO/Wait/流程控制。TypeScript 虚拟控制器负责执行 GRL/IR当遇到运动相关语义时把已经解析好的机器人模型、当前关节、目标点、速度、zone、tool、frame 传给 KDL WASM。
P0 阶段只要稳定实现 URDF 模型加载、FK/IK/Jacobian、MOVEJ/MOVEL/MOVEC、梯形速度、Path 批量验证和诊断,就可以支撑通用机器人程序的离线编程、虚拟运行、轨迹回放和多品牌后处理。