34 KiB
Motion 运动框架使用说明
1. 文档范围
本文档基于当前代码实际实现整理,描述 MainShell/Motion 目录下已经存在的运动控制能力、调用入口、约束行为与示例代码。
说明:
- 文档内容以当前源码实现为准。
- 若旧文档、注释或设计稿与代码不一致,以代码为准。
- 本文档仅描述已经实现的能力,不对未来规划功能做扩展解释。
适用对象:
- 业务流程开发人员
- 手动功能开发人员
- 运动控制维护人员
- 需要接入平台联动或视觉逼近对位功能的开发人员
2. 模块总览
当前 MainShell/Motion 目录中的能力主要包括:
- 单轴运动控制
- 批量安全运动入口
- 运动前安全检查与报警上报
- 平台三轴联动封装
- 速度参数下发管理
- 逼近对位流程框架
主要文件如下:
MotionController.cs:单轴底层执行器MotionInfrastructure.cs:运动报警、预检查、日志、控制器注册表MotionMoveRequest.cs:运动请求模型MotionResult.cs:单轴结果与批量结果模型SafeAxisMotion.cs:业务层统一运动入口StagePlatformMotionService.cs:平台三轴联动封装AxisSpeedManager.cs:轴速度曲线管理MotionSafetyStateProvider.cs:运动安全状态提供器ApproachAlignment/ApproachAlignment.cs:逼近对位的数据结构和接口定义ApproachAlignment/ApproachAlignmentService.cs:逼近对位主流程ApproachAlignment/CenterRecognizer.cs:视觉中心识别实现ApproachAlignment/CoordinateTransformer.cs:坐标转换实现
3. 分层理解
3.1 单轴执行层
MotionController 直接面向 IAxis / IAxisFunc,负责:
- 绝对运动
MoveAbsAsync() - 相对运动
MoveRelAsync() - Jog
JogAsync() - 停止
StopAsync() - 回零
HomeAsync() - 运动状态校验、软限位检查、超时与取消
- 运动开始/结束事件通知
3.2 基础设施层
MotionInfrastructure.cs 中提供了几类基础设施:
MotionAlarmReporter:统一报警上报MotionPrecheckService:运动前安全检查聚合入口MotionExecutionLogger:统一记录运动开始/结束日志MotionControllerRegistry:缓存并复用每根轴对应的MotionController
3.3 请求与结果模型层
MotionMoveRequest 与 MotionResult / MotionBatchResult 用于统一描述:
- 运动目标
- 超时时间
- 报警号
- 请求来源与标签
- 批次号与关联号
- 单轴结果
- 批量结果
3.4 业务统一入口层
SafeAxisMotion 是当前推荐的业务调用入口,负责:
- 通过轴名解析实际轴对象
- 复用
MotionController - 单轴绝对/相对运动
- 多轴绝对联动
- 单轴/多轴回零
- 调用
MotionPrecheckService.ValidateAsync()做运动前安全校验 - 失败时联动取消并停止相关轴
- 失败后按请求配置上报报警
- 为结果补充
CorrelationId/BatchId/FailureStage
3.5 业务场景服务层
StagePlatformMotionService 封装平台三轴动作:
- 等高移动
MoveFlatAsync() - 平面移动
MovePlaneAsync()
3.6 视觉逼近对位层
ApproachAlignmentService 封装迭代式逼近对位流程:
- 识别中心
- 将视觉中心转换为各轴目标位置
- 驱动多轴移动
- 再次识别中心
- 重新计算目标位置与当前误差
- 判断是否收敛
4. 当前代码中的真实能力
结合当前代码,以下能力已经明确存在:
- 单轴绝对移动
- 单轴相对移动
- 单轴 Jog
- 单轴停止
- 单轴回零
- 多轴绝对联动移动
- 多轴批量回零
- 运动前安全检查
- 失败报警上报
- 平台三轴等高/平面联动
- 基于视觉中心识别的迭代式逼近对位框架
- 轴速度配置与速度档位下发
以下内容需要特别注意:
- 批量移动仅支持绝对运动,不支持批量相对运动
- 逼近对位中的
CoordinateTransformer仍是占位实现 - 文档中若提到通过
SafeAxisMotion直接调用逼近对位,不符合当前代码真实入口
5. MotionController 说明
MotionController 是单轴动作的最终执行器。
5.1 关键属性
5.2 关键事件
5.3 关键方法
5.4 内部保障机制
MotionController 内部具备以下保障:
- 使用
SemaphoreSlim保证同一根轴同一时刻只执行一个动作,见_motionLock - 每次运动前调用
EnsureMotionStateReady()检查轴状态 - 运动执行过程中调用
EnsureMotionStateHealthyDuringExecution()检查状态是否恶化 - 绝对与相对移动执行前都会调用
EnsureWithinSoftLimit()做软限位检查 - 取消时通过
TryStop()自动尝试停轴 - 超时时通过
ThrowIfTimeoutExceeded()自动尝试停轴并抛出超时异常 - 完成后统一生成
MotionResult
5.5 失败返回行为
ExecuteProtectedMotionAsync() 会捕获执行异常,并在最终返回的 MotionResult 中体现成功、取消和异常信息,而不是始终直接向外抛出异常。
因此调用后建议统一执行:
var result = await controller.MoveAbsAsync(100.0, 10000, cancellationToken);
result.EnsureSuccess();
6. MotionInfrastructure 说明
MotionInfrastructure.cs 提供了运动框架的关键支撑能力。
6.1 MotionAlarmReporter
MotionAlarmReporter 对 AlarmOperate 做了一层封装:
- 传入
null报警号时直接返回false - 传入有效报警号时调用
ReportAlarmAsync()间接触发报警
6.2 MotionPrecheckService
MotionPrecheckService 在构造函数中聚合了以下安全检查:
MotionRequestDuplicateAxisCheckMotionBatchSameSourceCheckEmergencyStopReleasedCheckSafetyDoorClosedCheckAutoFlowModeCheckStageVacuumReadyCheckBondHeadSafePositionCheckStagePlatformPlaneMoveSafetyCheck
调用 ValidateAsync() 时,会:
- 逐条执行安全规则
- 对失败规则记录系统错误日志
- 使用规则上的
AlarmId或传入的fallbackAlarmId上报报警 - 最终抛出
InvalidOperationException
这意味着:
- 当前代码中已经存在统一运动前预检查机制
SafeAxisMotion的各类入口会先走预检查,再执行实际运动
6.3 MotionExecutionLogger
MotionExecutionLogger 负责处理:
它会输出开始位置、目标位置、结束位置、耗时、是否取消、失败阶段等日志信息。
6.4 MotionControllerRegistry
- 按轴名缓存控制器实例
- 对同名且同引用的轴复用已有控制器
- 在创建控制器时自动挂接
MotionExecutionLogger事件
业务侧一般不需要自己维护 MotionController 生命周期,直接通过 SafeAxisMotion 使用即可。
7. MotionMoveRequest 说明
MotionMoveRequest 当前并不轻量,除基础字段外还已经支持业务元数据。
7.1 主要属性
AxisNameAxisTargetPositionTimeoutMillisecondsAlarmIdRequestKindSourceTagsCorrelationIdBatchIdPositionToleranceStopOnFailure
7.2 创建方式
绝对运动:
相对运动:
补充元数据:
7.3 行为说明
TargetPosition对绝对运动表示目标位置,对相对运动表示位移量Tags会通过NormalizeTags()去空、去重WithMetadata()会保留原请求主体,仅覆盖指定元数据- 批量绝对移动时会由
SafeAxisMotion自动补充CorrelationId与BatchId
8. MotionResult 与 MotionBatchResult 说明
MotionResult 包含:
AxisNameOperationTargetPositionStartPositionEndPositionSucceededCancelledExceptionMessageAlarmReportedStartedAtUtcFinishedAtUtcCorrelationIdBatchIdFailureStageTimedOutStoppedByCoordinatorDurationMilliseconds
常用方法:
如果批量结果中只有一根轴失败,EnsureSuccess() 会直接抛该轴异常;如果多根轴失败,会抛 AggregateException。
9. SafeAxisMotion 说明
SafeAxisMotion 是当前业务最推荐使用的统一入口。
9.1 主要能力
- 单轴绝对移动
- 单轴相对移动
- 多轴绝对联动移动
- 单轴回零
- 多轴批量回零
- 轴名解析
- 控制器缓存与日志挂接
- 运动前安全预检查
- 失败联动停轴
- 失败报警
- 批次与关联信息补充
9.2 主要异步方法
单轴移动:
批量绝对移动:
回零:
同步封装:
9.3 真实执行流程
以 MoveAbsAsync() 为例,执行顺序为:
- 构造
MotionMoveRequest - 调用
EnsureRequestBatchMetadata()补齐关联元数据 - 解析轴对象
- 调用
MotionPrecheckService.ValidateAsync()执行预检查 - 调用内部
MoveAbsInternalAsync() - 通过
MotionControllerRegistry.GetController()获取控制器并执行运动 - 按请求补充结果元数据与失败阶段
- 必要时上报报警
9.4 批量运动行为说明
SafeMoveAsync() 当前执行的是多轴绝对联动:
- 请求数组为空时,返回空的
MotionBatchResult - 会先对整批请求生成
batchId - 会统一做安全检查
- 会并发启动各轴绝对运动任务
- 任一轴失败时,若请求
StopOnFailure = true,会调用CancelAndStopRelatedAxes() CancelAndStopRelatedAxes()会取消协调令牌,并逐轴调用StopAsync()
9.5 超时与失败细节
NormalizeTimeout()会把小于等于 0 的超时值恢复为默认值- 失败结果会通过
WithFailureDetails()写入FailureStage、TimedOut、StoppedByCoordinator、CorrelationId、BatchId - 当
alarmId为空时,失败不会触发报警 - 当
stopOnFailure = false时,失败不会触发联动停轴
10. MotionSafetyStateProvider 说明
MotionSafetyStateProvider 为预检查规则提供外部状态。
10.1 主要能力
- 读取当前机器模式
CurrentMachineMode - 判断急停是否释放
IsEmergencyStopReleased() - 判断安全门是否关闭
AreSafetyDoorsClosed() - 判断流程是否在运行
IsFlowRunning() - 获取当前流程名
CurrentFlowName - 判断平台真空是否就绪
AreStageVacuumsReady() - 获取吸嘴/打头相关不安全信号
GetUnsafeBondHeadSignals() - 判断来源是否属于自动流程
IsAutoWorkflowSource()
10.2 行为说明
- 当
DeviceIo离线时,多数安全状态会直接返回不可用或不安全结果 - 安全门支持
SecurityDoorShield旁路逻辑 - 自动流程判断不是只看精确名称,也支持来源字符串包含
Auto
11. StagePlatformMotionService 说明
StagePlatformMotionService 封装平台三轴 Axis_Stage_Z7、Axis_Stage_Z8、Axis_Stage_Z9 的联动动作。
11.1 主要方法
11.2 内部实现方式
MoveFlatAsync()实际调用MovePlaneAsync()MovePlaneAsync()会先调用EnsurePlaneTargetsOrdered()- 允许的三轴目标最大高差为
5.0 - 然后将三根轴封装为带
Source和Tags的MotionMoveRequest - 再统一调用
SafeAxisMotion.SafeMoveAsync() - 方法内部已经执行
EnsureSuccess()
11.3 使用建议
只要是平台三轴动作,建议统一走 StagePlatformMotionService,不要在业务代码里手工拼三轴请求。
12. AxisSpeedManager 说明
AxisSpeedManager 用于从系统参数生成速度曲线并下发到轴参数。
12.1 相关类型
AxisSpeedProfile:Low/Medium/High/CustomAxisMotionProfile:封装Velocity/Acceleration/Deceleration/Jerk
12.2 主要方法
SetAxisSpeed(string axisName, double speed)SetAxisSpeed(string axisName, AxisSpeedProfile profile)ApplySpeedSettings()
12.3 真实行为说明
SetAxisSpeed(string axisName, double speed) 的行为不是固定倍数计算,而是:
- 从速度参数表中找到该轴对应的
SpeedTypeItem - 以配置基准速度
speedItem.Speed为基数 - 用
speed / speedItem.Speed计算缩放比例 - 按比例缩放
Acc/Dec/Jerk - 最终通过
ApplyAxisMotionProfile()下发到轴参数
SetAxisSpeed(string axisName, AxisSpeedProfile profile) 的行为是:
- 读取当前轴配置中的
LowPercent/MedianPercent/HighPercent - 调用
CreateProfile()生成缩放后的运动参数 - 调用
ApplyAxisMotionProfile()下发
ApplySpeedSettings() 的行为是:
- 从
GlobalParam.SpeedParaSysSetting.SpeedTypeItemCollection.SpeedTypeItemList读取所有速度配置 - 根据当前
CurrentSpeedType通过MapCurrentSpeedTypeText()映射到Low/Medium/High - 对每根轴生成对应档位的速度参数并下发
12.4 校验与异常
AxisSpeedManager 会校验:
- 轴名不能为空
- 轴必须存在
- 轴必须有对应速度配置
- 速度、加速度、减速度、Jerk 必须为正且有限值,见
ValidatePositiveFinite() - 百分比必须在
(0, 100]范围内,见ValidatePercent()
13. 逼近对位模块说明
13.1 组成文件
ApproachAlignment/ApproachAlignment.csApproachAlignment/ApproachAlignmentService.csApproachAlignment/CenterRecognizer.csApproachAlignment/CoordinateTransformer.cs
13.2 核心类型
ApproachAlignment.cs 中定义了:
ApproachAlignmentAxisApproachAlignmentRequestApproachAlignmentResultCoordinateTransformResultICenterRecognizerICoordinateTransformer
13.3 ApproachAlignmentRequest 说明
ApproachAlignmentRequest 构造函数要求至少传入一根轴,并提供以下默认值:
Camera = CameraType.UpCameraMaxIterations = 5MoveTimeoutMilliseconds = 30000RecognitionTimeoutMilliseconds = 10000
13.4 ApproachAlignmentService 流程
ApproachAlignmentService.ApproachAlignmentAsync() 当前流程如下:
- 最多执行
MaxIterations次迭代 - 首次迭代调用
RecognizeCenterAsync()识别中心 - 调用
ICoordinateTransformer.TransformAsync()计算各轴目标位置 - 将目标位置转成
MotionMoveRequest.ForAxisName() - 调用
SafeAxisMotion.SafeMoveAsync()执行多轴移动 - 再次识别中心
- 再次转换,得到理论目标位置
- 读取各轴当前位置并计算误差
- 若全部轴误差都小于等于容差,则成功结束
- 否则进入下一轮迭代
13.5 CenterRecognizer 现状
CenterRecognizer 已接入视觉算法服务:
- 依赖
IVisionAlgorithmService - 使用
VisionProcessRequest AlgorithmType = VisionAlgorithmType.FindCenterCaptureOptions = CameraCaptureOptions.CreateStream(timeoutMilliseconds)- 从结果中读取
OffsetX/OffsetY - 识别失败或超时返回
null
13.6 CoordinateTransformer 现状
CoordinateTransformer 当前仍是占位实现。
实际行为:
- 若轴列表为空,则返回
Succeeded = false - 否则延时约 10ms 后,为每根轴写入
0.0作为目标位置 - 返回
Succeeded = true
这表示:
- 逼近对位的流程框架已经存在
- 但真实标定坐标变换尚未完成
- 若直接用于生产逻辑,会把各轴目标位置算成固定
0.0
13.7 当前真实入口
当前应直接注入并调用 ApproachAlignmentService.ApproachAlignmentAsync(),而不是通过 SafeAxisMotion 调用逼近对位。
14. 推荐调用方式
14.1 普通业务运动
优先调用 SafeAxisMotion:
- 单轴绝对移动用
MoveAbsAsync() - 单轴相对移动用
MoveRelAsync() - 多轴绝对联动用
SafeMoveAsync() - 单轴回零用
HomeAsync() - 多轴回零用
SafeHomeAsync()
14.2 平台三轴业务
统一调用 StagePlatformMotionService:
- 等高移动用
MoveFlatAsync() - 平面移动用
MovePlaneAsync()
14.3 单轴调试或事件监听
可以直接使用 MotionController:
- 适合底层调试
- 适合观察
MotionStarted/MotionFinished - 不建议作为一般业务入口
14.4 逼近对位业务
当前应直接调用 ApproachAlignmentService,前提是先替换 CoordinateTransformer 为真实可用的标定变换实现。
15. 示例代码
15.1 单轴绝对移动
public async Task MoveAxisXAsync(CancellationToken cancellationToken)
{
var result = await _safeAxisMotion.MoveAbsAsync(
"Axis_X",
100.0,
timeoutMilliseconds: 10000,
cancellationToken: cancellationToken,
alarmId: 5001);
result.EnsureSuccess();
}
15.2 单轴相对移动
public async Task NudgeAxisYAsync(CancellationToken cancellationToken)
{
var result = await _safeAxisMotion.MoveRelAsync(
"Axis_Y",
-2.0,
timeoutMilliseconds: 8000,
cancellationToken: cancellationToken,
alarmId: 5002);
result.EnsureSuccess();
}
15.3 带元数据的多轴绝对联动
public async Task MoveXYAsync(double x, double y, CancellationToken cancellationToken)
{
var batch = await _safeAxisMotion.SafeMoveAsync(
cancellationToken,
MotionMoveRequest.ForAxisName(
"Axis_X",
x,
timeoutMilliseconds: 12000,
alarmId: 6001,
source: "Manual.Align",
tags: new[] { "Manual", "Align" },
correlationId: "ALIGN-001",
batchId: "BATCH-ALIGN-001",
positionTolerance: 0.005,
stopOnFailure: true),
MotionMoveRequest.ForAxisName(
"Axis_Y",
y,
timeoutMilliseconds: 12000,
alarmId: 6002,
source: "Manual.Align",
tags: new[] { "Manual", "Align" },
correlationId: "ALIGN-002",
batchId: "BATCH-ALIGN-001",
positionTolerance: 0.005,
stopOnFailure: true));
batch.EnsureSuccess();
}
15.4 单轴回零
public async Task HomeAxisZAsync(CancellationToken cancellationToken)
{
var result = await _safeAxisMotion.HomeAsync(
"Axis_Z",
timeoutMilliseconds: 30000,
cancellationToken: cancellationToken,
alarmId: 7001);
result.EnsureSuccess();
}
15.5 多轴批量回零
public async Task HomeAllAxesAsync(CancellationToken cancellationToken)
{
var batch = await _safeAxisMotion.SafeHomeAsync(
cancellationToken,
"Axis_X",
"Axis_Y",
"Axis_Z");
batch.EnsureSuccess();
}
15.6 平台三轴等高移动
public async Task MoveStageFlatAsync(CancellationToken cancellationToken)
{
var batch = await _stagePlatformMotionService.MoveFlatAsync(
20.0,
timeoutMilliseconds: 20000,
cancellationToken: cancellationToken);
batch.EnsureSuccess();
}
15.7 平台三轴平面移动
public async Task MoveStagePlaneAsync(CancellationToken cancellationToken)
{
var batch = await _stagePlatformMotionService.MovePlaneAsync(
z7Target: 20.000,
z8Target: 20.150,
z9Target: 19.950,
timeoutMilliseconds: 25000,
cancellationToken: cancellationToken);
batch.EnsureSuccess();
}
15.8 直接使用 MotionController 监听事件
var controller = new MotionController(axis);
controller.MotionStarted += (sender, e) =>
{
Console.WriteLine(
$"Start Axis={e.AxisName}, Op={e.Operation}, Start={e.StartPosition}, Target={e.TargetPosition}");
};
controller.MotionFinished += (sender, e) =>
{
Console.WriteLine(
$"Finish Axis={e.AxisName}, Success={e.Succeeded}, Cancelled={e.Cancelled}, End={e.EndPosition}, Error={e.Exception}");
};
var result = await controller.MoveAbsAsync(50.0, 10000, cancellationToken);
result.EnsureSuccess();
15.9 使用 AxisSpeedManager 切换速度档位
public void ApplyMediumSpeedToStageX()
{
_axisSpeedManager.SetAxisSpeed("Axis_Stage_X", AxisSpeedProfile.Medium);
}
15.10 使用 AxisSpeedManager 设置自定义速度
public void ApplyCustomSpeedToStageX()
{
_axisSpeedManager.SetAxisSpeed("Axis_Stage_X", 150.0);
}
15.11 逼近对位调用示例
public async Task<ApproachAlignmentResult> RunApproachAlignmentAsync(CancellationToken cancellationToken)
{
var request = new ApproachAlignmentRequest(
new[]
{
new ApproachAlignmentAxis("Axis_X", 0.01) { Description = "X axis" },
new ApproachAlignmentAxis("Axis_Y", 0.01) { Description = "Y axis" }
},
camera: CameraType.UpCamera)
{
MaxIterations = 5,
MoveTimeoutMilliseconds = 30000,
RecognitionTimeoutMilliseconds = 10000
};
var result = await _approachAlignmentService.ApproachAlignmentAsync(
request,
cancellationToken);
if (!result.Succeeded)
{
throw result.Exception ?? new InvalidOperationException(result.Message);
}
return result;
}
15.12 自定义真实坐标转换器示例
public class CalibratedCoordinateTransformer : ICoordinateTransformer
{
public Task<CoordinateTransformResult> TransformAsync(
double centerX,
double centerY,
IEnumerable<ApproachAlignmentAxis> axes)
{
var result = new CoordinateTransformResult();
foreach (var axis in axes)
{
var target = CalculateTarget(axis.AxisName, centerX, centerY);
result.AxisPositions[axis.AxisName] = target;
}
result.Succeeded = true;
return Task.FromResult(result);
}
private double CalculateTarget(string axisName, double centerX, double centerY)
{
throw new NotImplementedException();
}
}
16. 注意事项
SafeAxisMotion.SafeMoveAsync()当前仅用于批量绝对移动- 单轴相对运动支持
MoveRelAsync(),但没有批量相对移动入口 - 运动前安全检查已经存在,不应再按旧文档理解为“未实现”
MotionMoveRequest已支持Source、Tags、CorrelationId、BatchId、PositionTolerance、StopOnFailureAxisSpeedManager的自定义速度是基于配置比例缩放,不是固定倍数算法CoordinateTransformer当前仍是占位实现,接入前必须替换ApproachAlignmentService是逼近对位真实入口
17. 总结
当前 MainShell/Motion 模块已经具备一套较完整的运动控制框架:
MotionController负责可靠单轴执行MotionPrecheckService负责运动前安全校验SafeAxisMotion负责业务层统一调用、批量联动与失败联停StagePlatformMotionService负责平台三轴动作封装AxisSpeedManager负责轴速度参数下发与档位管理ApproachAlignmentService提供逼近对位流程框架
其中基础运动控制、预检查、安全联停和平台联动已经可以作为业务入口直接使用;逼近对位部分仍需补齐真实坐标变换,才能形成可用于生产的完整闭环。