Merge remote-tracking branch 'origin/xtkuang_dev' into xtkuang_dev

This commit is contained in:
linbo 2026-08-19 11:18:55 +08:00
commit c66e25ec92
4 changed files with 36 additions and 19 deletions

View File

@ -106,9 +106,11 @@ cmake --install build
`RobotModeType` 和硬件急停来源;首次有效样本前、监控断线或样本过期时, `RobotModeType` 和硬件急停来源;首次有效样本前、监控断线或样本过期时,
所有 Move、Speed、Servo 和程序启动请求均按不安全状态拒绝; 所有 Move、Speed、Servo 和程序启动请求均按不安全状态拒绝;
- 硬件急停会立即使当前运动 generation 失效,并在急停输入有效期间保持锁存。 - 硬件急停会立即使当前运动 generation 失效,并在急停输入有效期间保持锁存。
检测到硬件急停输入消失且控制器重新报告 `Normal`/`ReducedMode` 后,后端应 AUBO SDK 将示教器/控制柜急停报告为 `RobotEmergencyStop`,将控制器系统急停
自动执行 `poweron()` 和 `startup()`,恢复到 `Running` 后再完成安全确认并开放新的 (外部系统急停输入)报告为 `SystemEmergencyStop`;两者在本后端都属于硬件急停。
gRPC 控制指令;防护停机和 Safety Fault/Violation 仍保持显式恢复语义; 检测到任一硬件急停输入消失且控制器重新报告 `Normal`/`ReducedMode` 后,后端自动
执行 `poweron()` 和 `startup()`,恢复到 `Running` 后再完成安全确认并开放新的 gRPC
控制指令;防护停机和 Safety Fault/Violation 仍保持显式恢复语义;
- `emergencyStop()` 使用独立的 `SoftwareEmergencyStop` 锁存。即使软件急停在真实 - `emergencyStop()` 使用独立的 `SoftwareEmergencyStop` 锁存。即使软件急停在真实
硬件急停有效期间触发,后续硬件采样也不能覆盖该锁存,释放硬件急停开关不会 硬件急停有效期间触发,后续硬件采样也不能覆盖该锁存,释放硬件急停开关不会
自动清除软件急停;它只能通过显式安全恢复流程解除; 自动清除软件急停;它只能通过显式安全恢复流程解除;

View File

@ -470,7 +470,7 @@ void publishSafetySample(
monitor->servo_mode_select.store(servo_mode_select); monitor->servo_mode_select.store(servo_mode_select);
monitor->last_sample_ns.store(monotonicNowNs()); monitor->last_sample_ns.store(monotonicNowNs());
if (emergency_stop_source != 0) { if (aubo_internal::isHardwareEmergencyStop(condition)) {
const bool first_sample_for_event = const bool first_sample_for_event =
!monitor->hardware_emergency_stop_latched.exchange(true); !monitor->hardware_emergency_stop_latched.exchange(true);
if (first_sample_for_event) { if (first_sample_for_event) {
@ -875,8 +875,7 @@ bool hardwareEmergencyStopRecoveryCurrent(
monitor->emergency_stop_source.load() == 0 && snapshot.latched && monitor->emergency_stop_source.load() == 0 && snapshot.latched &&
snapshot.recovery_in_progress && snapshot.epoch == token.epoch && snapshot.recovery_in_progress && snapshot.epoch == token.epoch &&
!snapshot.software_emergency_stop_latched && !snapshot.software_emergency_stop_latched &&
snapshot.latched_reason == aubo_internal::isHardwareEmergencyStop(snapshot.latched_reason) &&
aubo_internal::SafetyCondition::RobotEmergencyStop &&
aubo_internal::isMotionSafe(snapshot.observed); aubo_internal::isMotionSafe(snapshot.observed);
} }
@ -3899,13 +3898,16 @@ Result AuboArm::ensureMotionReady_(
" rejected: hardware safety state is unavailable or stale"); " rejected: hardware safety state is unavailable or stale");
} }
if (monitor->emergency_stop_source.load() != 0) { const auto sampled_condition =
aubo_internal::effectiveSafetyCondition(
safetyConditionFromSdk(static_cast<SafetyModeType>(
monitor->safety_mode.load())),
monitor->emergency_stop_source.load());
if (aubo_internal::isHardwareEmergencyStop(sampled_condition)) {
const auto previous = monitor->safety_state->snapshot(); const auto previous = monitor->safety_state->snapshot();
monitor->safety_state->observe( monitor->safety_state->observe(sampled_condition);
aubo_internal::SafetyCondition::RobotEmergencyStop);
if (!previous.latched || if (!previous.latched ||
previous.observed != previous.observed != sampled_condition) {
aubo_internal::SafetyCondition::RobotEmergencyStop) {
cancelForSafetyTransition(monitor); cancelForSafetyTransition(monitor);
} }
} }
@ -3935,8 +3937,7 @@ Result AuboArm::ensureMotionReady_(
} }
std::string recovery_instruction = std::string recovery_instruction =
"; clear the hardware condition and perform explicit recovery"; "; clear the hardware condition and perform explicit recovery";
if (condition == if (aubo_internal::isHardwareEmergencyStop(condition) &&
aubo_internal::SafetyCondition::RobotEmergencyStop &&
monitor->auto_power_on_after_hardware_estop_release && monitor->auto_power_on_after_hardware_estop_release &&
!monitor->automatic_recovery_suppressed.load()) { !monitor->automatic_recovery_suppressed.load()) {
recovery_instruction = recovery_instruction =

View File

@ -29,10 +29,23 @@ inline bool isMotionSafe(const SafetyCondition condition) noexcept
condition == SafetyCondition::Reduced; condition == SafetyCondition::Reduced;
} }
inline bool isHardwareEmergencyStop(
const SafetyCondition condition) noexcept
{
return condition == SafetyCondition::SystemEmergencyStop ||
condition == SafetyCondition::RobotEmergencyStop;
}
inline SafetyCondition effectiveSafetyCondition( inline SafetyCondition effectiveSafetyCondition(
const SafetyCondition reported_condition, const SafetyCondition reported_condition,
const int robot_emergency_stop_source) noexcept const int robot_emergency_stop_source) noexcept
{ {
// The source bitmask describes robot-side inputs such as the control box
// and teach pendant. Keep the SDK's SystemEmergencyStop classification for
// the separate external system-emergency input.
if (reported_condition == SafetyCondition::SystemEmergencyStop) {
return SafetyCondition::SystemEmergencyStop;
}
if (robot_emergency_stop_source < 0) { if (robot_emergency_stop_source < 0) {
return SafetyCondition::Unknown; return SafetyCondition::Unknown;
} }
@ -89,7 +102,7 @@ inline bool shouldAutoRecoverHardwareEmergencyStop(
hardware_emergency_stop_was_observed && snapshot.latched && hardware_emergency_stop_was_observed && snapshot.latched &&
!snapshot.recovery_in_progress && !snapshot.recovery_in_progress &&
!snapshot.software_emergency_stop_latched && !snapshot.software_emergency_stop_latched &&
snapshot.latched_reason == SafetyCondition::RobotEmergencyStop && isHardwareEmergencyStop(snapshot.latched_reason) &&
isMotionSafe(snapshot.observed) && isMotionSafe(snapshot.observed) &&
current_emergency_stop_source == 0; current_emergency_stop_source == 0;
} }
@ -116,7 +129,7 @@ public:
const bool preserve_hardware_estop_latch = const bool preserve_hardware_estop_latch =
condition == SafetyCondition::Unknown && latched_ && condition == SafetyCondition::Unknown && latched_ &&
latched_reason_ == SafetyCondition::RobotEmergencyStop && isHardwareEmergencyStop(latched_reason_) &&
!software_emergency_stop_latched_; !software_emergency_stop_latched_;
if (!latched_ || recovery_in_progress_ || if (!latched_ || recovery_in_progress_ ||
(changed && !preserve_hardware_estop_latch)) { (changed && !preserve_hardware_estop_latch)) {
@ -199,7 +212,7 @@ public:
if (!token.valid() || token.epoch != epoch_ || !latched_ || if (!token.valid() || token.epoch != epoch_ || !latched_ ||
!recovery_in_progress_ || !recovery_in_progress_ ||
software_emergency_stop_latched_ || software_emergency_stop_latched_ ||
latched_reason_ != SafetyCondition::RobotEmergencyStop || !isHardwareEmergencyStop(latched_reason_) ||
!isMotionSafe(observed_) || !robot_running || !controller_idle || !isMotionSafe(observed_) || !robot_running || !controller_idle ||
!cancellation_confirmed) { !cancellation_confirmed) {
return false; return false;

View File

@ -28,9 +28,10 @@
认证或 TLS 模式会启动失败,不会静默回退。匿名部署的恢复默认关闭,只有显式配置 认证或 TLS 模式会启动失败,不会静默回退。匿名部署的恢复默认关闭,只有显式配置
`RECOVERY_LOCAL_ONLY`、服务端确认实际 peer 为 loopback/Unix socket 且持久审计可写时才可开放。 `RECOVERY_LOCAL_ONLY`、服务端确认实际 peer 为 loopback/Unix socket 且持久审计可写时才可开放。
AUBO 另有一条设备内硬件语义:真实硬件急停曾有效、随后输入消失且控制器重新报告 AUBO 另有一条设备内硬件语义:示教器/控制柜 `RobotEmergencyStop` 或外部系统输入
`Normal/ReducedMode` 时,驱动会自动上电到 `Idle`、清理旧队列、执行 `startup()`,并在 `SystemEmergencyStop` 曾有效、随后输入消失且控制器重新报告 `Normal/ReducedMode` 时,
`Running` 下再次确认 quiescent 后解除该硬件锁存,使新的 gRPC 指令可以重新准入; 驱动会自动上电到 `Idle`、清理旧队列、执行 `startup()`,并在 `Running` 下再次确认
quiescent 后解除该硬件锁存,使新的 gRPC 指令可以重新准入;
软件 `emergencyStop()` 使用独立 `SoftwareEmergencyStop` 锁存,即使它与硬件急停重叠也绝不被 软件 `emergencyStop()` 使用独立 `SoftwareEmergencyStop` 锁存,即使它与硬件急停重叠也绝不被
硬件输入释放自动清除。自动流程不 resume、不重放旧目标;显式 Stop/PowerOff 会取消本轮自动上电。 硬件输入释放自动清除。自动流程不 resume、不重放旧目标;显式 Stop/PowerOff 会取消本轮自动上电。