From d6997b03b1490cd1e17564d4bbc8f8727d68e3f4 Mon Sep 17 00:00:00 2001 From: xtkuang <87661715@qq.com> Date: Tue, 18 Aug 2026 10:12:58 +0800 Subject: [PATCH 01/10] fix aubo hardware estop auto recovery --- .../devices/arm/aubo_arm/aubo_safety_state.h | 15 ++++++++++---- .../aubo_arm/tests/aubo_safety_state_test.cpp | 20 +++++++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/cmvr-es/devices/arm/aubo_arm/aubo_safety_state.h b/cmvr-es/devices/arm/aubo_arm/aubo_safety_state.h index b11fb94d..c99a0c60 100644 --- a/cmvr-es/devices/arm/aubo_arm/aubo_safety_state.h +++ b/cmvr-es/devices/arm/aubo_arm/aubo_safety_state.h @@ -114,7 +114,12 @@ public: return; } - if (!latched_ || recovery_in_progress_ || changed) { + const bool preserve_hardware_estop_latch = + condition == SafetyCondition::Unknown && latched_ && + latched_reason_ == SafetyCondition::RobotEmergencyStop && + !software_emergency_stop_latched_; + if (!latched_ || recovery_in_progress_ || + (changed && !preserve_hardware_estop_latch)) { ++epoch_; } latched_ = true; @@ -122,9 +127,11 @@ public: // A physical E-stop sample can continue arriving after a software // E-stop request. Keep the software stop independently latched so a // later physical-input release can never clear it automatically. - latched_reason_ = software_emergency_stop_latched_ - ? SafetyCondition::SoftwareEmergencyStop - : condition; + if (software_emergency_stop_latched_) { + latched_reason_ = SafetyCondition::SoftwareEmergencyStop; + } else if (!preserve_hardware_estop_latch) { + latched_reason_ = condition; + } } std::optional tryPermit() const diff --git a/cmvr-es/devices/arm/aubo_arm/tests/aubo_safety_state_test.cpp b/cmvr-es/devices/arm/aubo_arm/tests/aubo_safety_state_test.cpp index 716d2b00..1d350990 100644 --- a/cmvr-es/devices/arm/aubo_arm/tests/aubo_safety_state_test.cpp +++ b/cmvr-es/devices/arm/aubo_arm/tests/aubo_safety_state_test.cpp @@ -81,6 +81,26 @@ int main() CHECK_TRUE(recovered_permit.has_value()); CHECK_TRUE(state.validate(*recovered_permit)); + // Some AUBO cabinets drop the SDK connection while the physical E-stop is + // pressed. Losing the monitor sample must not erase the hardware E-stop + // latch; otherwise releasing the switch back to Normal would never trigger + // automatic power-on. + state.observe(SafetyCondition::RobotEmergencyStop); + const auto estop_epoch = state.snapshot().epoch; + state.observe(SafetyCondition::Unknown); + CHECK_TRUE(state.snapshot().latched); + CHECK_TRUE(state.snapshot().latched_reason == + SafetyCondition::RobotEmergencyStop); + CHECK_TRUE(state.snapshot().epoch == estop_epoch); + state.observe(SafetyCondition::Normal); + CHECK_TRUE(shouldAutoRecoverHardwareEmergencyStop( + state.snapshot(), true, 0, true, false)); + const auto disconnected_recovery = state.beginRecovery( + state.snapshot().epoch); + CHECK_TRUE(disconnected_recovery.has_value()); + CHECK_TRUE(state.completeHardwareEmergencyStopRecovery( + *disconnected_recovery, true, true, true)); + // Releasing a real E-stop must never clear a software-triggered stop that // was latched while the hardware input was active. state.observe(SafetyCondition::RobotEmergencyStop); From e28a0a43818e4896e8a61e13ec893f059099339a Mon Sep 17 00:00:00 2001 From: xtkuang <87661715@qq.com> Date: Tue, 18 Aug 2026 10:46:19 +0800 Subject: [PATCH 02/10] skip duplicate torqueOn when already enabled --- .../grpc/server/src/grpc_arm_service.cpp | 18 +++++++ .../server/src/grpc_command_transaction.cpp | 6 ++- .../server/tests/grpc_arm_service_test.cpp | 48 +++++++++++++++++-- 3 files changed, 66 insertions(+), 6 deletions(-) diff --git a/cmvr-es/service/grpc/server/src/grpc_arm_service.cpp b/cmvr-es/service/grpc/server/src/grpc_arm_service.cpp index 3c04f608..c1cb01f4 100644 --- a/cmvr-es/service/grpc/server/src/grpc_arm_service.cpp +++ b/cmvr-es/service/grpc/server/src/grpc_arm_service.cpp @@ -360,6 +360,20 @@ grpc::Status setControlDispatchFailure( " dispatch"); } +grpc::Status setAlreadyEnabled( + api::CommandHeader_Feedback* response, + const std::string& device_id, + const char* rpc_name) +{ + constexpr const char* kAlreadyEnabledMessage = + "RobotArm is already enabled"; + CMVR_LOG(WARNING) << "[gRPCArmServiceImpl] (" << rpc_name + << "): ignored because the device is already enabled, id=" + << device_id; + fillFeedback(response, true, kAlreadyEnabledMessage); + return grpc::Status::OK; +} + } // namespace gRPCArmServiceImpl::gRPCArmServiceImpl() @@ -423,6 +437,10 @@ grpc::Status gRPCArmServiceImpl::torqueOn(grpc::ServerContext* context, if (!arm) { return setDeviceNotFound(response, device_id); } + const auto state = arm->getRobotState(); + if (state.powered_on) { + return setAlreadyEnabled(response, device_id, "torqueOn"); + } ScopedUnaryControlLease control_lease( device_id, "torqueOn"); if (!control_lease.acquired()) { diff --git a/cmvr-es/service/grpc/server/src/grpc_command_transaction.cpp b/cmvr-es/service/grpc/server/src/grpc_command_transaction.cpp index bba5b75e..16549ed3 100644 --- a/cmvr-es/service/grpc/server/src/grpc_command_transaction.cpp +++ b/cmvr-es/service/grpc/server/src/grpc_command_transaction.cpp @@ -961,7 +961,9 @@ grpc::Status GrpcCommandTransaction::finish( : dispatch_started_ ? safety::CommandLifecycle::Failed : safety::CommandLifecycle::RejectedBeforeDispatch); const std::string detail = success - ? std::string{} + ? feedback && !feedback->error_message().empty() + ? feedback->error_message() + : std::string{} : feedback && !feedback->error_message().empty() ? feedback->error_message() : operation_status.error_message(); @@ -1134,7 +1136,7 @@ void GrpcCommandTransaction::populateFeedback_( feedback->set_error_message( detail.empty() ? safety::toString(reason) : detail); } - if (success) { + if (success && feedback->error_message().empty()) { feedback->clear_error_message(); } if (!feedback->has_timestamp()) { diff --git a/cmvr-es/service/grpc/server/tests/grpc_arm_service_test.cpp b/cmvr-es/service/grpc/server/tests/grpc_arm_service_test.cpp index 980d5b7f..f9720de4 100644 --- a/cmvr-es/service/grpc/server/tests/grpc_arm_service_test.cpp +++ b/cmvr-es/service/grpc/server/tests/grpc_arm_service_test.cpp @@ -1,5 +1,6 @@ #include "service/grpc/server/include/grpc_arm_service.h" +#include #include #include #include @@ -48,7 +49,16 @@ public: device::RobotModel getRobotModel() const override { return {}; } std::size_t getDof() const override { return 0U; } - device::ArmState getRobotState() const override { return {}; } + device::ArmState getRobotState() const override + { + device::ArmState state; + state.connected = true; + state.powered_on = powered_on_.load(); + state.robot_mode = state.powered_on + ? device::RobotMode::Running + : device::RobotMode::PowerOff; + return state; + } device::JointGroupState getJointState() const override { return {}; } device::CartesianPose getTcpPose( device::FrameType = device::FrameType::Base) const override @@ -325,6 +335,11 @@ public: return torque_on_calls_; } + void setPoweredOn(const bool powered_on) + { + powered_on_.store(powered_on); + } + bool lastTorqueOnHadCancellation() const { std::lock_guard lock(motion_mutex_); @@ -505,6 +520,7 @@ private: bool last_torque_on_cancellation_requested_{false}; bool last_motion_had_cancellation_{false}; bool last_motion_cancellation_requested_{false}; + std::atomic powered_on_{false}; }; class JsonCommandNonArmDevice final : public device::AbstractDevice { @@ -641,13 +657,20 @@ protected: return service_->torqueOff(&context, &request, &response); } - MoveOutcome torqueOn(const std::string& device_id) + grpc::Status torqueOn( + const std::string& device_id, + api::CommandHeader_Feedback& response) { api::CommandHeader_Request request; request.set_device_id(device_id); - api::CommandHeader_Feedback response; grpc::ServerContext context; - auto status = service_->torqueOn(&context, &request, &response); + return service_->torqueOn(&context, &request, &response); + } + + MoveOutcome torqueOn(const std::string& device_id) + { + api::CommandHeader_Feedback response; + auto status = torqueOn(device_id, response); return { std::move(status), response.success(), @@ -752,6 +775,23 @@ TEST_F(GrpcArmServiceTest, EXPECT_EQ(left_arm_->execute_calls, 0); } +TEST_F(GrpcArmServiceTest, + TorqueOnAlreadyEnabledArmReturnsOkWithoutDispatchingBackend) +{ + aubo_arm_->setPoweredOn(true); + + api::CommandHeader_Feedback response; + const auto status = torqueOn("aubo_arm", response); + + ASSERT_TRUE(status.ok()) << status.error_message(); + EXPECT_TRUE(response.success()); + EXPECT_EQ(response.error_message(), "RobotArm is already enabled"); + EXPECT_EQ( + response.reason_code(), + api::COMMAND_REASON_CODE_NONE); + EXPECT_EQ(aubo_arm_->torqueOnCalls(), 0); +} + TEST_F(GrpcArmServiceTest, StopMotionRevokesBlockedMoveJLeaseBeforeMoveLReturns) { From 1dfe23641d09cd1661c9e4eb6289d8b6c57c4afd Mon Sep 17 00:00:00 2001 From: xtkuang <87661715@qq.com> Date: Tue, 18 Aug 2026 11:27:12 +0800 Subject: [PATCH 03/10] fix aubo clearFault recovery --- cmvr-es/devices/arm/aubo_arm/aubo_arm.cpp | 62 ++++++++++++++++------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/cmvr-es/devices/arm/aubo_arm/aubo_arm.cpp b/cmvr-es/devices/arm/aubo_arm/aubo_arm.cpp index 4c0da356..78eca49a 100644 --- a/cmvr-es/devices/arm/aubo_arm/aubo_arm.cpp +++ b/cmvr-es/devices/arm/aubo_arm/aubo_arm.cpp @@ -3321,6 +3321,19 @@ Result AuboArm::clearFault() } std::unique_lock command_rpc_lock( monitor->command_rpc_mutex); + const auto recover_with_torque_on = + [this, &command_rpc_lock]() -> Result { + if (command_rpc_lock.owns_lock()) { + command_rpc_lock.unlock(); + } + auto recovery = torqueOn(); + if (!recovery.ok()) { + recovery.message = + "[AuboArm] clearFault recovery failed: " + + recovery.message; + } + return recovery; + }; Result interface_result; auto robot_interface = getPrimaryRobotInterface( rpc_client, "clearFault", interface_result); @@ -3330,18 +3343,15 @@ Result AuboArm::clearFault() refreshSafetySample(rpc_client, monitor, robot_interface); auto snapshot = monitor->safety_state->snapshot(); const std::uint64_t expected_safety_epoch = snapshot.epoch; + const int entry_robot_mode = monitor->robot_mode.load(); if (!snapshot.latched && aubo_internal::isMotionSafe(snapshot.observed) && - monitor->robot_mode.load() != - static_cast(RobotModeType::Error)) { - return Result::success(); - } - if (!snapshot.latched && - monitor->robot_mode.load() == - static_cast(RobotModeType::Error)) { - return Result::failure( - ArmErrorCode::RobotInFault, - "[AuboArm] clearFault rejected: RobotMode is Error even though the safety mode is Normal/Reduced"); + entry_robot_mode != static_cast(RobotModeType::Error)) { + if (entry_robot_mode == + static_cast(RobotModeType::Running)) { + return Result::success(); + } + return recover_with_torque_on(); } if (monitor->emergency_stop_source.load() != 0) { return Result::failure( @@ -3353,22 +3363,38 @@ Result AuboArm::clearFault() aubo_internal::needsProtectiveUnlock( snapshot.latched_reason)) { command_rpc_lock.unlock(); - return unlockProtectiveStop_(expected_safety_epoch); + auto unlock_result = + unlockProtectiveStop_(expected_safety_epoch); + if (unlock_result.ok()) { + return monitor->robot_mode.load() == + static_cast(RobotModeType::Running) + ? Result::success() + : recover_with_torque_on(); + } + if (unlock_result.code == ArmErrorCode::RobotNotPowered) { + return recover_with_torque_on(); + } + return unlock_result; } - if (aubo_internal::isMotionSafe(snapshot.observed)) { + const bool controller_fault_requires_restart = + aubo_internal::isMotionSafe(snapshot.observed) && + monitor->robot_mode.load() == + static_cast(RobotModeType::Error); + + if (aubo_internal::isMotionSafe(snapshot.observed) && + !controller_fault_requires_restart) { if (monitor->robot_mode.load() == static_cast(RobotModeType::Running)) { command_rpc_lock.unlock(); return completeSafetyRecovery_( "clearFault", expected_safety_epoch); } - return Result::failure( - ArmErrorCode::RobotNotPowered, - "[AuboArm] safety condition is clear, but torqueOn is required to verify the old queue and complete recovery"); + return recover_with_torque_on(); } - if (!aubo_internal::needsInterfaceBoardRestart( + if (!controller_fault_requires_restart && + !aubo_internal::needsInterfaceBoardRestart( snapshot.observed)) { const std::string guidance = snapshot.observed == @@ -3415,9 +3441,7 @@ Result AuboArm::clearFault() return completeSafetyRecovery_( "clearFault", expected_safety_epoch); } - return Result::failure( - ArmErrorCode::RobotNotPowered, - "[AuboArm] controller fault was reset, but the safety latch remains until torqueOn verifies an empty queue in Running mode"); + return recover_with_torque_on(); } catch (const std::exception& e) { return Result::failure( ArmErrorCode::CommandFailed, From 8ac1bff0997067ca3ad3c99587aa3df0989e3a96 Mon Sep 17 00:00:00 2001 From: xtkuang <87661715@qq.com> Date: Tue, 18 Aug 2026 15:03:17 +0800 Subject: [PATCH 04/10] add system operational state recovery --- .../src/device_safety_adapters.cpp | 127 +++++++- .../include/device_safety_endpoint.h | 11 + .../safety_manager/include/safety_manager.h | 8 +- .../safety_manager/src/safety_manager.cpp | 229 +++++++++++--- .../tests/safety_manager_test.cpp | 279 +++++++++++++++++- .../grpc/server/include/grpc_system_service.h | 1 + .../service/grpc/server/src/grpc_security.cpp | 3 + .../grpc/server/src/grpc_system_service.cpp | 160 ++++++++++ .../server/tests/grpc_system_service_test.cpp | 181 +++++++++++- ...evice_safety_control_plane_architecture.md | 24 +- protos/cmvr/api/safety_command.proto | 18 ++ protos/cmvr/api/system_service.proto | 1 + 12 files changed, 986 insertions(+), 56 deletions(-) diff --git a/cmvr-es/manager/device_manager/src/device_safety_adapters.cpp b/cmvr-es/manager/device_manager/src/device_safety_adapters.cpp index eb627d0f..9afdfa6c 100644 --- a/cmvr-es/manager/device_manager/src/device_safety_adapters.cpp +++ b/cmvr-es/manager/device_manager/src/device_safety_adapters.cpp @@ -55,6 +55,8 @@ using safety::TriState; using Probe = std::function; using Operation = std::function; +using RecoveryOperation = + std::function; TriState tri(const bool value) noexcept { @@ -66,6 +68,59 @@ bool agvStopResultAccepted(const AgvResult& result) noexcept return result.ok() || result.code == AgvErrorCode::UnsupportedCommand; } +bool armQuiescentForSafety(const ArmState& state) noexcept +{ + return state.protective_stopped || state.emergency_stopped || + (!state.moving && !state.program_running); +} + +SafetyReason armRecoveryReason(const ArmErrorCode code) noexcept +{ + switch (code) { + case ArmErrorCode::NotConnected: + case ArmErrorCode::ConnectionFailed: + return SafetyReason::DeviceDisconnected; + case ArmErrorCode::Timeout: + return SafetyReason::ParticipantTimeout; + case ArmErrorCode::RobotInEmergencyStop: + return SafetyReason::EmergencyStopActive; + case ArmErrorCode::RobotInProtectiveStop: + return SafetyReason::ProtectiveStopActive; + case ArmErrorCode::RobotInFault: + return SafetyReason::DeviceFault; + case ArmErrorCode::RobotNotReady: + case ArmErrorCode::RobotNotPowered: + return SafetyReason::DeviceNotReady; + case ArmErrorCode::UnsupportedCommand: + return SafetyReason::UnsupportedCommand; + case ArmErrorCode::OK: + return SafetyReason::None; + default: + return SafetyReason::DeviceFault; + } +} + +SafetyReason agvRecoveryReason(const AgvErrorCode code) noexcept +{ + switch (code) { + case AgvErrorCode::NotConnected: + case AgvErrorCode::ConnectionFailed: + return SafetyReason::DeviceDisconnected; + case AgvErrorCode::Timeout: + return SafetyReason::ParticipantTimeout; + case AgvErrorCode::EmergencyStopped: + return SafetyReason::EmergencyStopActive; + case AgvErrorCode::Fault: + return SafetyReason::DeviceFault; + case AgvErrorCode::UnsupportedCommand: + return SafetyReason::UnsupportedCommand; + case AgvErrorCode::OK: + return SafetyReason::None; + default: + return SafetyReason::DeviceFault; + } +} + SafetyBlocker blocker( const SafetyReason reason, const std::string& source) @@ -133,9 +188,13 @@ DeviceSafetyDescriptor defaultDescriptor(const AbstractDevice& device) class LegacyDeviceSafetyEndpoint final : public DeviceSafetyEndpoint { public: - LegacyDeviceSafetyEndpoint(DeviceSafetyDescriptor descriptor, Probe probe) + LegacyDeviceSafetyEndpoint( + DeviceSafetyDescriptor descriptor, + Probe probe, + RecoveryOperation operational_recovery) : descriptor_(std::move(descriptor)), probe_(std::move(probe)), + operational_recovery_(std::move(operational_recovery)), poll_interval_(std::clamp( descriptor_.maximum_snapshot_age / 2, std::chrono::milliseconds(50), @@ -272,6 +331,18 @@ public: return {true, SafetyReason::None, {}}; } + RecoveryCheckResult restoreOperationalState( + const RecoveryContext& context) override + { + if (!operational_recovery_) { + return { + false, + SafetyReason::UnsupportedCommand, + "device does not support operational recovery"}; + } + return operational_recovery_(context); + } + private: DeviceSafetySnapshot sample_() { @@ -334,6 +405,7 @@ private: DeviceSafetyDescriptor descriptor_; Probe probe_; + RecoveryOperation operational_recovery_; const std::chrono::milliseconds poll_interval_; std::atomic generation_{1}; std::atomic sequence_{0}; @@ -523,8 +595,9 @@ Probe probeFor(const std::shared_ptr& device) state.connected && state.powered_on && !state.fault && !state.emergency_stopped && !state.protective_stopped); - snapshot.quiescent = tri(!state.moving && !state.program_running); - snapshot.motion_active = tri(state.moving || state.program_running); + const bool quiescent = armQuiescentForSafety(state); + snapshot.quiescent = tri(quiescent); + snapshot.motion_active = tri(!quiescent); snapshot.actuator_enabled = tri(state.powered_on); snapshot.emergency_stop_active = tri(state.emergency_stopped); snapshot.protective_stop_active = tri(state.protective_stopped); @@ -571,7 +644,7 @@ Probe probeFor(const std::shared_ptr& device) snapshot.motion_active = tri(state.moving || active_navigation); snapshot.actuator_enabled = TriState::Unknown; snapshot.emergency_stop_active = tri(state.emergency_stopped); - snapshot.protective_stop_active = TriState::Unknown; + snapshot.protective_stop_active = TriState::False; snapshot.fault_active = tri(state.fault); snapshot.condition = !state.connected ? SafetyCondition::Unknown @@ -599,8 +672,6 @@ Probe probeFor(const std::shared_ptr& device) : TriState::Unknown; snapshot.motion_active = TriState::Unknown; snapshot.actuator_enabled = TriState::Unknown; - snapshot.emergency_stop_active = TriState::Unknown; - snapshot.protective_stop_active = TriState::Unknown; snapshot.fault_active = tri( state == AbstractDexHand::Status::FAULT); snapshot.condition = !connected @@ -715,8 +786,6 @@ Probe probeFor(const std::shared_ptr& device) snapshot.operational_ready = tri(!state.error); snapshot.quiescent = TriState::Unknown; snapshot.motion_active = TriState::Unknown; - snapshot.emergency_stop_active = TriState::Unknown; - snapshot.protective_stop_active = TriState::Unknown; snapshot.fault_active = tri(state.error); snapshot.condition = state.error ? SafetyCondition::Unsafe @@ -759,6 +828,42 @@ Probe probeFor(const std::shared_ptr& device) }; } +RecoveryOperation operationalRecoveryFor( + const std::shared_ptr& device) +{ + if (const auto arm = std::dynamic_pointer_cast(device)) { + return [arm](const RecoveryContext& context) { + if (SafetyClock::now() >= context.deadline) { + return RecoveryCheckResult{ + false, + SafetyReason::ParticipantTimeout, + "operational recovery deadline expired before clearFault"}; + } + const auto result = arm->clearFault(); + return RecoveryCheckResult{ + result.ok(), + armRecoveryReason(result.code), + result.ok() ? std::string{} : result.message}; + }; + } + if (const auto agv = std::dynamic_pointer_cast(device)) { + return [agv](const RecoveryContext& context) { + if (SafetyClock::now() >= context.deadline) { + return RecoveryCheckResult{ + false, + SafetyReason::ParticipantTimeout, + "operational recovery deadline expired before clearFault"}; + } + const auto result = agv->clearFault(); + return RecoveryCheckResult{ + result.ok(), + agvRecoveryReason(result.code), + result.ok() ? std::string{} : result.message}; + }; + } + return {}; +} + std::shared_ptr participantFor( const std::shared_ptr& device, const DeviceSafetyDescriptor& safety_descriptor, @@ -781,7 +886,7 @@ std::shared_ptr participantFor( }; verify = [arm] { const auto state = arm->getRobotState(); - const bool stopped = !state.moving && !state.program_running; + const bool stopped = armQuiescentForSafety(state); return ParticipantResult{ stopped, stopped ? SafetyReason::None @@ -998,7 +1103,9 @@ safety::DeviceSafetyRegistration makeDeviceSafetyRegistration( } else { registration.descriptor = defaultDescriptor(*device); registration.endpoint = std::make_shared( - registration.descriptor, probeFor(device)); + registration.descriptor, + probeFor(device), + operationalRecoveryFor(device)); } if (configured_maximum_age > std::chrono::milliseconds::zero()) { diff --git a/cmvr-es/manager/safety_manager/include/device_safety_endpoint.h b/cmvr-es/manager/safety_manager/include/device_safety_endpoint.h index 836ca6b8..c060b8b7 100644 --- a/cmvr-es/manager/safety_manager/include/device_safety_endpoint.h +++ b/cmvr-es/manager/safety_manager/include/device_safety_endpoint.h @@ -26,6 +26,17 @@ public: } virtual HardwareCheckResult validateBeforeDispatch( const AdmissionPermit& permit) = 0; + // Explicit operator-authorized recovery which may power or enable the + // device. RecoverSafetyState never calls this method; it is reserved for + // RestoreOperationalState transactions. + virtual RecoveryCheckResult restoreOperationalState( + const RecoveryContext&) + { + return { + false, + SafetyReason::UnsupportedCommand, + "device does not support operational recovery"}; + } virtual RecoveryCheckResult reconcileAdmissionState( const RecoveryContext& context) = 0; }; diff --git a/cmvr-es/manager/safety_manager/include/safety_manager.h b/cmvr-es/manager/safety_manager/include/safety_manager.h index 1ea4c982..20661939 100644 --- a/cmvr-es/manager/safety_manager/include/safety_manager.h +++ b/cmvr-es/manager/safety_manager/include/safety_manager.h @@ -118,11 +118,13 @@ struct RecoveryRequest { bool all_devices{false}; std::uint64_t expected_safety_epoch{0}; bool verify_only{true}; + bool restore_operational_state{false}; std::string reason; SafetyClock::time_point deadline{SafetyClock::time_point::max()}; - // Called only for a latch-clearing transaction, after hardware facts have - // been verified and before any software barrier is reconciled or released. - // A false result leaves admission latched. + // Authorizes the state-changing part of recovery. Operational restore + // calls this before invoking device recovery; software-only recovery calls + // it after hardware verification and before releasing admission barriers. + // A false result leaves admission latched and prevents device recovery. std::function authorize_clear; }; diff --git a/cmvr-es/manager/safety_manager/src/safety_manager.cpp b/cmvr-es/manager/safety_manager/src/safety_manager.cpp index bbb31eeb..10d3c42e 100644 --- a/cmvr-es/manager/safety_manager/src/safety_manager.cpp +++ b/cmvr-es/manager/safety_manager/src/safety_manager.cpp @@ -1759,7 +1759,10 @@ RecoveryResult SafetyManager::recover(const RecoveryRequest& request) RecoveryResult invalid; invalid.recovery_id = request.recovery_id; if (request.recovery_id.empty() || request.reason.empty() || - (!request.all_devices && request.device_ids.empty())) { + (!request.all_devices && request.device_ids.empty()) || + (request.restore_operational_state && + (request.verify_only || !request.all_devices || + !request.authorize_clear))) { invalid.result = RecoveryResultCode::Failed; invalid.targets.push_back({ "system", @@ -1767,7 +1770,9 @@ RecoveryResult SafetyManager::recover(const RecoveryRequest& request) request.reason.empty() ? SafetyReason::RecoveryReasonRequired : SafetyReason::InvalidArgument, - "recovery_id, reason, and an explicit non-empty scope are required"}); + request.restore_operational_state + ? "operational restore requires all_devices, latch clearing, and explicit authorization" + : "recovery_id, reason, and an explicit non-empty scope are required"}); return invalid; } std::unordered_set unique_ids; @@ -1787,7 +1792,9 @@ RecoveryResult SafetyManager::recover(const RecoveryRequest& request) std::sort(fingerprint_ids.begin(), fingerprint_ids.end()); std::ostringstream fingerprint; fingerprint << request.expected_safety_epoch << ':' - << request.verify_only << ':' << request.all_devices << ':' + << request.verify_only << ':' + << request.restore_operational_state << ':' + << request.all_devices << ':' << request.reason; for (const auto& id : fingerprint_ids) { fingerprint << ':' << id; @@ -1912,7 +1919,9 @@ RecoveryResult SafetyManager::recover(const RecoveryRequest& request) request.recovery_id, request.verify_only ? "recovery verification started" - : "software latch recovery started"); + : request.restore_operational_state + ? "operational state restoration started" + : "software latch recovery started"); } } @@ -1972,6 +1981,101 @@ RecoveryResult SafetyManager::recover(const RecoveryRequest& request) result.current_safety_epoch, deadline, request.verify_only}; + bool clear_authorization_checked = false; + bool clear_authorized = true; + if (request.restore_operational_state && request.authorize_clear) { + clear_authorization_checked = true; + try { + clear_authorized = request.authorize_clear(); + } catch (...) { + clear_authorized = false; + } + } + if (request.restore_operational_state && !clear_authorized && + targets.empty()) { + all_verified = false; + result.targets.push_back({ + "system", + false, + SafetyReason::RecoveryAuditFailed, + "persistent recovery audit did not authorize operational restore"}); + } + + const auto validate_snapshot = []( + const SafetySnapshotView& view, + const SafetyPolicyFamily policy, + const bool require_operational_ready) { + if (!view.fresh) { + return RecoveryCheckResult{ + false, + SafetyReason::SafetyStateStale, + "refreshed safety sample is stale"}; + } + if (view.snapshot.condition == SafetyCondition::Unknown) { + return RecoveryCheckResult{ + false, + SafetyReason::SafetyStateMissing, + "hardware safety condition remains unknown"}; + } + if (view.snapshot.connected != TriState::True) { + return RecoveryCheckResult{ + false, + SafetyReason::DeviceDisconnected, + "device connection is not confirmed"}; + } + if (policy == SafetyPolicyFamily::Control) { + if (view.snapshot.emergency_stop_active != TriState::False) { + return RecoveryCheckResult{ + false, + SafetyReason::EmergencyStopActive, + "emergency stop is active or unknown"}; + } + if (view.snapshot.protective_stop_active != TriState::False) { + return RecoveryCheckResult{ + false, + SafetyReason::ProtectiveStopActive, + "protective stop is active or unknown"}; + } + if (view.snapshot.fault_active != TriState::False) { + return RecoveryCheckResult{ + false, + SafetyReason::DeviceFault, + "device fault remains active or unknown"}; + } + } else if (view.snapshot.fault_active == TriState::True) { + return RecoveryCheckResult{ + false, + SafetyReason::DeviceFault, + "device fault remains active"}; + } + if (view.snapshot.condition == SafetyCondition::Unsafe) { + return RecoveryCheckResult{ + false, + SafetyReason::HardwareUnsafe, + "hardware safety condition remains unsafe"}; + } + if (policy == SafetyPolicyFamily::Control && + view.snapshot.quiescent != TriState::True) { + return RecoveryCheckResult{ + false, + SafetyReason::DeviceStillMoving, + "control device has not confirmed a quiescent state"}; + } + if (require_operational_ready && + (view.snapshot.condition != SafetyCondition::Nominal || + view.snapshot.operational_ready != TriState::True)) { + return RecoveryCheckResult{ + false, + SafetyReason::DeviceNotReady, + "device did not confirm a nominal operational state"}; + } + return RecoveryCheckResult{true, SafetyReason::None, {}}; + }; + + if (request.restore_operational_state) { + std::lock_guard lock(impl_->mutex); + impl_->active_operation_phase = "restore_devices"; + } for (const auto& target : targets) { SafetyTargetResult target_result; target_result.target_id = target.id; @@ -1990,37 +2094,81 @@ RecoveryResult SafetyManager::recover(const RecoveryRequest& request) target_result.reason = SafetyReason::SafetyStateStale; target_result.detail = "active safety refresh did not publish a newer sample"; - } else if (!view.fresh) { - target_result.reason = SafetyReason::SafetyStateStale; - target_result.detail = "refreshed safety sample is stale"; - } else if (view.snapshot.condition == SafetyCondition::Unknown) { - target_result.reason = SafetyReason::SafetyStateMissing; - target_result.detail = "hardware safety condition remains unknown"; - } else if (view.snapshot.condition == SafetyCondition::Unsafe) { - target_result.reason = SafetyReason::HardwareUnsafe; - target_result.detail = "hardware safety condition remains unsafe"; - } else if (view.snapshot.connected != TriState::True) { - target_result.reason = SafetyReason::DeviceDisconnected; - target_result.detail = "device connection is not confirmed"; - } else if (view.snapshot.emergency_stop_active != TriState::False) { - target_result.reason = SafetyReason::EmergencyStopActive; - target_result.detail = - "emergency stop must be released and observed as false"; - } else if (view.snapshot.protective_stop_active != TriState::False) { - target_result.reason = SafetyReason::ProtectiveStopActive; - target_result.detail = - "protective stop must be resolved by the typed hardware flow"; - } else if (view.snapshot.fault_active != TriState::False) { - target_result.reason = SafetyReason::DeviceFault; - target_result.detail = "device fault remains active or unknown"; - } else if (target.policy == SafetyPolicyFamily::Control && - view.snapshot.quiescent != TriState::True) { - target_result.reason = SafetyReason::DeviceStillMoving; - target_result.detail = - "control device has not confirmed a quiescent state"; } else { - target_result.success = true; - target_result.reason = SafetyReason::None; + RecoveryCheckResult checked; + if (!request.restore_operational_state) { + checked = validate_snapshot(view, target.policy, false); + } else if (!clear_authorized) { + checked = { + false, + SafetyReason::RecoveryAuditFailed, + "persistent recovery audit did not authorize operational restore"}; + } else if (!view.fresh) { + checked = { + false, + SafetyReason::SafetyStateStale, + "refreshed safety sample is stale"}; + } else if (view.snapshot.condition == SafetyCondition::Unknown) { + checked = { + false, + SafetyReason::SafetyStateMissing, + "hardware safety condition remains unknown"}; + } else if (view.snapshot.connected != TriState::True) { + checked = { + false, + SafetyReason::DeviceDisconnected, + "device connection is not confirmed"}; + } else if (target.policy == SafetyPolicyFamily::Control && + view.snapshot.emergency_stop_active != + TriState::False) { + checked = { + false, + SafetyReason::EmergencyStopActive, + "emergency stop must be released before operational recovery"}; + } else if (target.policy == SafetyPolicyFamily::Control && + view.snapshot.quiescent != TriState::True) { + checked = { + false, + SafetyReason::DeviceStillMoving, + "control device has not confirmed a quiescent state"}; + } else { + checked = validate_snapshot(view, target.policy, true); + if (!checked.reconciled) { + try { + checked = target.endpoint->restoreOperationalState( + recovery_context); + } catch (const std::exception& error) { + checked = { + false, SafetyReason::InternalError, error.what()}; + } catch (...) { + checked = { + false, + SafetyReason::InternalError, + "device operational recovery threw an unknown exception"}; + } + if (checked.reconciled) { + const auto restored_sequence = + view.snapshot.sample_sequence; + target.endpoint->requestSafetyRefresh(); + if (!impl_->snapshots.waitForNewerSample( + target.id, + restored_sequence, + deadline, + view)) { + checked = { + false, + SafetyReason::SafetyStateStale, + "operational recovery did not publish a newer safety sample"}; + } else { + checked = validate_snapshot( + view, target.policy, true); + } + } + } + } + target_result.success = checked.reconciled; + target_result.reason = checked.reason; + target_result.detail = std::move(checked.detail); } if (!target_result.success) { @@ -2030,7 +2178,10 @@ RecoveryResult SafetyManager::recover(const RecoveryRequest& request) } std::vector retained_candidate_ids; - if (!request.verify_only) { + const bool operational_hardware_verified = all_verified; + if (!request.verify_only && + (!request.restore_operational_state || + operational_hardware_verified)) { const bool has_device_clear_candidate = std::any_of( result.targets.begin(), result.targets.end(), [](const auto& target) { return target.success; }); @@ -2059,8 +2210,9 @@ RecoveryResult SafetyManager::recover(const RecoveryRequest& request) const bool has_clear_candidate = has_device_clear_candidate || !retained_candidate_ids.empty(); - bool clear_authorized = true; - if (has_clear_candidate && request.authorize_clear) { + if (has_clear_candidate && request.authorize_clear && + !clear_authorization_checked) { + clear_authorization_checked = true; try { clear_authorized = request.authorize_clear(); } catch (...) { @@ -2270,7 +2422,8 @@ RecoveryResult SafetyManager::recover(const RecoveryRequest& request) if (device == impl_->devices.end()) { continue; } - if (target.success && !request.verify_only) { + if (target.success && !request.verify_only && + (!request.restore_operational_state || all_verified)) { device->second.quarantined = false; device->second.software_blockers.clear(); } diff --git a/cmvr-es/manager/safety_manager/tests/safety_manager_test.cpp b/cmvr-es/manager/safety_manager/tests/safety_manager_test.cpp index 1667e251..04fd32c2 100644 --- a/cmvr-es/manager/safety_manager/tests/safety_manager_test.cpp +++ b/cmvr-es/manager/safety_manager/tests/safety_manager_test.cpp @@ -10,10 +10,10 @@ namespace cmvr::safety { namespace { -DeviceSafetyDescriptor controlDescriptor() +DeviceSafetyDescriptor controlDescriptor(std::string device_id = "arm") { DeviceSafetyDescriptor descriptor; - descriptor.device_id = "arm"; + descriptor.device_id = std::move(device_id); descriptor.kind = device::DeviceKind::Arm; descriptor.default_policy = SafetyPolicyFamily::Control; descriptor.maximum_snapshot_age = std::chrono::seconds(1); @@ -75,6 +75,23 @@ public: return recovery_check; } + RecoveryCheckResult restoreOperationalState( + const RecoveryContext&) override + { + ++operational_restores; + if (operational_restore_check.reconciled && + restore_to_nominal_on_success) { + condition = SafetyCondition::Nominal; + connected = TriState::True; + ready = TriState::True; + quiescent = TriState::True; + emergency_stop = TriState::False; + protective_stop = TriState::False; + fault = TriState::False; + } + return operational_restore_check; + } + DeviceSafetyDescriptor descriptor_; SafetySnapshotPublisher publisher_; SafetyCondition condition{SafetyCondition::Nominal}; @@ -86,11 +103,15 @@ public: TriState fault{TriState::False}; HardwareCheckResult final_check{true, SafetyReason::None, {}}; RecoveryCheckResult recovery_check{true, SafetyReason::None, {}}; + RecoveryCheckResult operational_restore_check{ + true, SafetyReason::None, {}}; std::uint64_t generation{1}; std::uint64_t sequence{0}; bool publish_on_refresh{true}; std::atomic hardware_checks{0}; std::atomic recoveries{0}; + std::atomic operational_restores{0}; + bool restore_to_nominal_on_success{true}; }; class FakeParticipant final : public SafetyParticipant { @@ -466,6 +487,260 @@ TEST(SafetyManagerTest, RecoveryCannotIgnoreEmergencyStop) EXPECT_EQ(endpoint->recoveries.load(), 0); } +TEST(SafetyManagerTest, + OperationalRestoreClearsRecoverableHardwareAndSoftwareState) +{ + SafetyManager coordinator; + auto endpoint = std::make_shared(controlDescriptor()); + endpoint->condition = SafetyCondition::Unsafe; + endpoint->ready = TriState::False; + endpoint->protective_stop = TriState::True; + endpoint->quiescent = TriState::True; + ASSERT_TRUE(coordinator.registerDevice( + {controlDescriptor(), endpoint, {}})); + coordinator.markStartupComplete(); + coordinator.quarantineDevice("arm", SafetyReason::OutcomeUnknown); + const auto before = coordinator.snapshot(); + + RecoveryRequest request; + request.recovery_id = "restore-operational"; + request.all_devices = true; + request.expected_safety_epoch = before.safety_epoch; + request.verify_only = false; + request.restore_operational_state = true; + request.reason = "operator confirmed the work cell is clear"; + request.deadline = SafetyClock::now() + std::chrono::seconds(1); + request.authorize_clear = [] { return true; }; + + const auto restored = coordinator.recover(request); + + EXPECT_EQ(restored.result, RecoveryResultCode::Recovered); + EXPECT_EQ(restored.system_state, SystemAdmissionState::Open); + ASSERT_EQ(restored.targets.size(), 1U); + EXPECT_TRUE(restored.targets.front().success) + << restored.targets.front().detail; + EXPECT_EQ(endpoint->operational_restores.load(), 1); + EXPECT_EQ(endpoint->recoveries.load(), 1); + EXPECT_EQ( + coordinator.snapshot().devices.front().admission_state, + DeviceAdmissionState::Open); +} + +TEST(SafetyManagerTest, OperationalRestoreFailsClosedOnActiveEmergencyStop) +{ + SafetyManager coordinator; + auto endpoint = std::make_shared(controlDescriptor()); + endpoint->condition = SafetyCondition::Unsafe; + endpoint->ready = TriState::False; + endpoint->emergency_stop = TriState::True; + endpoint->quiescent = TriState::True; + endpoint->operational_restore_check = { + false, + SafetyReason::EmergencyStopActive, + "hardware emergency-stop input is still active"}; + ASSERT_TRUE(coordinator.registerDevice( + {controlDescriptor(), endpoint, {}})); + coordinator.markStartupComplete(); + coordinator.quarantineDevice("arm", SafetyReason::OutcomeUnknown); + const auto before = coordinator.snapshot(); + + RecoveryRequest request; + request.recovery_id = "restore-active-estop"; + request.all_devices = true; + request.expected_safety_epoch = before.safety_epoch; + request.verify_only = false; + request.restore_operational_state = true; + request.reason = "operator requested recovery"; + request.deadline = SafetyClock::now() + std::chrono::seconds(1); + request.authorize_clear = [] { return true; }; + + const auto restored = coordinator.recover(request); + + EXPECT_EQ(restored.result, RecoveryResultCode::BlockerRemains); + EXPECT_EQ(restored.system_state, SystemAdmissionState::Latched); + ASSERT_EQ(restored.targets.size(), 1U); + EXPECT_FALSE(restored.targets.front().success); + EXPECT_EQ( + restored.targets.front().reason, + SafetyReason::EmergencyStopActive); + EXPECT_EQ(endpoint->operational_restores.load(), 0); + EXPECT_EQ(endpoint->recoveries.load(), 0); +} + +TEST(SafetyManagerTest, OperationalRestoreDoesNotRecoverAnActiveDevice) +{ + SafetyManager coordinator; + auto endpoint = std::make_shared(controlDescriptor()); + endpoint->condition = SafetyCondition::Unsafe; + endpoint->ready = TriState::False; + endpoint->quiescent = TriState::False; + endpoint->fault = TriState::True; + ASSERT_TRUE(coordinator.registerDevice( + {controlDescriptor(), endpoint, {}})); + coordinator.markStartupComplete(); + coordinator.quarantineDevice("arm", SafetyReason::OutcomeUnknown); + + RecoveryRequest request; + request.recovery_id = "restore-active-device"; + request.all_devices = true; + request.expected_safety_epoch = coordinator.snapshot().safety_epoch; + request.verify_only = false; + request.restore_operational_state = true; + request.reason = "operator requested recovery"; + request.deadline = SafetyClock::now() + std::chrono::seconds(1); + request.authorize_clear = [] { return true; }; + + const auto restored = coordinator.recover(request); + + EXPECT_EQ(restored.result, RecoveryResultCode::BlockerRemains); + ASSERT_EQ(restored.targets.size(), 1U); + EXPECT_EQ( + restored.targets.front().reason, + SafetyReason::DeviceStillMoving); + EXPECT_EQ(endpoint->operational_restores.load(), 0); + EXPECT_EQ(endpoint->recoveries.load(), 0); +} + +TEST(SafetyManagerTest, OperationalRestoreAuditFailurePreventsDeviceRecovery) +{ + SafetyManager coordinator; + auto endpoint = std::make_shared(controlDescriptor()); + endpoint->condition = SafetyCondition::Unsafe; + endpoint->ready = TriState::False; + endpoint->protective_stop = TriState::True; + ASSERT_TRUE(coordinator.registerDevice( + {controlDescriptor(), endpoint, {}})); + coordinator.markStartupComplete(); + coordinator.quarantineDevice("arm", SafetyReason::OutcomeUnknown); + + RecoveryRequest request; + request.recovery_id = "restore-audit-failure"; + request.all_devices = true; + request.expected_safety_epoch = coordinator.snapshot().safety_epoch; + request.verify_only = false; + request.restore_operational_state = true; + request.reason = "operator requested recovery"; + request.deadline = SafetyClock::now() + std::chrono::seconds(1); + request.authorize_clear = [] { return false; }; + + const auto restored = coordinator.recover(request); + + EXPECT_EQ(restored.result, RecoveryResultCode::BlockerRemains); + ASSERT_EQ(restored.targets.size(), 1U); + EXPECT_EQ( + restored.targets.front().reason, + SafetyReason::RecoveryAuditFailed); + EXPECT_EQ(endpoint->operational_restores.load(), 0); + EXPECT_EQ(endpoint->recoveries.load(), 0); +} + +TEST(SafetyManagerTest, OperationalRestoreRequiresExplicitAuthorization) +{ + SafetyManager coordinator; + auto endpoint = std::make_shared(controlDescriptor()); + ASSERT_TRUE(coordinator.registerDevice( + {controlDescriptor(), endpoint, {}})); + coordinator.markStartupComplete(); + + RecoveryRequest request; + request.recovery_id = "restore-without-authorization"; + request.all_devices = true; + request.expected_safety_epoch = coordinator.snapshot().safety_epoch; + request.verify_only = false; + request.restore_operational_state = true; + request.reason = "operator requested recovery"; + + const auto restored = coordinator.recover(request); + + EXPECT_EQ(restored.result, RecoveryResultCode::Failed); + ASSERT_EQ(restored.targets.size(), 1U); + EXPECT_EQ( + restored.targets.front().reason, + SafetyReason::InvalidArgument); + EXPECT_EQ(endpoint->operational_restores.load(), 0); +} + +TEST(SafetyManagerTest, + OperationalRestoreAuditFailureWithNoDevicesRemainsLatched) +{ + SafetyManager coordinator; + coordinator.markStartupComplete(); + + RecoveryRequest request; + request.recovery_id = "empty-restore-audit-failure"; + request.all_devices = true; + request.expected_safety_epoch = coordinator.snapshot().safety_epoch; + request.verify_only = false; + request.restore_operational_state = true; + request.reason = "operator requested recovery"; + request.deadline = SafetyClock::now() + std::chrono::seconds(1); + request.authorize_clear = [] { return false; }; + + const auto restored = coordinator.recover(request); + + EXPECT_EQ(restored.result, RecoveryResultCode::BlockerRemains); + EXPECT_EQ(restored.system_state, SystemAdmissionState::Latched); + ASSERT_EQ(restored.targets.size(), 1U); + EXPECT_EQ(restored.targets.front().target_id, "system"); + EXPECT_EQ( + restored.targets.front().reason, + SafetyReason::RecoveryAuditFailed); +} + +TEST(SafetyManagerTest, + OperationalRestoreDoesNotPartiallyReleaseSoftwareAdmission) +{ + SafetyManager coordinator; + auto first = std::make_shared( + controlDescriptor("arm-first")); + first->condition = SafetyCondition::Unsafe; + first->ready = TriState::False; + first->protective_stop = TriState::True; + auto second = std::make_shared( + controlDescriptor("arm-second")); + second->condition = SafetyCondition::Unsafe; + second->ready = TriState::False; + second->fault = TriState::True; + second->operational_restore_check = { + false, SafetyReason::DeviceFault, "fault reset failed"}; + ASSERT_TRUE(coordinator.registerDevice( + {controlDescriptor("arm-first"), first, {}})); + ASSERT_TRUE(coordinator.registerDevice( + {controlDescriptor("arm-second"), second, {}})); + coordinator.markStartupComplete(); + coordinator.quarantineDevice( + "arm-first", SafetyReason::OutcomeUnknown); + coordinator.quarantineDevice( + "arm-second", SafetyReason::OutcomeUnknown); + + RecoveryRequest request; + request.recovery_id = "restore-partial-failure"; + request.all_devices = true; + request.expected_safety_epoch = coordinator.snapshot().safety_epoch; + request.verify_only = false; + request.restore_operational_state = true; + request.reason = "operator requested recovery"; + request.deadline = SafetyClock::now() + std::chrono::seconds(1); + request.authorize_clear = [] { return true; }; + + const auto restored = coordinator.recover(request); + + EXPECT_EQ(restored.result, RecoveryResultCode::BlockerRemains); + EXPECT_EQ(restored.system_state, SystemAdmissionState::Latched); + EXPECT_EQ(first->operational_restores.load(), 1); + EXPECT_EQ(second->operational_restores.load(), 1); + EXPECT_EQ(first->recoveries.load(), 0); + EXPECT_EQ(second->recoveries.load(), 0); + const auto snapshot = coordinator.snapshot(); + ASSERT_EQ(snapshot.devices.size(), 2U); + for (const auto& device : snapshot.devices) { + EXPECT_EQ( + device.admission_state, + DeviceAdmissionState::Quarantined) + << device.descriptor.device_id; + } +} + TEST(SafetyManagerTest, RecoveryAuditFailureCannotReleaseLatch) { SafetyManager coordinator; diff --git a/cmvr-es/service/grpc/server/include/grpc_system_service.h b/cmvr-es/service/grpc/server/include/grpc_system_service.h index f0ae3deb..f6e8a3d5 100644 --- a/cmvr-es/service/grpc/server/include/grpc_system_service.h +++ b/cmvr-es/service/grpc/server/include/grpc_system_service.h @@ -50,6 +50,7 @@ namespace cmvr::service grpc::Status ExecuteActionQueue(grpc::ServerContext* context, const cmvr::api::ActionQueueCommand_Request* request, cmvr::api::ActionQueueCommand_Feedback* response) override; grpc::Status GetSafetyState(grpc::ServerContext* context, const cmvr::api::GetSafetyStateCommand_Request* request, cmvr::api::GetSafetyStateCommand_Feedback* response) override; grpc::Status RecoverSafetyState(grpc::ServerContext* context, const cmvr::api::RecoverSafetyStateCommand_Request* request, cmvr::api::RecoverSafetyStateCommand_Feedback* response) override; + grpc::Status RestoreOperationalState(grpc::ServerContext* context, const cmvr::api::RestoreOperationalStateCommand_Request* request, cmvr::api::RestoreOperationalStateCommand_Feedback* response) override; private: device::DeviceManager& dmgr_; const std::chrono::milliseconds stop_timeout_; diff --git a/cmvr-es/service/grpc/server/src/grpc_security.cpp b/cmvr-es/service/grpc/server/src/grpc_security.cpp index 78593af9..91271d8d 100644 --- a/cmvr-es/service/grpc/server/src/grpc_security.cpp +++ b/cmvr-es/service/grpc/server/src/grpc_security.cpp @@ -419,6 +419,9 @@ const GrpcMethodPolicyRegistry& defaultGrpcMethodPolicyRegistry() add("SystemService", "RecoverSafetyState", GrpcAccessClass::Recover, CommandIntent::RecoverAdmission, SafetyPolicyFamily::Control, true, true); + add("SystemService", "RestoreOperationalState", + GrpcAccessClass::Recover, CommandIntent::RecoverAdmission, + SafetyPolicyFamily::Control, true, true); add_many("ArmService", {"getJointState", "getPose", "getPoseMatrix", diff --git a/cmvr-es/service/grpc/server/src/grpc_system_service.cpp b/cmvr-es/service/grpc/server/src/grpc_system_service.cpp index 211d2f37..a8c619a5 100644 --- a/cmvr-es/service/grpc/server/src/grpc_system_service.cpp +++ b/cmvr-es/service/grpc/server/src/grpc_system_service.cpp @@ -1575,6 +1575,166 @@ grpc::Status gRPCSystemServiceImpl::RecoverSafetyState( return grpc::Status::OK; } +grpc::Status gRPCSystemServiceImpl::RestoreOperationalState( + grpc::ServerContext* context, + const cmvr::api::RestoreOperationalStateCommand_Request* request, + cmvr::api::RestoreOperationalStateCommand_Feedback* response) +{ + CMVR_GRPC_REQUIRE_REGISTERED_CALL( + security_gateway_, context, + "/cmvr.api.SystemService/RestoreOperationalState"); + if (!request || !response) { + return grpc::Status( + grpc::StatusCode::INVALID_ARGUMENT, + "RestoreOperationalState request and response are required"); + } + if (request->recovery_id().empty() || request->reason().empty()) { + const std::string detail = + "recovery_id and reason are required"; + setSafetyHeaderFailure( + response->mutable_header(), + request->reason().empty() + ? cmvr::safety::SafetyReason::RecoveryReasonRequired + : cmvr::safety::SafetyReason::InvalidArgument, + detail); + return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, detail); + } + if (!recovery_audit_sink_) { + const std::string detail = + "persistent recovery audit is not configured"; + setSafetyHeaderFailure( + response->mutable_header(), + cmvr::safety::SafetyReason::RecoveryAuditFailed, + detail); + return grpc::Status( + grpc::StatusCode::FAILED_PRECONDITION, + "RECOVERY_AUDIT_FAILED"); + } + + const auto accepted_snapshot = dmgr_.safetyManager().snapshot(); + RecoveryAuditRecord audit; + audit.occurred_at_unix_ms = unixTimeMs(); + audit.stage = "accepted"; + audit.correlation_id = cmvr_grpc_call_guard.context().correlation_id; + audit.principal_id = cmvr_grpc_call_guard.context().principal.id; + audit.peer = cmvr_grpc_call_guard.context().peer; + audit.recovery_id = request->recovery_id(); + audit.reason = request->reason(); + audit.mode = "restore_operational_state"; + audit.all_devices = true; + audit.expected_safety_epoch = accepted_snapshot.safety_epoch; + audit.result = "pending"; + std::string audit_error; + if (!recovery_audit_sink_->append(audit, &audit_error)) { + const auto detail = audit_error.empty() + ? std::string("persistent recovery audit write failed") + : audit_error; + setSafetyHeaderFailure( + response->mutable_header(), + cmvr::safety::SafetyReason::RecoveryAuditFailed, + detail); + return grpc::Status( + grpc::StatusCode::FAILED_PRECONDITION, + "RECOVERY_AUDIT_FAILED"); + } + + auto deadline = cmvr_grpc_call_guard.context().deadline; + const auto configured_deadline = + cmvr::safety::SafetyClock::now() + + dmgr_.safetyManager().config().recovery_timeout; + if (deadline == cmvr::safety::SafetyClock::time_point::max() || + configured_deadline < deadline) { + deadline = configured_deadline; + } + if (request->timeout_ms() != 0) { + deadline = std::min( + deadline, + cmvr::safety::SafetyClock::now() + + std::chrono::milliseconds(request->timeout_ms())); + } + + auto commit_audit = audit; + commit_audit.stage = "restore_commit"; + commit_audit.result = "authorized"; + const auto sink = recovery_audit_sink_; + + cmvr::safety::RecoveryRequest coordinator_request; + coordinator_request.recovery_id = request->recovery_id(); + coordinator_request.all_devices = true; + coordinator_request.expected_safety_epoch = + accepted_snapshot.safety_epoch; + coordinator_request.verify_only = false; + coordinator_request.restore_operational_state = true; + coordinator_request.reason = request->reason(); + coordinator_request.deadline = deadline; + coordinator_request.authorize_clear = + [sink, commit_audit = std::move(commit_audit)]() mutable { + commit_audit.occurred_at_unix_ms = unixTimeMs(); + std::string error; + const bool persisted = sink->append(commit_audit, &error); + if (!persisted) { + CMVR_LOG(ERROR) + << "[gRPCSystemServiceImpl] Operational restore audit " + "failed: " + << error; + } + return persisted; + }; + + const auto result = + dmgr_.safetyManager().recover(coordinator_request); + response->set_recovery_id(result.recovery_id); + response->set_result(toApiRecoveryResult(result.result)); + response->set_previous_safety_epoch(result.previous_safety_epoch); + response->set_current_safety_epoch(result.current_safety_epoch); + response->set_system_state( + toApiSystemAdmissionState(result.system_state)); + for (const auto& target : result.targets) { + populateSafetyTargetResult(target, *response->add_targets()); + } + + const bool success = recoveryCompletedAsRequested(result.result); + auto* header = response->mutable_header(); + header->set_success(success); + header->set_command_id(request->recovery_id()); + header->set_service_instance_id( + dmgr_.safetyManager().serviceInstanceId()); + header->set_safety_epoch(result.current_safety_epoch); + header->set_execution_state( + success ? cmvr::api::COMMAND_EXECUTION_STATE_COMPLETED + : cmvr::api::COMMAND_EXECUTION_STATE_FAILED); + if (success) { + header->set_reason_code(cmvr::api::COMMAND_REASON_CODE_NONE); + } else { + const auto failed = std::find_if( + result.targets.begin(), result.targets.end(), + [](const auto& target) { return !target.success; }); + if (failed != result.targets.end()) { + header->set_reason_code(toApiSafetyReason(failed->reason)); + header->set_error_message(failed->detail); + } else { + header->set_reason_code( + cmvr::api::COMMAND_REASON_CODE_INTERNAL_ERROR); + header->set_error_message( + "operational restore failed without a target result"); + } + } + setCurrentTimestamp(header->mutable_timestamp()); + + audit.occurred_at_unix_ms = unixTimeMs(); + audit.stage = "completed"; + audit.previous_safety_epoch = result.previous_safety_epoch; + audit.current_safety_epoch = result.current_safety_epoch; + audit.result = cmvr::safety::toString(result.result); + if (!recovery_audit_sink_->append(audit, &audit_error)) { + CMVR_LOG(ERROR) + << "[gRPCSystemServiceImpl] Operational restore completion audit " + "failed: " + << audit_error; + } + return grpc::Status::OK; +} + grpc::Status gRPCSystemServiceImpl::UpdateParams(grpc::ServerContext* context, const cmvr::api::UpdateParamsCommand_Request* request, cmvr::api::UpdateParamsCommand_Feedback* response) { CMVR_GRPC_REQUIRE_REGISTERED_CALL( diff --git a/cmvr-es/service/grpc/server/tests/grpc_system_service_test.cpp b/cmvr-es/service/grpc/server/tests/grpc_system_service_test.cpp index 3b3ba689..227355bd 100644 --- a/cmvr-es/service/grpc/server/tests/grpc_system_service_test.cpp +++ b/cmvr-es/service/grpc/server/tests/grpc_system_service_test.cpp @@ -646,7 +646,13 @@ public: return model; } std::size_t getDof() const override { return kDof; } - device::ArmState getRobotState() const override { return {}; } + device::ArmState getRobotState() const override + { + std::lock_guard lock(mutex_); + auto state = reported_state_; + state.moving = state.moving || active_motions_ != 0; + return state; + } device::JointGroupState getJointState() const override { return {}; } device::CartesianPose getTcpPose( device::FrameType = device::FrameType::Base) const override @@ -793,7 +799,19 @@ public: shutdown_calls_.fetch_add(1, std::memory_order_relaxed); return device::Result::success(); } - device::Result clearFault() override { return device::Result::success(); } + device::Result clearFault() override + { + std::lock_guard lock(mutex_); + ++clear_fault_calls_; + reported_state_.connected = true; + reported_state_.powered_on = true; + reported_state_.moving = false; + reported_state_.program_running = false; + reported_state_.fault = false; + reported_state_.emergency_stopped = false; + reported_state_.protective_stopped = false; + return device::Result::success(); + } device::Result unlockProtectiveStop() override { return device::Result::success(); @@ -949,6 +967,18 @@ public: return shutdown_calls_.load(std::memory_order_relaxed); } + int clearFaultCalls() const + { + std::lock_guard lock(mutex_); + return clear_fault_calls_; + } + + void setReportedState(const device::ArmState& state) + { + std::lock_guard lock(mutex_); + reported_state_ = state; + } + void blockHealthSnapshot() { std::lock_guard lock(health_mutex_); @@ -1096,6 +1126,8 @@ private: int health_snapshot_calls_{0}; bool block_health_snapshot_{false}; bool health_snapshot_entered_{false}; + device::ArmState reported_state_{}; + int clear_fault_calls_{0}; }; class ActionTestAgv final : public device::AbstractAGV { @@ -1342,6 +1374,18 @@ const api::SafetyOperationTargetResult* findSafetyTarget( return nullptr; } +const api::SafetyOperationTargetResult* findSafetyTarget( + const api::RestoreOperationalStateCommand_Feedback& response, + const std::string& id) +{ + for (const auto& target : response.targets()) { + if (target.target_id() == id) { + return ⌖ + } + } + return nullptr; +} + class GrpcSystemServiceTest : public ::testing::Test { protected: void SetUp() override @@ -1635,6 +1679,25 @@ TEST_F(GrpcSystemServiceTest, RecoveryIsDisabledByDefault) EXPECT_EQ(status.error_message(), "RECOVERY_RPC_DISABLED"); } +TEST_F(GrpcSystemServiceTest, OperationalRestoreIsDisabledByDefault) +{ + config::DeviceManagerConfig config; + (void)device::DeviceManager::getInstance(config); + service_ = std::make_unique(); + + api::RestoreOperationalStateCommand_Request request; + request.set_recovery_id("restore-disabled"); + request.set_reason("operator requested recovery"); + api::RestoreOperationalStateCommand_Feedback response; + grpc::ServerContext context; + + const auto status = service_->RestoreOperationalState( + &context, &request, &response); + + EXPECT_EQ(status.error_code(), grpc::StatusCode::FAILED_PRECONDITION); + EXPECT_EQ(status.error_message(), "RECOVERY_RPC_DISABLED"); +} + TEST_F(GrpcSystemServiceTest, RecoveryRequiresDurableAuditBeforeCoordinator) { config::DeviceManagerConfig config; @@ -1682,6 +1745,64 @@ TEST_F(GrpcSystemServiceTest, RecoveryRequiresDurableAuditBeforeCoordinator) epoch_before_failure); } +TEST_F(GrpcSystemServiceTest, + RestoreOperationalStateRecoversArmAndClearsAdmission) +{ + config::DeviceManagerConfig config; + auto& manager = device::DeviceManager::getInstance(config); + action_trace_ = std::make_shared(); + action_arm_ = std::make_shared( + "restore-arm", action_trace_); + device::ArmState protected_state; + protected_state.connected = true; + protected_state.powered_on = true; + protected_state.moving = true; + protected_state.program_running = true; + protected_state.protective_stopped = true; + action_arm_->setReportedState(protected_state); + manager.registerDevice(action_arm_); + manager.safetyManager().quarantineDevice( + action_arm_->id(), safety::SafetyReason::OutcomeUnknown); + + auto audit = std::make_shared(); + service_ = std::make_unique( + std::chrono::seconds(1), makeAllowAllRecoveryGateway(), audit); + + api::RestoreOperationalStateCommand_Request request; + request.set_recovery_id("restore-whole-system"); + request.set_reason("operator confirmed the work cell is clear"); + request.set_timeout_ms(1000); + api::RestoreOperationalStateCommand_Feedback response; + grpc::ServerContext context; + + const auto status = service_->RestoreOperationalState( + &context, &request, &response); + + ASSERT_TRUE(status.ok()) << status.error_message(); + ASSERT_TRUE(response.header().success()) + << response.header().error_message(); + EXPECT_EQ( + response.result(), api::SAFETY_OPERATION_RESULT_RECOVERED); + EXPECT_EQ( + response.system_state(), api::SYSTEM_ADMISSION_STATE_OPEN); + EXPECT_EQ(action_arm_->clearFaultCalls(), 1); + const auto* arm_target = findSafetyTarget(response, action_arm_->id()); + ASSERT_NE(arm_target, nullptr); + EXPECT_EQ( + arm_target->result(), api::SAFETY_OPERATION_RESULT_SUCCEEDED); + ASSERT_EQ(audit->records.size(), 3U); + EXPECT_EQ(audit->records[0].stage, "accepted"); + EXPECT_EQ(audit->records[1].stage, "restore_commit"); + EXPECT_EQ(audit->records[2].stage, "completed"); + + const auto snapshot = manager.safetyManager().snapshot(); + EXPECT_EQ(snapshot.system_state, safety::SystemAdmissionState::Open); + ASSERT_EQ(snapshot.devices.size(), 1U); + EXPECT_EQ( + snapshot.devices.front().admission_state, + safety::DeviceAdmissionState::Open); +} + TEST_F(GrpcSystemServiceTest, MapsEveryKnownDeviceKind) { struct ExpectedMapping { @@ -2956,6 +3077,62 @@ TEST_F(GrpcSystemServiceTest, EXPECT_FALSE(lease.acquired); } +TEST_F(GrpcSystemServiceTest, + StopAllAcceptsProtectedArmAsQuiescent) +{ + initializeActionDevices(); + device::ArmState protected_state; + protected_state.connected = true; + protected_state.powered_on = true; + protected_state.moving = true; + protected_state.program_running = true; + protected_state.protective_stopped = true; + action_arm_->setReportedState(protected_state); + + api::StopAllCommand_Request request; + api::StopAllCommand_Feedback response; + grpc::ServerContext context; + const auto status = service_->StopAll( + &context, &request, &response); + + ASSERT_TRUE(status.ok()) << status.error_message(); + EXPECT_TRUE(response.header().success()) + << response.header().error_message(); + const auto* arm_target = findSafetyTarget(response, action_arm_->id()); + ASSERT_NE(arm_target, nullptr); + EXPECT_EQ( + arm_target->result(), api::SAFETY_OPERATION_RESULT_SUCCEEDED); +} + +TEST_F(GrpcSystemServiceTest, + StopAllDoesNotTreatGenericArmFaultAsQuiescent) +{ + initializeActionDevices(); + device::ArmState fault_state; + fault_state.connected = true; + fault_state.powered_on = true; + fault_state.moving = true; + fault_state.program_running = true; + fault_state.fault = true; + action_arm_->setReportedState(fault_state); + + api::StopAllCommand_Request request; + api::StopAllCommand_Feedback response; + grpc::ServerContext context; + const auto status = service_->StopAll( + &context, &request, &response); + + ASSERT_TRUE(status.ok()) << status.error_message(); + EXPECT_FALSE(response.header().success()); + const auto* arm_target = findSafetyTarget(response, action_arm_->id()); + ASSERT_NE(arm_target, nullptr); + EXPECT_EQ( + arm_target->result(), api::SAFETY_OPERATION_RESULT_FAILED); + EXPECT_EQ( + arm_target->reason_code(), + api::COMMAND_REASON_CODE_DEVICE_STILL_MOVING); +} + TEST_F(GrpcSystemServiceTest, StopAllStopsActiveMediaWithoutStoppingDeviceLifecycles) { diff --git a/docs/device_safety_control_plane_architecture.md b/docs/device_safety_control_plane_architecture.md index d6675cd9..061c0800 100644 --- a/docs/device_safety_control_plane_architecture.md +++ b/docs/device_safety_control_plane_architecture.md @@ -535,6 +535,27 @@ struct AdmissionPermit { 不能把它登记成 ResetFault; - ResetFault 成功只触发安全快照刷新,不直接清除 central quarantine。 +### 8.2.1 整机运行态恢复 + +`SystemService.RestoreOperationalState` 是面向上层平台的整机恢复事务,与 +`RecoverSafetyState` 的软件准入恢复语义分离: + +- 请求必须携带唯一 `recovery_id`、非空 `reason`,并通过与 Recover 相同的 + `RecoveryExposure` 和持久审计策略; +- 事务固定覆盖全部已注册设备,并与 StopAll、其他恢复事务通过 process operation mutex + 串行;事务期间系统处于 Recovering,拒绝新的普通运动命令; +- 硬件恢复前必须主动取得新鲜快照,确认设备已连接;Control 设备还必须确认物理急停已释放 + 且已经静止。条件未知、急停仍有效、设备仍运动或审计授权失败时,不调用设备恢复能力; +- 对尚未达到 Nominal/operational-ready 的支持设备调用 + `DeviceSafetyEndpoint::restoreOperationalState()`。Legacy Arm 和 AGV adapter 分别调用设备 + `clearFault()`;该操作允许按设备实现执行上电、使能和故障复位,但不得恢复旧轨迹、导航、 + teleop session、control lease 或 ActionQueue; +- 每个硬件恢复动作完成后必须再次主动刷新,确认连接、新鲜度、急停、保护停、fault、静止和 + operational-ready。任一设备失败时系统保持 Latched,并返回逐设备失败原因;中央 quarantine、 + retained barrier 和全局 gate 不做部分释放; +- 只有全部必需设备验证成功后,才协调释放软件 latch 和 retained barrier,将系统切回 Open。 + 调用成功只表示整机已使能、空闲并可接受新的 gRPC 命令,不会续跑中断前的任务。 + ### 8.3 流式控制 Teleoperation、Motor cyclic stream 和未来连续控制不为每个 setpoint 写 unary ledger: @@ -1092,7 +1113,8 @@ public: `CommandIntent` 和最低 role。未知方法在 Authenticated Profile 中 fail-closed;Compatibility Profile 可以只为已有 RPC 保留当前行为,但仍必须产生 `unclassified_method` 告警并在阶段 2 前清零。 -`RecoverSafetyState` 额外使用独立的 `RecoveryExposure`: +`RecoverSafetyState` 和 `RestoreOperationalState` 额外使用独立的 +`RecoveryExposure`: | RecoveryExposure | 行为 | | --- | --- | diff --git a/protos/cmvr/api/safety_command.proto b/protos/cmvr/api/safety_command.proto index b227f842..4e5b774c 100644 --- a/protos/cmvr/api/safety_command.proto +++ b/protos/cmvr/api/safety_command.proto @@ -184,3 +184,21 @@ message RecoverSafetyStateCommand { string recovery_id = 7; } } + +message RestoreOperationalStateCommand { + message Request { + string recovery_id = 1; + string reason = 2; + uint32 timeout_ms = 3; + } + + message Feedback { + CommandHeader.Feedback header = 1; + SafetyOperationResult result = 2; + uint64 previous_safety_epoch = 3; + uint64 current_safety_epoch = 4; + SystemAdmissionState system_state = 5; + repeated SafetyOperationTargetResult targets = 6; + string recovery_id = 7; + } +} diff --git a/protos/cmvr/api/system_service.proto b/protos/cmvr/api/system_service.proto index 44267733..ac961ac2 100644 --- a/protos/cmvr/api/system_service.proto +++ b/protos/cmvr/api/system_service.proto @@ -19,4 +19,5 @@ service SystemService { rpc GetSafetyState(GetSafetyStateCommand.Request) returns (GetSafetyStateCommand.Feedback) {} rpc RecoverSafetyState(RecoverSafetyStateCommand.Request) returns (RecoverSafetyStateCommand.Feedback) {} + rpc RestoreOperationalState(RestoreOperationalStateCommand.Request) returns (RestoreOperationalStateCommand.Feedback) {} } From f611ad1db8e0730a2a18fa645f505a45ecaa5727 Mon Sep 17 00:00:00 2001 From: xtkuang <87661715@qq.com> Date: Tue, 18 Aug 2026 15:04:04 +0800 Subject: [PATCH 05/10] feat: implement SEER Robokit clear fault --- cmvr-es/devices/agv/seer_robokit/README.md | 4 +-- .../include/seer_robokit_protocol.h | 1 + .../src/seer_robokit_navigation.cpp | 10 ++++-- .../seer_robokit_control_authority_test.cpp | 32 +++++++++++++++++-- 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/cmvr-es/devices/agv/seer_robokit/README.md b/cmvr-es/devices/agv/seer_robokit/README.md index b2ee3d00..3cb6d77d 100644 --- a/cmvr-es/devices/agv/seer_robokit/README.md +++ b/cmvr-es/devices/agv/seer_robokit/README.md @@ -106,7 +106,7 @@ cmake --install build | `19204` | 状态、站点、地图和建图文件 | `1004`、`1007`、`1020`、`1101`、`1110`、`1300`、`1301`、`1780`、`1800` | | `19205` | 底盘控制 | `2000`、`2010`、`2022` | | `19206` | 导航任务 | `3001`、`3002`、`3003`、`3051`、`3066`、`3067` | -| `19207` | 控制权、地图上传下载 | `4005`、`4010`、`4011` | +| `19207` | 控制权、清错、地图上传下载 | `4005`、`4009`、`4010`、`4011` | | `19210` | 开始/停止建图 | `6100`、`6101` | | `19301` | 机器人状态推送 | `9300`/`19300` 配置,`19301` 推送 | @@ -126,7 +126,7 @@ gRPC 客户端另做一套租约逻辑。 | `getRuntimeState` | 推送缓存,缺失时查询 `1004/1007/1300` | 只读 | | `getNavigationStatus` | 跟踪任务查询 `1110`,无精确上下文时回退 `1020` | 只读;同步等待另用 `1101` 确认停车 | | `emergencyStop` | `2000`,再执行 `3003` 或 `3067` | 软件停止,不替代硬件急停 | -| `clearFault` | 未实现 | 返回 `UnsupportedCommand` | +| `clearFault` | `4009` | 抢权后发送无请求体命令,清除可恢复故障 | | `navigateToPose` | `3051` + `freeGo` | 地图绝对位姿,仅双轮差速底盘 | | `navigateToStation` | `3051` | 站点路径导航;PGV 二次定位也使用此方法 | | `followPath` | `3066` | 仙工“指定路径导航”,与 `3051` 不同 | diff --git a/cmvr-es/devices/agv/seer_robokit/include/seer_robokit_protocol.h b/cmvr-es/devices/agv/seer_robokit/include/seer_robokit_protocol.h index 89df8282..a0dd5db7 100644 --- a/cmvr-es/devices/agv/seer_robokit/include/seer_robokit_protocol.h +++ b/cmvr-es/devices/agv/seer_robokit/include/seer_robokit_protocol.h @@ -25,6 +25,7 @@ constexpr std::uint16_t kRobotTaskTranslate = 3055; constexpr std::uint16_t kRobotTaskGoTargetList = 3066; constexpr std::uint16_t kRobotTaskClearTargetList = 3067; constexpr std::uint16_t kRobotConfigLock = 4005; +constexpr std::uint16_t kRobotConfigClearFault = 4009; constexpr std::uint16_t kRobotConfigUploadMap = 4010; constexpr std::uint16_t kRobotConfigDownloadMap = 4011; constexpr std::uint16_t kRobotOtherStartMapping = 6100; diff --git a/cmvr-es/devices/agv/seer_robokit/src/seer_robokit_navigation.cpp b/cmvr-es/devices/agv/seer_robokit/src/seer_robokit_navigation.cpp index edf22ead..94d5137a 100644 --- a/cmvr-es/devices/agv/seer_robokit/src/seer_robokit_navigation.cpp +++ b/cmvr-es/devices/agv/seer_robokit/src/seer_robokit_navigation.cpp @@ -161,9 +161,13 @@ AgvResult SeerRobokitAgv::emergencyStopTrackedNavigation_( AgvResult SeerRobokitAgv::clearFault() { - return AgvResult::failure( - AgvErrorCode::UnsupportedCommand, - "SEER Robokit clearFault command is not implemented"); + Json::Value response; + auto result = sendControlledCommand_( + sock_config_, + kRobotConfigClearFault, + Json::Value(Json::objectValue), + &response); + return result.ok() ? resultFromResponse_(response) : result; } AgvResult SeerRobokitAgv::navigateToPose( diff --git a/cmvr-es/devices/agv/seer_robokit/tests/seer_robokit_control_authority_test.cpp b/cmvr-es/devices/agv/seer_robokit/tests/seer_robokit_control_authority_test.cpp index b1109f12..9198d90f 100644 --- a/cmvr-es/devices/agv/seer_robokit/tests/seer_robokit_control_authority_test.cpp +++ b/cmvr-es/devices/agv/seer_robokit/tests/seer_robokit_control_authority_test.cpp @@ -150,6 +150,7 @@ constexpr std::uint16_t kRobotTaskGoTarget = 3051; constexpr std::uint16_t kRobotTaskGoTargetList = 3066; constexpr std::uint16_t kRobotTaskClearTargetList = 3067; constexpr std::uint16_t kRobotConfigLock = 4005; +constexpr std::uint16_t kRobotConfigClearFault = 4009; constexpr std::uint16_t kRobotConfigUploadMap = 4010; constexpr std::uint16_t kRobotConfigDownloadMap = 4011; constexpr std::uint16_t kRobotOtherStartMapping = 6100; @@ -784,6 +785,9 @@ TEST_F(SeerRobokitControlAuthorityTest, EveryImplementedMutatingOperationAcquire [this]() { return agv_->emergencyStop(); }); + expectControlled(kRobotConfigClearFault, [this]() { + return agv_->clearFault(); + }); expectControlled(kRobotControlMotion, [this]() { return agv_->setVelocity(AgvVelocity{0.1, 0.0, 0.2}); }); @@ -3114,15 +3118,37 @@ TEST_F(SeerRobokitControlAuthorityTest, EmergencyStopAttemptsBothStopsAndAggrega EXPECT_EQ(records[2].command, kRobotTaskCancel); } -TEST_F(SeerRobokitControlAuthorityTest, UnsupportedClearFaultDoesNotAcquireAuthority) +TEST_F(SeerRobokitControlAuthorityTest, ClearFaultSends4009WithoutPayloadAfterAcquiringAuthority) { controller_.clearRecords(); const auto result = agv_->clearFault(); + ASSERT_TRUE(result.ok()) << result.message; + const auto records = controller_.records(); + ASSERT_EQ(records.size(), 2U); + EXPECT_EQ(records[0].command, kRobotConfigLock); + EXPECT_EQ(records[1].command, kRobotConfigClearFault); + EXPECT_TRUE(records[1].payload.empty()); +} + +TEST_F(SeerRobokitControlAuthorityTest, ClearFaultPreservesControllerFailure) +{ + controller_.setResponseCode(kRobotConfigClearFault, 44009); + controller_.clearRecords(); + + const auto result = agv_->clearFault(); + EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::UnsupportedCommand); - EXPECT_TRUE(controller_.records().empty()); + EXPECT_EQ(result.code, AgvErrorCode::CommandFailed); + EXPECT_NE(result.message.find("ret_code=44009"), std::string::npos); + EXPECT_NE( + result.message.find("simulated command failure"), + std::string::npos); + const auto records = controller_.records(); + ASSERT_EQ(records.size(), 2U); + EXPECT_EQ(records[0].command, kRobotConfigLock); + EXPECT_EQ(records[1].command, kRobotConfigClearFault); } TEST_F(SeerRobokitControlAuthorityTest, ReadOnlyMapDownloadDoesNotAcquireAuthority) From aac719a932db890e2613faed97dd16ed8e0ecae6 Mon Sep 17 00:00:00 2001 From: xtkuang <87661715@qq.com> Date: Tue, 18 Aug 2026 16:17:46 +0800 Subject: [PATCH 06/10] chore: remove branch-only tests and generated artifacts --- .gitignore | 12 + MUJOCO_LOG.TXT | 6 - .../controllers/ume_legacy/CMakeLists.txt | 56 - ...inocchio_ume_legacy_model_adapter_test.cpp | 392 -- .../ume_legacy_controller_golden_test.cpp | 216 - cmvr-es/common/CMakeLists.txt | 17 - cmvr-es/common/base/logging/CMakeLists.txt | 23 - .../common/base/logging/tests/logger_test.cpp | 93 - cmvr-es/common/vision/image_display.h | 609 -- cmvr-es/common/vision/matplotlibcpp.h | 2988 --------- cmvr-es/devices/README.md | 6 +- .../devices/agv/seer_robokit/CMakeLists.txt | 28 - cmvr-es/devices/agv/seer_robokit/README.md | 20 - .../seer_robokit_control_authority_test.cpp | 5567 ----------------- cmvr-es/devices/arm/aubo_arm/CMakeLists.txt | 85 - cmvr-es/devices/arm/aubo_arm/README.md | 16 - .../tests/aubo_arm_json_command_test.cpp | 84 - .../tests/aubo_arm_motion_result_test.cpp | 158 - .../aubo_arm/tests/aubo_motion_state_test.cpp | 213 - .../aubo_arm/tests/aubo_safety_state_test.cpp | 156 - cmvr-es/devices/arm/huayan_arm/CMakeLists.txt | 46 - .../huayan_arm/tests/huayan_arm_sdk_test.cpp | 874 --- .../tests/huayan_lifecycle_state_test.cpp | 232 - .../devices/arm/ume_robot_arm/CMakeLists.txt | 69 - .../tests/damiao_can_fd_chain_test.cpp | 407 -- .../tests/damiao_mit_codec_test.cpp | 150 - .../tests/ume_robot_arm_test.cpp | 338 - .../canbus/can_client/pcan/pcan_client.cc | 205 - .../canbus/can_client/pcan/pcan_client.h | 86 - .../can_client/pcan/pcan_client_test.cpp | 46 - .../dexhand/rh56dftp_dexhand/CMakeLists.txt | 27 - .../tests/rh56dftp_dexhand_stop_all_test.cpp | 348 -- cmvr-es/devices/motor/README.md | 11 - .../speaker/ffmpeg_speaker/CMakeLists.txt | 29 - .../tests/ffmpeg_speaker_lifecycle_test.cpp | 54 - cmvr-es/manager/README.md | 10 - .../control_authority_manager/CMakeLists.txt | 20 - .../tests/control_authority_manager_test.cpp | 923 --- cmvr-es/manager/device_manager/CMakeLists.txt | 23 - .../tests/device_manager_lifecycle_test.cpp | 153 - .../media_source_manager/CMakeLists.txt | 52 - .../device_media_source_adapter_test.cpp | 113 - .../tests/media_source_manager_test.cpp | 1338 ---- cmvr-es/manager/safety_manager/CMakeLists.txt | 47 - .../safety_manager/include/safety_manager.h | 11 +- .../safety_manager/src/safety_manager.cpp | 61 +- .../tests/command_ledger_test.cpp | 122 - .../tests/safety_manager_test.cpp | 782 --- .../tests/safety_snapshot_store_test.cpp | 111 - cmvr-es/manager/task_manager/CMakeLists.txt | 27 - .../tests/task_manager_lifecycle_test.cpp | 428 -- cmvr-es/runtime/CMakeLists.txt | 30 - .../runtime/tests/runtime_lifecycle_test.cpp | 266 - cmvr-es/service/README.md | 1 - cmvr-es/service/grpc/CMakeLists.txt | 430 -- cmvr-es/service/grpc/client/CMakeLists.txt | 22 - .../tests/grpc_arm_teleop_client_test.cpp | 220 - ...era_operational_activity_registry_test.cpp | 491 -- .../camera_ptz_activity_registry_test.cpp | 349 -- .../server/tests/grpc_agv_service_test.cpp | 806 --- .../server/tests/grpc_arm_service_test.cpp | 1276 ---- .../tests/grpc_arm_teleop_service_test.cpp | 920 --- .../tests/grpc_command_transaction_test.cpp | 454 -- .../tests/grpc_dexhand_service_test.cpp | 351 -- .../grpc_error_logging_interceptor_test.cpp | 864 --- .../server/tests/grpc_head_service_test.cpp | 391 -- .../server/tests/grpc_motor_service_test.cpp | 1856 ------ .../grpc_robot_arm_teleop_backend_test.cpp | 525 -- .../grpc/server/tests/grpc_security_test.cpp | 294 - .../server/tests/grpc_system_service_test.cpp | 3612 ----------- .../tests/media_activity_coordinator_test.cpp | 279 - .../tests/motor_activity_coordinator_test.cpp | 283 - .../tests/stop_all_admission_gate_test.cpp | 104 - .../tests/stop_operation_dispatcher_test.cpp | 399 -- cmvr-es/task/CMakeLists.txt | 28 - .../src/touch_screen_admission_test.cpp | 559 -- cmvr-es/task/ume_teleop_task/CMakeLists.txt | 23 - .../tests/ume_teleop_task_test.cpp | 530 -- compile_commands.json | 986 --- data/plot.png | Bin 50981 -> 0 bytes data/plot1.png | Bin 62702 -> 0 bytes data/s_curve_acceleration.png | Bin 83843 -> 0 bytes data/s_curve_acceleration.svg | 544 -- data/s_curve_jerk.png | Bin 54931 -> 0 bytes data/s_curve_jerk.svg | 518 -- data/s_curve_position.png | Bin 74164 -> 0 bytes data/s_curve_position.svg | 531 -- data/s_curve_velocity.png | Bin 101914 -> 0 bytes data/s_curve_velocity.svg | 544 -- model/ume/README.md | 2 +- .../__pycache__/save_poses.cpython-310.pyc | Bin 2446 -> 0 bytes .../__pycache__/auxiliary.cpython-310.pyc | Bin 2525 -> 0 bytes .../__pycache__/log_setting.cpython-310.pyc | Bin 2157 -> 0 bytes python/hand_eye_calibration/libs/web-log | 256 - .../libs/web-log.2025-08-19.log | Bin 3173 -> 0 bytes .../libs/web-log.2025-08-20.log | 1104 ---- .../libs/web-log.2025-08-22.log | 704 --- .../libs/web-log.2025-08-28.log | 46 - .../libs/web-log.2025-09-05.log | 167 - .../__pycache__/follow_target.cpython-310.pyc | Bin 10448 -> 0 bytes .../get_chessboard_position.cpython-310.pyc | Bin 3139 -> 0 bytes python/vision_servo/red_point.png | Bin 1305854 -> 0 bytes python/vision_servo/robot_warpper_test.py | 66 - python/vision_servo/test.py | 0 python/vision_servo/to.py | 26 - script/test.py | 168 - ...erate_collision_primitives.cpython-312.pyc | Bin 51627 -> 0 bytes ...erate_collision_primitives.cpython-313.pyc | Bin 33593 -> 0 bytes ..._urdf_collision_primitives.cpython-312.pyc | Bin 21897 -> 0 bytes .../test_collision_primitives.cpython-312.pyc | Bin 7192 -> 0 bytes .../test_collision_primitives.cpython-313.pyc | Bin 7201 -> 0 bytes .../view_urdf_collisions.cpython-313.pyc | Bin 34960 -> 0 bytes 112 files changed, 19 insertions(+), 38894 deletions(-) delete mode 100644 MUJOCO_LOG.TXT delete mode 100644 cmvr-es/algorithms/controllers/ume_legacy/tests/pinocchio_ume_legacy_model_adapter_test.cpp delete mode 100644 cmvr-es/algorithms/controllers/ume_legacy/tests/ume_legacy_controller_golden_test.cpp delete mode 100644 cmvr-es/common/base/logging/tests/logger_test.cpp delete mode 100644 cmvr-es/common/vision/image_display.h delete mode 100644 cmvr-es/common/vision/matplotlibcpp.h delete mode 100644 cmvr-es/devices/agv/seer_robokit/tests/seer_robokit_control_authority_test.cpp delete mode 100644 cmvr-es/devices/arm/aubo_arm/tests/aubo_arm_json_command_test.cpp delete mode 100644 cmvr-es/devices/arm/aubo_arm/tests/aubo_arm_motion_result_test.cpp delete mode 100644 cmvr-es/devices/arm/aubo_arm/tests/aubo_motion_state_test.cpp delete mode 100644 cmvr-es/devices/arm/aubo_arm/tests/aubo_safety_state_test.cpp delete mode 100644 cmvr-es/devices/arm/huayan_arm/tests/huayan_arm_sdk_test.cpp delete mode 100644 cmvr-es/devices/arm/huayan_arm/tests/huayan_lifecycle_state_test.cpp delete mode 100644 cmvr-es/devices/arm/ume_robot_arm/tests/damiao_can_fd_chain_test.cpp delete mode 100644 cmvr-es/devices/arm/ume_robot_arm/tests/damiao_mit_codec_test.cpp delete mode 100644 cmvr-es/devices/arm/ume_robot_arm/tests/ume_robot_arm_test.cpp delete mode 100644 cmvr-es/devices/canbus/can_client/pcan/pcan_client.cc delete mode 100644 cmvr-es/devices/canbus/can_client/pcan/pcan_client.h delete mode 100644 cmvr-es/devices/canbus/can_client/pcan/pcan_client_test.cpp delete mode 100644 cmvr-es/devices/dexhand/rh56dftp_dexhand/tests/rh56dftp_dexhand_stop_all_test.cpp delete mode 100644 cmvr-es/devices/speaker/ffmpeg_speaker/tests/ffmpeg_speaker_lifecycle_test.cpp delete mode 100644 cmvr-es/manager/control_authority_manager/tests/control_authority_manager_test.cpp delete mode 100644 cmvr-es/manager/device_manager/tests/device_manager_lifecycle_test.cpp delete mode 100644 cmvr-es/manager/media_source_manager/tests/device_media_source_adapter_test.cpp delete mode 100644 cmvr-es/manager/media_source_manager/tests/media_source_manager_test.cpp delete mode 100644 cmvr-es/manager/safety_manager/tests/command_ledger_test.cpp delete mode 100644 cmvr-es/manager/safety_manager/tests/safety_manager_test.cpp delete mode 100644 cmvr-es/manager/safety_manager/tests/safety_snapshot_store_test.cpp delete mode 100644 cmvr-es/manager/task_manager/tests/task_manager_lifecycle_test.cpp delete mode 100644 cmvr-es/runtime/tests/runtime_lifecycle_test.cpp delete mode 100644 cmvr-es/service/grpc/client/tests/grpc_arm_teleop_client_test.cpp delete mode 100644 cmvr-es/service/grpc/server/tests/camera_operational_activity_registry_test.cpp delete mode 100644 cmvr-es/service/grpc/server/tests/camera_ptz_activity_registry_test.cpp delete mode 100644 cmvr-es/service/grpc/server/tests/grpc_agv_service_test.cpp delete mode 100644 cmvr-es/service/grpc/server/tests/grpc_arm_service_test.cpp delete mode 100644 cmvr-es/service/grpc/server/tests/grpc_arm_teleop_service_test.cpp delete mode 100644 cmvr-es/service/grpc/server/tests/grpc_command_transaction_test.cpp delete mode 100644 cmvr-es/service/grpc/server/tests/grpc_dexhand_service_test.cpp delete mode 100644 cmvr-es/service/grpc/server/tests/grpc_error_logging_interceptor_test.cpp delete mode 100644 cmvr-es/service/grpc/server/tests/grpc_head_service_test.cpp delete mode 100644 cmvr-es/service/grpc/server/tests/grpc_motor_service_test.cpp delete mode 100644 cmvr-es/service/grpc/server/tests/grpc_robot_arm_teleop_backend_test.cpp delete mode 100644 cmvr-es/service/grpc/server/tests/grpc_security_test.cpp delete mode 100644 cmvr-es/service/grpc/server/tests/grpc_system_service_test.cpp delete mode 100644 cmvr-es/service/grpc/server/tests/media_activity_coordinator_test.cpp delete mode 100644 cmvr-es/service/grpc/server/tests/motor_activity_coordinator_test.cpp delete mode 100644 cmvr-es/service/grpc/stop_all/tests/stop_all_admission_gate_test.cpp delete mode 100644 cmvr-es/service/grpc/stop_all/tests/stop_operation_dispatcher_test.cpp delete mode 100644 cmvr-es/task/touch_screen_task/src/touch_screen_admission_test.cpp delete mode 100644 cmvr-es/task/ume_teleop_task/tests/ume_teleop_task_test.cpp delete mode 100644 compile_commands.json delete mode 100644 data/plot.png delete mode 100644 data/plot1.png delete mode 100644 data/s_curve_acceleration.png delete mode 100644 data/s_curve_acceleration.svg delete mode 100644 data/s_curve_jerk.png delete mode 100644 data/s_curve_jerk.svg delete mode 100644 data/s_curve_position.png delete mode 100644 data/s_curve_position.svg delete mode 100644 data/s_curve_velocity.png delete mode 100644 data/s_curve_velocity.svg delete mode 100644 python/hand_eye_calibration/__pycache__/save_poses.cpython-310.pyc delete mode 100644 python/hand_eye_calibration/libs/__pycache__/auxiliary.cpython-310.pyc delete mode 100644 python/hand_eye_calibration/libs/__pycache__/log_setting.cpython-310.pyc delete mode 100644 python/hand_eye_calibration/libs/web-log delete mode 100644 python/hand_eye_calibration/libs/web-log.2025-08-19.log delete mode 100644 python/hand_eye_calibration/libs/web-log.2025-08-20.log delete mode 100644 python/hand_eye_calibration/libs/web-log.2025-08-22.log delete mode 100644 python/hand_eye_calibration/libs/web-log.2025-08-28.log delete mode 100644 python/hand_eye_calibration/libs/web-log.2025-09-05.log delete mode 100644 python/vision_servo/__pycache__/follow_target.cpython-310.pyc delete mode 100644 python/vision_servo/__pycache__/get_chessboard_position.cpython-310.pyc delete mode 100644 python/vision_servo/red_point.png delete mode 100644 python/vision_servo/robot_warpper_test.py delete mode 100644 python/vision_servo/test.py delete mode 100644 python/vision_servo/to.py delete mode 100644 script/test.py delete mode 100644 scripts/isaac_sim/__pycache__/generate_collision_primitives.cpython-312.pyc delete mode 100644 scripts/isaac_sim/__pycache__/generate_collision_primitives.cpython-313.pyc delete mode 100644 scripts/isaac_sim/__pycache__/generate_urdf_collision_primitives.cpython-312.pyc delete mode 100644 scripts/isaac_sim/__pycache__/test_collision_primitives.cpython-312.pyc delete mode 100644 scripts/isaac_sim/__pycache__/test_collision_primitives.cpython-313.pyc delete mode 100644 scripts/meshcat/__pycache__/view_urdf_collisions.cpython-313.pyc diff --git a/.gitignore b/.gitignore index db7a09e0..8ffc5fb9 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,15 @@ /third_party/osqp/ /third_party/OsqpEigen/ /output + +# Generated development artifacts +compile_commands.json +MUJOCO_LOG.TXT +__pycache__/ +*.py[cod] +*.log + +# Generated plots and vision debug output +/data/*.png +/data/*.svg +/python/vision_servo/red_point.png diff --git a/MUJOCO_LOG.TXT b/MUJOCO_LOG.TXT deleted file mode 100644 index 55930968..00000000 --- a/MUJOCO_LOG.TXT +++ /dev/null @@ -1,6 +0,0 @@ -Fri Jul 24 15:39:05 2026 -ERROR: could not create window - -Fri Jul 24 15:40:37 2026 -ERROR: could not create window - diff --git a/cmvr-es/algorithms/controllers/ume_legacy/CMakeLists.txt b/cmvr-es/algorithms/controllers/ume_legacy/CMakeLists.txt index 73bc703c..6e847056 100644 --- a/cmvr-es/algorithms/controllers/ume_legacy/CMakeLists.txt +++ b/cmvr-es/algorithms/controllers/ume_legacy/CMakeLists.txt @@ -20,59 +20,3 @@ add_library( ) install(TARGETS ume_legacy_controller LIBRARY DESTINATION lib) - -if(BUILD_TESTING) - add_executable(ume_legacy_controller_golden_test - tests/ume_legacy_controller_golden_test.cpp - ) - add_executable(pinocchio_ume_legacy_model_adapter_test - tests/pinocchio_ume_legacy_model_adapter_test.cpp - ) - - target_link_libraries(ume_legacy_controller_golden_test - PRIVATE - cmvr_es::algorithms::ume_legacy - gtest - gtest_main - pthread - ) - target_link_libraries(pinocchio_ume_legacy_model_adapter_test - PRIVATE - cmvr_es::algorithms::ume_legacy - gtest - gtest_main - pthread - ) - - foreach(_ume_legacy_test_target - ume_legacy_controller_golden_test - pinocchio_ume_legacy_model_adapter_test) - target_compile_definitions(${_ume_legacy_test_target} - PRIVATE - CMVR_UME_FIXED_MODEL_PATH="${CMAKE_SOURCE_DIR}/model/ume/v6_bimanual/robot.xml" - CMVR_UME_FLOATING_MODEL_PATH="${CMAKE_SOURCE_DIR}/model/ume/v6_imu/robot.xml" - ) - add_test( - NAME ${_ume_legacy_test_target} - COMMAND ${_ume_legacy_test_target} - ) - endforeach() - - set(_ume_legacy_test_environment - "LD_LIBRARY_PATH=${CMVR_TEST_EXTERNAL_LIBRARY_PATH}" - ) - - if(CMVR_TEST_SYSTEM_LIBSTDCXX) - list(APPEND _ume_legacy_test_environment - "LD_PRELOAD=${CMVR_TEST_SYSTEM_LIBSTDCXX}") - endif() - - foreach(_ume_legacy_test_target - ume_legacy_controller_golden_test - pinocchio_ume_legacy_model_adapter_test) - set_tests_properties(${_ume_legacy_test_target} PROPERTIES - TIMEOUT 10 - ENVIRONMENT "${_ume_legacy_test_environment}" - ) - endforeach() -endif() diff --git a/cmvr-es/algorithms/controllers/ume_legacy/tests/pinocchio_ume_legacy_model_adapter_test.cpp b/cmvr-es/algorithms/controllers/ume_legacy/tests/pinocchio_ume_legacy_model_adapter_test.cpp deleted file mode 100644 index 568ff28e..00000000 --- a/cmvr-es/algorithms/controllers/ume_legacy/tests/pinocchio_ume_legacy_model_adapter_test.cpp +++ /dev/null @@ -1,392 +0,0 @@ -#include "pinocchio_ume_legacy_model_adapter.h" - -#include -#include -#include -#include -#include -#include - -#include - -#ifndef CMVR_UME_FIXED_MODEL_PATH -#error "CMVR_UME_FIXED_MODEL_PATH must identify the deployed fixed UME MJCF" -#endif - -#ifndef CMVR_UME_FLOATING_MODEL_PATH -#error "CMVR_UME_FLOATING_MODEL_PATH must identify the deployed floating UME MJCF" -#endif - -namespace cmvr::ume_legacy { -namespace { - -constexpr double kNumericalTolerance = 1e-10; - -PinocchioUmeLegacyModelAdapter makeAdapter() -{ - return PinocchioUmeLegacyModelAdapter( - CMVR_UME_FIXED_MODEL_PATH, - CMVR_UME_FLOATING_MODEL_PATH); -} - -BimanualModelState makeGoldenState( - const PinocchioUmeLegacyModelAdapter& adapter) -{ - BimanualModelState state; - state.world_from_imu = - adapter.contract().base_from_imu; - state.right_position_rad = - {0.1, -0.2, 0.3, -0.4, - 0.2, -0.1, 0.15, -0.05}; - state.left_position_rad = - {-0.1, 0.2, -0.3, 0.4, - -0.2, 0.1, -0.15, 0.05}; - return state; -} - -template -void expectFinite(const std::array& values) -{ - for (std::size_t index = 0; index < Size; ++index) { - EXPECT_TRUE(std::isfinite(values[index])) - << "index " << index; - } -} - -template -void expectNear( - const std::array& actual, - const std::array& expected, - double tolerance = kNumericalTolerance) -{ - for (std::size_t index = 0; index < Size; ++index) { - EXPECT_NEAR(actual[index], expected[index], tolerance) - << "index " << index; - } -} - -Transform4x4RowMajor multiplyTransforms( - const Transform4x4RowMajor& left, - const Transform4x4RowMajor& right) -{ - Transform4x4RowMajor result{}; - for (std::size_t row = 0; row < 4; ++row) { - for (std::size_t column = 0; column < 4; ++column) { - for (std::size_t inner = 0; inner < 4; ++inner) { - result[row * 4 + column] += - left[row * 4 + inner] * - right[inner * 4 + column]; - } - } - } - return result; -} - -Transform4x4RowMajor makeNoncommutingWorldFromBase() -{ - constexpr double roll = 0.2; - constexpr double pitch = -0.35; - constexpr double yaw = 0.47; - const double sr = std::sin(roll); - const double cr = std::cos(roll); - const double sp = std::sin(pitch); - const double cp = std::cos(pitch); - const double sy = std::sin(yaw); - const double cy = std::cos(yaw); - return { - cy * cp, - cy * sp * sr - sy * cr, - cy * sp * cr + sy * sr, - 0.4, - sy * cp, - sy * sp * sr + cy * cr, - sy * sp * cr - cy * sr, - -0.1, - -sp, - cp * sr, - cp * cr, - 0.8, - 0.0, 0.0, 0.0, 1.0}; -} - -TEST(PinocchioUmeLegacyModelAdapterTest, - LoadsOriginalMjcfWithoutGeometryAssetsAndFreezesContract) -{ - const auto adapter = makeAdapter(); - const auto& contract = adapter.contract(); - - EXPECT_EQ(contract.fixed_nq, 16U); - EXPECT_EQ(contract.fixed_nv, 16U); - EXPECT_EQ(contract.floating_nq, 23U); - EXPECT_EQ(contract.floating_nv, 22U); - EXPECT_EQ(adapter.fixedModelPath(), CMVR_UME_FIXED_MODEL_PATH); - EXPECT_EQ( - adapter.floatingModelPath(), - CMVR_UME_FLOATING_MODEL_PATH); - - // This transform comes from the original floating model's imu site. - // Pinocchio buildModel parses it without loading STL geometry. - const Transform4x4RowMajor expected_base_from_imu{ - 0.0, 0.0, -1.0, -0.0298, - 0.0, 1.0, 0.0, 0.0, - 1.0, 0.0, 0.0, -0.229564, - 0.0, 0.0, 0.0, 1.0}; - expectNear( - contract.base_from_imu, - expected_base_from_imu, - 1e-5); -} - -TEST(PinocchioUmeLegacyModelAdapterTest, - FloatingBaseRneaProducesFiniteFrozenJointEfforts) -{ - const auto adapter = makeAdapter(); - const auto state = makeGoldenState(adapter); - JointVector right{}; - JointVector left{}; - - ASSERT_TRUE( - adapter.computeGravityCompensation( - state, right, left)); - expectFinite(right); - expectFinite(left); - expectNear( - right, - {4.2579946000243867, - -3.101883528283977, - 5.8349126697703291, - -3.2335040596068012, - 0.54313804667559806, - -0.28419763993223052, - 0.075420409617272505, - -0.0050792810993999194}); - expectNear( - left, - {-4.2570142852347947, - 3.1002195124462104, - -5.8319486672094438, - 3.2334454894750602, - -0.54274278459746039, - 0.28419800074629464, - -0.075420524366616282, - 0.0050792800399334561}); -} - -TEST(PinocchioUmeLegacyModelAdapterTest, - ImuDerivedBaseOrientationReversesGravityUnderHalfTurn) -{ - const auto adapter = makeAdapter(); - auto state = makeGoldenState(adapter); - JointVector upright_right{}; - JointVector upright_left{}; - ASSERT_TRUE(adapter.computeGravityCompensation( - state, upright_right, upright_left)); - - const Transform4x4RowMajor world_from_base_half_turn_x{ - 1.0, 0.0, 0.0, 0.0, - 0.0, -1.0, 0.0, 0.0, - 0.0, 0.0, -1.0, 0.0, - 0.0, 0.0, 0.0, 1.0}; - state.world_from_imu = multiplyTransforms( - world_from_base_half_turn_x, - adapter.contract().base_from_imu); - - JointVector inverted_right{}; - JointVector inverted_left{}; - ASSERT_TRUE(adapter.computeGravityCompensation( - state, inverted_right, inverted_left)); - for (std::size_t index = 0; index < kArmDof; ++index) { - EXPECT_NEAR( - inverted_right[index], - -upright_right[index], - kNumericalTolerance) - << "right joint index " << index; - EXPECT_NEAR( - inverted_left[index], - -upright_left[index], - kNumericalTolerance) - << "left joint index " << index; - } -} - -TEST(PinocchioUmeLegacyModelAdapterTest, - NoncommutingImuPoseAndAsymmetricVelocitiesMatchFrozenRnea) -{ - const auto adapter = makeAdapter(); - auto state = makeGoldenState(adapter); - state.world_from_imu = multiplyTransforms( - makeNoncommutingWorldFromBase(), - adapter.contract().base_from_imu); - state.right_velocity_rad_s = - {0.7, -0.4, 0.2, -0.1, - 1.1, -0.8, 0.5, -0.3}; - state.left_velocity_rad_s = - {-0.6, 0.9, -0.2, 0.4, - -1.0, 0.7, -0.5, 0.25}; - - JointVector right{}; - JointVector left{}; - ASSERT_TRUE(adapter.computeGravityCompensation( - state, right, left)); - expectFinite(right); - expectFinite(left); - expectNear( - right, - {2.080988418159027, - -1.3277143244666021, - 2.3194639604892364, - -2.0699331198781317, - 0.40716561983947641, - -0.20631486209184946, - 0.19335176308712126, - -0.01319194690287678}); - expectNear( - left, - {-5.6976332776660232, - 2.9915426497221254, - -2.5700109870406949, - 2.1379083447512071, - -0.36441212045948712, - 0.19226687457105307, - -0.085601264411386338, - 0.0065129700338426369}); -} - -TEST(PinocchioUmeLegacyModelAdapterTest, - FixedModelRotationalProjectionMatchesFrozenValues) -{ - const auto adapter = makeAdapter(); - const auto state = makeGoldenState(adapter); - RawHapticFeedback feedback; - feedback.shoulder_moment = {0.5, -0.2, 0.3}; - feedback.elbow_effort = 1.2; - feedback.wrist_moment = {-0.4, 0.1, 0.6}; - feedback.gripper_effort = -0.7; - - ProjectedHapticEffort right{}; - ASSERT_TRUE(adapter.projectHapticFeedback( - state, ArmSide::Right, feedback, right)); - expectFinite(right.shoulder_joint_torque); - expectFinite(right.wrist_joint_torque); - expectNear( - right.shoulder_joint_torque, - {-0.5, - -0.12674237993402607, - -0.30915027509149773}); - expectNear( - right.wrist_joint_torque, - {-0.065872923184419674, - -0.028130723042130143, - -0.72743566625468636}); - EXPECT_DOUBLE_EQ(right.elbow_effort, feedback.elbow_effort); - EXPECT_DOUBLE_EQ( - right.gripper_effort, - feedback.gripper_effort); - - ProjectedHapticEffort left{}; - ASSERT_TRUE(adapter.projectHapticFeedback( - state, ArmSide::Left, feedback, left)); - expectFinite(left.shoulder_joint_torque); - expectFinite(left.wrist_joint_torque); - expectNear( - left.shoulder_joint_torque, - {-0.5, - -0.36032671657345572, - 0.083245914753940151}); - expectNear( - left.wrist_joint_torque, - {-0.13497315246130309, - 0.15764759010789803, - -0.70779204949804098}); - EXPECT_DOUBLE_EQ(left.elbow_effort, feedback.elbow_effort); - EXPECT_DOUBLE_EQ( - left.gripper_effort, - feedback.gripper_effort); -} - -TEST(PinocchioUmeLegacyModelAdapterTest, - RejectsNonRigidOrNonFiniteInputsAndZerosOutputs) -{ - const auto adapter = makeAdapter(); - auto state = makeGoldenState(adapter); - JointVector right; - JointVector left; - right.fill(1.0); - left.fill(1.0); - - state.world_from_imu = {}; - EXPECT_FALSE(adapter.computeGravityCompensation( - state, right, left)); - expectNear(right, JointVector{}); - expectNear(left, JointVector{}); - - state = makeGoldenState(adapter); - state.right_position_rad[3] = - std::numeric_limits::quiet_NaN(); - right.fill(1.0); - left.fill(1.0); - EXPECT_FALSE(adapter.computeGravityCompensation( - state, right, left)); - expectNear(right, JointVector{}); - expectNear(left, JointVector{}); - - state = makeGoldenState(adapter); - RawHapticFeedback feedback; - feedback.shoulder_moment[1] = - std::numeric_limits::infinity(); - ProjectedHapticEffort projected; - projected.elbow_effort = 1.0; - EXPECT_FALSE(adapter.projectHapticFeedback( - state, ArmSide::Right, feedback, projected)); - expectNear( - projected.shoulder_joint_torque, - Vector3{}); - expectNear(projected.wrist_joint_torque, Vector3{}); - EXPECT_DOUBLE_EQ(projected.elbow_effort, 0.0); - EXPECT_DOUBLE_EQ(projected.gripper_effort, 0.0); - - feedback = {}; - projected.elbow_effort = 1.0; - EXPECT_FALSE(adapter.projectHapticFeedback( - state, - static_cast(99), - feedback, - projected)); - expectNear( - projected.shoulder_joint_torque, - Vector3{}); - expectNear(projected.wrist_joint_torque, Vector3{}); - EXPECT_DOUBLE_EQ(projected.elbow_effort, 0.0); - EXPECT_DOUBLE_EQ(projected.gripper_effort, 0.0); -} - -TEST(PinocchioUmeLegacyModelAdapterTest, - MissingModelFailsAtConstruction) -{ - EXPECT_THROW( - PinocchioUmeLegacyModelAdapter( - "/definitely/missing/ume_fixed.xml", - CMVR_UME_FLOATING_MODEL_PATH), - std::runtime_error); -} - -TEST(PinocchioUmeLegacyModelAdapterTest, - RejectsModelRoleSwapEvenThoughBothMjcfFilesParse) -{ - try { - PinocchioUmeLegacyModelAdapter adapter( - CMVR_UME_FLOATING_MODEL_PATH, - CMVR_UME_FIXED_MODEL_PATH); - (void)adapter; - FAIL() << "swapped fixed/floating models were accepted"; - } catch (const std::runtime_error& error) { - EXPECT_NE( - std::string(error.what()).find( - "UME fixed MJCF contract violation: " - "expected nq/nv/njoints 16/16/17"), - std::string::npos); - } -} - -} // namespace -} // namespace cmvr::ume_legacy diff --git a/cmvr-es/algorithms/controllers/ume_legacy/tests/ume_legacy_controller_golden_test.cpp b/cmvr-es/algorithms/controllers/ume_legacy/tests/ume_legacy_controller_golden_test.cpp deleted file mode 100644 index b5610c20..00000000 --- a/cmvr-es/algorithms/controllers/ume_legacy/tests/ume_legacy_controller_golden_test.cpp +++ /dev/null @@ -1,216 +0,0 @@ -#include "ume_legacy_controller.h" -#include "ume_legacy_model_adapter.h" - -#include -#include -#include -#include - -#include - -namespace cmvr::ume_legacy { -namespace { - -constexpr double kTolerance = 1e-12; - -void expectJointVectorNear( - const JointVector& actual, - const JointVector& expected, - double tolerance = kTolerance) -{ - for (std::size_t index = 0; index < kArmDof; ++index) { - EXPECT_NEAR(actual[index], expected[index], tolerance) - << "joint index " << index; - } -} - -TEST(UmeLegacyControllerGoldenTest, - OriginalTuningAndFrictionMatchPythonOracle) -{ - const auto tuning = originalTuning(); - EXPECT_DOUBLE_EQ(tuning.friction_coefficient[0], 1.6); - EXPECT_DOUBLE_EQ(tuning.friction_coefficient[4], 0.032); - EXPECT_DOUBLE_EQ(tuning.feedback_limit_dm4340_nm, 4.0); - EXPECT_DOUBLE_EQ(tuning.feedback_limit_dm4310_nm, 1.0); - - const JointVector velocity{ - -1.0, -0.1, 0.0, 2.0 * std::acos(-1.0) / 180.0, - -10.0, -1.0, 1.0, 10.0}; - const JointVector expected{ - -0.4, -0.16000000000000003, 0.0, - 0.055850536063818547, - -0.1, -0.032, 0.032, 0.1}; - - expectJointVectorNear( - frictionCompensation(velocity, tuning), - expected); -} - -TEST(UmeLegacyControllerGoldenTest, - StictionUsesStrictLegacyThresholds) -{ - const auto tuning = originalTuning(); - const double minimum = - tuning.stiction_threshold_min_rad_s[0]; - const double maximum = - tuning.stiction_threshold_max_rad_s[0]; - const JointVector at_threshold{ - minimum, - -minimum, - maximum, - -maximum, - 0.0, 0.0, 0.0, 0.0}; - expectJointVectorNear( - stictionCompensation(at_threshold, tuning), - JointVector{}); - - const JointVector strictly_inside{ - 2.0 * minimum, - -2.0 * minimum, - std::nextafter( - minimum, std::numeric_limits::infinity()), - std::nextafter(maximum, 0.0), - 2.0 * minimum, - -2.0 * minimum, - std::nextafter( - minimum, std::numeric_limits::infinity()), - std::nextafter(maximum, 0.0)}; - expectJointVectorNear( - stictionCompensation(strictly_inside, tuning), - {0.5, -0.5, 0.5, 0.5, - 0.0, 0.0, 0.0, 0.0}); -} - -TEST(UmeLegacyControllerGoldenTest, - FeedbackScaleMatchesLegacyNormAndTanhGoldenValues) -{ - const auto tuning = originalTuning(); - EXPECT_NEAR( - feedbackScale(0.0, tuning), - 0.20680448412090907, - kTolerance); - EXPECT_DOUBLE_EQ( - feedbackScale(tuning.feedback_error_tolerance_rad, tuning), - 0.25); - EXPECT_NEAR( - feedbackScale(0.05, tuning), - 0.32861047013244982, - kTolerance); - EXPECT_NEAR( - feedbackScale(-0.2, tuning), - 0.48734517579834447, - kTolerance); -} - -TEST(UmeLegacyControllerGoldenTest, - CompleteRightSideCommandMatchesPythonGoldenVector) -{ - SideControlInput input; - input.side = ArmSide::Right; - input.joint_velocity_rad_s = { - -1.0, -0.1, 0.0, 2.0 * std::acos(-1.0) / 180.0, - -10.0, -1.0, 1.0, 10.0}; - input.gravity_compensation_nm = - {0.5, -0.5, 1.0, -1.0, - 0.25, -0.25, 0.75, -0.75}; - input.projected_haptic.shoulder_joint_torque = - {1.2, -3.0, 10.0}; - input.projected_haptic.elbow_effort = 2.0; - input.projected_haptic.wrist_joint_torque = - {0.5, -2.0, 5.0}; - input.projected_haptic.gripper_effort = 3.0; - input.tracking_error.shoulder_rotation = {0.0, 0.0, 0.0}; - input.tracking_error.elbow = - originalTuning().feedback_error_tolerance_rad; - input.tracking_error.wrist_rotation = {0.03, 0.04, 0.0}; - input.tracking_error.gripper = -0.2; - - const auto output = computeSideCommand(input); - - expectJointVectorNear( - output.friction_compensation_nm, - {-0.4, -0.16000000000000003, 0.0, - 0.055850536063818547, - -0.1, -0.032, 0.032, 0.1}); - expectJointVectorNear( - output.stiction_compensation_nm, - {0.0, -0.5, 0.0, 0.5, - 0.0, 0.0, 0.0, 0.0}); - expectJointVectorNear( - output.feedforward_without_haptic_nm, - {0.099999999999999978, -1.1600000000000001, - 1.0, -0.44414946393618149, - 0.14999999999999999, -0.28200000000000003, - 0.78200000000000003, -0.65000000000000002}); - expectJointVectorNear( - output.signed_interaction_nm, - {1.2, -3.0, 10.0, 2.0, - 0.5, -2.0, 5.0, -3.0}); - expectJointVectorNear( - output.limited_feedback_nm, - {0.24816538094509089, -0.62041345236272716, - 2.0680448412090908, 0.5, - 0.16430523506622491, -0.65722094026489963, - 1.0, -1.0}); - expectJointVectorNear( - output.command_torque_nm, - {-0.14816538094509091, -0.53958654763727298, - -1.0680448412090908, -0.94414946393618149, - -0.014305235066224914, 0.37522094026489961, - -0.21799999999999997, 0.34999999999999998}); -} - -TEST(UmeLegacyControllerGoldenTest, - LeftAndRightScalarSignsAndGroupLimitsArePreserved) -{ - SideControlInput input; - input.projected_haptic.shoulder_joint_torque = - {100.0, -100.0, 100.0}; - input.projected_haptic.elbow_effort = 100.0; - input.projected_haptic.wrist_joint_torque = - {100.0, -100.0, 100.0}; - input.projected_haptic.gripper_effort = 100.0; - input.tracking_error.shoulder_rotation = {10.0, 0.0, 0.0}; - input.tracking_error.elbow = 10.0; - input.tracking_error.wrist_rotation = {10.0, 0.0, 0.0}; - input.tracking_error.gripper = 10.0; - - input.side = ArmSide::Right; - const auto right = computeSideCommand(input); - expectJointVectorNear( - right.signed_interaction_nm, - {100.0, -100.0, 100.0, 100.0, - 100.0, -100.0, 100.0, -100.0}); - expectJointVectorNear( - right.command_torque_nm, - {-4.0, 4.0, -4.0, -4.0, - -1.0, 1.0, -1.0, 1.0}); - - input.side = ArmSide::Left; - const auto left = computeSideCommand(input); - expectJointVectorNear( - left.signed_interaction_nm, - {100.0, -100.0, 100.0, -100.0, - 100.0, -100.0, 100.0, 100.0}); - expectJointVectorNear( - left.command_torque_nm, - {-4.0, 4.0, -4.0, 4.0, - -1.0, 1.0, -1.0, -1.0}); -} - -TEST(UmeLegacyControllerGoldenTest, - FeedbackClipDoesNotClampOtherFeedforwardTerms) -{ - SideControlInput input; - input.gravity_compensation_nm = - {50.0, -50.0, 0.0, 0.0, 0.0, 0.0, 20.0, -20.0}; - const auto output = computeSideCommand(input); - - EXPECT_DOUBLE_EQ(output.command_torque_nm[0], 50.0); - EXPECT_DOUBLE_EQ(output.command_torque_nm[1], -50.0); - EXPECT_DOUBLE_EQ(output.command_torque_nm[6], 20.0); - EXPECT_DOUBLE_EQ(output.command_torque_nm[7], -20.0); -} - -} // namespace -} // namespace cmvr::ume_legacy diff --git a/cmvr-es/common/CMakeLists.txt b/cmvr-es/common/CMakeLists.txt index 3bedb230..b34192ff 100644 --- a/cmvr-es/common/CMakeLists.txt +++ b/cmvr-es/common/CMakeLists.txt @@ -28,20 +28,3 @@ target_link_libraries(common PUBLIC add_library(cmvr_es::common ALIAS common) install(TARGETS common LIBRARY DESTINATION lib) - -#add_executable(image_display_test -# utils/visualization/image_display_test.cpp -#) -# -#target_link_libraries(image_display_test -# PRIVATE -# cmvr_es::common -# cmvr_es::perception -# cmvr_es::device::realsense_camera -# cmvr_es::proto -# glog -# gtest -# gtest_main -# pthread -#) -# diff --git a/cmvr-es/common/base/logging/CMakeLists.txt b/cmvr-es/common/base/logging/CMakeLists.txt index 5322a2e5..c6c31e5c 100644 --- a/cmvr-es/common/base/logging/CMakeLists.txt +++ b/cmvr-es/common/base/logging/CMakeLists.txt @@ -13,26 +13,3 @@ target_link_libraries(logging PUBLIC add_library(cmvr_es::logging ALIAS logging) install(TARGETS logging ARCHIVE DESTINATION lib) - -if(BUILD_TESTING) - add_executable(logger_test - tests/logger_test.cpp - ) - target_link_libraries(logger_test PRIVATE - cmvr_es::logging - gtest - gtest_main - pthread - ) - add_test(NAME logger_test COMMAND logger_test) - set(_logger_test_environment - "LD_LIBRARY_PATH=${CMVR_TEST_EXTERNAL_LIBRARY_PATH}") - if(CMVR_TEST_SYSTEM_LIBSTDCXX) - list(APPEND _logger_test_environment - "LD_PRELOAD=${CMVR_TEST_SYSTEM_LIBSTDCXX}") - endif() - set_tests_properties(logger_test PROPERTIES - TIMEOUT 10 - ENVIRONMENT "${_logger_test_environment}" - ) -endif() diff --git a/cmvr-es/common/base/logging/tests/logger_test.cpp b/cmvr-es/common/base/logging/tests/logger_test.cpp deleted file mode 100644 index cc0aef19..00000000 --- a/cmvr-es/common/base/logging/tests/logger_test.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include "common/base/logging/logger.h" - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace cmvr::logging { -namespace { - -class LoggerTest : public testing::Test { -protected: - void SetUp() override - { - std::array pattern{}; - const std::string value = "/tmp/cmvr-logger-test-XXXXXX"; - std::copy(value.begin(), value.end(), pattern.begin()); - if (char* created = ::mkdtemp(pattern.data())) { - directory_ = created; - } - ASSERT_FALSE(directory_.empty()); - } - - void TearDown() override - { - shutdownLogging(); - std::error_code error; - std::filesystem::remove_all(directory_, error); - } - - config::LoggerConfig warningFileConfig() const - { - config::LoggerConfig config; - config.set_minimum_level(config::LOG_LEVEL_DEBUG); - config.set_directory(directory_.string()); - config.set_flush_interval_seconds(3600); - auto* route = config.add_routes(); - route->set_level(config::LOG_LEVEL_WARNING); - route->set_terminal(false); - route->set_file(true); - return config; - } - - std::string fileContents() const - { - std::ifstream input(directory_ / "logger_test.log"); - return {std::istreambuf_iterator(input), - std::istreambuf_iterator()}; - } - - std::filesystem::path directory_; -}; - -TEST_F(LoggerTest, ExplicitFlushMakesWarningVisibleInFile) -{ - ASSERT_TRUE(initLogging( - warningFileConfig(), "logger_test", directory_)); - - Logger::instance().write( - Level::WARNING, __FILE__, __LINE__, "warning sentinel"); - Logger::instance().flush(); - - EXPECT_NE(fileContents().find("warning sentinel"), std::string::npos); -} - -TEST_F(LoggerTest, ErrorIsVisibleInFileImmediately) -{ - auto config = warningFileConfig(); - config.mutable_routes(0)->set_level(config::LOG_LEVEL_ERROR); - ASSERT_TRUE(initLogging(config, "logger_test", directory_)); - - Logger::instance().write( - Level::ERROR, __FILE__, __LINE__, "error sentinel"); - - EXPECT_NE(fileContents().find("error sentinel"), std::string::npos); -} - -TEST_F(LoggerTest, FlushIsSafeOutsideInitializedLifetime) -{ - Logger::instance().flush(); - ASSERT_TRUE(initLogging( - warningFileConfig(), "logger_test", directory_)); - shutdownLogging(); - Logger::instance().flush(); -} - -} // namespace -} // namespace cmvr::logging diff --git a/cmvr-es/common/vision/image_display.h b/cmvr-es/common/vision/image_display.h deleted file mode 100644 index 67b3f781..00000000 --- a/cmvr-es/common/vision/image_display.h +++ /dev/null @@ -1,609 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace cmvr::common { - -/** - * @brief 图像像素坐标。 - * - * 坐标系约定: - * - `u`:图像列坐标,向右为正,单位像素。 - * - `v`:图像行坐标,向下为正,单位像素。 - */ -struct Pixel { - int u{0}; // 图像像素列坐标,单位像素。 - int v{0}; // 图像像素行坐标,单位像素。 -}; - -/** - * @brief BGR 颜色定义。 - */ -struct Color { - uint8_t b{0}; // 蓝色通道,范围 [0, 255]。 - uint8_t g{255}; // 绿色通道,范围 [0, 255]。 - uint8_t r{0}; // 红色通道,范围 [0, 255]。 - - /** - * @brief 转为 OpenCV 的 `cv::Scalar`。 - */ - cv::Scalar toCvScalar() const { - return cv::Scalar(static_cast(b), - static_cast(g), - static_cast(r)); - } - - /** - * @brief 预定义红色。 - */ - static Color red() { return Color{0, 0, 255}; } - - /** - * @brief 预定义绿色。 - */ - static Color green() { return Color{0, 255, 0}; } - - /** - * @brief 预定义蓝色。 - */ - static Color blue() { return Color{255, 0, 0}; } - - /** - * @brief 预定义黄色。 - */ - static Color yellow() { return Color{0, 255, 255}; } - - /** - * @brief 预定义白色。 - */ - static Color white() { return Color{255, 255, 255}; } - - /** - * @brief 预定义黑色。 - */ - static Color black() { return Color{0, 0, 0}; } -}; - -/** - * @brief 图像上的文本叠加配置。 - */ -struct TextOverlay { - std::string text; // 需要显示的字符串内容。 - Pixel position_px{}; // 文本左下角在图像像素坐标系中的位置。 - Color color{Color::green()}; // 文本颜色。 - double font_scale{0.7}; // OpenCV 字体缩放系数。 - int thickness{2}; // 文本线宽,单位像素。 - int font_face{cv::FONT_HERSHEY_SIMPLEX}; // OpenCV 字体类型。 - bool draw_background{false}; // 是否绘制文本背景框。 - Color background_color{Color::black()}; // 文本背景框颜色。 - int background_padding_px{2}; // 文本背景框四周留白,单位像素。 -}; - -/** - * @brief 图像上的点叠加配置。 - */ -struct PointOverlay { - Pixel position_px{}; // 点中心在图像像素坐标系中的位置。 - Color color{Color::red()}; // 点颜色。 - int radius_px{5}; // 圆点半径,单位像素。 - int thickness{2}; // 线宽,`-1` 表示填充。 - std::string label; // 点旁边附带显示的字符串;为空时不显示。 - Pixel label_offset_px{8, -8}; // 标签相对点中心的像素偏移。 - double label_font_scale{0.6}; // 点标签字体缩放系数。 - int label_thickness{2}; // 点标签线宽,单位像素。 -}; - -/** - * @brief 图像上的圆圈叠加配置。 - */ -struct CircleOverlay { - Pixel center_px{}; // 圆心在图像像素坐标系中的位置。 - int radius_px{10}; // 圆半径,单位像素。 - Color color{Color::yellow()}; // 圆圈颜色。 - int thickness{2}; // 圆圈线宽,单位像素,`-1` 表示填充。 -}; - -/** - * @brief 图像上的十字叠加配置。 - */ -struct CrossOverlay { - Pixel center_px{}; // 十字中心在图像像素坐标系中的位置。 - int arm_length_px{8}; // 单侧十字臂长度,单位像素。 - Color color{Color::blue()}; // 十字颜色。 - int thickness{2}; // 十字线宽,单位像素。 -}; - -/** - * @brief 通用图像叠加显示接口。 - * - * 该接口不依赖任何感知或跟踪类,只抽象三类输入: - * - 待显示的图像数据; - * - 文本叠加项; - * - 点叠加项。 - */ -class ImageDisplay { -public: - virtual ~ImageDisplay() = default; - - /** - * @brief 设置窗口名称。 - * @param window_name 显示窗口名称。 - */ - virtual void setWindowName(const std::string& window_name) = 0; - - /** - * @brief 设置待显示的图像。 - * @param image 输入图像,支持灰度图、BGR 图或 BGRA 图。 - */ - virtual void setImage(const cv::Mat& image) = 0; - - /** - * @brief 清空所有叠加项,但保留当前图像。 - */ - virtual void clearOverlays() = 0; - - /** - * @brief 添加文本叠加项。 - * @param overlay 文本叠加配置。 - */ - virtual void showText(const TextOverlay& overlay) = 0; - - /** - * @brief 按位置、字符串、颜色和大小直接添加文本。 - * @param text 需要显示的字符串内容。 - * @param position_px 文本左下角在图像像素坐标系中的位置。 - * @param color 文本颜色。 - * @param font_scale OpenCV 字体缩放系数。 - * @param thickness 文本线宽,单位像素。 - */ - virtual void showText(const std::string& text, - const Pixel& position_px, - const Color& color, - double font_scale = 0.7, - int thickness = 2) = 0; - - /** - * @brief 添加点叠加项。 - * @param overlay 点叠加配置。 - */ - virtual void showPoint(const PointOverlay& overlay) = 0; - - /** - * @brief 按位置、颜色和大小直接添加点。 - * @param position_px 点中心在图像像素坐标系中的位置。 - * @param color 点颜色。 - * @param radius_px 圆点半径,单位像素。 - * @param thickness 线宽,`-1` 表示填充。 - * @param label 点旁边附带显示的字符串;为空时不显示。 - */ - virtual void showPoint(const Pixel& position_px, - const Color& color, - int radius_px = 5, - int thickness = 2, - const std::string& label = {}) = 0; - - /** - * @brief 显示圆圈叠加项。 - * @param overlay 圆圈叠加配置。 - */ - virtual void showCircle(const CircleOverlay& overlay) = 0; - - /** - * @brief 按位置、半径、颜色和线宽直接显示圆圈。 - * @param center_px 圆心在图像像素坐标系中的位置。 - * @param radius_px 圆半径,单位像素。 - * @param color 圆圈颜色。 - * @param thickness 圆圈线宽,单位像素,`-1` 表示填充。 - */ - virtual void showCircle(const Pixel& center_px, - int radius_px, - const Color& color, - int thickness = 2) = 0; - - /** - * @brief 显示十字叠加项。 - * @param overlay 十字叠加配置。 - */ - virtual void showCross(const CrossOverlay& overlay) = 0; - - /** - * @brief 按位置、尺寸、颜色和线宽直接显示十字。 - * @param center_px 十字中心在图像像素坐标系中的位置。 - * @param arm_length_px 单侧十字臂长度,单位像素。 - * @param color 十字颜色。 - * @param thickness 十字线宽,单位像素。 - */ - virtual void showCross(const Pixel& center_px, - int arm_length_px, - const Color& color, - int thickness = 2) = 0; - - /** - * @brief 判断当前是否已有待显示图像。 - */ - virtual bool hasImage() const = 0; - - /** - * @brief 将当前图像和叠加项渲染到输出图像。 - * @param rendered_image 输出的渲染结果图像,BGR 三通道。 - * @return 渲染成功返回 `true`。 - */ - virtual bool render(cv::Mat& rendered_image) const = 0; - - /** - * @brief 显示当前渲染结果。 - * @param wait_key_ms `cv::waitKey` 等待时间,单位毫秒。 - * @return 返回 `cv::waitKey` 的按键值;若没有可显示图像则返回 `-1`。 - */ - virtual int show(int wait_key_ms = 1) = 0; - - /** - * @brief 关闭显示窗口。 - */ - virtual void close() = 0; -}; - -/** - * @brief 基于 OpenCV HighGUI 的图像叠加显示实现。 - */ -class OpenCvImageCvDisplay final : public ImageDisplay { -public: - /** - * @brief 构造显示器。 - * @param window_name 显示窗口名称。 - */ - explicit OpenCvImageCvDisplay(std::string window_name = "image_overlay") - : window_name_(std::move(window_name)) {} - - /** - * @brief 设置窗口名称。 - * @param window_name 显示窗口名称。 - */ - void setWindowName(const std::string& window_name) override { - window_name_ = window_name; - } - - /** - * @brief 设置待显示图像。 - * @param image 输入图像,支持灰度图、BGR 图或 BGRA 图。 - */ - void setImage(const cv::Mat& image) override { - image_ = image.clone(); - } - - /** - * @brief 清空所有叠加项,但保留当前图像。 - */ - void clearOverlays() override { - texts_.clear(); - points_.clear(); - circles_.clear(); - crosses_.clear(); - } - - /** - * @brief 添加文本叠加项。 - * @param overlay 文本叠加配置。 - */ - void showText(const TextOverlay& overlay) override { - texts_.push_back(overlay); - } - - /** - * @brief 按位置、字符串、颜色和大小直接添加文本。 - * @param text 需要显示的字符串内容。 - * @param position_px 文本左下角在图像像素坐标系中的位置。 - * @param color 文本颜色。 - * @param font_scale OpenCV 字体缩放系数。 - * @param thickness 文本线宽,单位像素。 - */ - void showText(const std::string& text, - const Pixel& position_px, - const Color& color, - double font_scale = 0.7, - int thickness = 2) override { - TextOverlay overlay; - overlay.text = text; - overlay.position_px = position_px; - overlay.color = color; - overlay.font_scale = font_scale; - overlay.thickness = thickness; - showText(overlay); - } - - /** - * @brief 添加点叠加项。 - * @param overlay 点叠加配置。 - */ - void showPoint(const PointOverlay& overlay) override { - points_.push_back(overlay); - } - - /** - * @brief 按位置、颜色和大小直接添加点。 - * @param position_px 点中心在图像像素坐标系中的位置。 - * @param color 点颜色。 - * @param radius_px 圆点半径,单位像素。 - * @param thickness 线宽,`-1` 表示填充。 - * @param label 点旁边附带显示的字符串;为空时不显示。 - */ - void showPoint(const Pixel& position_px, - const Color& color, - int radius_px = 5, - int thickness = 2, - const std::string& label = {}) override { - PointOverlay overlay; - overlay.position_px = position_px; - overlay.color = color; - overlay.radius_px = radius_px; - overlay.thickness = thickness; - overlay.label = label; - showPoint(overlay); - } - - /** - * @brief 显示圆圈叠加项。 - * @param overlay 圆圈叠加配置。 - */ - void showCircle(const CircleOverlay& overlay) override { - circles_.push_back(overlay); - } - - /** - * @brief 按位置、半径、颜色和线宽直接显示圆圈。 - * @param center_px 圆心在图像像素坐标系中的位置。 - * @param radius_px 圆半径,单位像素。 - * @param color 圆圈颜色。 - * @param thickness 圆圈线宽,单位像素,`-1` 表示填充。 - */ - void showCircle(const Pixel& center_px, - int radius_px, - const Color& color, - int thickness = 2) override { - CircleOverlay overlay; - overlay.center_px = center_px; - overlay.radius_px = radius_px; - overlay.color = color; - overlay.thickness = thickness; - showCircle(overlay); - } - - /** - * @brief 显示十字叠加项。 - * @param overlay 十字叠加配置。 - */ - void showCross(const CrossOverlay& overlay) override { - crosses_.push_back(overlay); - } - - /** - * @brief 按位置、尺寸、颜色和线宽直接显示十字。 - * @param center_px 十字中心在图像像素坐标系中的位置。 - * @param arm_length_px 单侧十字臂长度,单位像素。 - * @param color 十字颜色。 - * @param thickness 十字线宽,单位像素。 - */ - void showCross(const Pixel& center_px, - int arm_length_px, - const Color& color, - int thickness = 2) override { - CrossOverlay overlay; - overlay.center_px = center_px; - overlay.arm_length_px = arm_length_px; - overlay.color = color; - overlay.thickness = thickness; - showCross(overlay); - } - - /** - * @brief 判断当前是否已有待显示图像。 - */ - bool hasImage() const override { - return !image_.empty(); - } - - /** - * @brief 将当前图像和叠加项渲染到输出图像。 - * @param rendered_image 输出的渲染结果图像,BGR 三通道。 - * @return 渲染成功返回 `true`。 - */ - bool render(cv::Mat& rendered_image) const override { - if (!toBgrImage(image_, rendered_image)) { - return false; - } - - for (const CircleOverlay& overlay : circles_) { - drawCircle(rendered_image, overlay); - } - for (const CrossOverlay& overlay : crosses_) { - drawCross(rendered_image, overlay); - } - for (const PointOverlay& overlay : points_) { - drawPoint(rendered_image, overlay); - } - for (const TextOverlay& overlay : texts_) { - drawText(rendered_image, overlay); - } - return true; - } - - /** - * @brief 显示当前渲染结果。 - * @param wait_key_ms `cv::waitKey` 等待时间,单位毫秒。 - * @return 返回 `cv::waitKey` 的按键值;若没有可显示图像则返回 `-1`。 - */ - int show(int wait_key_ms = 1) override { - cv::Mat rendered_image; - if (!render(rendered_image)) { - return -1; - } - - if (!window_created_) { - cv::namedWindow(window_name_, cv::WINDOW_NORMAL); - window_created_ = true; - } - cv::imshow(window_name_, rendered_image); - return cv::waitKey(wait_key_ms); - } - - /** - * @brief 关闭显示窗口。 - */ - void close() override { - if (!window_created_) { - return; - } - cv::destroyWindow(window_name_); - window_created_ = false; - } - -private: - /** - * @brief 将输入图像转换为可叠加绘制的 BGR 三通道图像。 - * @param input 输入图像。 - * @param output 输出 BGR 图像。 - * @return 转换成功返回 `true`。 - */ - static bool toBgrImage(const cv::Mat& input, cv::Mat& output) { - if (input.empty()) { - return false; - } - - if (input.channels() == 1) { - cv::cvtColor(input, output, cv::COLOR_GRAY2BGR); - return true; - } - if (input.channels() == 3) { - output = input.clone(); - return true; - } - if (input.channels() == 4) { - cv::cvtColor(input, output, cv::COLOR_BGRA2BGR); - return true; - } - return false; - } - - /** - * @brief 在图像上绘制文本叠加项。 - * @param image 目标图像,BGR 三通道。 - * @param overlay 文本叠加配置。 - */ - static void drawText(cv::Mat& image, const TextOverlay& overlay) { - const cv::Point origin(overlay.position_px.u, overlay.position_px.v); - const int thickness = std::max(1, overlay.thickness); - const double font_scale = std::max(0.0, overlay.font_scale); - - if (overlay.draw_background) { - int baseline = 0; - const cv::Size text_size = cv::getTextSize(overlay.text, - overlay.font_face, - font_scale, - thickness, - &baseline); - const int pad = std::max(0, overlay.background_padding_px); - const cv::Point top_left(origin.x - pad, origin.y - text_size.height - pad); - const cv::Point bottom_right(origin.x + text_size.width + pad, origin.y + baseline + pad); - cv::rectangle(image, - top_left, - bottom_right, - overlay.background_color.toCvScalar(), - cv::FILLED); - } - - cv::putText(image, - overlay.text, - origin, - overlay.font_face, - font_scale, - overlay.color.toCvScalar(), - thickness, - cv::LINE_AA); - } - - /** - * @brief 在图像上绘制点叠加项。 - * @param image 目标图像,BGR 三通道。 - * @param overlay 点叠加配置。 - */ - static void drawPoint(cv::Mat& image, const PointOverlay& overlay) { - const cv::Point center(overlay.position_px.u, overlay.position_px.v); - const int radius = std::max(1, overlay.radius_px); - cv::circle(image, - center, - radius, - overlay.color.toCvScalar(), - overlay.thickness, - cv::LINE_AA); - - if (!overlay.label.empty()) { - TextOverlay label_overlay; - label_overlay.text = overlay.label; - label_overlay.position_px = Pixel{center.x + overlay.label_offset_px.u, - center.y + overlay.label_offset_px.v}; - label_overlay.color = overlay.color; - label_overlay.font_scale = overlay.label_font_scale; - label_overlay.thickness = overlay.label_thickness; - drawText(image, label_overlay); - } - } - - /** - * @brief 在图像上绘制圆圈叠加项。 - * @param image 目标图像,BGR 三通道。 - * @param overlay 圆圈叠加配置。 - */ - static void drawCircle(cv::Mat& image, const CircleOverlay& overlay) { - const cv::Point center(overlay.center_px.u, overlay.center_px.v); - const int radius = std::max(1, overlay.radius_px); - const int thickness = (overlay.thickness == 0) ? 1 : overlay.thickness; - cv::circle(image, - center, - radius, - overlay.color.toCvScalar(), - thickness, - cv::LINE_AA); - } - - /** - * @brief 在图像上绘制十字叠加项。 - * @param image 目标图像,BGR 三通道。 - * @param overlay 十字叠加配置。 - */ - static void drawCross(cv::Mat& image, const CrossOverlay& overlay) { - const cv::Point center(overlay.center_px.u, overlay.center_px.v); - const int arm_length = std::max(1, overlay.arm_length_px); - const int thickness = std::max(1, overlay.thickness); - const cv::Scalar color = overlay.color.toCvScalar(); - cv::line(image, - cv::Point(center.x - arm_length, center.y), - cv::Point(center.x + arm_length, center.y), - color, - thickness, - cv::LINE_AA); - cv::line(image, - cv::Point(center.x, center.y - arm_length), - cv::Point(center.x, center.y + arm_length), - color, - thickness, - cv::LINE_AA); - } - - std::string window_name_; // 显示窗口名称。 - cv::Mat image_; // 当前待显示图像。 - std::vector texts_; // 当前待绘制的文本叠加列表。 - std::vector points_; // 当前待绘制的点叠加列表。 - std::vector circles_; // 当前待绘制的圆圈叠加列表。 - std::vector crosses_; // 当前待绘制的十字叠加列表。 - bool window_created_{false}; // 显示窗口是否已经创建。 -}; - -} // namespace cmvr::common diff --git a/cmvr-es/common/vision/matplotlibcpp.h b/cmvr-es/common/vision/matplotlibcpp.h deleted file mode 100644 index 06735df4..00000000 --- a/cmvr-es/common/vision/matplotlibcpp.h +++ /dev/null @@ -1,2988 +0,0 @@ -#pragma once - -// Python headers must be included before any system headers, since -// they define _POSIX_C_SOURCE -#include - -#include -#include -#include -#include -#include -#include -#include -#include // requires c++11 support -#include -#include // std::stod - -#ifndef WITHOUT_NUMPY -# define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION -# include - -# ifdef WITH_OPENCV -# include -# endif // WITH_OPENCV - -/* - * A bunch of constants were removed in OpenCV 4 in favour of enum classes, so - * define the ones we need here. - */ -# if CV_MAJOR_VERSION > 3 -# define CV_BGR2RGB cv::COLOR_BGR2RGB -# define CV_BGRA2RGBA cv::COLOR_BGRA2RGBA -# endif -#endif // WITHOUT_NUMPY - -#if PY_MAJOR_VERSION >= 3 -# define PyString_FromString PyUnicode_FromString -# define PyInt_FromLong PyLong_FromLong -# define PyString_FromString PyUnicode_FromString -#endif - - -namespace matplotlibcpp { -namespace detail { - -static std::string s_backend; - -struct _interpreter { - PyObject* s_python_function_arrow; - PyObject *s_python_function_show; - PyObject *s_python_function_close; - PyObject *s_python_function_draw; - PyObject *s_python_function_pause; - PyObject *s_python_function_save; - PyObject *s_python_function_figure; - PyObject *s_python_function_fignum_exists; - PyObject *s_python_function_plot; - PyObject *s_python_function_quiver; - PyObject* s_python_function_contour; - PyObject *s_python_function_semilogx; - PyObject *s_python_function_semilogy; - PyObject *s_python_function_loglog; - PyObject *s_python_function_fill; - PyObject *s_python_function_fill_between; - PyObject *s_python_function_hist; - PyObject *s_python_function_imshow; - PyObject *s_python_function_scatter; - PyObject *s_python_function_boxplot; - PyObject *s_python_function_subplot; - PyObject *s_python_function_subplot2grid; - PyObject *s_python_function_legend; - PyObject *s_python_function_xlim; - PyObject *s_python_function_ion; - PyObject *s_python_function_ginput; - PyObject *s_python_function_ylim; - PyObject *s_python_function_title; - PyObject *s_python_function_axis; - PyObject *s_python_function_axhline; - PyObject *s_python_function_axvline; - PyObject *s_python_function_axvspan; - PyObject *s_python_function_xlabel; - PyObject *s_python_function_ylabel; - PyObject *s_python_function_gca; - PyObject *s_python_function_xticks; - PyObject *s_python_function_yticks; - PyObject* s_python_function_margins; - PyObject *s_python_function_tick_params; - PyObject *s_python_function_grid; - PyObject* s_python_function_cla; - PyObject *s_python_function_clf; - PyObject *s_python_function_errorbar; - PyObject *s_python_function_annotate; - PyObject *s_python_function_tight_layout; - PyObject *s_python_colormap; - PyObject *s_python_empty_tuple; - PyObject *s_python_function_stem; - PyObject *s_python_function_xkcd; - PyObject *s_python_function_text; - PyObject *s_python_function_suptitle; - PyObject *s_python_function_bar; - PyObject *s_python_function_barh; - PyObject *s_python_function_colorbar; - PyObject *s_python_function_subplots_adjust; - PyObject *s_python_function_rcparams; - PyObject *s_python_function_spy; - - /* For now, _interpreter is implemented as a singleton since its currently not possible to have - multiple independent embedded python interpreters without patching the python source code - or starting a separate process for each. [1] - Furthermore, many python objects expect that they are destructed in the same thread as they - were constructed. [2] So for advanced usage, a `kill()` function is provided so that library - users can manually ensure that the interpreter is constructed and destroyed within the - same thread. - - 1: http://bytes.com/topic/python/answers/793370-multiple-independent-python-interpreters-c-c-program - 2: https://github.com/lava/matplotlib-cpp/pull/202#issue-436220256 - */ - - static _interpreter& get() { - return interkeeper(false); - } - - static _interpreter& kill() { - return interkeeper(true); - } - - // Stores the actual singleton object referenced by `get()` and `kill()`. - static _interpreter& interkeeper(bool should_kill) { - static _interpreter ctx; - if (should_kill) - ctx.~_interpreter(); - return ctx; - } - - PyObject* safe_import(PyObject* module, std::string fname) { - PyObject* fn = PyObject_GetAttrString(module, fname.c_str()); - - if (!fn) - throw std::runtime_error(std::string("Couldn't find required function: ") + fname); - - if (!PyFunction_Check(fn)) - throw std::runtime_error(fname + std::string(" is unexpectedly not a PyFunction.")); - - return fn; - } - -private: - -#ifndef WITHOUT_NUMPY -# if PY_MAJOR_VERSION >= 3 - - void *import_numpy() { - import_array(); // initialize C-API - return NULL; - } - -# else - - void import_numpy() { - import_array(); // initialize C-API - } - -# endif -#endif - - _interpreter() { - - // optional but recommended -#if PY_MAJOR_VERSION >= 3 - wchar_t name[] = L"plotting"; -#else - char name[] = "plotting"; -#endif - Py_SetProgramName(name); - Py_Initialize(); - - wchar_t const *dummy_args[] = {L"Python", NULL}; // const is needed because literals must not be modified - wchar_t const **argv = dummy_args; - int argc = sizeof(dummy_args)/sizeof(dummy_args[0])-1; - -#if PY_MAJOR_VERSION >= 3 - PySys_SetArgv(argc, const_cast(argv)); -#else - PySys_SetArgv(argc, (char **)(argv)); -#endif - -#ifndef WITHOUT_NUMPY - import_numpy(); // initialize numpy C-API -#endif - - PyObject* matplotlibname = PyString_FromString("matplotlib"); - PyObject* pyplotname = PyString_FromString("matplotlib.pyplot"); - PyObject* cmname = PyString_FromString("matplotlib.cm"); - PyObject* pylabname = PyString_FromString("pylab"); - if (!pyplotname || !pylabname || !matplotlibname || !cmname) { - throw std::runtime_error("couldnt create string"); - } - - PyObject* matplotlib = PyImport_Import(matplotlibname); - - Py_DECREF(matplotlibname); - if (!matplotlib) { - PyErr_Print(); - throw std::runtime_error("Error loading module matplotlib!"); - } - - // matplotlib.use() must be called *before* pylab, matplotlib.pyplot, - // or matplotlib.backends is imported for the first time - if (!s_backend.empty()) { - PyObject_CallMethod(matplotlib, const_cast("use"), const_cast("s"), s_backend.c_str()); - } - - - - PyObject* pymod = PyImport_Import(pyplotname); - Py_DECREF(pyplotname); - if (!pymod) { throw std::runtime_error("Error loading module matplotlib.pyplot!"); } - - s_python_colormap = PyImport_Import(cmname); - Py_DECREF(cmname); - if (!s_python_colormap) { throw std::runtime_error("Error loading module matplotlib.cm!"); } - - PyObject* pylabmod = PyImport_Import(pylabname); - Py_DECREF(pylabname); - if (!pylabmod) { throw std::runtime_error("Error loading module pylab!"); } - - s_python_function_arrow = safe_import(pymod, "arrow"); - s_python_function_show = safe_import(pymod, "show"); - s_python_function_close = safe_import(pymod, "close"); - s_python_function_draw = safe_import(pymod, "draw"); - s_python_function_pause = safe_import(pymod, "pause"); - s_python_function_figure = safe_import(pymod, "figure"); - s_python_function_fignum_exists = safe_import(pymod, "fignum_exists"); - s_python_function_plot = safe_import(pymod, "plot"); - s_python_function_quiver = safe_import(pymod, "quiver"); - s_python_function_contour = safe_import(pymod, "contour"); - s_python_function_semilogx = safe_import(pymod, "semilogx"); - s_python_function_semilogy = safe_import(pymod, "semilogy"); - s_python_function_loglog = safe_import(pymod, "loglog"); - s_python_function_fill = safe_import(pymod, "fill"); - s_python_function_fill_between = safe_import(pymod, "fill_between"); - s_python_function_hist = safe_import(pymod,"hist"); - s_python_function_scatter = safe_import(pymod,"scatter"); - s_python_function_boxplot = safe_import(pymod,"boxplot"); - s_python_function_subplot = safe_import(pymod, "subplot"); - s_python_function_subplot2grid = safe_import(pymod, "subplot2grid"); - s_python_function_legend = safe_import(pymod, "legend"); - s_python_function_xlim = safe_import(pymod, "xlim"); - s_python_function_ylim = safe_import(pymod, "ylim"); - s_python_function_title = safe_import(pymod, "title"); - s_python_function_axis = safe_import(pymod, "axis"); - s_python_function_axhline = safe_import(pymod, "axhline"); - s_python_function_axvline = safe_import(pymod, "axvline"); - s_python_function_axvspan = safe_import(pymod, "axvspan"); - s_python_function_xlabel = safe_import(pymod, "xlabel"); - s_python_function_ylabel = safe_import(pymod, "ylabel"); - s_python_function_gca = safe_import(pymod, "gca"); - s_python_function_xticks = safe_import(pymod, "xticks"); - s_python_function_yticks = safe_import(pymod, "yticks"); - s_python_function_margins = safe_import(pymod, "margins"); - s_python_function_tick_params = safe_import(pymod, "tick_params"); - s_python_function_grid = safe_import(pymod, "grid"); - s_python_function_ion = safe_import(pymod, "ion"); - s_python_function_ginput = safe_import(pymod, "ginput"); - s_python_function_save = safe_import(pylabmod, "savefig"); - s_python_function_annotate = safe_import(pymod,"annotate"); - s_python_function_cla = safe_import(pymod, "cla"); - s_python_function_clf = safe_import(pymod, "clf"); - s_python_function_errorbar = safe_import(pymod, "errorbar"); - s_python_function_tight_layout = safe_import(pymod, "tight_layout"); - s_python_function_stem = safe_import(pymod, "stem"); - s_python_function_xkcd = safe_import(pymod, "xkcd"); - s_python_function_text = safe_import(pymod, "text"); - s_python_function_suptitle = safe_import(pymod, "suptitle"); - s_python_function_bar = safe_import(pymod,"bar"); - s_python_function_barh = safe_import(pymod, "barh"); - s_python_function_colorbar = PyObject_GetAttrString(pymod, "colorbar"); - s_python_function_subplots_adjust = safe_import(pymod,"subplots_adjust"); - s_python_function_rcparams = PyObject_GetAttrString(pymod, "rcParams"); - s_python_function_spy = PyObject_GetAttrString(pymod, "spy"); -#ifndef WITHOUT_NUMPY - s_python_function_imshow = safe_import(pymod, "imshow"); -#endif - s_python_empty_tuple = PyTuple_New(0); - } - - ~_interpreter() { - Py_Finalize(); - } -}; - -} // end namespace detail - -/// Select the backend -/// -/// **NOTE:** This must be called before the first plot command to have -/// any effect. -/// -/// Mainly useful to select the non-interactive 'Agg' backend when running -/// matplotlibcpp in headless mode, for example on a machine with no display. -/// -/// See also: https://matplotlib.org/2.0.2/api/matplotlib_configuration_api.html#matplotlib.use -inline void backend(const std::string& name) -{ - detail::s_backend = name; -} - -inline bool annotate(std::string annotation, double x, double y) -{ - detail::_interpreter::get(); - - PyObject * xy = PyTuple_New(2); - PyObject * str = PyString_FromString(annotation.c_str()); - - PyTuple_SetItem(xy,0,PyFloat_FromDouble(x)); - PyTuple_SetItem(xy,1,PyFloat_FromDouble(y)); - - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "xy", xy); - - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, str); - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_annotate, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - - if(res) Py_DECREF(res); - - return res; -} - -namespace detail { - -#ifndef WITHOUT_NUMPY -// Type selector for numpy array conversion -template struct select_npy_type { const static NPY_TYPES type = NPY_NOTYPE; }; //Default -template <> struct select_npy_type { const static NPY_TYPES type = NPY_DOUBLE; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_FLOAT; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_BOOL; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_INT8; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_SHORT; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_INT; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_INT64; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_UINT8; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_USHORT; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_ULONG; }; -template <> struct select_npy_type { const static NPY_TYPES type = NPY_UINT64; }; - -// Sanity checks; comment them out or change the numpy type below if you're compiling on -// a platform where they don't apply -static_assert(sizeof(long long) == 8); -template <> struct select_npy_type { const static NPY_TYPES type = NPY_INT64; }; -static_assert(sizeof(unsigned long long) == 8); -template <> struct select_npy_type { const static NPY_TYPES type = NPY_UINT64; }; - -template -PyObject* get_array(const std::vector& v) -{ - npy_intp vsize = v.size(); - NPY_TYPES type = select_npy_type::type; - if (type == NPY_NOTYPE) { - size_t memsize = v.size()*sizeof(double); - double* dp = static_cast(::malloc(memsize)); - for (size_t i=0; i(varray), NPY_ARRAY_OWNDATA); - return varray; - } - - PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data())); - return varray; -} - - -template -PyObject* get_2darray(const std::vector<::std::vector>& v) -{ - if (v.size() < 1) throw std::runtime_error("get_2d_array v too small"); - - npy_intp vsize[2] = {static_cast(v.size()), - static_cast(v[0].size())}; - - PyArrayObject *varray = - (PyArrayObject *)PyArray_SimpleNew(2, vsize, NPY_DOUBLE); - - double *vd_begin = static_cast(PyArray_DATA(varray)); - - for (const ::std::vector &v_row : v) { - if (v_row.size() != static_cast(vsize[1])) - throw std::runtime_error("Missmatched array size"); - std::copy(v_row.begin(), v_row.end(), vd_begin); - vd_begin += vsize[1]; - } - - return reinterpret_cast(varray); -} - -#else // fallback if we don't have numpy: copy every element of the given vector - -template -PyObject* get_array(const std::vector& v) -{ - PyObject* list = PyList_New(v.size()); - for(size_t i = 0; i < v.size(); ++i) { - PyList_SetItem(list, i, PyFloat_FromDouble(v.at(i))); - } - return list; -} - -#endif // WITHOUT_NUMPY - -// sometimes, for labels and such, we need string arrays -inline PyObject * get_array(const std::vector& strings) -{ - PyObject* list = PyList_New(strings.size()); - for (std::size_t i = 0; i < strings.size(); ++i) { - PyList_SetItem(list, i, PyString_FromString(strings[i].c_str())); - } - return list; -} - -// not all matplotlib need 2d arrays, some prefer lists of lists -template -PyObject* get_listlist(const std::vector>& ll) -{ - PyObject* listlist = PyList_New(ll.size()); - for (std::size_t i = 0; i < ll.size(); ++i) { - PyList_SetItem(listlist, i, get_array(ll[i])); - } - return listlist; -} - -} // namespace detail - -/// Plot a line through the given x and y data points.. -/// -/// See: https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.pyplot.plot.html -template -bool plot(const std::vector &x, const std::vector &y, const std::map& keywords) -{ - assert(x.size() == y.size()); - - detail::_interpreter::get(); - - // using numpy arrays - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - // construct positional args - PyObject* args = PyTuple_New(2); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); - } - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - if(res) Py_DECREF(res); - - return res; -} - -// TODO - it should be possible to make this work by implementing -// a non-numpy alternative for `detail::get_2darray()`. -#ifndef WITHOUT_NUMPY -template -void plot_surface(const std::vector<::std::vector> &x, - const std::vector<::std::vector> &y, - const std::vector<::std::vector> &z, - const std::map &keywords = - std::map(), - const long fig_number=0) -{ - detail::_interpreter::get(); - - // We lazily load the modules here the first time this function is called - // because I'm not sure that we can assume "matplotlib installed" implies - // "mpl_toolkits installed" on all platforms, and we don't want to require - // it for people who don't need 3d plots. - static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; - if (!mpl_toolkitsmod) { - detail::_interpreter::get(); - - PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits"); - PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d"); - if (!mpl_toolkits || !axis3d) { throw std::runtime_error("couldnt create string"); } - - mpl_toolkitsmod = PyImport_Import(mpl_toolkits); - Py_DECREF(mpl_toolkits); - if (!mpl_toolkitsmod) { throw std::runtime_error("Error loading module mpl_toolkits!"); } - - axis3dmod = PyImport_Import(axis3d); - Py_DECREF(axis3d); - if (!axis3dmod) { throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); } - } - - assert(x.size() == y.size()); - assert(y.size() == z.size()); - - // using numpy arrays - PyObject *xarray = detail::get_2darray(x); - PyObject *yarray = detail::get_2darray(y); - PyObject *zarray = detail::get_2darray(z); - - // construct positional args - PyObject *args = PyTuple_New(3); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - PyTuple_SetItem(args, 2, zarray); - - // Build up the kw args. - PyObject *kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "rstride", PyInt_FromLong(1)); - PyDict_SetItemString(kwargs, "cstride", PyInt_FromLong(1)); - - PyObject *python_colormap_coolwarm = PyObject_GetAttrString( - detail::_interpreter::get().s_python_colormap, "coolwarm"); - - PyDict_SetItemString(kwargs, "cmap", python_colormap_coolwarm); - - for (std::map::const_iterator it = keywords.begin(); - it != keywords.end(); ++it) { - if (it->first == "linewidth" || it->first == "alpha") { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyFloat_FromDouble(std::stod(it->second))); - } else { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); - } - } - - PyObject *fig_args = PyTuple_New(1); - PyObject* fig = nullptr; - PyTuple_SetItem(fig_args, 0, PyLong_FromLong(fig_number)); - PyObject *fig_exists = - PyObject_CallObject( - detail::_interpreter::get().s_python_function_fignum_exists, fig_args); - if (!PyObject_IsTrue(fig_exists)) { - fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple); - } else { - fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - fig_args); - } - Py_DECREF(fig_exists); - if (!fig) throw std::runtime_error("Call to figure() failed."); - - PyObject *gca_kwargs = PyDict_New(); - PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); - - PyObject *gca = PyObject_GetAttrString(fig, "gca"); - if (!gca) throw std::runtime_error("No gca"); - Py_INCREF(gca); - PyObject *axis = PyObject_Call( - gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); - - if (!axis) throw std::runtime_error("No axis"); - Py_INCREF(axis); - - Py_DECREF(gca); - Py_DECREF(gca_kwargs); - - PyObject *plot_surface = PyObject_GetAttrString(axis, "plot_surface"); - if (!plot_surface) throw std::runtime_error("No surface"); - Py_INCREF(plot_surface); - PyObject *res = PyObject_Call(plot_surface, args, kwargs); - if (!res) throw std::runtime_error("failed surface"); - Py_DECREF(plot_surface); - - Py_DECREF(axis); - Py_DECREF(args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); -} - -template -void contour(const std::vector<::std::vector> &x, - const std::vector<::std::vector> &y, - const std::vector<::std::vector> &z, - const std::map &keywords = {}) -{ - detail::_interpreter::get(); - - // using numpy arrays - PyObject *xarray = detail::get_2darray(x); - PyObject *yarray = detail::get_2darray(y); - PyObject *zarray = detail::get_2darray(z); - - // construct positional args - PyObject *args = PyTuple_New(3); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - PyTuple_SetItem(args, 2, zarray); - - // Build up the kw args. - PyObject *kwargs = PyDict_New(); - - PyObject *python_colormap_coolwarm = PyObject_GetAttrString( - detail::_interpreter::get().s_python_colormap, "coolwarm"); - - PyDict_SetItemString(kwargs, "cmap", python_colormap_coolwarm); - - for (std::map::const_iterator it = keywords.begin(); - it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); - } - - PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_contour, args, kwargs); - if (!res) - throw std::runtime_error("failed contour"); - - Py_DECREF(args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); -} - -template -void spy(const std::vector<::std::vector> &x, - const double markersize = -1, // -1 for default matplotlib size - const std::map &keywords = {}) -{ - detail::_interpreter::get(); - - PyObject *xarray = detail::get_2darray(x); - - PyObject *kwargs = PyDict_New(); - if (markersize != -1) { - PyDict_SetItemString(kwargs, "markersize", PyFloat_FromDouble(markersize)); - } - for (std::map::const_iterator it = keywords.begin(); - it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); - } - - PyObject *plot_args = PyTuple_New(1); - PyTuple_SetItem(plot_args, 0, xarray); - - PyObject *res = PyObject_Call( - detail::_interpreter::get().s_python_function_spy, plot_args, kwargs); - - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); -} -#endif // WITHOUT_NUMPY - -template -void plot3(const std::vector &x, - const std::vector &y, - const std::vector &z, - const std::map &keywords = - std::map(), - const long fig_number=0) -{ - detail::_interpreter::get(); - - // Same as with plot_surface: We lazily load the modules here the first time - // this function is called because I'm not sure that we can assume "matplotlib - // installed" implies "mpl_toolkits installed" on all platforms, and we don't - // want to require it for people who don't need 3d plots. - static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; - if (!mpl_toolkitsmod) { - detail::_interpreter::get(); - - PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits"); - PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d"); - if (!mpl_toolkits || !axis3d) { throw std::runtime_error("couldnt create string"); } - - mpl_toolkitsmod = PyImport_Import(mpl_toolkits); - Py_DECREF(mpl_toolkits); - if (!mpl_toolkitsmod) { throw std::runtime_error("Error loading module mpl_toolkits!"); } - - axis3dmod = PyImport_Import(axis3d); - Py_DECREF(axis3d); - if (!axis3dmod) { throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); } - } - - assert(x.size() == y.size()); - assert(y.size() == z.size()); - - PyObject *xarray = detail::get_array(x); - PyObject *yarray = detail::get_array(y); - PyObject *zarray = detail::get_array(z); - - // construct positional args - PyObject *args = PyTuple_New(3); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - PyTuple_SetItem(args, 2, zarray); - - // Build up the kw args. - PyObject *kwargs = PyDict_New(); - - for (std::map::const_iterator it = keywords.begin(); - it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); - } - - PyObject *fig_args = PyTuple_New(1); - PyObject* fig = nullptr; - PyTuple_SetItem(fig_args, 0, PyLong_FromLong(fig_number)); - PyObject *fig_exists = - PyObject_CallObject(detail::_interpreter::get().s_python_function_fignum_exists, fig_args); - if (!PyObject_IsTrue(fig_exists)) { - fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple); - } else { - fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - fig_args); - } - if (!fig) throw std::runtime_error("Call to figure() failed."); - - PyObject *gca_kwargs = PyDict_New(); - PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); - - PyObject *gca = PyObject_GetAttrString(fig, "gca"); - if (!gca) throw std::runtime_error("No gca"); - Py_INCREF(gca); - PyObject *axis = PyObject_Call( - gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); - - if (!axis) throw std::runtime_error("No axis"); - Py_INCREF(axis); - - Py_DECREF(gca); - Py_DECREF(gca_kwargs); - - PyObject *plot3 = PyObject_GetAttrString(axis, "plot"); - if (!plot3) throw std::runtime_error("No 3D line plot"); - Py_INCREF(plot3); - PyObject *res = PyObject_Call(plot3, args, kwargs); - if (!res) throw std::runtime_error("Failed 3D line plot"); - Py_DECREF(plot3); - - Py_DECREF(axis); - Py_DECREF(args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); -} - -template -bool stem(const std::vector &x, const std::vector &y, const std::map& keywords) -{ - assert(x.size() == y.size()); - - detail::_interpreter::get(); - - // using numpy arrays - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - // construct positional args - PyObject* args = PyTuple_New(2); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for (std::map::const_iterator it = - keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); - } - - PyObject* res = PyObject_Call( - detail::_interpreter::get().s_python_function_stem, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - if (res) - Py_DECREF(res); - - return res; -} - -template< typename Numeric > -bool fill(const std::vector& x, const std::vector& y, const std::map& keywords) -{ - assert(x.size() == y.size()); - - detail::_interpreter::get(); - - // using numpy arrays - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - // construct positional args - PyObject* args = PyTuple_New(2); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_fill, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - - if (res) Py_DECREF(res); - - return res; -} - -template< typename Numeric > -bool fill_between(const std::vector& x, const std::vector& y1, const std::vector& y2, const std::map& keywords) -{ - assert(x.size() == y1.size()); - assert(x.size() == y2.size()); - - detail::_interpreter::get(); - - // using numpy arrays - PyObject* xarray = detail::get_array(x); - PyObject* y1array = detail::get_array(y1); - PyObject* y2array = detail::get_array(y2); - - // construct positional args - PyObject* args = PyTuple_New(3); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, y1array); - PyTuple_SetItem(args, 2, y2array); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_fill_between, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - if(res) Py_DECREF(res); - - return res; -} - -template -bool arrow(Numeric x, Numeric y, Numeric end_x, Numeric end_y, const std::string& fc = "r", - const std::string ec = "k", Numeric head_length = 0.25, Numeric head_width = 0.1625) { - PyObject* obj_x = PyFloat_FromDouble(x); - PyObject* obj_y = PyFloat_FromDouble(y); - PyObject* obj_end_x = PyFloat_FromDouble(end_x); - PyObject* obj_end_y = PyFloat_FromDouble(end_y); - - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "fc", PyString_FromString(fc.c_str())); - PyDict_SetItemString(kwargs, "ec", PyString_FromString(ec.c_str())); - PyDict_SetItemString(kwargs, "head_width", PyFloat_FromDouble(head_width)); - PyDict_SetItemString(kwargs, "head_length", PyFloat_FromDouble(head_length)); - - PyObject* plot_args = PyTuple_New(4); - PyTuple_SetItem(plot_args, 0, obj_x); - PyTuple_SetItem(plot_args, 1, obj_y); - PyTuple_SetItem(plot_args, 2, obj_end_x); - PyTuple_SetItem(plot_args, 3, obj_end_y); - - PyObject* res = - PyObject_Call(detail::_interpreter::get().s_python_function_arrow, plot_args, kwargs); - - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if (res) - Py_DECREF(res); - - return res; -} - -template< typename Numeric> -bool hist(const std::vector& y, long bins=10,std::string color="b", - double alpha=1.0, bool cumulative=false) -{ - detail::_interpreter::get(); - - PyObject* yarray = detail::get_array(y); - - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins)); - PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str())); - PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha)); - PyDict_SetItemString(kwargs, "cumulative", cumulative ? Py_True : Py_False); - - PyObject* plot_args = PyTuple_New(1); - - PyTuple_SetItem(plot_args, 0, yarray); - - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs); - - - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if(res) Py_DECREF(res); - - return res; -} - -#ifndef WITHOUT_NUMPY -namespace detail { - -inline void imshow(void *ptr, const NPY_TYPES type, const int rows, const int columns, const int colors, const std::map &keywords, PyObject** out) -{ - assert(type == NPY_UINT8 || type == NPY_FLOAT); - assert(colors == 1 || colors == 3 || colors == 4); - - detail::_interpreter::get(); - - // construct args - npy_intp dims[3] = { rows, columns, colors }; - PyObject *args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyArray_SimpleNewFromData(colors == 1 ? 2 : 3, dims, type, ptr)); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } - - PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_imshow, args, kwargs); - Py_DECREF(args); - Py_DECREF(kwargs); - if (!res) - throw std::runtime_error("Call to imshow() failed"); - if (out) - *out = res; - else - Py_DECREF(res); -} - -} // namespace detail - -inline void imshow(const unsigned char *ptr, const int rows, const int columns, const int colors, const std::map &keywords = {}, PyObject** out = nullptr) -{ - detail::imshow((void *) ptr, NPY_UINT8, rows, columns, colors, keywords, out); -} - -inline void imshow(const float *ptr, const int rows, const int columns, const int colors, const std::map &keywords = {}, PyObject** out = nullptr) -{ - detail::imshow((void *) ptr, NPY_FLOAT, rows, columns, colors, keywords, out); -} - -#ifdef WITH_OPENCV -void imshow(const cv::Mat &image, const std::map &keywords = {}) -{ - // Convert underlying type of matrix, if needed - cv::Mat image2; - NPY_TYPES npy_type = NPY_UINT8; - switch (image.type() & CV_MAT_DEPTH_MASK) { - case CV_8U: - image2 = image; - break; - case CV_32F: - image2 = image; - npy_type = NPY_FLOAT; - break; - default: - image.convertTo(image2, CV_MAKETYPE(CV_8U, image.channels())); - } - - // If color image, convert from BGR to RGB - switch (image2.channels()) { - case 3: - cv::cvtColor(image2, image2, CV_BGR2RGB); - break; - case 4: - cv::cvtColor(image2, image2, CV_BGRA2RGBA); - } - - detail::imshow(image2.data, npy_type, image2.rows, image2.cols, image2.channels(), keywords); -} -#endif // WITH_OPENCV -#endif // WITHOUT_NUMPY - -template -bool scatter(const std::vector& x, - const std::vector& y, - const double s=1.0, // The marker size in points**2 - const std::map & keywords = {}) -{ - detail::_interpreter::get(); - - assert(x.size() == y.size()); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); - for (const auto& it : keywords) - { - PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); - } - - PyObject* plot_args = PyTuple_New(2); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_scatter, plot_args, kwargs); - - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if(res) Py_DECREF(res); - - return res; -} - -template - bool scatter_colored(const std::vector& x, - const std::vector& y, - const std::vector& colors, - const double s=1.0, // The marker size in points**2 - const std::map & keywords = {}) - { - detail::_interpreter::get(); - - assert(x.size() == y.size()); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - PyObject* colors_array = detail::get_array(colors); - - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s)); - PyDict_SetItemString(kwargs, "c", colors_array); - - for (const auto& it : keywords) - { - PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); - } - - PyObject* plot_args = PyTuple_New(2); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_scatter, plot_args, kwargs); - - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if(res) Py_DECREF(res); - - return res; - } - - -template -bool scatter(const std::vector& x, - const std::vector& y, - const std::vector& z, - const double s=1.0, // The marker size in points**2 - const std::map & keywords = {}, - const long fig_number=0) { - detail::_interpreter::get(); - - // Same as with plot_surface: We lazily load the modules here the first time - // this function is called because I'm not sure that we can assume "matplotlib - // installed" implies "mpl_toolkits installed" on all platforms, and we don't - // want to require it for people who don't need 3d plots. - static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; - if (!mpl_toolkitsmod) { - detail::_interpreter::get(); - - PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits"); - PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d"); - if (!mpl_toolkits || !axis3d) { throw std::runtime_error("couldnt create string"); } - - mpl_toolkitsmod = PyImport_Import(mpl_toolkits); - Py_DECREF(mpl_toolkits); - if (!mpl_toolkitsmod) { throw std::runtime_error("Error loading module mpl_toolkits!"); } - - axis3dmod = PyImport_Import(axis3d); - Py_DECREF(axis3d); - if (!axis3dmod) { throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); } - } - - assert(x.size() == y.size()); - assert(y.size() == z.size()); - - PyObject *xarray = detail::get_array(x); - PyObject *yarray = detail::get_array(y); - PyObject *zarray = detail::get_array(z); - - // construct positional args - PyObject *args = PyTuple_New(3); - PyTuple_SetItem(args, 0, xarray); - PyTuple_SetItem(args, 1, yarray); - PyTuple_SetItem(args, 2, zarray); - - // Build up the kw args. - PyObject *kwargs = PyDict_New(); - - for (std::map::const_iterator it = keywords.begin(); - it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); - } - PyObject *fig_args = PyTuple_New(1); - PyObject* fig = nullptr; - PyTuple_SetItem(fig_args, 0, PyLong_FromLong(fig_number)); - PyObject *fig_exists = - PyObject_CallObject(detail::_interpreter::get().s_python_function_fignum_exists, fig_args); - if (!PyObject_IsTrue(fig_exists)) { - fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple); - } else { - fig = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - fig_args); - } - Py_DECREF(fig_exists); - if (!fig) throw std::runtime_error("Call to figure() failed."); - - PyObject *gca_kwargs = PyDict_New(); - PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); - - PyObject *gca = PyObject_GetAttrString(fig, "gca"); - if (!gca) throw std::runtime_error("No gca"); - Py_INCREF(gca); - PyObject *axis = PyObject_Call( - gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); - - if (!axis) throw std::runtime_error("No axis"); - Py_INCREF(axis); - - Py_DECREF(gca); - Py_DECREF(gca_kwargs); - - PyObject *plot3 = PyObject_GetAttrString(axis, "scatter"); - if (!plot3) throw std::runtime_error("No 3D line plot"); - Py_INCREF(plot3); - PyObject *res = PyObject_Call(plot3, args, kwargs); - if (!res) throw std::runtime_error("Failed 3D line plot"); - Py_DECREF(plot3); - - Py_DECREF(axis); - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(fig); - if (res) Py_DECREF(res); - return res; - -} - -template -bool boxplot(const std::vector>& data, - const std::vector& labels = {}, - const std::map & keywords = {}) -{ - detail::_interpreter::get(); - - PyObject* listlist = detail::get_listlist(data); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, listlist); - - PyObject* kwargs = PyDict_New(); - - // kwargs needs the labels, if there are (the correct number of) labels - if (!labels.empty() && labels.size() == data.size()) { - PyDict_SetItemString(kwargs, "labels", detail::get_array(labels)); - } - - // take care of the remaining keywords - for (const auto& it : keywords) - { - PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); - } - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - - if(res) Py_DECREF(res); - - return res; -} - -template -bool boxplot(const std::vector& data, - const std::map & keywords = {}) -{ - detail::_interpreter::get(); - - PyObject* vector = detail::get_array(data); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, vector); - - PyObject* kwargs = PyDict_New(); - for (const auto& it : keywords) - { - PyDict_SetItemString(kwargs, it.first.c_str(), PyString_FromString(it.second.c_str())); - } - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_boxplot, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - - if(res) Py_DECREF(res); - - return res; -} - -template -bool bar(const std::vector & x, - const std::vector & y, - std::string ec = "black", - std::string ls = "-", - double lw = 1.0, - const std::map & keywords = {}) -{ - detail::_interpreter::get(); - - PyObject * xarray = detail::get_array(x); - PyObject * yarray = detail::get_array(y); - - PyObject * kwargs = PyDict_New(); - - PyDict_SetItemString(kwargs, "ec", PyString_FromString(ec.c_str())); - PyDict_SetItemString(kwargs, "ls", PyString_FromString(ls.c_str())); - PyDict_SetItemString(kwargs, "lw", PyFloat_FromDouble(lw)); - - for (std::map::const_iterator it = - keywords.begin(); - it != keywords.end(); - ++it) { - PyDict_SetItemString( - kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } - - PyObject * plot_args = PyTuple_New(2); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - - PyObject * res = PyObject_Call( - detail::_interpreter::get().s_python_function_bar, plot_args, kwargs); - - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); - - return res; -} - -template -bool bar(const std::vector & y, - std::string ec = "black", - std::string ls = "-", - double lw = 1.0, - const std::map & keywords = {}) -{ - using T = typename std::remove_reference::type::value_type; - - detail::_interpreter::get(); - - std::vector x; - for (std::size_t i = 0; i < y.size(); i++) { x.push_back(i); } - - return bar(x, y, ec, ls, lw, keywords); -} - - -template -bool barh(const std::vector &x, const std::vector &y, std::string ec = "black", std::string ls = "-", double lw = 1.0, const std::map &keywords = { }) { - PyObject *xarray = detail::get_array(x); - PyObject *yarray = detail::get_array(y); - - PyObject *kwargs = PyDict_New(); - - PyDict_SetItemString(kwargs, "ec", PyString_FromString(ec.c_str())); - PyDict_SetItemString(kwargs, "ls", PyString_FromString(ls.c_str())); - PyDict_SetItemString(kwargs, "lw", PyFloat_FromDouble(lw)); - - for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } - - PyObject *plot_args = PyTuple_New(2); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - - PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_barh, plot_args, kwargs); - - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); - - return res; -} - - -inline bool subplots_adjust(const std::map& keywords = {}) -{ - detail::_interpreter::get(); - - PyObject* kwargs = PyDict_New(); - for (std::map::const_iterator it = - keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyFloat_FromDouble(it->second)); - } - - - PyObject* plot_args = PyTuple_New(0); - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_subplots_adjust, plot_args, kwargs); - - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if(res) Py_DECREF(res); - - return res; -} - -template< typename Numeric> -bool named_hist(std::string label,const std::vector& y, long bins=10, std::string color="b", double alpha=1.0) -{ - detail::_interpreter::get(); - - PyObject* yarray = detail::get_array(y); - - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(label.c_str())); - PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins)); - PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str())); - PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha)); - - - PyObject* plot_args = PyTuple_New(1); - PyTuple_SetItem(plot_args, 0, yarray); - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs); - - Py_DECREF(plot_args); - Py_DECREF(kwargs); - if(res) Py_DECREF(res); - - return res; -} - -template -bool plot(const std::vector& x, const std::vector& y, const std::string& s = "") -{ - assert(x.size() == y.size()); - - detail::_interpreter::get(); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - PyObject* pystring = PyString_FromString(s.c_str()); - - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args); - - Py_DECREF(plot_args); - if(res) Py_DECREF(res); - - return res; -} - -template -bool contour(const std::vector& x, const std::vector& y, - const std::vector& z, - const std::map& keywords = {}) { - assert(x.size() == y.size() && x.size() == z.size()); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - PyObject* zarray = detail::get_array(z); - - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, zarray); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for (std::map::const_iterator it = keywords.begin(); - it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } - - PyObject* res = - PyObject_Call(detail::_interpreter::get().s_python_function_contour, plot_args, kwargs); - - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) - Py_DECREF(res); - - return res; -} - -template -bool quiver(const std::vector& x, const std::vector& y, const std::vector& u, const std::vector& w, const std::map& keywords = {}) -{ - assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size()); - - detail::_interpreter::get(); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - PyObject* uarray = detail::get_array(u); - PyObject* warray = detail::get_array(w); - - PyObject* plot_args = PyTuple_New(4); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, uarray); - PyTuple_SetItem(plot_args, 3, warray); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } - - PyObject* res = PyObject_Call( - detail::_interpreter::get().s_python_function_quiver, plot_args, kwargs); - - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) - Py_DECREF(res); - - return res; -} - -template -bool quiver(const std::vector& x, const std::vector& y, const std::vector& z, const std::vector& u, const std::vector& w, const std::vector& v, const std::map& keywords = {}) -{ - //set up 3d axes stuff - static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; - if (!mpl_toolkitsmod) { - detail::_interpreter::get(); - - PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits"); - PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d"); - if (!mpl_toolkits || !axis3d) { throw std::runtime_error("couldnt create string"); } - - mpl_toolkitsmod = PyImport_Import(mpl_toolkits); - Py_DECREF(mpl_toolkits); - if (!mpl_toolkitsmod) { throw std::runtime_error("Error loading module mpl_toolkits!"); } - - axis3dmod = PyImport_Import(axis3d); - Py_DECREF(axis3d); - if (!axis3dmod) { throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); } - } - - //assert sizes match up - assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size() && x.size() == z.size() && x.size() == v.size() && u.size() == v.size()); - - //set up parameters - detail::_interpreter::get(); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - PyObject* zarray = detail::get_array(z); - PyObject* uarray = detail::get_array(u); - PyObject* warray = detail::get_array(w); - PyObject* varray = detail::get_array(v); - - PyObject* plot_args = PyTuple_New(6); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, zarray); - PyTuple_SetItem(plot_args, 3, uarray); - PyTuple_SetItem(plot_args, 4, warray); - PyTuple_SetItem(plot_args, 5, varray); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } - - //get figure gca to enable 3d projection - PyObject *fig = - PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple); - if (!fig) throw std::runtime_error("Call to figure() failed."); - - PyObject *gca_kwargs = PyDict_New(); - PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d")); - - PyObject *gca = PyObject_GetAttrString(fig, "gca"); - if (!gca) throw std::runtime_error("No gca"); - Py_INCREF(gca); - PyObject *axis = PyObject_Call( - gca, detail::_interpreter::get().s_python_empty_tuple, gca_kwargs); - - if (!axis) throw std::runtime_error("No axis"); - Py_INCREF(axis); - Py_DECREF(gca); - Py_DECREF(gca_kwargs); - - //plot our boys bravely, plot them strongly, plot them with a wink and clap - PyObject *plot3 = PyObject_GetAttrString(axis, "quiver"); - if (!plot3) throw std::runtime_error("No 3D line plot"); - Py_INCREF(plot3); - PyObject* res = PyObject_Call( - plot3, plot_args, kwargs); - if (!res) throw std::runtime_error("Failed 3D plot"); - Py_DECREF(plot3); - Py_DECREF(axis); - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) - Py_DECREF(res); - - return res; -} - -template -bool stem(const std::vector& x, const std::vector& y, const std::string& s = "") -{ - assert(x.size() == y.size()); - - detail::_interpreter::get(); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - PyObject* pystring = PyString_FromString(s.c_str()); - - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); - - PyObject* res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_stem, plot_args); - - Py_DECREF(plot_args); - if (res) - Py_DECREF(res); - - return res; -} - -template -bool semilogx(const std::vector& x, const std::vector& y, const std::string& s = "") -{ - assert(x.size() == y.size()); - - detail::_interpreter::get(); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - PyObject* pystring = PyString_FromString(s.c_str()); - - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_semilogx, plot_args); - - Py_DECREF(plot_args); - if(res) Py_DECREF(res); - - return res; -} - -template -bool semilogy(const std::vector& x, const std::vector& y, const std::string& s = "") -{ - assert(x.size() == y.size()); - - detail::_interpreter::get(); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - PyObject* pystring = PyString_FromString(s.c_str()); - - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_semilogy, plot_args); - - Py_DECREF(plot_args); - if(res) Py_DECREF(res); - - return res; -} - -template -bool loglog(const std::vector& x, const std::vector& y, const std::string& s = "") -{ - assert(x.size() == y.size()); - - detail::_interpreter::get(); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - PyObject* pystring = PyString_FromString(s.c_str()); - - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_loglog, plot_args); - - Py_DECREF(plot_args); - if(res) Py_DECREF(res); - - return res; -} - -template -bool errorbar(const std::vector &x, const std::vector &y, const std::vector &yerr, const std::map &keywords = {}) -{ - assert(x.size() == y.size()); - - detail::_interpreter::get(); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - PyObject* yerrarray = detail::get_array(yerr); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); - } - - PyDict_SetItemString(kwargs, "yerr", yerrarray); - - PyObject *plot_args = PyTuple_New(2); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - - PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_errorbar, plot_args, kwargs); - - Py_DECREF(kwargs); - Py_DECREF(plot_args); - - if (res) - Py_DECREF(res); - else - throw std::runtime_error("Call to errorbar() failed."); - - return res; -} - -template -bool named_plot(const std::string& name, const std::vector& y, const std::string& format = "") -{ - detail::_interpreter::get(); - - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - - PyObject* yarray = detail::get_array(y); - - PyObject* pystring = PyString_FromString(format.c_str()); - - PyObject* plot_args = PyTuple_New(2); - - PyTuple_SetItem(plot_args, 0, yarray); - PyTuple_SetItem(plot_args, 1, pystring); - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); - - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); - - return res; -} - -template -bool named_plot(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ - detail::_interpreter::get(); - - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - PyObject* pystring = PyString_FromString(format.c_str()); - - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); - - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); - - return res; -} - -template -bool named_semilogx(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ - detail::_interpreter::get(); - - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - PyObject* pystring = PyString_FromString(format.c_str()); - - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogx, plot_args, kwargs); - - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); - - return res; -} - -template -bool named_semilogy(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ - detail::_interpreter::get(); - - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - PyObject* pystring = PyString_FromString(format.c_str()); - - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_semilogy, plot_args, kwargs); - - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); - - return res; -} - -template -bool named_loglog(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") -{ - detail::_interpreter::get(); - - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - PyObject* pystring = PyString_FromString(format.c_str()); - - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_loglog, plot_args, kwargs); - - Py_DECREF(kwargs); - Py_DECREF(plot_args); - if (res) Py_DECREF(res); - - return res; -} - -template -bool plot(const std::vector& y, const std::string& format = "") -{ - std::vector x(y.size()); - for(size_t i=0; i -bool plot(const std::vector& y, const std::map& keywords) -{ - std::vector x(y.size()); - for(size_t i=0; i -bool stem(const std::vector& y, const std::string& format = "") -{ - std::vector x(y.size()); - for (size_t i = 0; i < x.size(); ++i) x.at(i) = i; - return stem(x, y, format); -} - -template -void text(Numeric x, Numeric y, const std::string& s = "") -{ - detail::_interpreter::get(); - - PyObject* args = PyTuple_New(3); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(x)); - PyTuple_SetItem(args, 1, PyFloat_FromDouble(y)); - PyTuple_SetItem(args, 2, PyString_FromString(s.c_str())); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_text, args); - if(!res) throw std::runtime_error("Call to text() failed."); - - Py_DECREF(args); - Py_DECREF(res); -} - -inline void colorbar(PyObject* mappable = NULL, const std::map& keywords = {}) -{ - if (mappable == NULL) - throw std::runtime_error("Must call colorbar with PyObject* returned from an image, contour, surface, etc."); - - detail::_interpreter::get(); - - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, mappable); - - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyFloat_FromDouble(it->second)); - } - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_colorbar, args, kwargs); - if(!res) throw std::runtime_error("Call to colorbar() failed."); - - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(res); -} - - -inline long figure(long number = -1) -{ - detail::_interpreter::get(); - - PyObject *res; - if (number == -1) - res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, detail::_interpreter::get().s_python_empty_tuple); - else { - assert(number > 0); - - // Make sure interpreter is initialised - detail::_interpreter::get(); - - PyObject *args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyLong_FromLong(number)); - res = PyObject_CallObject(detail::_interpreter::get().s_python_function_figure, args); - Py_DECREF(args); - } - - if(!res) throw std::runtime_error("Call to figure() failed."); - - PyObject* num = PyObject_GetAttrString(res, "number"); - if (!num) throw std::runtime_error("Could not get number attribute of figure object"); - const long figureNumber = PyLong_AsLong(num); - - Py_DECREF(num); - Py_DECREF(res); - - return figureNumber; -} - -inline bool fignum_exists(long number) -{ - detail::_interpreter::get(); - - PyObject *args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyLong_FromLong(number)); - PyObject *res = PyObject_CallObject(detail::_interpreter::get().s_python_function_fignum_exists, args); - if(!res) throw std::runtime_error("Call to fignum_exists() failed."); - - bool ret = PyObject_IsTrue(res); - Py_DECREF(res); - Py_DECREF(args); - - return ret; -} - -inline void figure_size(size_t w, size_t h) -{ - detail::_interpreter::get(); - - const size_t dpi = 100; - PyObject* size = PyTuple_New(2); - PyTuple_SetItem(size, 0, PyFloat_FromDouble((double)w / dpi)); - PyTuple_SetItem(size, 1, PyFloat_FromDouble((double)h / dpi)); - - PyObject* kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "figsize", size); - PyDict_SetItemString(kwargs, "dpi", PyLong_FromSize_t(dpi)); - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_figure, - detail::_interpreter::get().s_python_empty_tuple, kwargs); - - Py_DECREF(kwargs); - - if(!res) throw std::runtime_error("Call to figure_size() failed."); - Py_DECREF(res); -} - -inline void legend() -{ - detail::_interpreter::get(); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_legend, detail::_interpreter::get().s_python_empty_tuple); - if(!res) throw std::runtime_error("Call to legend() failed."); - - Py_DECREF(res); -} - -inline void legend(const std::map& keywords) -{ - detail::_interpreter::get(); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); - } - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_legend, detail::_interpreter::get().s_python_empty_tuple, kwargs); - if(!res) throw std::runtime_error("Call to legend() failed."); - - Py_DECREF(kwargs); - Py_DECREF(res); -} - -template -inline void set_aspect(Numeric ratio) -{ - detail::_interpreter::get(); - - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(ratio)); - PyObject* kwargs = PyDict_New(); - - PyObject *ax = - PyObject_CallObject(detail::_interpreter::get().s_python_function_gca, - detail::_interpreter::get().s_python_empty_tuple); - if (!ax) throw std::runtime_error("Call to gca() failed."); - Py_INCREF(ax); - - PyObject *set_aspect = PyObject_GetAttrString(ax, "set_aspect"); - if (!set_aspect) throw std::runtime_error("Attribute set_aspect not found."); - Py_INCREF(set_aspect); - - PyObject *res = PyObject_Call(set_aspect, args, kwargs); - if (!res) throw std::runtime_error("Call to set_aspect() failed."); - Py_DECREF(set_aspect); - - Py_DECREF(ax); - Py_DECREF(args); - Py_DECREF(kwargs); -} - -inline void set_aspect_equal() -{ - // expect ratio == "equal". Leaving error handling to matplotlib. - detail::_interpreter::get(); - - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyString_FromString("equal")); - PyObject* kwargs = PyDict_New(); - - PyObject *ax = - PyObject_CallObject(detail::_interpreter::get().s_python_function_gca, - detail::_interpreter::get().s_python_empty_tuple); - if (!ax) throw std::runtime_error("Call to gca() failed."); - Py_INCREF(ax); - - PyObject *set_aspect = PyObject_GetAttrString(ax, "set_aspect"); - if (!set_aspect) throw std::runtime_error("Attribute set_aspect not found."); - Py_INCREF(set_aspect); - - PyObject *res = PyObject_Call(set_aspect, args, kwargs); - if (!res) throw std::runtime_error("Call to set_aspect() failed."); - Py_DECREF(set_aspect); - - Py_DECREF(ax); - Py_DECREF(args); - Py_DECREF(kwargs); -} - -template -void ylim(Numeric left, Numeric right) -{ - detail::_interpreter::get(); - - PyObject* list = PyList_New(2); - PyList_SetItem(list, 0, PyFloat_FromDouble(left)); - PyList_SetItem(list, 1, PyFloat_FromDouble(right)); - - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, list); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); - if(!res) throw std::runtime_error("Call to ylim() failed."); - - Py_DECREF(args); - Py_DECREF(res); -} - -template -void xlim(Numeric left, Numeric right) -{ - detail::_interpreter::get(); - - PyObject* list = PyList_New(2); - PyList_SetItem(list, 0, PyFloat_FromDouble(left)); - PyList_SetItem(list, 1, PyFloat_FromDouble(right)); - - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, list); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); - if(!res) throw std::runtime_error("Call to xlim() failed."); - - Py_DECREF(args); - Py_DECREF(res); -} - - -inline std::array xlim() -{ - PyObject* args = PyTuple_New(0); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); - - if(!res) throw std::runtime_error("Call to xlim() failed."); - - Py_DECREF(res); - - PyObject* left = PyTuple_GetItem(res,0); - PyObject* right = PyTuple_GetItem(res,1); - return { PyFloat_AsDouble(left), PyFloat_AsDouble(right) }; -} - - -inline std::array ylim() -{ - PyObject* args = PyTuple_New(0); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); - - if(!res) throw std::runtime_error("Call to ylim() failed."); - - Py_DECREF(res); - - PyObject* left = PyTuple_GetItem(res,0); - PyObject* right = PyTuple_GetItem(res,1); - return { PyFloat_AsDouble(left), PyFloat_AsDouble(right) }; -} - -template -inline void xticks(const std::vector &ticks, const std::vector &labels = {}, const std::map& keywords = {}) -{ - assert(labels.size() == 0 || ticks.size() == labels.size()); - - detail::_interpreter::get(); - - // using numpy array - PyObject* ticksarray = detail::get_array(ticks); - - PyObject* args; - if(labels.size() == 0) { - // construct positional args - args = PyTuple_New(1); - PyTuple_SetItem(args, 0, ticksarray); - } else { - // make tuple of tick labels - PyObject* labelstuple = PyTuple_New(labels.size()); - for (size_t i = 0; i < labels.size(); i++) - PyTuple_SetItem(labelstuple, i, PyUnicode_FromString(labels[i].c_str())); - - // construct positional args - args = PyTuple_New(2); - PyTuple_SetItem(args, 0, ticksarray); - PyTuple_SetItem(args, 1, labelstuple); - } - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); - } - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_xticks, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - if(!res) throw std::runtime_error("Call to xticks() failed"); - - Py_DECREF(res); -} - -template -inline void xticks(const std::vector &ticks, const std::map& keywords) -{ - xticks(ticks, {}, keywords); -} - -template -inline void yticks(const std::vector &ticks, const std::vector &labels = {}, const std::map& keywords = {}) -{ - assert(labels.size() == 0 || ticks.size() == labels.size()); - - detail::_interpreter::get(); - - // using numpy array - PyObject* ticksarray = detail::get_array(ticks); - - PyObject* args; - if(labels.size() == 0) { - // construct positional args - args = PyTuple_New(1); - PyTuple_SetItem(args, 0, ticksarray); - } else { - // make tuple of tick labels - PyObject* labelstuple = PyTuple_New(labels.size()); - for (size_t i = 0; i < labels.size(); i++) - PyTuple_SetItem(labelstuple, i, PyUnicode_FromString(labels[i].c_str())); - - // construct positional args - args = PyTuple_New(2); - PyTuple_SetItem(args, 0, ticksarray); - PyTuple_SetItem(args, 1, labelstuple); - } - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); - } - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_yticks, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - if(!res) throw std::runtime_error("Call to yticks() failed"); - - Py_DECREF(res); -} - -template -inline void yticks(const std::vector &ticks, const std::map& keywords) -{ - yticks(ticks, {}, keywords); -} - -template inline void margins(Numeric margin) -{ - // construct positional args - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(margin)); - - PyObject* res = - PyObject_CallObject(detail::_interpreter::get().s_python_function_margins, args); - if (!res) - throw std::runtime_error("Call to margins() failed."); - - Py_DECREF(args); - Py_DECREF(res); -} - -template inline void margins(Numeric margin_x, Numeric margin_y) -{ - // construct positional args - PyObject* args = PyTuple_New(2); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(margin_x)); - PyTuple_SetItem(args, 1, PyFloat_FromDouble(margin_y)); - - PyObject* res = - PyObject_CallObject(detail::_interpreter::get().s_python_function_margins, args); - if (!res) - throw std::runtime_error("Call to margins() failed."); - - Py_DECREF(args); - Py_DECREF(res); -} - - -inline void tick_params(const std::map& keywords, const std::string axis = "both") -{ - detail::_interpreter::get(); - - // construct positional args - PyObject* args; - args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyString_FromString(axis.c_str())); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for (std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); - } - - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_tick_params, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - if (!res) throw std::runtime_error("Call to tick_params() failed"); - - Py_DECREF(res); -} - inline void subplot(long nrows, long ncols, long plot_number) -{ - detail::_interpreter::get(); - - // construct positional args - PyObject* args = PyTuple_New(3); - PyTuple_SetItem(args, 0, PyLong_FromLong(nrows)); - PyTuple_SetItem(args, 1, PyLong_FromLong(ncols)); - PyTuple_SetItem(args, 2, PyLong_FromLong(plot_number)); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args); - if(!res) throw std::runtime_error("Call to subplot() failed."); - - Py_DECREF(args); - Py_DECREF(res); -} - - - - -inline void subplot2grid(long nrows, long ncols, long rowid=0, long colid=0, long rowspan=1, long colspan=1) -{ - detail::_interpreter::get(); - - PyObject* shape = PyTuple_New(2); - PyTuple_SetItem(shape, 0, PyLong_FromLong(nrows)); - PyTuple_SetItem(shape, 1, PyLong_FromLong(ncols)); - - PyObject* loc = PyTuple_New(2); - PyTuple_SetItem(loc, 0, PyLong_FromLong(rowid)); - PyTuple_SetItem(loc, 1, PyLong_FromLong(colid)); - - PyObject* args = PyTuple_New(4); - PyTuple_SetItem(args, 0, shape); - PyTuple_SetItem(args, 1, loc); - PyTuple_SetItem(args, 2, PyLong_FromLong(rowspan)); - PyTuple_SetItem(args, 3, PyLong_FromLong(colspan)); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot2grid, args); - if(!res) throw std::runtime_error("Call to subplot2grid() failed."); - - Py_DECREF(shape); - Py_DECREF(loc); - Py_DECREF(args); - Py_DECREF(res); -} - -inline void title(const std::string &titlestr, const std::map &keywords = {}) -{ - detail::_interpreter::get(); - - PyObject* pytitlestr = PyString_FromString(titlestr.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pytitlestr); - - PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_title, args, kwargs); - if(!res) throw std::runtime_error("Call to title() failed."); - - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(res); -} - -inline void suptitle(const std::string &suptitlestr, const std::map &keywords = {}) -{ - detail::_interpreter::get(); - - PyObject* pysuptitlestr = PyString_FromString(suptitlestr.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pysuptitlestr); - - PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_suptitle, args, kwargs); - if(!res) throw std::runtime_error("Call to suptitle() failed."); - - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(res); -} - -inline void axis(const std::string &axisstr) -{ - detail::_interpreter::get(); - - PyObject* str = PyString_FromString(axisstr.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, str); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args); - if(!res) throw std::runtime_error("Call to title() failed."); - - Py_DECREF(args); - Py_DECREF(res); -} - -inline void axhline(double y, double xmin = 0., double xmax = 1., const std::map& keywords = std::map()) -{ - detail::_interpreter::get(); - - // construct positional args - PyObject* args = PyTuple_New(3); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(y)); - PyTuple_SetItem(args, 1, PyFloat_FromDouble(xmin)); - PyTuple_SetItem(args, 2, PyFloat_FromDouble(xmax)); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); - } - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_axhline, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - - if(res) Py_DECREF(res); -} - -inline void axvline(double x, double ymin = 0., double ymax = 1., const std::map& keywords = std::map()) -{ - detail::_interpreter::get(); - - // construct positional args - PyObject* args = PyTuple_New(3); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(x)); - PyTuple_SetItem(args, 1, PyFloat_FromDouble(ymin)); - PyTuple_SetItem(args, 2, PyFloat_FromDouble(ymax)); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); - } - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_axvline, args, kwargs); - - Py_DECREF(args); - Py_DECREF(kwargs); - - if(res) Py_DECREF(res); -} - -inline void axvspan(double xmin, double xmax, double ymin = 0., double ymax = 1., const std::map& keywords = std::map()) -{ - // construct positional args - PyObject* args = PyTuple_New(4); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(xmin)); - PyTuple_SetItem(args, 1, PyFloat_FromDouble(xmax)); - PyTuple_SetItem(args, 2, PyFloat_FromDouble(ymin)); - PyTuple_SetItem(args, 3, PyFloat_FromDouble(ymax)); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - if (it->first == "linewidth" || it->first == "alpha") { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyFloat_FromDouble(std::stod(it->second))); - } else { - PyDict_SetItemString(kwargs, it->first.c_str(), - PyString_FromString(it->second.c_str())); - } - } - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_axvspan, args, kwargs); - Py_DECREF(args); - Py_DECREF(kwargs); - - if(res) Py_DECREF(res); -} - -inline void xlabel(const std::string &str, const std::map &keywords = {}) -{ - detail::_interpreter::get(); - - PyObject* pystr = PyString_FromString(str.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pystr); - - PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_xlabel, args, kwargs); - if(!res) throw std::runtime_error("Call to xlabel() failed."); - - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(res); -} - -inline void ylabel(const std::string &str, const std::map& keywords = {}) -{ - detail::_interpreter::get(); - - PyObject* pystr = PyString_FromString(str.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pystr); - - PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_ylabel, args, kwargs); - if(!res) throw std::runtime_error("Call to ylabel() failed."); - - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(res); -} - -inline void set_zlabel(const std::string &str, const std::map& keywords = {}) -{ - detail::_interpreter::get(); - - // Same as with plot_surface: We lazily load the modules here the first time - // this function is called because I'm not sure that we can assume "matplotlib - // installed" implies "mpl_toolkits installed" on all platforms, and we don't - // want to require it for people who don't need 3d plots. - static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr; - if (!mpl_toolkitsmod) { - PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits"); - PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d"); - if (!mpl_toolkits || !axis3d) { throw std::runtime_error("couldnt create string"); } - - mpl_toolkitsmod = PyImport_Import(mpl_toolkits); - Py_DECREF(mpl_toolkits); - if (!mpl_toolkitsmod) { throw std::runtime_error("Error loading module mpl_toolkits!"); } - - axis3dmod = PyImport_Import(axis3d); - Py_DECREF(axis3d); - if (!axis3dmod) { throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); } - } - - PyObject* pystr = PyString_FromString(str.c_str()); - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pystr); - - PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } - - PyObject *ax = - PyObject_CallObject(detail::_interpreter::get().s_python_function_gca, - detail::_interpreter::get().s_python_empty_tuple); - if (!ax) throw std::runtime_error("Call to gca() failed."); - Py_INCREF(ax); - - PyObject *zlabel = PyObject_GetAttrString(ax, "set_zlabel"); - if (!zlabel) throw std::runtime_error("Attribute set_zlabel not found."); - Py_INCREF(zlabel); - - PyObject *res = PyObject_Call(zlabel, args, kwargs); - if (!res) throw std::runtime_error("Call to set_zlabel() failed."); - Py_DECREF(zlabel); - - Py_DECREF(ax); - Py_DECREF(args); - Py_DECREF(kwargs); - if (res) Py_DECREF(res); -} - -inline void grid(bool flag) -{ - detail::_interpreter::get(); - - PyObject* pyflag = flag ? Py_True : Py_False; - Py_INCREF(pyflag); - - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pyflag); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args); - if(!res) throw std::runtime_error("Call to grid() failed."); - - Py_DECREF(args); - Py_DECREF(res); -} - -inline void show(const bool block = true) -{ - detail::_interpreter::get(); - - PyObject* res; - if(block) - { - res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_show, - detail::_interpreter::get().s_python_empty_tuple); - } - else - { - PyObject *kwargs = PyDict_New(); - PyDict_SetItemString(kwargs, "block", Py_False); - res = PyObject_Call( detail::_interpreter::get().s_python_function_show, detail::_interpreter::get().s_python_empty_tuple, kwargs); - Py_DECREF(kwargs); - } - - - if (!res) throw std::runtime_error("Call to show() failed."); - - Py_DECREF(res); -} - -inline void close() -{ - detail::_interpreter::get(); - - PyObject* res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_close, - detail::_interpreter::get().s_python_empty_tuple); - - if (!res) throw std::runtime_error("Call to close() failed."); - - Py_DECREF(res); -} - -inline void xkcd() { - detail::_interpreter::get(); - - PyObject* res; - PyObject *kwargs = PyDict_New(); - - res = PyObject_Call(detail::_interpreter::get().s_python_function_xkcd, - detail::_interpreter::get().s_python_empty_tuple, kwargs); - - Py_DECREF(kwargs); - - if (!res) - throw std::runtime_error("Call to show() failed."); - - Py_DECREF(res); -} - -inline void draw() -{ - detail::_interpreter::get(); - - PyObject* res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_draw, - detail::_interpreter::get().s_python_empty_tuple); - - if (!res) throw std::runtime_error("Call to draw() failed."); - - Py_DECREF(res); -} - -template -inline void pause(Numeric interval) -{ - detail::_interpreter::get(); - - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(interval)); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_pause, args); - if(!res) throw std::runtime_error("Call to pause() failed."); - - Py_DECREF(args); - Py_DECREF(res); -} - -inline void save(const std::string& filename, const int dpi=0) -{ - detail::_interpreter::get(); - - PyObject* pyfilename = PyString_FromString(filename.c_str()); - - PyObject* args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pyfilename); - - PyObject* kwargs = PyDict_New(); - - if(dpi > 0) - { - PyDict_SetItemString(kwargs, "dpi", PyLong_FromLong(dpi)); - } - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_save, args, kwargs); - if (!res) throw std::runtime_error("Call to save() failed."); - - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(res); -} - -inline void rcparams(const std::map& keywords = {}) { - detail::_interpreter::get(); - PyObject* args = PyTuple_New(0); - PyObject* kwargs = PyDict_New(); - for (auto it = keywords.begin(); it != keywords.end(); ++it) { - if ("text.usetex" == it->first) - PyDict_SetItemString(kwargs, it->first.c_str(), PyLong_FromLong(std::stoi(it->second.c_str()))); - else PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); - } - - PyObject * update = PyObject_GetAttrString(detail::_interpreter::get().s_python_function_rcparams, "update"); - PyObject * res = PyObject_Call(update, args, kwargs); - if(!res) throw std::runtime_error("Call to rcParams.update() failed."); - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(update); - Py_DECREF(res); -} - -inline void clf() { - detail::_interpreter::get(); - - PyObject *res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_clf, - detail::_interpreter::get().s_python_empty_tuple); - - if (!res) throw std::runtime_error("Call to clf() failed."); - - Py_DECREF(res); -} - -inline void cla() { - detail::_interpreter::get(); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_cla, - detail::_interpreter::get().s_python_empty_tuple); - - if (!res) - throw std::runtime_error("Call to cla() failed."); - - Py_DECREF(res); -} - -inline void ion() { - detail::_interpreter::get(); - - PyObject *res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_ion, - detail::_interpreter::get().s_python_empty_tuple); - - if (!res) throw std::runtime_error("Call to ion() failed."); - - Py_DECREF(res); -} - -inline std::vector> ginput(const int numClicks = 1, const std::map& keywords = {}) -{ - detail::_interpreter::get(); - - PyObject *args = PyTuple_New(1); - PyTuple_SetItem(args, 0, PyLong_FromLong(numClicks)); - - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); - } - - PyObject* res = PyObject_Call( - detail::_interpreter::get().s_python_function_ginput, args, kwargs); - - Py_DECREF(kwargs); - Py_DECREF(args); - if (!res) throw std::runtime_error("Call to ginput() failed."); - - const size_t len = PyList_Size(res); - std::vector> out; - out.reserve(len); - for (size_t i = 0; i < len; i++) { - PyObject *current = PyList_GetItem(res, i); - std::array position; - position[0] = PyFloat_AsDouble(PyTuple_GetItem(current, 0)); - position[1] = PyFloat_AsDouble(PyTuple_GetItem(current, 1)); - out.push_back(position); - } - Py_DECREF(res); - - return out; -} - -// Actually, is there any reason not to call this automatically for every plot? -inline void tight_layout() { - detail::_interpreter::get(); - - PyObject *res = PyObject_CallObject( - detail::_interpreter::get().s_python_function_tight_layout, - detail::_interpreter::get().s_python_empty_tuple); - - if (!res) throw std::runtime_error("Call to tight_layout() failed."); - - Py_DECREF(res); -} - -// Support for variadic plot() and initializer lists: - -namespace detail { - -template -using is_function = typename std::is_function>>::type; - -template -struct is_callable_impl; - -template -struct is_callable_impl -{ - typedef is_function type; -}; // a non-object is callable iff it is a function - -template -struct is_callable_impl -{ - struct Fallback { void operator()(); }; - struct Derived : T, Fallback { }; - - template struct Check; - - template - static std::true_type test( ... ); // use a variadic function to make sure (1) it accepts everything and (2) its always the worst match - - template - static std::false_type test( Check* ); - -public: - typedef decltype(test(nullptr)) type; - typedef decltype(&Fallback::operator()) dtype; - static constexpr bool value = type::value; -}; // an object is callable iff it defines operator() - -template -struct is_callable -{ - // dispatch to is_callable_impl or is_callable_impl depending on whether T is of class type or not - typedef typename is_callable_impl::value, T>::type type; -}; - -template -struct plot_impl { }; - -template<> -struct plot_impl -{ - template - bool operator()(const IterableX& x, const IterableY& y, const std::string& format) - { - detail::_interpreter::get(); - - // 2-phase lookup for distance, begin, end - using std::distance; - using std::begin; - using std::end; - - auto xs = distance(begin(x), end(x)); - auto ys = distance(begin(y), end(y)); - assert(xs == ys && "x and y data must have the same number of elements!"); - - PyObject* xlist = PyList_New(xs); - PyObject* ylist = PyList_New(ys); - PyObject* pystring = PyString_FromString(format.c_str()); - - auto itx = begin(x), ity = begin(y); - for(size_t i = 0; i < xs; ++i) { - PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++)); - PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++)); - } - - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xlist); - PyTuple_SetItem(plot_args, 1, ylist); - PyTuple_SetItem(plot_args, 2, pystring); - - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args); - - Py_DECREF(plot_args); - if(res) Py_DECREF(res); - - return res; - } -}; - -template<> -struct plot_impl -{ - template - bool operator()(const Iterable& ticks, const Callable& f, const std::string& format) - { - if(begin(ticks) == end(ticks)) return true; - - // We could use additional meta-programming to deduce the correct element type of y, - // but all values have to be convertible to double anyways - std::vector y; - for(auto x : ticks) y.push_back(f(x)); - return plot_impl()(ticks,y,format); - } -}; - -} // end namespace detail - -// recursion stop for the above -template -bool plot() { return true; } - -template -bool plot(const A& a, const B& b, const std::string& format, Args... args) -{ - return detail::plot_impl::type>()(a,b,format) && plot(args...); -} - -/* - * This group of plot() functions is needed to support initializer lists, i.e. calling - * plot( {1,2,3,4} ) - */ -inline bool plot(const std::vector& x, const std::vector& y, const std::string& format = "") { - return plot(x,y,format); -} - -inline bool plot(const std::vector& y, const std::string& format = "") { - return plot(y,format); -} - -inline bool plot(const std::vector& x, const std::vector& y, const std::map& keywords) { - return plot(x,y,keywords); -} - -/* - * This class allows dynamic plots, ie changing the plotted data without clearing and re-plotting - */ -class Plot -{ -public: - // default initialization with plot label, some data and format - template - Plot(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") { - detail::_interpreter::get(); - - assert(x.size() == y.size()); - - PyObject* kwargs = PyDict_New(); - if(name != "") - PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); - - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - PyObject* pystring = PyString_FromString(format.c_str()); - - PyObject* plot_args = PyTuple_New(3); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - PyTuple_SetItem(plot_args, 2, pystring); - - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); - - Py_DECREF(kwargs); - Py_DECREF(plot_args); - - if(res) - { - line= PyList_GetItem(res, 0); - - if(line) - set_data_fct = PyObject_GetAttrString(line,"set_data"); - else - Py_DECREF(line); - Py_DECREF(res); - } - } - - // shorter initialization with name or format only - // basically calls line, = plot([], []) - Plot(const std::string& name = "", const std::string& format = "") - : Plot(name, std::vector(), std::vector(), format) {} - - template - bool update(const std::vector& x, const std::vector& y) { - assert(x.size() == y.size()); - if(set_data_fct) - { - PyObject* xarray = detail::get_array(x); - PyObject* yarray = detail::get_array(y); - - PyObject* plot_args = PyTuple_New(2); - PyTuple_SetItem(plot_args, 0, xarray); - PyTuple_SetItem(plot_args, 1, yarray); - - PyObject* res = PyObject_CallObject(set_data_fct, plot_args); - if (res) Py_DECREF(res); - return res; - } - return false; - } - - // clears the plot but keep it available - bool clear() { - return update(std::vector(), std::vector()); - } - - // definitely remove this line - void remove() { - if(line) - { - auto remove_fct = PyObject_GetAttrString(line,"remove"); - PyObject* args = PyTuple_New(0); - PyObject* res = PyObject_CallObject(remove_fct, args); - if (res) Py_DECREF(res); - } - decref(); - } - - ~Plot() { - decref(); - } -private: - - void decref() { - if(line) - Py_DECREF(line); - if(set_data_fct) - Py_DECREF(set_data_fct); - } - - - PyObject* line = nullptr; - PyObject* set_data_fct = nullptr; -}; - -} // end namespace matplotlibcpp \ No newline at end of file diff --git a/cmvr-es/devices/README.md b/cmvr-es/devices/README.md index f7175729..3668f6b9 100644 --- a/cmvr-es/devices/README.md +++ b/cmvr-es/devices/README.md @@ -334,19 +334,17 @@ MediaSourceManager Subscription 同样是单消费者对象,不同协议或客 无硬件参考测试: - [`camera/hikvision_camera/tests/hikvision_camera_callback_test.cpp`](camera/hikvision_camera/tests/hikvision_camera_callback_test.cpp) -- [`../manager/media_source_manager/tests/media_source_manager_test.cpp`](../manager/media_source_manager/tests/media_source_manager_test.cpp) ```bash cmake -S . -B build \ -DCMVR_ARCH=x86 \ - -DBUILD_TESTING=ON \ - -DCMVR_MEDIA_SOURCE_MANAGER_BUILD_TESTS=ON + -DBUILD_TESTING=ON cmake --build build -j"$(nproc)" ctest \ --test-dir build \ - -R 'hikvision_camera_callback_test|media_source_manager_test' \ + -R '^hikvision_camera_callback_test$' \ --output-on-failure ``` diff --git a/cmvr-es/devices/agv/seer_robokit/CMakeLists.txt b/cmvr-es/devices/agv/seer_robokit/CMakeLists.txt index 35ce8bad..2dd0307f 100644 --- a/cmvr-es/devices/agv/seer_robokit/CMakeLists.txt +++ b/cmvr-es/devices/agv/seer_robokit/CMakeLists.txt @@ -27,31 +27,3 @@ target_link_libraries(seer_robokit_agv add_library(cmvr_es::device::seer_robokit_agv ALIAS seer_robokit_agv) install(TARGETS seer_robokit_agv LIBRARY DESTINATION lib) - -if(BUILD_TESTING) - add_executable(seer_robokit_control_authority_test - tests/seer_robokit_control_authority_test.cpp - ) - target_link_libraries(seer_robokit_control_authority_test - PRIVATE - cmvr_es::device::seer_robokit_agv - gtest - gtest_main - pthread - ) - add_test( - NAME seer_robokit_control_authority_test - COMMAND seer_robokit_control_authority_test - ) - set(_seer_robokit_control_authority_test_environment - "LD_LIBRARY_PATH=${CMVR_TEST_EXTERNAL_LIBRARY_PATH}" - ) - if(CMVR_TEST_SYSTEM_LIBSTDCXX) - list(APPEND _seer_robokit_control_authority_test_environment - "LD_PRELOAD=${CMVR_TEST_SYSTEM_LIBSTDCXX}") - endif() - set_tests_properties(seer_robokit_control_authority_test PROPERTIES - TIMEOUT 180 - ENVIRONMENT "${_seer_robokit_control_authority_test_environment}" - ) -endif() diff --git a/cmvr-es/devices/agv/seer_robokit/README.md b/cmvr-es/devices/agv/seer_robokit/README.md index 3cb6d77d..dc20dfd1 100644 --- a/cmvr-es/devices/agv/seer_robokit/README.md +++ b/cmvr-es/devices/agv/seer_robokit/README.md @@ -35,8 +35,6 @@ - 阻塞等待与停车确认: [`src/seer_robokit_navigation_wait.cpp`](src/seer_robokit_navigation_wait.cpp) - 地图和建图:[`src/seer_robokit_map.cpp`](src/seer_robokit_map.cpp) -- 假控制器测试: - [`tests/seer_robokit_control_authority_test.cpp`](tests/seer_robokit_control_authority_test.cpp) - 设备配置: [`../../../config/devices/agv/seer_robokit.pb.txt`](../../../config/devices/agv/seer_robokit.pb.txt) - DeviceManager 配置: @@ -375,21 +373,3 @@ unknown,调用方不能自动重发运动命令,应先查询状态并取消 验证后才能据此联动机械臂。异步成功更不代表 PGV 调整完成。 - 地图切换、地图上传和开始建图会改变控制器状态,也会先抢占控制权;不要和 现场调度系统并行操作。 -- 本目录的假控制器测试验证软件协议、错误路径和并发逻辑,不代表真实 SEER Robokit、 - 底盘、PGV、地图或安全链已经验收。 - -## 测试 - -```bash -cmake --build build \ - --target seer_robokit_control_authority_test grpc_agv_service_test \ - -j2 - -ctest --test-dir build \ - -R '^(seer_robokit_control_authority_test|grpc_agv_service_test)$' \ - --output-on-failure -``` - -`seer_robokit_control_authority_test` 使用本机回环 TCP 假控制器,需要允许本地 -bind/listen。受限沙箱若禁止创建 socket,只能证明编译通过,不能把未执行的 -fake-controller 场景报告为测试通过。测试过程不会连接真实 AGV。 diff --git a/cmvr-es/devices/agv/seer_robokit/tests/seer_robokit_control_authority_test.cpp b/cmvr-es/devices/agv/seer_robokit/tests/seer_robokit_control_authority_test.cpp deleted file mode 100644 index 9198d90f..00000000 --- a/cmvr-es/devices/agv/seer_robokit/tests/seer_robokit_control_authority_test.cpp +++ /dev/null @@ -1,5567 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "seer_robokit_agv.h" - -namespace cmvr::device { - -class SeerRobokitAgvTestPeer { -public: - static void installSockets( - SeerRobokitAgv& agv, - const int status, - const int control, - const int navigation, - const int config, - const int other) - { - agv.sock_status_ = status; - agv.sock_control_ = control; - agv.sock_navigation_ = navigation; - agv.sock_config_ = config; - agv.sock_other_ = other; - } - - static void cacheRuntimeState(SeerRobokitAgv& agv, const Json::Value& payload) - { - agv.updateCachedRuntimeState_(payload); - } - - static void setAdapterError(SeerRobokitAgv& agv, std::string error) - { - std::lock_guard lock(agv.mutex_); - agv.last_error_ = std::move(error); - } - - static void setFaultStateUnknown(SeerRobokitAgv& agv) - { - agv.invalidateControllerFaultState_(); - } - - static void setFaultStateAge( - SeerRobokitAgv& agv, - const std::chrono::milliseconds age) - { - std::lock_guard lock(agv.runtime_state_mutex_); - agv.controller_fault_state_observed_ = true; - agv.controller_fault_state_observed_at_ = - std::chrono::steady_clock::now() - age; - agv.active_controller_fault_detail_.clear(); - } - - static bool hasTrackedPoseTask(const SeerRobokitAgv& agv) - { - SeerRobokitAgv::PoseTaskContext context; - return agv.currentPoseTask_(context); - } - - static bool hasTrackedNavigation( - const SeerRobokitAgv& agv, - const AgvTaskType expected_type) - { - SeerRobokitAgv::TrackedNavigationContext context; - return agv.currentTrackedNavigation_(context) - && context.type == expected_type; - } - - static AgvResult disconnect(SeerRobokitAgv& agv) - { - return agv.disconnect_(); - } - - static void setNavigationReceiveTimeout( - SeerRobokitAgv& agv, - const std::chrono::milliseconds timeout) - { - timeval value{}; - value.tv_sec = static_cast(timeout.count() / 1000); - value.tv_usec = static_cast( - (timeout.count() % 1000) * 1000); - ASSERT_EQ( - ::setsockopt( - agv.sock_navigation_, - SOL_SOCKET, - SO_RCVTIMEO, - &value, - sizeof(value)), - 0); - } - - static void setStatusReceiveTimeout( - SeerRobokitAgv& agv, - const std::chrono::milliseconds timeout) - { - timeval value{}; - value.tv_sec = static_cast(timeout.count() / 1000); - value.tv_usec = static_cast( - (timeout.count() % 1000) * 1000); - ASSERT_EQ( - ::setsockopt( - agv.sock_status_, - SOL_SOCKET, - SO_RCVTIMEO, - &value, - sizeof(value)), - 0); - } - - static void closeNavigationSocket(SeerRobokitAgv& agv) - { - std::lock_guard lock(agv.mutex_); - agv.closeSocket_(agv.sock_navigation_); - } -}; - -namespace { - -constexpr std::uint16_t kRobotStatusTask = 1020; -constexpr std::uint16_t kRobotStatusLoc = 1004; -constexpr std::uint16_t kRobotStatusAll2 = 1101; -constexpr std::uint16_t kRobotStatusTaskPackage = 1110; -constexpr std::uint16_t kRobotControlStop = 2000; -constexpr std::uint16_t kRobotControlMotion = 2010; -constexpr std::uint16_t kRobotControlLoadMap = 2022; -constexpr std::uint16_t kRobotTaskPause = 3001; -constexpr std::uint16_t kRobotTaskResume = 3002; -constexpr std::uint16_t kRobotTaskCancel = 3003; -constexpr std::uint16_t kRobotTaskGoTarget = 3051; -constexpr std::uint16_t kRobotTaskGoTargetList = 3066; -constexpr std::uint16_t kRobotTaskClearTargetList = 3067; -constexpr std::uint16_t kRobotConfigLock = 4005; -constexpr std::uint16_t kRobotConfigClearFault = 4009; -constexpr std::uint16_t kRobotConfigUploadMap = 4010; -constexpr std::uint16_t kRobotConfigDownloadMap = 4011; -constexpr std::uint16_t kRobotOtherStartMapping = 6100; -constexpr std::uint16_t kRobotOtherStopMapping = 6101; - -enum class Channel : std::size_t { - Status = 0, - Control, - Navigation, - Config, - Other, - Count -}; - -struct CommandRecord { - std::uint16_t command{0}; - std::string payload; -}; - -Json::Value parsePayload(const CommandRecord& record) -{ - Json::Value payload; - Json::CharReaderBuilder builder; - std::string error; - std::unique_ptr reader(builder.newCharReader()); - if (!reader->parse( - record.payload.data(), - record.payload.data() + record.payload.size(), - &payload, - &error)) { - ADD_FAILURE() << "Failed to parse command " << record.command - << " payload: " << error; - } - return payload; -} - -const Json::Value& payloadValue(const Json::Value& payload, const char* key) -{ - const auto* value = payload.find(key, key + std::strlen(key)); - if (!value) { - ADD_FAILURE() << "Missing JSON field: " << key; - static const Json::Value null_value; - return null_value; - } - return *value; -} - -bool payloadHas(const Json::Value& payload, const char* key) -{ - return payload.find(key, key + std::strlen(key)) != nullptr; -} - -AgvMotionOptions asynchronousMotionOptions() -{ - AgvMotionOptions options; - options.asynchronous = true; - return options; -} - -bool receiveExact(const int fd, void* output, const std::size_t size) -{ - auto* bytes = static_cast(output); - std::size_t offset = 0; - while (offset < size) { - const auto count = ::recv(fd, bytes + offset, size - offset, 0); - if (count > 0) { - offset += static_cast(count); - continue; - } - if (count < 0 && errno == EINTR) { - continue; - } - return false; - } - return true; -} - -bool sendAll(const int fd, const std::vector& data) -{ - std::size_t offset = 0; - while (offset < data.size()) { - const auto count = ::send( - fd, - data.data() + offset, - data.size() - offset, - MSG_NOSIGNAL); - if (count > 0) { - offset += static_cast(count); - continue; - } - if (count < 0 && errno == EINTR) { - continue; - } - return false; - } - return true; -} - -std::vector responseFrame( - const std::uint16_t response_command, - const std::string& payload) -{ - std::vector frame(16 + payload.size(), 0); - frame[0] = 0x5A; - frame[1] = 0x01; - frame[3] = 0x01; - const auto length = static_cast(payload.size()); - frame[4] = static_cast((length >> 24U) & 0xFFU); - frame[5] = static_cast((length >> 16U) & 0xFFU); - frame[6] = static_cast((length >> 8U) & 0xFFU); - frame[7] = static_cast(length & 0xFFU); - frame[8] = static_cast((response_command >> 8U) & 0xFFU); - frame[9] = static_cast(response_command & 0xFFU); - std::copy(payload.begin(), payload.end(), frame.begin() + 16); - return frame; -} - -std::string injectRequestedTaskId( - std::string response_payload, - const std::string& request_payload) -{ - constexpr char kTaskIdToken[] = "${TASK_ID}"; - Json::Value request; - Json::CharReaderBuilder builder; - std::string error; - std::unique_ptr reader(builder.newCharReader()); - if (!reader->parse( - request_payload.data(), - request_payload.data() + request_payload.size(), - &request, - &error)) { - return response_payload; - } - const auto* task_ids = request.find("task_ids", "task_ids" + std::strlen("task_ids")); - if (!task_ids || !task_ids->isArray() || task_ids->empty()) { - return response_payload; - } - - const auto replace_all = [&response_payload]( - const std::string& token, - const std::string& value) { - std::size_t position = 0; - while ((position = response_payload.find(token, position)) - != std::string::npos) { - response_payload.replace(position, token.size(), value); - position += value.size(); - } - }; - for (Json::ArrayIndex index = 0; index < task_ids->size(); ++index) { - replace_all( - "${TASK_ID_" + std::to_string(index) + "}", - (*task_ids)[index].asString()); - } - replace_all(kTaskIdToken, (*task_ids)[0].asString()); - return response_payload; -} - -class FakeSeerRobokitController { -public: - FakeSeerRobokitController() - { - for (auto& endpoint : endpoints_) { - int pair[2]{-1, -1}; - if (::socketpair(AF_UNIX, SOCK_STREAM, 0, pair) != 0) { - throw std::runtime_error("socketpair failed"); - } - endpoint.client = pair[0]; - endpoint.server = pair[1]; - } - for (std::size_t index = 0; index < endpoints_.size(); ++index) { - endpoints_[index].worker = std::thread( - &FakeSeerRobokitController::serve, - this, - index); - } - } - - ~FakeSeerRobokitController() - { - for (auto& endpoint : endpoints_) { - if (endpoint.client >= 0) { - ::shutdown(endpoint.client, SHUT_RDWR); - ::close(endpoint.client); - endpoint.client = -1; - } - if (endpoint.server >= 0) { - ::shutdown(endpoint.server, SHUT_RDWR); - } - } - for (auto& endpoint : endpoints_) { - if (endpoint.worker.joinable()) { - endpoint.worker.join(); - } - if (endpoint.server >= 0) { - ::close(endpoint.server); - endpoint.server = -1; - } - } - } - - int takeClient(const Channel channel) - { - auto& endpoint = endpoints_[static_cast(channel)]; - const int client = endpoint.client; - endpoint.client = -1; - return client; - } - - void setResponseCode(const std::uint16_t command, const int ret_code) - { - std::lock_guard lock(response_codes_mutex_); - response_codes_[command] = ret_code; - response_payloads_.erase(command); - } - - void setResponsePayload(const std::uint16_t command, std::string payload) - { - std::lock_guard lock(response_codes_mutex_); - response_codes_.erase(command); - response_payloads_[command] = {std::move(payload)}; - } - - void queueResponsePayload(const std::uint16_t command, std::string payload) - { - std::lock_guard lock(response_codes_mutex_); - response_codes_.erase(command); - response_payloads_[command].push_back(std::move(payload)); - } - - void setResponseDelay( - const std::uint16_t command, - const std::chrono::milliseconds delay) - { - std::lock_guard lock(response_codes_mutex_); - response_delays_[command] = delay; - } - - void setResponseCommand( - const std::uint16_t request_command, - const std::uint16_t response_command) - { - std::lock_guard lock(response_codes_mutex_); - response_commands_[request_command] = response_command; - } - - void clearRecords() - { - std::lock_guard lock(records_mutex_); - records_.clear(); - } - - std::vector records() const - { - std::lock_guard lock(records_mutex_); - return records_; - } - -private: - struct Endpoint { - int client{-1}; - int server{-1}; - std::thread worker; - }; - - void serve(const std::size_t index) - { - const int fd = endpoints_[index].server; - while (true) { - std::array header{}; - if (!receiveExact(fd, header.data(), header.size())) { - return; - } - const auto length = (static_cast(header[4]) << 24U) - | (static_cast(header[5]) << 16U) - | (static_cast(header[6]) << 8U) - | static_cast(header[7]); - const auto command = static_cast( - (static_cast(header[8]) << 8U) | header[9]); - std::string payload(length, '\0'); - if (length > 0 && !receiveExact(fd, payload.data(), payload.size())) { - return; - } - { - std::lock_guard lock(records_mutex_); - records_.push_back({command, payload}); - } - int ret_code = 0; - std::string response_payload; - std::chrono::milliseconds response_delay{0}; - std::uint16_t response_command = static_cast( - command + 10000U); - { - std::lock_guard lock(response_codes_mutex_); - const auto payloads = response_payloads_.find(command); - if (payloads != response_payloads_.end() && !payloads->second.empty()) { - response_payload = payloads->second.front(); - if (payloads->second.size() > 1U) { - payloads->second.pop_front(); - } - } - const auto response_code = response_codes_.find(command); - if (response_code != response_codes_.end()) { - ret_code = response_code->second; - } - const auto delay = response_delays_.find(command); - if (delay != response_delays_.end()) { - response_delay = delay->second; - } - const auto response_command_override = response_commands_.find(command); - if (response_command_override != response_commands_.end()) { - response_command = response_command_override->second; - } - } - if (response_delay.count() > 0) { - std::this_thread::sleep_for(response_delay); - } - if (response_payload.empty()) { - response_payload = ret_code == 0 - ? R"({"ret_code":0,"err_msg":""})" - : "{\"ret_code\":" + std::to_string(ret_code) - + R"(,"err_msg":"simulated command failure"})"; - } - response_payload = injectRequestedTaskId( - std::move(response_payload), - payload); - if (!sendAll(fd, responseFrame(response_command, response_payload))) { - return; - } - } - } - - std::array(Channel::Count)> endpoints_; - mutable std::mutex records_mutex_; - std::vector records_; - std::mutex response_codes_mutex_; - std::unordered_map response_codes_; - std::unordered_map> response_payloads_; - std::unordered_map response_delays_; - std::unordered_map response_commands_; -}; - -class SeerRobokitControlAuthorityTest : public ::testing::Test { -protected: - void SetUp() override - { - config::SeerRobokitAgvConfig cfg; - cfg.set_id("src1100"); - cfg.set_ip("invalid-ip"); - cfg.set_recv_timeout_ms(100); - cfg.set_control_nick_name("cmvr-test"); - cfg.set_enable_state_push(true); - cfg.set_state_push_interval_ms(200); - controller_.setResponsePayload( - kRobotStatusTask, - R"({"ret_code":0,"err_msg":"","task_status":2,"task_type":1,"target_point":[1.0,2.0,0.5]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"err_msg":"","task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"err_msg":"","task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[],"warnings":[]})"); - agv_ = std::make_unique(cfg); - const int status_socket = controller_.takeClient(Channel::Status); - const int control_socket = controller_.takeClient(Channel::Control); - const int navigation_socket = controller_.takeClient(Channel::Navigation); - const int config_socket = controller_.takeClient(Channel::Config); - const int other_socket = controller_.takeClient(Channel::Other); - SeerRobokitAgvTestPeer::installSockets( - *agv_, - status_socket, - control_socket, - navigation_socket, - config_socket, - other_socket); - Json::Value fault_state_push(Json::objectValue); - *fault_state_push.demand( - "errors", - "errors" + std::strlen("errors")) = - Json::Value(Json::arrayValue); - *fault_state_push.demand( - "fatals", - "fatals" + std::strlen("fatals")) = - Json::Value(Json::arrayValue); - SeerRobokitAgvTestPeer::cacheRuntimeState(*agv_, fault_state_push); - } - - void TearDown() override - { - agv_.reset(); - } - - void expectControlledSequence( - const std::vector& commands, - const std::function& invoke) - { - controller_.clearRecords(); - const auto result = invoke(); - ASSERT_TRUE(result.ok()) << result.message; - - const auto records = controller_.records(); - ASSERT_EQ(records.size(), commands.size() + 1U); - EXPECT_EQ(records[0].command, kRobotConfigLock); - for (std::size_t index = 0; index < commands.size(); ++index) { - EXPECT_EQ(records[index + 1U].command, commands[index]); - } - - Json::Value lock_payload; - Json::CharReaderBuilder builder; - std::string error; - std::unique_ptr reader(builder.newCharReader()); - ASSERT_TRUE(reader->parse( - records[0].payload.data(), - records[0].payload.data() + records[0].payload.size(), - &lock_payload, - &error)) << error; - constexpr char kNickName[] = "nick_name"; - const auto* nick_name = lock_payload.find( - kNickName, - kNickName + std::strlen(kNickName)); - ASSERT_NE(nick_name, nullptr); - EXPECT_EQ(nick_name->asString(), "cmvr-test"); - } - - void expectControlled( - const std::uint16_t command, - const std::function& invoke) - { - expectControlledSequence({command}, invoke); - } - - bool waitForCommandCount( - const std::uint16_t command, - const std::size_t expected_count, - const int max_attempts = 3000) const - { - for (int attempt = 0; attempt < max_attempts; ++attempt) { - const auto records = controller_.records(); - const auto count = static_cast(std::count_if( - records.begin(), - records.end(), - [command](const CommandRecord& record) { - return record.command == command; - })); - if (count >= expected_count) { - return true; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - return false; - } - - FakeSeerRobokitController controller_; - std::unique_ptr agv_; -}; - -TEST_F(SeerRobokitControlAuthorityTest, DeclaresSynchronousActionSupport) -{ - EXPECT_TRUE(agv_->supportsSynchronousAction( - AgvActionKind::NavigateToPose)); - EXPECT_TRUE(agv_->supportsSynchronousAction( - AgvActionKind::NavigateToStation)); - EXPECT_TRUE(agv_->supportsSynchronousAction( - AgvActionKind::FollowPath)); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - ConfirmMotionStoppedWithoutTrackedTaskUsesGlobalStatusOnly) -{ - controller_.clearRecords(); - - const auto result = agv_->confirmMotionStopped(); - - ASSERT_TRUE(result.ok()) << result.message; - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusAll2; - }), - 2); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }), - 0); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - ConfirmMotionStoppedForTrackedStationChecksExactTaskAndGlobalVelocity) -{ - const auto navigate_result = agv_->navigateToStation( - "station-confirm-stop", - asynchronousMotionOptions()); - ASSERT_TRUE(navigate_result.ok()) << navigate_result.message; - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":2}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":2,"target_id":"station-confirm-stop","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.clearRecords(); - - const auto result = agv_->confirmMotionStopped(); - - ASSERT_TRUE(result.ok()) << result.message; - const auto records = controller_.records(); - EXPECT_GE( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }), - 2); - EXPECT_GE( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusAll2; - }), - 2); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - ConfirmMotionStoppedTimesOutWhenTrackedTaskIsTerminalButVelocityIsNonzero) -{ - const auto navigate_result = agv_->navigateToStation( - "station-still-moving", - asynchronousMotionOptions()); - ASSERT_TRUE(navigate_result.ok()) << navigate_result.message; - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":2}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":2,"target_id":"station-still-moving","blocked":false,"vx":0.1,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.clearRecords(); - - const auto result = agv_->confirmMotionStopped(); - - EXPECT_EQ(result.code, AgvErrorCode::Timeout); - EXPECT_NE( - result.message.find("stopped velocity were not confirmed"), - std::string::npos); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - ConfirmMotionStoppedWaitsForGlobalTaskToBecomeTerminal) -{ - const auto navigate_result = agv_->navigateToStation( - "station-global-active", - asynchronousMotionOptions()); - ASSERT_TRUE(navigate_result.ok()) << navigate_result.message; - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":2}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":2,"task_type":2,"target_id":"station-global-active","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.clearRecords(); - std::atomic finished{false}; - AgvResult result; - - std::thread confirmation([this, &finished, &result]() { - result = agv_->confirmMotionStopped(); - finished.store(true, std::memory_order_release); - }); - const bool zero_samples_observed = waitForCommandCount( - kRobotStatusAll2, 2, 1000); - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - const bool returned_while_global_active = - finished.load(std::memory_order_acquire); - - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":2,"target_id":"station-global-active","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - confirmation.join(); - - EXPECT_TRUE(zero_samples_observed); - EXPECT_FALSE(returned_while_global_active); - EXPECT_TRUE(result.ok()) << result.message; -} - -TEST_F(SeerRobokitControlAuthorityTest, EveryImplementedMutatingOperationAcquiresAuthorityFirst) -{ - controller_.clearRecords(); - const auto pose_result = - agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - ASSERT_TRUE(pose_result.ok()) << pose_result.message; - const auto pose_records = controller_.records(); - ASSERT_GE(pose_records.size(), 4U); - EXPECT_EQ(pose_records[0].command, kRobotConfigLock); - EXPECT_EQ(pose_records[1].command, kRobotTaskGoTarget); - for (std::size_t index = 2; index < pose_records.size(); ++index) { - EXPECT_EQ(pose_records[index].command, kRobotStatusTaskPackage); - } - expectControlled(kRobotTaskGoTarget, [this]() { - return agv_->navigateToStation("station-1", asynchronousMotionOptions()); - }); - expectControlled(kRobotTaskGoTargetList, [this]() { - return agv_->followPath( - {AgvPathSegment{"station-1", "station-2"}}, - asynchronousMotionOptions()); - }); - expectControlled(kRobotTaskPause, [this]() { - return agv_->pauseNavigation(); - }); - expectControlled(kRobotTaskResume, [this]() { - return agv_->resumeNavigation(); - }); - controller_.clearRecords(); - const auto cancel_result = agv_->cancelNavigation(); - ASSERT_TRUE(cancel_result.ok()) << cancel_result.message; - const auto cancel_records = controller_.records(); - ASSERT_EQ(cancel_records.size(), 4U); - EXPECT_EQ(cancel_records[0].command, kRobotStatusTaskPackage); - EXPECT_EQ(cancel_records[1].command, kRobotStatusAll2); - EXPECT_EQ(cancel_records[2].command, kRobotConfigLock); - EXPECT_EQ(cancel_records[3].command, kRobotTaskClearTargetList); - expectControlledSequence( - {kRobotControlStop, kRobotTaskClearTargetList}, - [this]() { - return agv_->emergencyStop(); - }); - expectControlled(kRobotConfigClearFault, [this]() { - return agv_->clearFault(); - }); - expectControlled(kRobotControlMotion, [this]() { - return agv_->setVelocity(AgvVelocity{0.1, 0.0, 0.2}); - }); - expectControlled(kRobotControlMotion, [this]() { - return agv_->stopVelocityControl(); - }); - expectControlled(kRobotControlLoadMap, [this]() { - return agv_->switchMap("map-1"); - }); - expectControlled(kRobotConfigUploadMap, [this]() { - return agv_->uploadMap("map-1", "{}"); - }); - expectControlled(kRobotOtherStartMapping, [this]() { - return agv_->startMapping(); - }); - expectControlled(kRobotOtherStopMapping, [this]() { - return agv_->stopMapping(); - }); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - SynchronousPoseNavigationWaitsForVerifiedCompletionAndStoppedVelocity) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":2,"task_type":1,"blocked":false,"vx":0.1,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusLoc, - R"({"ret_code":0,"x":1.0,"y":2.0,"angle":0.5,"confidence":1.0})"); - AgvMotionOptions options; - options.asynchronous = false; - options.wait_timeout_ms = 3000; - options.poll_interval_ms = 20; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &finished, &result]() { - result = agv_->navigateToPose( - math::Pose2d{1.0, 2.0, 0.5}, - options); - finished.store(true, std::memory_order_release); - }); - - const bool terminal_wait_observed = waitForCommandCount( - kRobotStatusAll2, - 2); - EXPECT_TRUE(terminal_wait_observed); - EXPECT_FALSE(finished.load(std::memory_order_acquire)); - - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":1,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - ASSERT_TRUE(result.ok()) << result.message; - EXPECT_TRUE(finished.load(std::memory_order_acquire)); - const auto records = controller_.records(); - EXPECT_GE( - static_cast(std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusAll2; - })), - 3U); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - SynchronousPoseRechecksTargetAfterCompletedTaskStops) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":1,"blocked":false,"vx":0.05,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusLoc, - R"({"ret_code":0,"x":1.2,"y":2.0,"angle":0.5})"); - AgvMotionOptions options; - options.wait_timeout_ms = 2000; - options.poll_interval_ms = 20; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &finished, &result]() { - result = agv_->navigateToPose( - math::Pose2d{1.0, 2.0, 0.5}, - options); - finished.store(true, std::memory_order_release); - }); - - const bool moving_completion_observed = - waitForCommandCount(kRobotStatusAll2, 2); - EXPECT_TRUE(moving_completion_observed); - EXPECT_FALSE(finished.load(std::memory_order_acquire)); - const auto moving_records = controller_.records(); - EXPECT_EQ( - std::count_if( - moving_records.begin(), - moving_records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusLoc; - }), - 0); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":1,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::TaskRejected); - EXPECT_NE( - result.message.find("final pose was outside"), - std::string::npos); - EXPECT_NE( - result.message.find("distance_error=0.2"), - std::string::npos); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - SynchronousPoseReconcilesIndeterminateCommandAcknowledgment) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":2,"task_type":1,"blocked":false,"vx":0.05,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":1}]}})"); - controller_.setResponsePayload( - kRobotTaskGoTarget, - R"({"err_msg":"pose acknowledgment lost"})"); - controller_.setResponsePayload( - kRobotStatusLoc, - R"({"ret_code":0,"x":1.0,"y":2.0,"angle":0.5})"); - AgvMotionOptions options; - options.wait_timeout_ms = 3000; - options.poll_interval_ms = 20; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &finished, &result]() { - result = agv_->navigateToPose( - math::Pose2d{1.0, 2.0, 0.5}, - options); - finished.store(true, std::memory_order_release); - }); - - const bool pose_status_observed = waitForCommandCount( - kRobotStatusTaskPackage, - 3, - 1000); - EXPECT_TRUE(pose_status_observed); - EXPECT_FALSE(finished.load(std::memory_order_acquire)); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":1,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - ASSERT_TRUE(result.ok()) << result.message; - EXPECT_NE( - result.message.find("indeterminate command acknowledgment"), - std::string::npos); - EXPECT_NE( - result.message.find("missing a numeric ret_code"), - std::string::npos); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - PoseWaitDoesNotLetGlobalTerminalOverrideExactRunningAfterGrace) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":5,"task_type":1,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusLoc, - R"({"ret_code":0,"x":1.0,"y":2.0,"angle":0.5})"); - AgvMotionOptions options; - options.wait_timeout_ms = 3000; - options.poll_interval_ms = 20; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &finished, &result]() { - result = agv_->navigateToPose( - math::Pose2d{1.0, 2.0, 0.5}, - options); - finished.store(true, std::memory_order_release); - }); - - const bool grace_elapsed_while_polling = waitForCommandCount( - kRobotStatusTaskPackage, - 90, - 2500); - EXPECT_TRUE(grace_elapsed_while_polling); - EXPECT_FALSE(finished.load(std::memory_order_acquire)); - const auto records_before_completion = controller_.records(); - EXPECT_EQ( - std::count_if( - records_before_completion.begin(), - records_before_completion.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 0); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":1,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - ASSERT_TRUE(result.ok()) << result.message; -} - -TEST_F( - SeerRobokitControlAuthorityTest, - SynchronousStationNavigationWaitsForExactTaskCompletion) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":2,"task_type":2,"target_id":"station-2","blocked":false,"vx":0.1,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":2}]}})"); - AgvMotionOptions options; - options.asynchronous = false; - options.wait_timeout_ms = 3000; - options.poll_interval_ms = 20; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &finished, &result]() { - result = agv_->navigateToStation("station-2", options); - finished.store(true, std::memory_order_release); - }); - - const bool terminal_wait_observed = waitForCommandCount( - kRobotStatusAll2, - 2); - EXPECT_TRUE(terminal_wait_observed); - EXPECT_FALSE(finished.load(std::memory_order_acquire)); - - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":2}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":2,"target_id":"station-2","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - ASSERT_TRUE(result.ok()) << result.message; - const auto records = controller_.records(); - const auto command = std::find_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskGoTarget; - }); - ASSERT_NE(command, records.end()); - const auto payload = parsePayload(*command); - EXPECT_FALSE(payloadValue(payload, "task_id").asString().empty()); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - SynchronousStationAcceptsExactCompletionAfterGlobalStateClears) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":2}]}})"); - AgvMotionOptions options; - options.wait_timeout_ms = 2500; - options.poll_interval_ms = 20; - - const auto result = agv_->navigateToStation( - "station-cleared", - options); - - ASSERT_TRUE(result.ok()) << result.message; -} - -TEST_F( - SeerRobokitControlAuthorityTest, - StationWaitIgnoresStaleGlobalTaskUntilExactTaskIdAppears) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":2,"task_type":1,"blocked":false,"vx":0.1,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":5,"task_type":1,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":2,"task_type":2,"target_id":"station-delayed","blocked":false,"vx":0.1,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[]}})"); - controller_.queueResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":2}]}})"); - AgvMotionOptions options; - options.wait_timeout_ms = 2000; - options.poll_interval_ms = 20; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &finished, &result]() { - result = agv_->navigateToStation("station-delayed", options); - finished.store(true, std::memory_order_release); - }); - - const bool exact_task_appeared = waitForCommandCount( - kRobotStatusTaskPackage, - 3, - 1000); - EXPECT_TRUE(exact_task_appeared); - EXPECT_FALSE(finished.load(std::memory_order_acquire)); - const auto records_before_completion = controller_.records(); - EXPECT_EQ( - std::count_if( - records_before_completion.begin(), - records_before_completion.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 0); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":2}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":2,"target_id":"station-delayed","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - ASSERT_TRUE(result.ok()) << result.message; - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 0); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - SynchronousStationReconcilesIndeterminateCommandAcknowledgment) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":2,"task_type":2,"target_id":"station-ack","blocked":false,"vx":0.05,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":2}]}})"); - controller_.setResponsePayload( - kRobotTaskGoTarget, - R"({"err_msg":"station acknowledgment lost"})"); - AgvMotionOptions options; - options.wait_timeout_ms = 3000; - options.poll_interval_ms = 20; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &finished, &result]() { - result = agv_->navigateToStation("station-ack", options); - finished.store(true, std::memory_order_release); - }); - - const bool station_status_observed = waitForCommandCount( - kRobotStatusTaskPackage, - 3, - 1000); - EXPECT_TRUE(station_status_observed); - EXPECT_FALSE(finished.load(std::memory_order_acquire)); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":2}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":2,"target_id":"station-ack","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - ASSERT_TRUE(result.ok()) << result.message; - EXPECT_NE( - result.message.find("indeterminate command acknowledgment"), - std::string::npos); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - StationWaitDoesNotLetGlobalTerminalOverrideExactRunningAfterGrace) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":5,"task_type":2,"target_id":"station-current","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":2}]}})"); - AgvMotionOptions options; - options.wait_timeout_ms = 3000; - options.poll_interval_ms = 20; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &finished, &result]() { - result = agv_->navigateToStation("station-current", options); - finished.store(true, std::memory_order_release); - }); - - const bool grace_elapsed_while_polling = waitForCommandCount( - kRobotStatusTaskPackage, - 90, - 2500); - EXPECT_TRUE(grace_elapsed_while_polling); - EXPECT_FALSE(finished.load(std::memory_order_acquire)); - const auto records_before_completion = controller_.records(); - EXPECT_EQ( - std::count_if( - records_before_completion.begin(), - records_before_completion.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 0); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":2}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":2,"target_id":"station-current","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - ASSERT_TRUE(result.ok()) << result.message; -} - -TEST_F( - SeerRobokitControlAuthorityTest, - SynchronousStationMapsTaskStatusSevenToFailedAfterStop) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":7,"task_type":2,"target_id":"station-timeout","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":7,"type":2}]}})"); - AgvMotionOptions options; - options.wait_timeout_ms = 1000; - options.poll_interval_ms = 20; - controller_.clearRecords(); - - const auto result = agv_->navigateToStation( - "station-timeout", - options); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::TaskFailed); - EXPECT_NE(result.message.find("task_status=7"), std::string::npos); - EXPECT_NE( - result.message.find("stopped velocity confirmed"), - std::string::npos); - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 0); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - SynchronousFollowPathWaitsForFinalExactTaskAndStoppedVelocity) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":2,"task_type":3,"target_id":"station-3","blocked":false,"vx":0.1,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID_0}","status":2},{"task_id":"${TASK_ID_1}","status":1}]}})"); - AgvMotionOptions options; - options.asynchronous = false; - options.wait_timeout_ms = 3000; - options.poll_interval_ms = 20; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &finished, &result]() { - result = agv_->followPath( - { - AgvPathSegment{"station-1", "station-2"}, - AgvPathSegment{"station-2", "station-3"}, - }, - options); - finished.store(true, std::memory_order_release); - }); - - const bool terminal_wait_observed = waitForCommandCount( - kRobotStatusAll2, - 2); - EXPECT_TRUE(terminal_wait_observed); - EXPECT_FALSE(finished.load(std::memory_order_acquire)); - - const auto records_before_completion = controller_.records(); - const auto all2_count_before_completion = static_cast( - std::count_if( - records_before_completion.begin(), - records_before_completion.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusAll2; - })); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID_0}","status":4},{"task_id":"${TASK_ID_1}","status":4}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":3,"target_id":"station-3","blocked":false,"vx":0.05,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":3,"target_id":"station-3","blocked":false,"vx":0.05,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - const bool completed_moving_sample_observed = waitForCommandCount( - kRobotStatusAll2, - all2_count_before_completion + 2U); - EXPECT_TRUE(completed_moving_sample_observed); - EXPECT_FALSE(finished.load(std::memory_order_acquire)); - - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":3,"target_id":"station-3","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - ASSERT_TRUE(result.ok()) << result.message; - const auto records = controller_.records(); - const auto command = std::find_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskGoTargetList; - }); - ASSERT_NE(command, records.end()); - const auto payload = parsePayload(*command); - const auto& tasks = payloadValue(payload, "move_task_list"); - ASSERT_TRUE(tasks.isArray()); - ASSERT_EQ(tasks.size(), 2U); - const std::string first_task_id = - payloadValue(tasks[0], "task_id").asString(); - const std::string final_task_id = - payloadValue(tasks[1], "task_id").asString(); - EXPECT_FALSE(first_task_id.empty()); - EXPECT_FALSE(final_task_id.empty()); - EXPECT_NE(first_task_id, final_task_id); - - const auto status_query = std::find_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }); - ASSERT_NE(status_query, records.end()); - const auto status_payload = parsePayload(*status_query); - const auto& requested_ids = payloadValue(status_payload, "task_ids"); - ASSERT_TRUE(requested_ids.isArray()); - ASSERT_EQ(requested_ids.size(), 2U); - EXPECT_EQ(requested_ids[0].asString(), first_task_id); - EXPECT_EQ(requested_ids[1].asString(), final_task_id); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - FollowPathDoesNotFinishWhileEarlierExactSegmentIsStillActive) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":3,"target_id":"station-3","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID_0}","status":2},{"task_id":"${TASK_ID_1}","status":4}]}})"); - AgvMotionOptions options; - options.wait_timeout_ms = 2000; - options.poll_interval_ms = 20; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &finished, &result]() { - result = agv_->followPath( - { - AgvPathSegment{"station-1", "station-2"}, - AgvPathSegment{"station-2", "station-3"}, - }, - options); - finished.store(true, std::memory_order_release); - }); - - const bool continued_polling = waitForCommandCount( - kRobotStatusTaskPackage, - 5, - 1000); - EXPECT_TRUE(continued_polling); - EXPECT_FALSE(finished.load(std::memory_order_acquire)); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID_0}","status":4},{"task_id":"${TASK_ID_1}","status":4}]}})"); - navigation_thread.join(); - - ASSERT_TRUE(result.ok()) << result.message; -} - -TEST_F( - SeerRobokitControlAuthorityTest, - SynchronousFollowPathReconcilesIndeterminateCommandAcknowledgment) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":2,"task_type":3,"target_id":"station-3","blocked":false,"vx":0.05,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID_0}","status":2},{"task_id":"${TASK_ID_1}","status":1}]}})"); - controller_.setResponsePayload( - kRobotTaskGoTargetList, - R"({"err_msg":"path acknowledgment lost"})"); - AgvMotionOptions options; - options.wait_timeout_ms = 3000; - options.poll_interval_ms = 20; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &finished, &result]() { - result = agv_->followPath( - { - AgvPathSegment{"station-1", "station-2"}, - AgvPathSegment{"station-2", "station-3"}, - }, - options); - finished.store(true, std::memory_order_release); - }); - - const bool path_status_observed = waitForCommandCount( - kRobotStatusTaskPackage, - 3, - 1000); - EXPECT_TRUE(path_status_observed); - EXPECT_FALSE(finished.load(std::memory_order_acquire)); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID_0}","status":4},{"task_id":"${TASK_ID_1}","status":4}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":3,"target_id":"station-3","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - ASSERT_TRUE(result.ok()) << result.message; - EXPECT_NE( - result.message.find("indeterminate command acknowledgment"), - std::string::npos); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - TerminalPathTimeoutRetainsTrackingUntilStoppedVelocityIsConfirmed) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":3,"target_id":"station-3","blocked":false,"vx":0.05,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID_0}","status":4},{"task_id":"${TASK_ID_1}","status":4}]}})"); - AgvMotionOptions options; - options.wait_timeout_ms = 100; - options.poll_interval_ms = 20; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &finished, &result]() { - result = agv_->followPath( - { - AgvPathSegment{"station-1", "station-2"}, - AgvPathSegment{"station-2", "station-3"}, - }, - options); - finished.store(true, std::memory_order_release); - }); - - const bool timeout_cleanup_started = waitForCommandCount( - kRobotStatusAll2, - 2, - 1000); - EXPECT_TRUE(timeout_cleanup_started); - std::this_thread::sleep_for(std::chrono::milliseconds(150)); - EXPECT_FALSE(finished.load(std::memory_order_acquire)); - EXPECT_TRUE(SeerRobokitAgvTestPeer::hasTrackedNavigation( - *agv_, - AgvTaskType::FollowPath)); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":3,"target_id":"station-3","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - EXPECT_EQ(result.code, AgvErrorCode::Timeout); - EXPECT_NE( - result.message.find("stopped state was confirmed"), - std::string::npos); - EXPECT_FALSE(SeerRobokitAgvTestPeer::hasTrackedNavigation( - *agv_, - AgvTaskType::FollowPath)); - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskClearTargetList; - }), - 0); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - TerminalPoseTimeoutRetainsTrackingUntilStoppedVelocityIsConfirmed) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":1,"blocked":false,"vx":0.05,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusLoc, - R"({"ret_code":0,"x":1.0,"y":2.0,"angle":0.5})"); - AgvMotionOptions options; - options.wait_timeout_ms = 100; - options.poll_interval_ms = 20; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &finished, &result]() { - result = agv_->navigateToPose( - math::Pose2d{1.0, 2.0, 0.5}, - options); - finished.store(true, std::memory_order_release); - }); - - const bool timeout_cleanup_started = waitForCommandCount( - kRobotStatusAll2, - 2, - 1000); - EXPECT_TRUE(timeout_cleanup_started); - std::this_thread::sleep_for(std::chrono::milliseconds(150)); - EXPECT_FALSE(finished.load(std::memory_order_acquire)); - EXPECT_TRUE(SeerRobokitAgvTestPeer::hasTrackedPoseTask(*agv_)); - EXPECT_TRUE(SeerRobokitAgvTestPeer::hasTrackedNavigation( - *agv_, - AgvTaskType::NavigateToPose)); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":1,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - EXPECT_EQ(result.code, AgvErrorCode::Timeout); - EXPECT_NE( - result.message.find("stopped state was confirmed"), - std::string::npos); - EXPECT_FALSE(SeerRobokitAgvTestPeer::hasTrackedPoseTask(*agv_)); - EXPECT_FALSE(SeerRobokitAgvTestPeer::hasTrackedNavigation( - *agv_, - AgvTaskType::NavigateToPose)); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - PersistentBlockedNavigationConditionallyCancelsAndConfirmsStoppedTask) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":2,"task_type":2,"target_id":"station-blocked","blocked":true,"block_reason":3,"block_x":1.2,"block_y":0.1,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":2}]}})"); - controller_.setResponseDelay( - kRobotTaskCancel, - std::chrono::milliseconds(50)); - AgvMotionOptions options; - options.asynchronous = false; - options.wait_timeout_ms = 3000; - options.poll_interval_ms = 20; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &finished, &result]() { - result = agv_->navigateToStation("station-blocked", options); - finished.store(true, std::memory_order_release); - }); - - const bool cancel_observed = waitForCommandCount(kRobotTaskCancel, 1); - EXPECT_TRUE(cancel_observed); - EXPECT_FALSE(finished.load(std::memory_order_acquire)); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":6,"type":2}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":6,"task_type":2,"target_id":"station-blocked","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::TaskFailed); - EXPECT_NE(result.message.find("block_reason=3(collision)"), std::string::npos); - EXPECT_NE(result.message.find("canceled"), std::string::npos); - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 1); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotConfigLock; - }), - 2); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - FollowPathUsesUniqueTaskIdsAcrossCalls) -{ - controller_.clearRecords(); - const auto first_result = agv_->followPath( - {AgvPathSegment{"station-1", "station-2"}}, - asynchronousMotionOptions()); - ASSERT_TRUE(first_result.ok()) << first_result.message; - const auto first_records = controller_.records(); - const auto first_command = std::find_if( - first_records.begin(), - first_records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskGoTargetList; - }); - ASSERT_NE(first_command, first_records.end()); - const auto first_payload = parsePayload(*first_command); - const std::string first_task_id = payloadValue( - payloadValue(first_payload, "move_task_list")[0], - "task_id").asString(); - - controller_.clearRecords(); - const auto second_result = agv_->followPath( - {AgvPathSegment{"station-1", "station-2"}}, - asynchronousMotionOptions()); - ASSERT_TRUE(second_result.ok()) << second_result.message; - const auto second_records = controller_.records(); - const auto second_command = std::find_if( - second_records.begin(), - second_records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskGoTargetList; - }); - ASSERT_NE(second_command, second_records.end()); - const auto second_payload = parsePayload(*second_command); - const std::string second_task_id = payloadValue( - payloadValue(second_payload, "move_task_list")[0], - "task_id").asString(); - - EXPECT_FALSE(first_task_id.empty()); - EXPECT_FALSE(second_task_id.empty()); - EXPECT_NE(first_task_id, second_task_id); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - ExactTaskStatusWithoutTypeStillConfirmsAsynchronousPoseStart) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2}]}})"); - - const auto result = agv_->navigateToPose( - math::Pose2d{1.0, 2.0, 0.5}, - asynchronousMotionOptions()); - - ASSERT_TRUE(result.ok()) << result.message; -} - -TEST_F( - SeerRobokitControlAuthorityTest, - PoseStartTreatsTaskStatus404AsNotYetPresent) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":404,"type":1}]}})"); - controller_.queueResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":1}]}})"); - controller_.clearRecords(); - - const auto result = agv_->navigateToPose( - math::Pose2d{1.0, 2.0, 0.5}, - asynchronousMotionOptions()); - - ASSERT_TRUE(result.ok()) << result.message; - const auto records = controller_.records(); - EXPECT_GE( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }), - 3); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - PoseStartMapsControllerTaskStatusSevenToTaskFailed) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"info":"controller terminated free navigation","task_status_list":[{"task_id":"${TASK_ID}","status":7,"type":1}]}})"); - controller_.clearRecords(); - - const auto result = agv_->navigateToPose( - math::Pose2d{1.0, 2.0, 0.5}, - asynchronousMotionOptions()); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::TaskFailed); - EXPECT_NE(result.message.find("controller terminated free navigation"), std::string::npos); - EXPECT_NE(result.message.find("task_status=7"), std::string::npos); - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 0); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - CancelNavigationClearsTrackedAsynchronousPathWithCommand3067) -{ - const auto path_result = agv_->followPath( - {AgvPathSegment{"station-1", "station-2"}}, - asynchronousMotionOptions()); - ASSERT_TRUE(path_result.ok()) << path_result.message; - ASSERT_TRUE(SeerRobokitAgvTestPeer::hasTrackedNavigation( - *agv_, - AgvTaskType::FollowPath)); - controller_.clearRecords(); - - const auto cancel_result = agv_->cancelNavigation(); - - ASSERT_TRUE(cancel_result.ok()) << cancel_result.message; - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskClearTargetList; - }), - 1); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 0); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigationDefaultsToSynchronousAndRejectsUnboundedPolling) -{ - EXPECT_FALSE(AgvMotionOptions{}.asynchronous); - - AgvMotionOptions options; - options.poll_interval_ms = 5001; - controller_.clearRecords(); - const auto result = agv_->navigateToStation("station-1", options); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::InvalidArgument); - EXPECT_NE(result.message.find("must not exceed 5000"), std::string::npos); - EXPECT_TRUE(controller_.records().empty()); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - PreCanceledNavigationDoesNotAcquireAuthorityOrSendMotion) -{ - AgvMotionOptions options; - options.cancellation_requested = []() { return true; }; - - controller_.clearRecords(); - const auto pose_result = agv_->navigateToPose( - math::Pose2d{1.0, 2.0, 0.5}, - options); - EXPECT_EQ(pose_result.code, AgvErrorCode::TaskCanceled); - EXPECT_TRUE(controller_.records().empty()); - - const auto station_result = - agv_->navigateToStation("station-1", options); - EXPECT_EQ(station_result.code, AgvErrorCode::TaskCanceled); - EXPECT_TRUE(controller_.records().empty()); - - const auto path_result = agv_->followPath( - {AgvPathSegment{"station-1", "station-2"}}, - options); - EXPECT_EQ(path_result.code, AgvErrorCode::TaskCanceled); - EXPECT_TRUE(controller_.records().empty()); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - CancellationDuringAuthorityAcquisitionPreventsNavigationWrite) -{ - std::atomic canceled{false}; - AgvMotionOptions options = asynchronousMotionOptions(); - options.cancellation_requested = [&canceled]() { - return canceled.load(std::memory_order_acquire); - }; - controller_.setResponseDelay( - kRobotConfigLock, - std::chrono::milliseconds(100)); - controller_.clearRecords(); - AgvResult result; - - std::thread navigation_thread([this, &options, &result]() { - result = agv_->navigateToStation("station-1", options); - }); - ASSERT_TRUE(waitForCommandCount(kRobotConfigLock, 1)); - canceled.store(true, std::memory_order_release); - navigation_thread.join(); - - EXPECT_EQ(result.code, AgvErrorCode::TaskCanceled); - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskGoTarget; - }), - 0); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - SynchronousStationPublicCancelStillWaitsForTerminalZeroVelocity) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":2,"task_type":2,"target_id":"station-public-cancel","blocked":false,"vx":0.05,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":2}]}})"); - std::atomic caller_canceled{false}; - AgvMotionOptions options; - options.wait_timeout_ms = 2500; - options.poll_interval_ms = 20; - options.cancellation_requested = [&caller_canceled]() { - return caller_canceled.load(std::memory_order_acquire); - }; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread( - [this, &options, &finished, &result]() { - result = agv_->navigateToStation( - "station-public-cancel", - options); - finished.store(true, std::memory_order_release); - }); - - const bool terminal_wait_started = waitForCommandCount( - kRobotStatusAll2, - 2, - 1500); - const auto public_cancel_result = agv_->cancelNavigation(); - caller_canceled.store(true, std::memory_order_release); - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - const bool returned_while_exact_task_was_active = - finished.load(std::memory_order_acquire); - - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":6,"type":2}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":6,"task_type":2,"target_id":"station-public-cancel","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - EXPECT_TRUE(terminal_wait_started); - ASSERT_TRUE(public_cancel_result.ok()) - << public_cancel_result.message; - EXPECT_FALSE(returned_while_exact_task_was_active); - EXPECT_EQ(result.code, AgvErrorCode::TaskCanceled); - EXPECT_NE( - result.message.find("stopped state was confirmed"), - std::string::npos); - const auto records = controller_.records(); - EXPECT_GE( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 1); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - TerminalTaskWithoutVelocityStatusEscalatesToTrackedFailSafeStop) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":41101,"err_msg":"1101 unavailable after terminal task"})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":2}]}})"); - AgvMotionOptions options; - options.wait_timeout_ms = 100; - options.poll_interval_ms = 20; - controller_.clearRecords(); - - const auto result = agv_->navigateToStation( - "station-terminal-no-velocity", - options); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::Timeout); - EXPECT_NE( - result.message.find("tracked fail-safe software stop"), - std::string::npos); - EXPECT_NE( - result.message.find("stopped state remains unconfirmed"), - std::string::npos); - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotControlStop; - }), - 1); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 1); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - SynchronousPosePublicCancelStillWaitsForTerminalZeroVelocity) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":2,"task_type":1,"blocked":false,"vx":0.05,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":1}]}})"); - std::atomic caller_canceled{false}; - AgvMotionOptions options; - options.wait_timeout_ms = 2500; - options.poll_interval_ms = 20; - options.cancellation_requested = [&caller_canceled]() { - return caller_canceled.load(std::memory_order_acquire); - }; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread( - [this, &options, &finished, &result]() { - result = agv_->navigateToPose( - math::Pose2d{1.0, 2.0, 0.5}, - options); - finished.store(true, std::memory_order_release); - }); - - const bool terminal_wait_started = waitForCommandCount( - kRobotStatusAll2, - 2, - 1500); - const auto public_cancel_result = agv_->cancelNavigation(); - caller_canceled.store(true, std::memory_order_release); - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - const bool returned_while_exact_task_was_active = - finished.load(std::memory_order_acquire); - - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":6,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":6,"task_type":1,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - EXPECT_TRUE(terminal_wait_started); - ASSERT_TRUE(public_cancel_result.ok()) - << public_cancel_result.message; - EXPECT_FALSE(returned_while_exact_task_was_active); - EXPECT_EQ(result.code, AgvErrorCode::TaskCanceled); - EXPECT_NE( - result.message.find("stopped state was confirmed"), - std::string::npos); - const auto records = controller_.records(); - EXPECT_GE( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 1); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - SynchronousStationEmergencyStopStillWaitsForTerminalZeroVelocity) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":2,"task_type":2,"target_id":"station-emergency-stop","blocked":false,"vx":0.05,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":2}]}})"); - AgvMotionOptions options; - options.wait_timeout_ms = 2500; - options.poll_interval_ms = 20; - std::atomic finished{false}; - AgvResult result; - - std::thread navigation_thread( - [this, &options, &finished, &result]() { - result = agv_->navigateToStation( - "station-emergency-stop", - options); - finished.store(true, std::memory_order_release); - }); - - const bool terminal_wait_started = waitForCommandCount( - kRobotStatusAll2, - 2, - 1500); - const auto emergency_stop_result = agv_->emergencyStop(); - const auto records_before_terminal = controller_.records(); - const auto exact_queries_before_terminal = - static_cast(std::count_if( - records_before_terminal.begin(), - records_before_terminal.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - })); - - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":6,"type":2}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":6,"task_type":2,"target_id":"station-emergency-stop","blocked":false,"vx":0.05,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - const bool moving_terminal_observed = waitForCommandCount( - kRobotStatusTaskPackage, - exact_queries_before_terminal + 1U, - 1000); - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - const bool returned_while_velocity_was_nonzero = - finished.load(std::memory_order_acquire); - - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":6,"task_type":2,"target_id":"station-emergency-stop","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - EXPECT_TRUE(terminal_wait_started); - ASSERT_TRUE(emergency_stop_result.ok()) - << emergency_stop_result.message; - EXPECT_TRUE(moving_terminal_observed); - EXPECT_FALSE(returned_while_velocity_was_nonzero); - EXPECT_EQ(result.code, AgvErrorCode::TaskCanceled); - EXPECT_NE( - result.message.find("stopped velocity confirmed"), - std::string::npos); - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotControlStop; - }), - 1); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 1); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - SynchronousStationStatusTimeoutStillCancelsAndReportsUnconfirmedStop) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":2,"task_type":2,"target_id":"station-status-timeout","blocked":false,"vx":0.05,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":2}]}})"); - SeerRobokitAgvTestPeer::setStatusReceiveTimeout( - *agv_, - std::chrono::milliseconds(50)); - AgvMotionOptions options; - options.wait_timeout_ms = 2000; - options.poll_interval_ms = 100; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &result]() { - result = agv_->navigateToStation( - "station-status-timeout", - options); - }); - - const bool running_status_observed = waitForCommandCount( - kRobotStatusAll2, - 2, - 1000); - controller_.setResponseDelay( - kRobotStatusTaskPackage, - std::chrono::milliseconds(200)); - navigation_thread.join(); - - EXPECT_TRUE(running_status_observed); - EXPECT_EQ(result.code, AgvErrorCode::Timeout); - EXPECT_NE( - result.message.find("navigation cancel was sent"), - std::string::npos); - EXPECT_NE( - result.message.find("termination could not be queried"), - std::string::npos); - EXPECT_EQ( - result.message.find("stopped state was confirmed"), - std::string::npos); - const auto records = controller_.records(); - EXPECT_GE( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 1); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotControlStop; - }), - 1); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - FollowPathAcceptsCurrentSegmentOnlyTaskStatusProgression) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":2,"task_type":3,"target_id":"station-2","blocked":false,"vx":0.1,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID_0}","status":2}]}})"); - controller_.queueResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[]}})"); - controller_.queueResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID_1}","status":2}]}})"); - AgvMotionOptions options; - options.wait_timeout_ms = 3000; - options.poll_interval_ms = 20; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &finished, &result]() { - result = agv_->followPath( - { - AgvPathSegment{"station-1", "station-2"}, - AgvPathSegment{"station-2", "station-3"}, - }, - options); - finished.store(true, std::memory_order_release); - }); - - ASSERT_TRUE(waitForCommandCount(kRobotStatusTaskPackage, 3)); - EXPECT_FALSE(finished.load(std::memory_order_acquire)); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID_1}","status":4}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":3,"target_id":"station-3","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - ASSERT_TRUE(result.ok()) << result.message; - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 0); - const auto command = std::find_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskGoTargetList; - }); - ASSERT_NE(command, records.end()); - const auto command_payload = parsePayload(*command); - const auto& tasks = payloadValue(command_payload, "move_task_list"); - ASSERT_EQ(tasks.size(), 2U); - const std::string first_id = - payloadValue(tasks[0], "task_id").asString(); - const std::string second_id = - payloadValue(tasks[1], "task_id").asString(); - for (const auto& record : records) { - if (record.command != kRobotStatusTaskPackage) { - continue; - } - const auto payload = parsePayload(record); - const auto& requested = payloadValue(payload, "task_ids"); - ASSERT_EQ(requested.size(), 2U); - EXPECT_EQ(requested[0].asString(), first_id); - EXPECT_EQ(requested[1].asString(), second_id); - } -} - -TEST_F( - SeerRobokitControlAuthorityTest, - FailedStationTaskDoesNotReturnUntilStoppedVelocityIsConfirmed) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":5,"task_type":2,"target_id":"station-failed","blocked":false,"vx":0.1,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":5}]}})"); - AgvMotionOptions options; - options.wait_timeout_ms = 3000; - options.poll_interval_ms = 20; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &finished, &result]() { - result = agv_->navigateToStation("station-failed", options); - finished.store(true, std::memory_order_release); - }); - - ASSERT_TRUE(waitForCommandCount(kRobotStatusAll2, 2)); - EXPECT_FALSE(finished.load(std::memory_order_acquire)); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":5,"task_type":2,"target_id":"station-failed","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - EXPECT_EQ(result.code, AgvErrorCode::TaskFailed); - EXPECT_NE(result.message.find("stopped velocity confirmed"), std::string::npos); - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 0); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - FailedPathSegmentCancelsRemainingActiveSegmentsBeforeReturning) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":2,"task_type":3,"target_id":"station-2","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID_0}","status":5},{"task_id":"${TASK_ID_1}","status":1}]}})"); - controller_.setResponseDelay( - kRobotTaskClearTargetList, - std::chrono::milliseconds(50)); - AgvMotionOptions options; - options.wait_timeout_ms = 3000; - options.poll_interval_ms = 20; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &finished, &result]() { - result = agv_->followPath( - { - AgvPathSegment{"station-1", "station-2"}, - AgvPathSegment{"station-2", "station-3"}, - }, - options); - finished.store(true, std::memory_order_release); - }); - - ASSERT_TRUE(waitForCommandCount(kRobotTaskClearTargetList, 1)); - EXPECT_FALSE(finished.load(std::memory_order_acquire)); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID_0}","status":5},{"task_id":"${TASK_ID_1}","status":6}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":6,"task_type":3,"target_id":"station-3","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - EXPECT_EQ(result.code, AgvErrorCode::TaskFailed); - EXPECT_NE(result.message.find("still active"), std::string::npos); - EXPECT_NE(result.message.find("conditionally canceled"), std::string::npos); - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskClearTargetList; - }), - 1); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - CurrentSegmentOnlyFailureCancelsHiddenPathAndWaitsForGlobalTerminalStop) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":2,"task_type":3,"target_id":"station-2","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - // This firmware shape reports only the current segment. The failed first - // segment is visible, while the later queued segment is temporarily absent. - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID_0}","status":5}]}})"); - controller_.setResponseDelay( - kRobotTaskClearTargetList, - std::chrono::milliseconds(100)); - AgvMotionOptions options; - options.wait_timeout_ms = 3000; - options.poll_interval_ms = 20; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &finished, &result]() { - result = agv_->followPath( - { - AgvPathSegment{"station-1", "station-2"}, - AgvPathSegment{"station-2", "station-3"}, - }, - options); - finished.store(true, std::memory_order_release); - }); - - const bool cancel_observed = waitForCommandCount( - kRobotTaskClearTargetList, - 1, - 750); - std::size_t all2_count_at_cancel = 0; - if (cancel_observed) { - const auto records = controller_.records(); - all2_count_at_cancel = static_cast(std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusAll2; - })); - - // The cancel ACK is delayed above, so these become the first - // post-cancel observations: one exact task is canceled, the other is - // still absent, and 1101 still says navigation is active but stationary. - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID_0}","status":6}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":2,"task_type":3,"target_id":"station-3","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - } - - const bool active_zero_samples_observed = cancel_observed - && waitForCommandCount( - kRobotStatusAll2, - all2_count_at_cancel + 2U, - 1500); - const bool returned_before_global_terminal = - finished.load(std::memory_order_acquire); - - // Allow both the correct and the intentionally failing implementation to - // terminate cleanly before joining the test thread. - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID_0}","status":6}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":6,"task_type":3,"target_id":"station-3","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - EXPECT_TRUE(cancel_observed); - EXPECT_TRUE(active_zero_samples_observed); - EXPECT_FALSE(returned_before_global_terminal); - EXPECT_EQ(result.code, AgvErrorCode::TaskFailed); - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskClearTargetList; - }), - 1); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - ExactActivePathEscalatesToFailSafeWhenGlobalOwnershipIsUnavailable) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - // If the waiter asks for 1101 after seeing exact states 5 + 1, this queued - // controller error is returned. A bare global 3067 is unsafe without the - // global ownership snapshot, so the adapter must use its explicit - // software-stop escalation sequence. - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":41101,"err_msg":"simulated 1101 failure after exact segment failure"})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID_0}","status":5},{"task_id":"${TASK_ID_1}","status":1}]}})"); - controller_.setResponseDelay( - kRobotTaskClearTargetList, - std::chrono::milliseconds(100)); - AgvMotionOptions options; - options.wait_timeout_ms = 2000; - options.poll_interval_ms = 20; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &result]() { - result = agv_->followPath( - { - AgvPathSegment{"station-1", "station-2"}, - AgvPathSegment{"station-2", "station-3"}, - }, - options); - }); - - const bool cancel_observed = waitForCommandCount( - kRobotTaskClearTargetList, - 1, - 750); - // Replace the queued failing 1101 response while the cancel ACK is delayed, - // so a correct implementation can confirm the post-cancel terminal stop. - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID_0}","status":5},{"task_id":"${TASK_ID_1}","status":6}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":6,"task_type":3,"target_id":"station-3","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - EXPECT_TRUE(cancel_observed); - EXPECT_EQ(result.code, AgvErrorCode::TaskFailed); - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskClearTargetList; - }), - 1); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotControlStop; - }), - 1); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - AsynchronousPoseCancellationAfterAckCancelsAndConfirmsStoppedTask) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":1}]}})"); - controller_.setResponseDelay( - kRobotTaskCancel, - std::chrono::milliseconds(100)); - std::atomic canceled{false}; - AgvMotionOptions options = asynchronousMotionOptions(); - options.cancellation_requested = [&canceled]() { - return canceled.load(std::memory_order_acquire); - }; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &result]() { - result = agv_->navigateToPose( - math::Pose2d{1.0, 2.0, 0.5}, - options); - }); - - // The first 1110 request proves that 3051 already returned its ACK and the - // asynchronous pose start-confirmation phase is in progress. - const bool post_ack_status_observed = waitForCommandCount( - kRobotStatusTaskPackage, - 1, - 750); - canceled.store(true, std::memory_order_release); - const bool cancel_observed = waitForCommandCount( - kRobotTaskCancel, - 1, - 750); - - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":6,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":6,"task_type":1,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - EXPECT_TRUE(post_ack_status_observed); - EXPECT_TRUE(cancel_observed); - EXPECT_EQ(result.code, AgvErrorCode::TaskCanceled); - EXPECT_NE(result.message.find("conditionally canceled"), std::string::npos); - EXPECT_NE(result.message.find("stopped state was confirmed"), std::string::npos); - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 1); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - GlobalTaskStatusSevenDoesNotOverrideExactRunningSynchronousPose) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":7,"task_type":1,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusLoc, - R"({"ret_code":0,"x":1.0,"y":2.0,"angle":0.5})"); - AgvMotionOptions options; - options.wait_timeout_ms = 3000; - options.poll_interval_ms = 20; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &finished, &result]() { - result = agv_->navigateToPose( - math::Pose2d{1.0, 2.0, 0.5}, - options); - finished.store(true, std::memory_order_release); - }); - - const bool grace_elapsed_while_exact_running = waitForCommandCount( - kRobotStatusTaskPackage, - 90, - 2500); - EXPECT_TRUE(grace_elapsed_while_exact_running); - EXPECT_FALSE(finished.load(std::memory_order_acquire)); - const auto records_before_completion = controller_.records(); - EXPECT_EQ( - std::count_if( - records_before_completion.begin(), - records_before_completion.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 0); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":1,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - ASSERT_TRUE(result.ok()) << result.message; - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 0); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskClearTargetList; - }), - 0); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - CompletedPoseDoesNotFinishAfterExactTaskReturnsToRunning) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":1}]}})"); - controller_.queueResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusLoc, - R"({"ret_code":0,"x":1.0,"y":2.0,"angle":0.5})"); - AgvMotionOptions options; - options.wait_timeout_ms = 3000; - options.poll_interval_ms = 20; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread( - [this, &options, &finished, &result]() { - result = agv_->navigateToPose( - math::Pose2d{1.0, 2.0, 0.5}, - options); - finished.store(true, std::memory_order_release); - }); - - const bool running_after_completed_observed = waitForCommandCount( - kRobotStatusTaskPackage, - 10, - 1500); - EXPECT_TRUE(running_after_completed_observed); - EXPECT_FALSE(finished.load(std::memory_order_acquire)); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":1,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - ASSERT_TRUE(result.ok()) << result.message; -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigationStatusDoesNotSupersedeSynchronousPoseWaiter) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":2,"task_type":1,"blocked":false,"vx":0.05,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusLoc, - R"({"ret_code":0,"x":1.0,"y":2.0,"angle":0.5})"); - AgvMotionOptions options; - options.wait_timeout_ms = 3000; - options.poll_interval_ms = 20; - std::atomic finished{false}; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread( - [this, &options, &finished, &result]() { - result = agv_->navigateToPose( - math::Pose2d{1.0, 2.0, 0.5}, - options); - finished.store(true, std::memory_order_release); - }); - - const bool terminal_wait_started = waitForCommandCount( - kRobotStatusAll2, - 2, - 2000); - const auto observed_status = agv_->navigationStatus(); - EXPECT_TRUE(terminal_wait_started); - EXPECT_EQ(observed_status.state, AgvTaskState::Running); - EXPECT_FALSE(finished.load(std::memory_order_acquire)); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":4,"task_type":1,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - navigation_thread.join(); - - ASSERT_TRUE(result.ok()) << result.message; - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 0); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - ConditionalCancelRefusesDifferentActiveControllerTask) -{ - const auto navigation_result = agv_->navigateToStation( - "station-owned", - asynchronousMotionOptions()); - ASSERT_TRUE(navigation_result.ok()) << navigation_result.message; - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":2}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":2,"task_type":3,"target_id":"station-external","blocked":false,"vx":0.05,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.clearRecords(); - - const auto cancel_result = agv_->cancelNavigation(); - - EXPECT_FALSE(cancel_result.ok()); - EXPECT_EQ(cancel_result.code, AgvErrorCode::TaskCanceled); - EXPECT_NE( - cancel_result.message.find("another active task"), - std::string::npos); - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotConfigLock - || record.command == kRobotTaskCancel - || record.command == kRobotTaskClearTargetList; - }), - 0); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - CanceledOldPathWithExactTerminalTasksIgnoresReplacementGlobalSnapshot) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID_0}","status":5},{"task_id":"${TASK_ID_1}","status":1}]}})"); - controller_.setResponseDelay( - kRobotTaskClearTargetList, - std::chrono::milliseconds(100)); - AgvMotionOptions options; - options.wait_timeout_ms = 3000; - options.poll_interval_ms = 20; - AgvResult old_result; - controller_.clearRecords(); - - std::thread old_navigation_thread([this, &options, &old_result]() { - old_result = agv_->followPath( - { - AgvPathSegment{"station-1", "station-2"}, - AgvPathSegment{"station-2", "station-3"}, - }, - options); - }); - - const bool cancel_observed = waitForCommandCount( - kRobotTaskClearTargetList, - 1, - 1000); - const auto records_at_cancel = controller_.records(); - const auto all2_count_at_cancel = static_cast(std::count_if( - records_at_cancel.begin(), - records_at_cancel.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusAll2; - })); - const auto exact_count_at_cancel = static_cast(std::count_if( - records_at_cancel.begin(), - records_at_cancel.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - })); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID_0}","status":6},{"task_id":"${TASK_ID_1}","status":6}]}})"); - controller_.setResponseDelay( - kRobotStatusTaskPackage, - std::chrono::milliseconds(300)); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":41101,"err_msg":"replacement task owns global 1101"})"); - const bool post_cancel_exact_query_observed = cancel_observed - && waitForCommandCount( - kRobotStatusTaskPackage, - exact_count_at_cancel + 1U, - 1000); - - const auto replacement_result = agv_->navigateToStation( - "replacement-station", - asynchronousMotionOptions()); - old_navigation_thread.join(); - - EXPECT_TRUE(cancel_observed); - EXPECT_TRUE(post_cancel_exact_query_observed); - ASSERT_TRUE(replacement_result.ok()) << replacement_result.message; - EXPECT_EQ(old_result.code, AgvErrorCode::TaskFailed); - EXPECT_NE( - old_result.message.find("old exact task ids are terminal"), - std::string::npos); - EXPECT_NE( - old_result.message.find("global stopped state was not inspected"), - std::string::npos); - EXPECT_EQ( - old_result.message.find("stopped state was confirmed"), - std::string::npos); - EXPECT_TRUE(SeerRobokitAgvTestPeer::hasTrackedNavigation( - *agv_, - AgvTaskType::NavigateToStation)); - const auto records = controller_.records(); - EXPECT_EQ( - static_cast(std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusAll2; - })), - all2_count_at_cancel); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskClearTargetList; - }), - 1); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 0); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - CurrentSegmentFailureClearsPathQueueDuringGlobalIdleTransitionWindow) -{ - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.queueResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":2,"task_type":3,"target_id":"station-3","blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID_0}","status":5}]}})"); - controller_.setResponseDelay( - kRobotConfigLock, - std::chrono::milliseconds(100)); - controller_.setResponseDelay( - kRobotTaskClearTargetList, - std::chrono::milliseconds(100)); - AgvMotionOptions options; - options.wait_timeout_ms = 3000; - options.poll_interval_ms = 20; - AgvResult result; - controller_.clearRecords(); - - std::thread navigation_thread([this, &options, &result]() { - result = agv_->followPath( - { - AgvPathSegment{"station-1", "station-2"}, - AgvPathSegment{"station-2", "station-3"}, - }, - options); - }); - - const bool cancel_authority_observed = waitForCommandCount( - kRobotConfigLock, - 2, - 1500); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":0,"task_type":0,"blocked":false,"vx":0.0,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - const bool clear_path_observed = waitForCommandCount( - kRobotTaskClearTargetList, - 1, - 1000); - navigation_thread.join(); - - EXPECT_TRUE(cancel_authority_observed); - EXPECT_TRUE(clear_path_observed); - EXPECT_EQ(result.code, AgvErrorCode::TaskFailed); - EXPECT_NE(result.message.find("conditionally canceled"), std::string::npos); - EXPECT_NE(result.message.find("stopped state was confirmed"), std::string::npos); - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskClearTargetList; - }), - 1); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 0); -} - -TEST_F(SeerRobokitControlAuthorityTest, AcquisitionFailureDoesNotSendControlCommand) -{ - controller_.setResponseCode(kRobotConfigLock, 40020); - controller_.clearRecords(); - - const auto result = agv_->setVelocity(AgvVelocity{0.1, 0.0, 0.0}); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::CommandFailed); - EXPECT_NE(result.message.find("acquire control authority failed"), std::string::npos); - EXPECT_NE(result.message.find("ret_code=40020"), std::string::npos); - const auto records = controller_.records(); - ASSERT_EQ(records.size(), 1U); - EXPECT_EQ(records[0].command, kRobotConfigLock); -} - -TEST_F(SeerRobokitControlAuthorityTest, EmergencyStopAcquisitionFailureDoesNotSendStopCommands) -{ - controller_.setResponseCode(kRobotConfigLock, 40020); - controller_.clearRecords(); - - const auto result = agv_->emergencyStop(); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::CommandFailed); - EXPECT_NE(result.message.find("acquire control authority failed"), std::string::npos); - EXPECT_NE(result.message.find("ret_code=40020"), std::string::npos); - const auto records = controller_.records(); - ASSERT_EQ(records.size(), 1U); - EXPECT_EQ(records[0].command, kRobotConfigLock); -} - -TEST_F(SeerRobokitControlAuthorityTest, EmergencyStopAttemptsBothStopsAndAggregatesFailures) -{ - controller_.setResponseCode(kRobotControlStop, 50001); - controller_.setResponseCode(kRobotTaskCancel, 50002); - controller_.clearRecords(); - - const auto result = agv_->emergencyStop(); - - EXPECT_FALSE(result.ok()); - EXPECT_NE(result.message.find("control stop"), std::string::npos); - EXPECT_NE(result.message.find("cancel navigation"), std::string::npos); - EXPECT_NE(result.message.find("ret_code=50001"), std::string::npos); - EXPECT_NE(result.message.find("ret_code=50002"), std::string::npos); - const auto records = controller_.records(); - ASSERT_EQ(records.size(), 3U); - EXPECT_EQ(records[0].command, kRobotConfigLock); - EXPECT_EQ(records[1].command, kRobotControlStop); - EXPECT_EQ(records[2].command, kRobotTaskCancel); -} - -TEST_F(SeerRobokitControlAuthorityTest, ClearFaultSends4009WithoutPayloadAfterAcquiringAuthority) -{ - controller_.clearRecords(); - - const auto result = agv_->clearFault(); - - ASSERT_TRUE(result.ok()) << result.message; - const auto records = controller_.records(); - ASSERT_EQ(records.size(), 2U); - EXPECT_EQ(records[0].command, kRobotConfigLock); - EXPECT_EQ(records[1].command, kRobotConfigClearFault); - EXPECT_TRUE(records[1].payload.empty()); -} - -TEST_F(SeerRobokitControlAuthorityTest, ClearFaultPreservesControllerFailure) -{ - controller_.setResponseCode(kRobotConfigClearFault, 44009); - controller_.clearRecords(); - - const auto result = agv_->clearFault(); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::CommandFailed); - EXPECT_NE(result.message.find("ret_code=44009"), std::string::npos); - EXPECT_NE( - result.message.find("simulated command failure"), - std::string::npos); - const auto records = controller_.records(); - ASSERT_EQ(records.size(), 2U); - EXPECT_EQ(records[0].command, kRobotConfigLock); - EXPECT_EQ(records[1].command, kRobotConfigClearFault); -} - -TEST_F(SeerRobokitControlAuthorityTest, ReadOnlyMapDownloadDoesNotAcquireAuthority) -{ - controller_.clearRecords(); - std::string content; - - const auto result = agv_->downloadMap("map-1", content); - - ASSERT_TRUE(result.ok()) << result.message; - const auto records = controller_.records(); - ASSERT_EQ(records.size(), 1U); - EXPECT_EQ(records[0].command, kRobotConfigDownloadMap); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPoseUsesLegacyCompatibleFreeGoPayloadWithTypedMotionLimits) -{ - AgvMotionOptions options; - options.asynchronous = true; - options.max_speed = 0.6; - options.max_angular_speed = 0.7; - options.max_acceleration = 0.8; - options.max_angular_acceleration = 0.9; - options.reach_distance = 0.1; - options.reach_angle = 0.2; - controller_.clearRecords(); - - const auto result = agv_->navigateToPose( - math::Pose2d{1.0, 2.0, 0.5}, - options); - - ASSERT_TRUE(result.ok()) << result.message; - const auto records = controller_.records(); - ASSERT_GE(records.size(), 4U); - EXPECT_EQ(records[0].command, kRobotConfigLock); - EXPECT_EQ(records[1].command, kRobotTaskGoTarget); - for (std::size_t index = 2; index < records.size(); ++index) { - EXPECT_EQ(records[index].command, kRobotStatusTaskPackage); - } - - const auto payload = parsePayload(records[1]); - EXPECT_EQ(payloadValue(payload, "source_id").asString(), "SELF_POSITION"); - EXPECT_EQ(payloadValue(payload, "id").asString(), ""); - EXPECT_FALSE(payloadValue(payload, "task_id").asString().empty()); - const auto& free_go = payloadValue(payload, "freeGo"); - EXPECT_TRUE(payloadValue(free_go, "x").isNumeric()); - EXPECT_TRUE(payloadValue(free_go, "y").isNumeric()); - EXPECT_TRUE(payloadValue(free_go, "theta").isNumeric()); - EXPECT_DOUBLE_EQ(payloadValue(free_go, "x").asDouble(), 1.0); - EXPECT_DOUBLE_EQ(payloadValue(free_go, "y").asDouble(), 2.0); - EXPECT_DOUBLE_EQ(payloadValue(free_go, "theta").asDouble(), 0.5); - EXPECT_DOUBLE_EQ(payloadValue(payload, "max_speed").asDouble(), 0.6); - EXPECT_DOUBLE_EQ(payloadValue(payload, "max_wspeed").asDouble(), 0.7); - EXPECT_DOUBLE_EQ(payloadValue(payload, "max_acc").asDouble(), 0.8); - EXPECT_DOUBLE_EQ(payloadValue(payload, "max_wacc").asDouble(), 0.9); - EXPECT_DOUBLE_EQ(payloadValue(payload, "reach_dist").asDouble(), 0.1); - EXPECT_DOUBLE_EQ(payloadValue(payload, "reach_angle").asDouble(), 0.2); - EXPECT_EQ( - payloadValue(payload, "skill_name").asString(), - "GotoSpecifiedPose"); - EXPECT_FALSE(payloadHas(payload, "x")); - EXPECT_FALSE(payloadHas(payload, "y")); - EXPECT_FALSE(payloadHas(payload, "angle")); - EXPECT_FALSE(payloadHas(payload, "jack_height")); - - const auto status_payload = parsePayload(records[2]); - const auto& requested_task_ids = payloadValue(status_payload, "task_ids"); - ASSERT_TRUE(requested_task_ids.isArray()); - ASSERT_EQ(requested_task_ids.size(), 1U); - ASSERT_TRUE(requested_task_ids[0].isString()); - EXPECT_EQ( - requested_task_ids[0].asString(), - payloadValue(payload, "task_id").asString()); - const auto second_status_payload = parsePayload(records.back()); - const auto& second_requested_task_ids = - payloadValue(second_status_payload, "task_ids"); - ASSERT_TRUE(second_requested_task_ids.isArray()); - ASSERT_EQ(second_requested_task_ids.size(), 1U); - EXPECT_EQ( - second_requested_task_ids[0].asString(), - payloadValue(payload, "task_id").asString()); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPoseUsesExplicitTaskIdAsUniquePrefixAndWhitelistsAdapterFields) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":1}]}})"); - AgvAdapterParams adapter_params; - adapter_params.values.emplace("source_id", "SELF_POSITION"); - adapter_params.values.emplace("target_id", "SELF_POSITION"); - adapter_params.values.emplace("task_id", "pose-task"); - adapter_params.values.emplace("skill_name", "GotoSpecifiedPose"); - adapter_params.values.emplace("operation", "JackHeight"); - adapter_params.values.emplace("jack_height", "0.5"); - adapter_params.values.emplace("script_name", "unsafe-script"); - adapter_params.values.emplace("unknown_field", "unsafe-value"); - controller_.clearRecords(); - - const auto result = agv_->navigateToPose( - math::Pose2d{0.0, 0.0, 0.5}, - asynchronousMotionOptions(), - adapter_params); - - ASSERT_TRUE(result.ok()) << result.message; - const auto records = controller_.records(); - ASSERT_GE(records.size(), 4U); - EXPECT_EQ(records[0].command, kRobotConfigLock); - EXPECT_EQ(records[1].command, kRobotTaskGoTarget); - for (std::size_t index = 2; index < records.size(); ++index) { - EXPECT_EQ(records[index].command, kRobotStatusTaskPackage); - } - - const auto payload = parsePayload(records[1]); - const std::string first_task_id = - payloadValue(payload, "task_id").asString(); - EXPECT_EQ(payloadValue(payload, "source_id").asString(), "SELF_POSITION"); - EXPECT_EQ(payloadValue(payload, "id").asString(), ""); - EXPECT_EQ( - first_task_id.find("pose-task_pose_"), - 0U); - EXPECT_EQ(payloadValue(payload, "skill_name").asString(), "GotoSpecifiedPose"); - const auto& free_go = payloadValue(payload, "freeGo"); - EXPECT_DOUBLE_EQ(payloadValue(free_go, "x").asDouble(), 0.0); - EXPECT_DOUBLE_EQ(payloadValue(free_go, "y").asDouble(), 0.0); - EXPECT_DOUBLE_EQ(payloadValue(free_go, "theta").asDouble(), 0.5); - EXPECT_FALSE(payloadHas(payload, "operation")); - EXPECT_FALSE(payloadHas(payload, "jack_height")); - EXPECT_FALSE(payloadHas(payload, "script_name")); - EXPECT_FALSE(payloadHas(payload, "unknown_field")); - - controller_.clearRecords(); - const auto second_result = agv_->navigateToPose( - math::Pose2d{0.0, 0.0, 0.5}, - asynchronousMotionOptions(), - adapter_params); - ASSERT_TRUE(second_result.ok()) << second_result.message; - const auto second_records = controller_.records(); - ASSERT_GE(second_records.size(), 2U); - const auto second_payload = parsePayload(second_records[1]); - const std::string second_task_id = - payloadValue(second_payload, "task_id").asString(); - EXPECT_EQ(second_task_id.find("pose-task_pose_"), 0U); - EXPECT_NE(first_task_id, second_task_id); -} - -TEST_F(SeerRobokitControlAuthorityTest, NavigateToPoseRejectsUnsafeFallbackStationAndSkill) -{ - AgvAdapterParams adapter_params; - adapter_params.values.emplace("source_id", "station-0"); - controller_.clearRecords(); - - auto result = agv_->navigateToPose( - math::Pose2d{1.0, 2.0, 0.5}, - {}, - adapter_params); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::InvalidArgument); - EXPECT_NE(result.message.find("source_id must be SELF_POSITION"), std::string::npos); - EXPECT_TRUE(controller_.records().empty()); - - adapter_params.values.clear(); - adapter_params.values.emplace("target_id", "station-1"); - controller_.clearRecords(); - - result = agv_->navigateToPose( - math::Pose2d{1.0, 2.0, 0.5}, - {}, - adapter_params); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::InvalidArgument); - EXPECT_NE(result.message.find("target_id must be empty"), std::string::npos); - EXPECT_TRUE(controller_.records().empty()); - - adapter_params.values.clear(); - adapter_params.values.emplace("skill_name", "unsafe-custom-skill"); - controller_.clearRecords(); - - result = agv_->navigateToPose( - math::Pose2d{1.0, 2.0, 0.5}, - {}, - adapter_params); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::InvalidArgument); - EXPECT_NE(result.message.find("skill_name must be GotoSpecifiedPose"), std::string::npos); - EXPECT_TRUE(controller_.records().empty()); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - MotionCommandsRejectNonFiniteNumericInputsBeforeAcquiringAuthority) -{ - const double nan = std::numeric_limits::quiet_NaN(); - const double infinity = std::numeric_limits::infinity(); - - controller_.clearRecords(); - auto result = agv_->navigateToPose(math::Pose2d{nan, 0.0, 0.0}, asynchronousMotionOptions()); - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::InvalidArgument); - EXPECT_NE(result.message.find("pose"), std::string::npos); - EXPECT_TRUE(controller_.records().empty()); - - AgvMotionOptions pose_options; - pose_options.reach_distance = infinity; - controller_.clearRecords(); - result = agv_->navigateToPose( - math::Pose2d{0.0, 0.0, 0.0}, - pose_options); - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::InvalidArgument); - EXPECT_NE(result.message.find("reach_distance"), std::string::npos); - EXPECT_TRUE(controller_.records().empty()); - - AgvMotionOptions station_options; - station_options.max_acceleration = nan; - controller_.clearRecords(); - result = agv_->navigateToStation("station-1", station_options); - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::InvalidArgument); - EXPECT_NE(result.message.find("max_acceleration"), std::string::npos); - EXPECT_TRUE(controller_.records().empty()); - - AgvMotionOptions negative_options; - negative_options.max_speed = -0.1; - controller_.clearRecords(); - result = agv_->navigateToPose( - math::Pose2d{0.0, 0.0, 0.0}, - negative_options); - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::InvalidArgument); - EXPECT_NE(result.message.find("non-negative"), std::string::npos); - EXPECT_TRUE(controller_.records().empty()); - - AgvAdapterParams invalid_adapter; - invalid_adapter.values.emplace("jack_height", "inf"); - controller_.clearRecords(); - result = agv_->navigateToStation( - "station-1", - {}, - invalid_adapter); - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::InvalidArgument); - EXPECT_NE(result.message.find("jack_height"), std::string::npos); - EXPECT_TRUE(controller_.records().empty()); - - controller_.clearRecords(); - result = agv_->setVelocity(AgvVelocity{0.0, infinity, 0.0}); - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::InvalidArgument); - EXPECT_NE(result.message.find("velocity"), std::string::npos); - EXPECT_TRUE(controller_.records().empty()); -} - -TEST_F(SeerRobokitControlAuthorityTest, NavigateToPoseIgnoresUncorrelatedStatusUntilPoseTaskAppears) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"old-pose-task","status":2,"type":1}]}})"); - controller_.queueResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":1}]}})"); - controller_.clearRecords(); - - const auto result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - - ASSERT_TRUE(result.ok()) << result.message; - const auto records = controller_.records(); - ASSERT_GE(records.size(), 5U); - EXPECT_EQ(records[0].command, kRobotConfigLock); - EXPECT_EQ(records[1].command, kRobotTaskGoTarget); - for (std::size_t index = 2; index < records.size(); ++index) { - EXPECT_EQ(records[index].command, kRobotStatusTaskPackage); - } -} - -TEST_F(SeerRobokitControlAuthorityTest, NavigateToPoseWaitsForStableRunningAfterWaiting) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":1,"type":1}]}})"); - controller_.queueResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":1}]}})"); - controller_.clearRecords(); - - const auto result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - - ASSERT_TRUE(result.ok()) << result.message; - const auto records = controller_.records(); - ASSERT_GE(records.size(), 5U); - EXPECT_EQ(records[0].command, kRobotConfigLock); - EXPECT_EQ(records[1].command, kRobotTaskGoTarget); - for (std::size_t index = 2; index < records.size(); ++index) { - EXPECT_EQ(records[index].command, kRobotStatusTaskPackage); - } -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPoseDoesNotReturnSuccessBeforeLateRunningFaultPush) -{ - controller_.clearRecords(); - AgvResult result = AgvResult::success(); - - std::thread pose_thread([this, &result]() { - result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - }); - - bool status_query_observed = false; - for (int attempt = 0; attempt < 200; ++attempt) { - const auto records = controller_.records(); - status_query_observed = std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }); - if (status_query_observed) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_TRUE(status_query_observed); - - Json::Value fault_push(Json::objectValue); - Json::Value errors(Json::arrayValue); - errors.append("E_RUNNING_31: safety controller rejected free navigation"); - *fault_push.demand("errors", "errors" + std::strlen("errors")) = errors; - SeerRobokitAgvTestPeer::cacheRuntimeState(*agv_, fault_push); - pose_thread.join(); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::Fault); - EXPECT_NE(result.message.find("E_RUNNING_31"), std::string::npos); - EXPECT_NE(result.message.find("Running state"), std::string::npos); - EXPECT_NE( - result.message.find("do not retry automatically"), - std::string::npos); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPoseFailsIfFaultPushChannelInvalidatesDuringStartConfirmation) -{ - controller_.clearRecords(); - AgvResult result = AgvResult::success(); - - std::thread pose_thread([this, &result]() { - result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - }); - - bool status_query_observed = false; - for (int attempt = 0; attempt < 200; ++attempt) { - const auto records = controller_.records(); - status_query_observed = std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }); - if (status_query_observed) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_TRUE(status_query_observed); - - SeerRobokitAgvTestPeer::setFaultStateUnknown(*agv_); - pose_thread.join(); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::Fault); - EXPECT_NE( - result.message.find("fault monitoring became unavailable"), - std::string::npos); - EXPECT_NE( - result.message.find("push channel changed or was invalidated"), - std::string::npos); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPoseRejectsCompletedTargetWhenLateControllerFaultArrives) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusLoc, - R"({"ret_code":0,"x":1.0,"y":2.0,"angle":0.5})"); - controller_.clearRecords(); - AgvResult result = AgvResult::success(); - - std::thread pose_thread([this, &result]() { - result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - }); - - bool status_query_observed = false; - for (int attempt = 0; attempt < 200; ++attempt) { - const auto records = controller_.records(); - status_query_observed = std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }); - if (status_query_observed) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_TRUE(status_query_observed); - - Json::Value fault_push(Json::objectValue); - Json::Value errors(Json::arrayValue); - errors.append("E_COMPLETED_45: controller rejected completed pose"); - *fault_push.demand("errors", "errors" + std::strlen("errors")) = errors; - *fault_push.demand("fatals", "fatals" + std::strlen("fatals")) = - Json::Value(Json::arrayValue); - SeerRobokitAgvTestPeer::cacheRuntimeState(*agv_, fault_push); - pose_thread.join(); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::Fault); - EXPECT_NE(result.message.find("reported Completed"), std::string::npos); - EXPECT_NE(result.message.find("E_COMPLETED_45"), std::string::npos); - const auto records = controller_.records(); - EXPECT_FALSE(std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusLoc; - })); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPoseRejectsFaultArrivingDuringCompletedPoseVerification) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusLoc, - R"({"ret_code":0,"x":1.0,"y":2.0,"angle":0.5})"); - controller_.setResponseDelay( - kRobotStatusLoc, - std::chrono::milliseconds(300)); - controller_.clearRecords(); - AgvResult result = AgvResult::success(); - - std::thread pose_thread([this, &result]() { - result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - }); - - bool location_query_observed = false; - for (int attempt = 0; attempt < 700; ++attempt) { - const auto records = controller_.records(); - location_query_observed = std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusLoc; - }); - if (location_query_observed) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_TRUE(location_query_observed); - - Json::Value fault_push(Json::objectValue); - Json::Value errors(Json::arrayValue); - errors.append("E_POSE_VERIFY_46: fault during target verification"); - *fault_push.demand("errors", "errors" + std::strlen("errors")) = errors; - *fault_push.demand("fatals", "fatals" + std::strlen("fatals")) = - Json::Value(Json::arrayValue); - SeerRobokitAgvTestPeer::cacheRuntimeState(*agv_, fault_push); - pose_thread.join(); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::Fault); - EXPECT_NE(result.message.find("target verification"), std::string::npos); - EXPECT_NE(result.message.find("E_POSE_VERIFY_46"), std::string::npos); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPoseDoesNotMisattributeFaultFromCommandAwaitingAck) -{ - controller_.clearRecords(); - AgvResult pose_result = AgvResult::success(); - AgvResult station_result = AgvResult::success(); - - std::thread pose_thread([this, &pose_result]() { - pose_result = - agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - }); - - bool status_query_observed = false; - for (int attempt = 0; attempt < 200; ++attempt) { - const auto records = controller_.records(); - status_query_observed = std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }); - if (status_query_observed) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_TRUE(status_query_observed); - - controller_.setResponseDelay( - kRobotTaskGoTarget, - std::chrono::milliseconds(300)); - std::thread station_thread([this, &station_result]() { - station_result = agv_->navigateToStation("station-1", asynchronousMotionOptions()); - }); - - bool station_command_observed = false; - for (int attempt = 0; attempt < 500; ++attempt) { - const auto records = controller_.records(); - const auto go_target_count = std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskGoTarget; - }); - station_command_observed = go_target_count >= 2; - if (station_command_observed) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_TRUE(station_command_observed); - - Json::Value fault_push(Json::objectValue); - Json::Value errors(Json::arrayValue); - errors.append("E_STATION_ACK_18: fault from concurrent station command"); - *fault_push.demand("errors", "errors" + std::strlen("errors")) = errors; - SeerRobokitAgvTestPeer::cacheRuntimeState(*agv_, fault_push); - - pose_thread.join(); - station_thread.join(); - - EXPECT_FALSE(pose_result.ok()); - EXPECT_EQ(pose_result.code, AgvErrorCode::Fault) - << pose_result.message; - EXPECT_NE( - pose_result.message.find("another control command attempt"), - std::string::npos); - EXPECT_NE( - pose_result.message.find("cannot be attributed"), - std::string::npos); - EXPECT_NE( - pose_result.message.find("E_STATION_ACK_18"), - std::string::npos); - ASSERT_TRUE(station_result.ok()) << station_result.message; -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPoseDoesNotMisattributeFaultObservedAfterAnotherCommandAck) -{ - controller_.clearRecords(); - AgvResult pose_result = AgvResult::success(); - - std::thread pose_thread([this, &pose_result]() { - pose_result = - agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - }); - - bool status_query_observed = false; - for (int attempt = 0; attempt < 200; ++attempt) { - const auto records = controller_.records(); - status_query_observed = std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }); - if (status_query_observed) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_TRUE(status_query_observed); - - controller_.setResponseCode(kRobotTaskGoTarget, 4188); - const auto station_result = agv_->navigateToStation("station-1", asynchronousMotionOptions()); - EXPECT_FALSE(station_result.ok()); - EXPECT_NE(station_result.message.find("ret_code=4188"), std::string::npos); - - Json::Value fault_push(Json::objectValue); - Json::Value errors(Json::arrayValue); - errors.append("E_AFTER_ACK_19: delayed station command alarm"); - *fault_push.demand("errors", "errors" + std::strlen("errors")) = errors; - *fault_push.demand("fatals", "fatals" + std::strlen("fatals")) = - Json::Value(Json::arrayValue); - SeerRobokitAgvTestPeer::cacheRuntimeState(*agv_, fault_push); - pose_thread.join(); - - EXPECT_FALSE(pose_result.ok()); - EXPECT_EQ(pose_result.code, AgvErrorCode::Fault); - EXPECT_NE( - pose_result.message.find("another control command attempt"), - std::string::npos); - EXPECT_NE( - pose_result.message.find("cannot be attributed"), - std::string::npos); - EXPECT_NE(pose_result.message.find("E_AFTER_ACK_19"), std::string::npos); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - PauseDuringPoseCommandAckPreservesPublishedTaskContext) -{ - controller_.setResponseDelay( - kRobotTaskGoTarget, - std::chrono::milliseconds(300)); - controller_.clearRecords(); - AgvResult pose_result = AgvResult::success(); - AgvResult pause_result = AgvResult::failure( - AgvErrorCode::CommandFailed, - "pause not called"); - - std::thread pose_thread([this, &pose_result]() { - pose_result = - agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - }); - - bool pose_command_observed = false; - for (int attempt = 0; attempt < 200; ++attempt) { - const auto records = controller_.records(); - pose_command_observed = std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskGoTarget; - }); - if (pose_command_observed) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_TRUE(pose_command_observed); - - std::thread pause_thread([this, &pause_result]() { - pause_result = agv_->pauseNavigation(); - }); - pause_thread.join(); - pose_thread.join(); - - ASSERT_TRUE(pause_result.ok()) << pause_result.message; - EXPECT_FALSE(pose_result.ok()); - EXPECT_NE(pose_result.message.find("superseded"), std::string::npos); - EXPECT_TRUE(SeerRobokitAgvTestPeer::hasTrackedPoseTask(*agv_)); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPoseReturnsAcceptedWhenMatchingTaskRemainsQueued) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"info":"queued","task_status_list":[{"task_id":"${TASK_ID}","status":1,"type":1}]}})"); - controller_.clearRecords(); - - const auto result = - agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - - ASSERT_TRUE(result.ok()) << result.message; - const auto records = controller_.records(); - const auto status_query_count = std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }); - EXPECT_GT(status_query_count, 2); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPoseReturnsControllerFaultWhenQueuedTaskRaisesAlarm) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"info":"queued","task_status_list":[{"task_id":"${TASK_ID}","status":1,"type":1}]}})"); - controller_.clearRecords(); - AgvResult result = AgvResult::success(); - - std::thread pose_thread([this, &result]() { - result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - }); - - bool status_query_observed = false; - for (int attempt = 0; attempt < 200; ++attempt) { - const auto records = controller_.records(); - status_query_observed = std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }); - if (status_query_observed) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_TRUE(status_query_observed); - - Json::Value fault_push(Json::objectValue); - Json::Value errors(Json::arrayValue); - errors.append("E_WAIT_19: safety interlock"); - *fault_push.demand("errors", "errors" + std::strlen("errors")) = errors; - SeerRobokitAgvTestPeer::cacheRuntimeState(*agv_, fault_push); - pose_thread.join(); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::Fault); - EXPECT_NE(result.message.find("remains active"), std::string::npos); - EXPECT_NE(result.message.find("E_WAIT_19"), std::string::npos); - EXPECT_NE(result.message.find("do not retry automatically"), std::string::npos); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPoseDoesNotReportAcceptedAfterMatchingTaskDisappears) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":1,"type":1}]}})"); - controller_.queueResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[]}})"); - controller_.clearRecords(); - - const auto result = - agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::TaskRejected); - EXPECT_NE( - result.message.find("not present in task_status_package"), - std::string::npos); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPoseDoesNotHangWhenRunningTaskDisappears) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":1}]}})"); - controller_.queueResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[]}})"); - controller_.clearRecords(); - - const auto started_at = std::chrono::steady_clock::now(); - const auto result = - agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - const auto elapsed = std::chrono::duration_cast( - std::chrono::steady_clock::now() - started_at); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::TaskRejected); - EXPECT_NE( - result.message.find("not present in task_status_package"), - std::string::npos); - EXPECT_LT(elapsed, std::chrono::seconds(3)); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPoseReturnsFailureAfterWaitingTransitionsToFailed) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":1,"type":1}]}})"); - controller_.queueResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"create_on":"2026-07-31T10:00:00Z","err_msg":"controller task failed","task_status_package":{"closest_target":"goal-7","source_name":"SELF_POSITION","target_name":"free-goal","percentage":0.0,"distance":1.4,"info":"planner rejected pose","task_status_list":[{"task_id":"${TASK_ID}","status":5,"type":1}]}})"); - controller_.clearRecords(); - - const auto result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::TaskFailed); - EXPECT_NE(result.message.find("planner rejected pose"), std::string::npos); - EXPECT_NE(result.message.find("task_status=5"), std::string::npos); - EXPECT_NE(result.message.find("status_query_ret_code=0"), std::string::npos); - EXPECT_NE(result.message.find("controller task failed"), std::string::npos); - EXPECT_NE(result.message.find("closest_target=goal-7"), std::string::npos); - EXPECT_NE(result.message.find("distance=1.400000"), std::string::npos); - const auto records = controller_.records(); - EXPECT_GE( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }), - 2); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 0); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPoseRejectsCompletedTaskWhenRequestedTargetWasNotReached) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusLoc, - R"({"ret_code":0,"x":0.0,"y":0.0,"angle":0.0})"); - controller_.clearRecords(); - - const auto result = agv_->navigateToPose(math::Pose2d{1.0, 0.0, 0.0}, asynchronousMotionOptions()); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::TaskRejected); - EXPECT_NE(result.message.find("target was not reached"), std::string::npos); - EXPECT_NE(result.message.find("distance_error=1"), std::string::npos); - const auto records = controller_.records(); - EXPECT_GE( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }), - 2); - EXPECT_GE( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusLoc; - }), - 1); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 0); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPoseAcceptsCompletedTaskOnlyWhenRequestedTargetWasReached) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusLoc, - R"({"ret_code":0,"x":1.0,"y":2.0,"angle":0.5})"); - controller_.clearRecords(); - - const auto result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - - ASSERT_TRUE(result.ok()) << result.message; - const auto records = controller_.records(); - ASSERT_EQ(records.size(), 4U); - EXPECT_EQ(records[2].command, kRobotStatusTaskPackage); - EXPECT_EQ(records[3].command, kRobotStatusLoc); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPoseDoesNotUseFaultOnlyPushAsAValidCompletedPose) -{ - Json::Value push_payload(Json::objectValue); - Json::Value errors(Json::arrayValue); - errors.append("controller fault without pose fields"); - *push_payload.demand("errors", "errors" + std::strlen("errors")) = errors; - SeerRobokitAgvTestPeer::cacheRuntimeState(*agv_, push_payload); - Json::Value cleared_push(Json::objectValue); - *cleared_push.demand("errors", "errors" + std::strlen("errors")) = - Json::Value(Json::arrayValue); - *cleared_push.demand("fatals", "fatals" + std::strlen("fatals")) = - Json::Value(Json::arrayValue); - SeerRobokitAgvTestPeer::cacheRuntimeState(*agv_, cleared_push); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusLoc, - R"({"ret_code":0,"err_msg":""})"); - controller_.clearRecords(); - - const auto result = agv_->navigateToPose(math::Pose2d{0.0, 0.0, 0.0}, asynchronousMotionOptions()); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::TaskRejected); - EXPECT_NE( - result.message.find("target pose could not be verified"), - std::string::npos); - EXPECT_NE( - result.message.find("did not contain numeric x/y/angle"), - std::string::npos); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPoseRejectsCompletedTaskWithNonNumericControllerPose) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusLoc, - R"({"ret_code":0,"x":null,"y":false,"angle":"0.0"})"); - controller_.clearRecords(); - - const auto result = agv_->navigateToPose(math::Pose2d{0.0, 0.0, 0.0}, asynchronousMotionOptions()); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::TaskRejected); - EXPECT_NE( - result.message.find("did not contain numeric x/y/angle"), - std::string::npos); -} - -TEST_F(SeerRobokitControlAuthorityTest, NavigateToPoseReturnsAsynchronousControllerFailure) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"info":"planner rejected pose","task_status_list":[{"task_id":"${TASK_ID}","status":5,"type":1}]}})"); - controller_.clearRecords(); - - const auto result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::TaskFailed); - EXPECT_NE(result.message.find("planner rejected pose"), std::string::npos); - EXPECT_NE(result.message.find("task_status=5"), std::string::npos); - EXPECT_NE(result.message.find("task_type=1"), std::string::npos); -} - -TEST_F(SeerRobokitControlAuthorityTest, NavigateToPosePreservesSynchronousControllerCode) -{ - controller_.setResponseCode(kRobotTaskGoTarget, 43051); - controller_.clearRecords(); - - const auto result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::CommandFailed); - EXPECT_NE(result.message.find("ret_code=43051"), std::string::npos); - EXPECT_NE(result.message.find("err_msg=simulated command failure"), std::string::npos); - const auto records = controller_.records(); - ASSERT_EQ(records.size(), 2U); - EXPECT_EQ(records[0].command, kRobotConfigLock); - EXPECT_EQ(records[1].command, kRobotTaskGoTarget); -} - -TEST_F(SeerRobokitControlAuthorityTest, NavigateToPosePreservesStatusQueryControllerCode) -{ - controller_.setResponseCode(kRobotStatusTaskPackage, 41110); - controller_.clearRecords(); - - const auto result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::CommandFailed); - EXPECT_NE(result.message.find("ret_code=41110"), std::string::npos); - EXPECT_NE(result.message.find("err_msg=simulated command failure"), std::string::npos); -} - -TEST_F(SeerRobokitControlAuthorityTest, NavigateToPoseRejectsWrongResponseCommand) -{ - controller_.setResponseCommand(kRobotTaskGoTarget, 13052); - controller_.clearRecords(); - - const auto result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::CommandFailed); - EXPECT_NE(result.message.find("expected=13051"), std::string::npos); - EXPECT_NE(result.message.find("actual=13052"), std::string::npos); - EXPECT_NE(result.message.find("channel closed"), std::string::npos); - EXPECT_NE(result.message.find("controller outcome is unknown"), std::string::npos); - const auto records = controller_.records(); - ASSERT_EQ(records.size(), 2U); - EXPECT_EQ(records[1].command, kRobotTaskGoTarget); -} - -TEST_F(SeerRobokitControlAuthorityTest, NavigateToPoseRejectsMissingControllerCode) -{ - controller_.setResponsePayload( - kRobotTaskGoTarget, - R"({"err_msg":"missing acknowledgment code"})"); - controller_.clearRecords(); - - const auto result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::CommandFailed); - EXPECT_NE(result.message.find("missing a numeric ret_code"), std::string::npos); - EXPECT_NE(result.message.find("controller outcome is unknown"), std::string::npos); - const auto records = controller_.records(); - ASSERT_EQ(records.size(), 2U); - EXPECT_EQ(records[1].command, kRobotTaskGoTarget); -} - -TEST_F(SeerRobokitControlAuthorityTest, NavigateToPoseReportsPausedTaskExplicitly) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"info":"safety pause","task_status_list":[{"task_id":"${TASK_ID}","status":3,"type":1}]}})"); - controller_.clearRecords(); - - const auto result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::TaskRejected); - EXPECT_NE(result.message.find("established but is paused"), std::string::npos); - EXPECT_NE(result.message.find("safety pause"), std::string::npos); - EXPECT_NE(result.message.find("do not retry automatically"), std::string::npos); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPosePreservesControllerFaultWhenTaskImmediatelyPauses) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"info":"safety pause","task_status_list":[{"task_id":"${TASK_ID}","status":3,"type":1}]}})"); - controller_.clearRecords(); - AgvResult result = AgvResult::success(); - - std::thread pose_thread([this, &result]() { - result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - }); - - bool status_query_observed = false; - for (int attempt = 0; attempt < 200; ++attempt) { - const auto records = controller_.records(); - status_query_observed = std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }); - if (status_query_observed) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_TRUE(status_query_observed); - - Json::Value fault_push(Json::objectValue); - Json::Value errors(Json::arrayValue); - errors.append("E_PAUSED_55: safety controller paused failed task"); - *fault_push.demand("errors", "errors" + std::strlen("errors")) = errors; - *fault_push.demand("fatals", "fatals" + std::strlen("fatals")) = - Json::Value(Json::arrayValue); - SeerRobokitAgvTestPeer::cacheRuntimeState(*agv_, fault_push); - pose_thread.join(); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::Fault); - EXPECT_NE(result.message.find("paused"), std::string::npos); - EXPECT_NE(result.message.find("E_PAUSED_55"), std::string::npos); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPoseIncludesTaskCorrelatedRawControllerFaultDetail) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[]}})"); - controller_.clearRecords(); - AgvResult result = AgvResult::success(); - - std::thread pose_thread([this, &result]() { - result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - }); - - bool status_query_observed = false; - for (int attempt = 0; attempt < 200; ++attempt) { - const auto records = controller_.records(); - status_query_observed = std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }); - if (status_query_observed) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_TRUE(status_query_observed); - - Json::Value fault_push(Json::objectValue); - Json::Value errors(Json::arrayValue); - errors.append("E_NAV_42: planner alarm"); - *fault_push.demand("errors", "errors" + std::strlen("errors")) = errors; - SeerRobokitAgvTestPeer::cacheRuntimeState(*agv_, fault_push); - - Json::Value cleared_push(Json::objectValue); - *cleared_push.demand("errors", "errors" + std::strlen("errors")) = - Json::Value(Json::arrayValue); - *cleared_push.demand("fatals", "fatals" + std::strlen("fatals")) = - Json::Value(Json::arrayValue); - SeerRobokitAgvTestPeer::cacheRuntimeState(*agv_, cleared_push); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"info":"navigation failed","task_status_list":[{"task_id":"${TASK_ID}","status":5,"type":1}]}})"); - pose_thread.join(); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::TaskFailed); - EXPECT_NE(result.message.find("E_NAV_42"), std::string::npos); - EXPECT_NE(result.message.find("planner alarm"), std::string::npos); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPoseRejectsPreexistingControllerFaultWithoutSendingTask) -{ - Json::Value push_payload(Json::objectValue); - Json::Value errors(Json::arrayValue); - errors.append("OLD_FAULT_FROM_PREVIOUS_TASK"); - *push_payload.demand("errors", "errors" + std::strlen("errors")) = errors; - SeerRobokitAgvTestPeer::cacheRuntimeState(*agv_, push_payload); - controller_.clearRecords(); - const auto result = - agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::Fault); - EXPECT_NE( - result.message.find("OLD_FAULT_FROM_PREVIOUS_TASK"), - std::string::npos); - EXPECT_NE(result.message.find("was not sent"), std::string::npos); - const auto records = controller_.records(); - ASSERT_EQ(records.size(), 1U); - EXPECT_EQ(records[0].command, kRobotConfigLock); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPoseRejectsUnknownOrStaleFaultStateWithoutSendingTask) -{ - SeerRobokitAgvTestPeer::setFaultStateUnknown(*agv_); - controller_.clearRecords(); - - auto result = - agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::Fault); - EXPECT_NE( - result.message.find("no state push containing fatals/errors"), - std::string::npos); - auto records = controller_.records(); - ASSERT_EQ(records.size(), 1U); - EXPECT_EQ(records[0].command, kRobotConfigLock); - - SeerRobokitAgvTestPeer::setFaultStateAge( - *agv_, - std::chrono::seconds(3)); - controller_.clearRecords(); - - result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::Fault); - EXPECT_NE(result.message.find("state push is stale"), std::string::npos); - records = controller_.records(); - ASSERT_EQ(records.size(), 1U); - EXPECT_EQ(records[0].command, kRobotConfigLock); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPoseRejectsMalformedFaultStateWithoutSendingTask) -{ - Json::Value malformed_push(Json::objectValue); - *malformed_push.demand("errors", "errors" + std::strlen("errors")) = - Json::Value(); - *malformed_push.demand("fatals", "fatals" + std::strlen("fatals")) = - Json::Value(Json::arrayValue); - SeerRobokitAgvTestPeer::cacheRuntimeState(*agv_, malformed_push); - controller_.clearRecords(); - - const auto result = - agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::Fault); - EXPECT_NE( - result.message.find("incomplete or malformed"), - std::string::npos); - EXPECT_NE(result.message.find("errors=null"), std::string::npos) - << result.message; - const auto records = controller_.records(); - ASSERT_EQ(records.size(), 1U); - EXPECT_EQ(records[0].command, kRobotConfigLock); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToPoseDoesNotAttributeClearedFaultHistoryToNewTask) -{ - Json::Value fault_push(Json::objectValue); - Json::Value errors(Json::arrayValue); - errors.append("OLD_CLEARED_FAULT"); - *fault_push.demand("errors", "errors" + std::strlen("errors")) = errors; - SeerRobokitAgvTestPeer::cacheRuntimeState(*agv_, fault_push); - - Json::Value cleared_push(Json::objectValue); - *cleared_push.demand("errors", "errors" + std::strlen("errors")) = - Json::Value(Json::arrayValue); - *cleared_push.demand("fatals", "fatals" + std::strlen("fatals")) = - Json::Value(Json::arrayValue); - SeerRobokitAgvTestPeer::cacheRuntimeState(*agv_, cleared_push); - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"info":"new task failed","task_status_list":[{"task_id":"${TASK_ID}","status":5,"type":1}]}})"); - controller_.clearRecords(); - - const auto result = - agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::TaskFailed); - EXPECT_NE(result.message.find("new task failed"), std::string::npos); - EXPECT_EQ(result.message.find("OLD_CLEARED_FAULT"), std::string::npos); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - CancelDoesNotSupersedeAlreadyCompletedPoseDuringLocationVerification) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusLoc, - R"({"ret_code":0,"x":1.0,"y":2.0,"angle":0.5})"); - controller_.setResponseDelay( - kRobotStatusLoc, - std::chrono::milliseconds(300)); - controller_.clearRecords(); - AgvResult pose_result = AgvResult::success(); - - std::thread pose_thread([this, &pose_result]() { - pose_result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - }); - - bool location_query_observed = false; - for (int attempt = 0; attempt < 500; ++attempt) { - const auto records = controller_.records(); - location_query_observed = std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusLoc; - }); - if (location_query_observed) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_TRUE(location_query_observed); - - const auto cancel_result = agv_->cancelNavigation(); - pose_thread.join(); - - ASSERT_TRUE(cancel_result.ok()) << cancel_result.message; - ASSERT_TRUE(pose_result.ok()) << pose_result.message; - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }), - 0); -} - -TEST_F(SeerRobokitControlAuthorityTest, CancelSupersedesPoseStartConfirmation) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[]}})"); - controller_.clearRecords(); - AgvResult pose_result = AgvResult::success(); - - std::thread pose_thread([this, &pose_result]() { - pose_result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - }); - - bool status_query_observed = false; - for (int attempt = 0; attempt < 200; ++attempt) { - const auto records = controller_.records(); - status_query_observed = std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }); - if (status_query_observed) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - - const auto cancel_result = agv_->cancelNavigation(); - pose_thread.join(); - - EXPECT_TRUE(status_query_observed); - ASSERT_TRUE(cancel_result.ok()) << cancel_result.message; - EXPECT_FALSE(pose_result.ok()); - EXPECT_EQ(pose_result.code, AgvErrorCode::CommandFailed); - EXPECT_NE(pose_result.message.find("superseded"), std::string::npos); - EXPECT_NE(pose_result.message.find("state is unknown"), std::string::npos); -} - -TEST_F(SeerRobokitControlAuthorityTest, FailedCancelDoesNotSupersedePoseStartConfirmation) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[]}})"); - controller_.clearRecords(); - AgvResult pose_result = AgvResult::success(); - std::atomic_bool pose_finished{false}; - - std::thread pose_thread([this, &pose_result, &pose_finished]() { - pose_result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - pose_finished.store(true, std::memory_order_release); - }); - - bool status_query_observed = false; - for (int attempt = 0; attempt < 200; ++attempt) { - const auto records = controller_.records(); - status_query_observed = std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }); - if (status_query_observed) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_TRUE(status_query_observed); - - controller_.setResponseCode(kRobotConfigLock, 17); - const auto authority_failure = agv_->cancelNavigation(); - EXPECT_FALSE(authority_failure.ok()); - std::this_thread::sleep_for(std::chrono::milliseconds(75)); - EXPECT_FALSE(pose_finished.load(std::memory_order_acquire)); - - controller_.setResponseCode(kRobotConfigLock, 0); - controller_.setResponseCode(kRobotTaskCancel, 23); - const auto command_failure = agv_->cancelNavigation(); - EXPECT_FALSE(command_failure.ok()); - std::this_thread::sleep_for(std::chrono::milliseconds(75)); - EXPECT_FALSE(pose_finished.load(std::memory_order_acquire)); - - controller_.setResponseCode(kRobotTaskCancel, 0); - const auto successful_cancel = agv_->cancelNavigation(); - pose_thread.join(); - - ASSERT_TRUE(successful_cancel.ok()) << successful_cancel.message; - EXPECT_TRUE(pose_finished.load(std::memory_order_acquire)); - EXPECT_FALSE(pose_result.ok()); - EXPECT_EQ(pose_result.code, AgvErrorCode::CommandFailed); - EXPECT_NE(pose_result.message.find("superseded"), std::string::npos); - EXPECT_NE(pose_result.message.find("state is unknown"), std::string::npos); -} - -TEST_F(SeerRobokitControlAuthorityTest, IndeterminateCancelSupersedesPoseStartConfirmation) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[]}})"); - controller_.clearRecords(); - AgvResult pose_result = AgvResult::success(); - - std::thread pose_thread([this, &pose_result]() { - pose_result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - }); - - bool status_query_observed = false; - for (int attempt = 0; attempt < 200; ++attempt) { - const auto records = controller_.records(); - status_query_observed = std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }); - if (status_query_observed) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_TRUE(status_query_observed); - - controller_.setResponsePayload( - kRobotTaskCancel, - R"({"err_msg":"acknowledgment lost"})"); - const auto cancel_result = agv_->cancelNavigation(); - pose_thread.join(); - - EXPECT_FALSE(cancel_result.ok()); - EXPECT_NE(cancel_result.message.find("missing a numeric ret_code"), std::string::npos); - EXPECT_NE(cancel_result.message.find("controller outcome is unknown"), std::string::npos); - EXPECT_NE( - cancel_result.message.find("do not issue another motion command automatically"), - std::string::npos); - EXPECT_FALSE(pose_result.ok()); - EXPECT_EQ(pose_result.code, AgvErrorCode::CommandFailed); - EXPECT_NE(pose_result.message.find("state is unknown"), std::string::npos); -} - -TEST_F(SeerRobokitControlAuthorityTest, TimedOutChannelIsClosedBeforeSameCommandCanRetry) -{ - SeerRobokitAgvTestPeer::setNavigationReceiveTimeout( - *agv_, - std::chrono::milliseconds(50)); - controller_.setResponseDelay( - kRobotTaskCancel, - std::chrono::milliseconds(200)); - controller_.clearRecords(); - - const auto first_result = agv_->cancelNavigation(); - const auto second_result = agv_->cancelNavigation(); - - EXPECT_FALSE(first_result.ok()); - EXPECT_EQ(first_result.code, AgvErrorCode::Timeout); - EXPECT_NE(first_result.message.find("channel closed"), std::string::npos); - EXPECT_NE( - first_result.message.find("controller outcome is unknown"), - std::string::npos); - EXPECT_FALSE(second_result.ok()); - EXPECT_EQ(second_result.code, AgvErrorCode::NotConnected); - EXPECT_EQ( - second_result.message.find("controller outcome is unknown"), - std::string::npos); - - const auto records = controller_.records(); - const auto cancel_count = std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }); - EXPECT_EQ(cancel_count, 1); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigationWriteNotStartedDoesNotPublishFalseTracking) -{ - SeerRobokitAgvTestPeer::closeNavigationSocket(*agv_); - AgvMotionOptions options; - options.wait_timeout_ms = 500; - options.poll_interval_ms = 20; - controller_.clearRecords(); - - const auto result = agv_->navigateToStation( - "station-not-sent", - options); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::NotConnected); - EXPECT_EQ( - result.message.find("controller outcome is unknown"), - std::string::npos); - EXPECT_FALSE(SeerRobokitAgvTestPeer::hasTrackedNavigation( - *agv_, - AgvTaskType::NavigateToStation)); - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskGoTarget - || record.command == kRobotStatusTaskPackage - || record.command == kRobotTaskCancel; - }), - 0); -} - -TEST_F(SeerRobokitControlAuthorityTest, SlowTaskStatusDoesNotBlockEmergencyStop) -{ - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[]}})"); - controller_.setResponseDelay( - kRobotStatusTaskPackage, - std::chrono::milliseconds(300)); - controller_.clearRecords(); - AgvResult pose_result = AgvResult::success(); - - std::thread pose_thread([this, &pose_result]() { - pose_result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - }); - - bool status_query_observed = false; - for (int attempt = 0; attempt < 200; ++attempt) { - const auto records = controller_.records(); - status_query_observed = std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }); - if (status_query_observed) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - ASSERT_TRUE(status_query_observed); - - const auto start = std::chrono::steady_clock::now(); - const auto stop_result = agv_->emergencyStop(); - const auto elapsed = std::chrono::duration_cast( - std::chrono::steady_clock::now() - start); - pose_thread.join(); - - ASSERT_TRUE(stop_result.ok()) << stop_result.message; - EXPECT_LT(elapsed.count(), 150); - EXPECT_FALSE(pose_result.ok()); - EXPECT_EQ(pose_result.code, AgvErrorCode::CommandFailed); - EXPECT_NE(pose_result.message.find("state is unknown"), std::string::npos); - - const auto records = controller_.records(); - const auto control_stop = std::find_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotControlStop; - }); - const auto navigation_cancel = std::find_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskCancel; - }); - ASSERT_NE(control_stop, records.end()); - ASSERT_NE(navigation_cancel, records.end()); - EXPECT_LT(control_stop, navigation_cancel); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - SlowConditionalCancelPreflightDoesNotBlockOrFollowEmergencyStop) -{ - const auto path_result = agv_->followPath( - {AgvPathSegment{"station-1", "station-2"}}, - asynchronousMotionOptions()); - ASSERT_TRUE(path_result.ok()) << path_result.message; - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"task_status_list":[{"task_id":"${TASK_ID}","status":2,"type":3}]}})"); - controller_.setResponsePayload( - kRobotStatusAll2, - R"({"ret_code":0,"task_status":2,"task_type":3,"target_id":"station-2","blocked":false,"vx":0.05,"vy":0.0,"w":0.0,"fatals":[],"errors":[]})"); - controller_.setResponseDelay( - kRobotStatusTaskPackage, - std::chrono::milliseconds(300)); - controller_.clearRecords(); - AgvResult cancel_result; - - std::thread cancel_thread([this, &cancel_result]() { - cancel_result = agv_->cancelNavigation(); - }); - const bool cancel_preflight_started = waitForCommandCount( - kRobotStatusTaskPackage, - 1, - 1000); - const auto stop_started_at = std::chrono::steady_clock::now(); - const auto stop_result = agv_->emergencyStop(); - const auto stop_elapsed = std::chrono::duration_cast< - std::chrono::milliseconds>( - std::chrono::steady_clock::now() - stop_started_at); - cancel_thread.join(); - - EXPECT_TRUE(cancel_preflight_started); - ASSERT_TRUE(stop_result.ok()) << stop_result.message; - EXPECT_LT(stop_elapsed.count(), 200); - EXPECT_FALSE(cancel_result.ok()); - EXPECT_EQ(cancel_result.code, AgvErrorCode::TaskCanceled); - const auto records = controller_.records(); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotControlStop; - }), - 1); - EXPECT_EQ( - std::count_if( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotTaskClearTargetList; - }), - 1); -} - -TEST_F(SeerRobokitControlAuthorityTest, EmergencyStopInvalidatesPoseAfterFirstAcceptedStop) -{ - controller_.setResponseDelay( - kRobotStatusTaskPackage, - std::chrono::milliseconds(200)); - controller_.setResponseDelay( - kRobotTaskCancel, - std::chrono::milliseconds(400)); - controller_.clearRecords(); - AgvResult pose_result = AgvResult::success(); - AgvResult stop_result = AgvResult::success(); - std::atomic_bool pose_finished{false}; - std::atomic_bool stop_finished{false}; - - std::thread pose_thread([this, &pose_result, &pose_finished]() { - pose_result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - pose_finished.store(true, std::memory_order_release); - }); - - bool status_query_observed = false; - for (int attempt = 0; attempt < 200; ++attempt) { - const auto records = controller_.records(); - status_query_observed = std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }); - if (status_query_observed) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_TRUE(status_query_observed); - - std::thread stop_thread([this, &stop_result, &stop_finished]() { - stop_result = agv_->emergencyStop(); - stop_finished.store(true, std::memory_order_release); - }); - - bool control_stop_observed = false; - for (int attempt = 0; attempt < 200; ++attempt) { - const auto records = controller_.records(); - control_stop_observed = std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotControlStop; - }); - if (control_stop_observed) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_TRUE(control_stop_observed); - - for (int attempt = 0; attempt < 350; ++attempt) { - if (pose_finished.load(std::memory_order_acquire)) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - const bool pose_finished_before_navigation_cancel = - pose_finished.load(std::memory_order_acquire); - const bool stop_finished_before_pose_result = - stop_finished.load(std::memory_order_acquire); - stop_thread.join(); - pose_thread.join(); - EXPECT_TRUE(pose_finished_before_navigation_cancel); - EXPECT_FALSE(stop_finished_before_pose_result); - EXPECT_FALSE(pose_result.ok()); - EXPECT_EQ(pose_result.code, AgvErrorCode::CommandFailed); - EXPECT_NE(pose_result.message.find("state is unknown"), std::string::npos); - ASSERT_TRUE(stop_result.ok()) << stop_result.message; -} - -TEST_F(SeerRobokitControlAuthorityTest, NavigateToStationForwardsTypedMotionOptions) -{ - AgvMotionOptions options; - options.asynchronous = true; - options.max_speed = 0.4; - options.max_angular_speed = 0.5; - options.max_acceleration = 0.6; - options.max_angular_acceleration = 0.7; - AgvAdapterParams adapter_params; - adapter_params.values.emplace("id", "wrong-station"); - adapter_params.values.emplace("x", "99.0"); - adapter_params.values.emplace("freeGo", "invalid"); - adapter_params.values.emplace("max_speed", "not-a-number"); - adapter_params.values.emplace("reach_dist", "not-a-number"); - controller_.clearRecords(); - - const auto result = agv_->navigateToStation( - "station-1", - options, - adapter_params); - - ASSERT_TRUE(result.ok()) << result.message; - const auto records = controller_.records(); - ASSERT_EQ(records.size(), 2U); - EXPECT_EQ(records[0].command, kRobotConfigLock); - EXPECT_EQ(records[1].command, kRobotTaskGoTarget); - - const auto payload = parsePayload(records[1]); - EXPECT_EQ(payloadValue(payload, "source_id").asString(), "SELF_POSITION"); - EXPECT_EQ(payloadValue(payload, "id").asString(), "station-1"); - EXPECT_TRUE(payloadValue(payload, "max_speed").isNumeric()); - EXPECT_TRUE(payloadValue(payload, "max_wspeed").isNumeric()); - EXPECT_TRUE(payloadValue(payload, "max_acc").isNumeric()); - EXPECT_TRUE(payloadValue(payload, "max_wacc").isNumeric()); - EXPECT_DOUBLE_EQ(payloadValue(payload, "max_speed").asDouble(), 0.4); - EXPECT_DOUBLE_EQ(payloadValue(payload, "max_wspeed").asDouble(), 0.5); - EXPECT_DOUBLE_EQ(payloadValue(payload, "max_acc").asDouble(), 0.6); - EXPECT_DOUBLE_EQ(payloadValue(payload, "max_wacc").asDouble(), 0.7); - EXPECT_FALSE(payloadHas(payload, "x")); - EXPECT_FALSE(payloadHas(payload, "freeGo")); - EXPECT_FALSE(payloadHas(payload, "reach_dist")); - EXPECT_FALSE(payloadHas(payload, "jack_height")); - EXPECT_FALSE(payloadHas(payload, "use_pgv")); - EXPECT_FALSE(payloadHas(payload, "use_down_pgv")); - EXPECT_FALSE(payloadHas(payload, "pgv_adjust_dist")); - EXPECT_FALSE(payloadHas(payload, "pgv_adjust_cx")); - EXPECT_FALSE(payloadHas(payload, "pgv_adjust_cy")); - EXPECT_FALSE(payloadHas(payload, "pgv_x_adjust")); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToStationForwardsPgvAdjustmentUsingNativeJsonTypes) -{ - AgvMotionOptions options; - options.asynchronous = true; - AgvAdapterParams adapter_params; - adapter_params.values.emplace("source_id", "LM2"); - adapter_params.values.emplace("use_pgv", "true"); - adapter_params.values.emplace("pgv_adjust_dist", "0.3"); - adapter_params.values.emplace("pgv_adjust_cx", "-0.3"); - adapter_params.values.emplace("pgv_adjust_cy", "0"); - adapter_params.values.emplace("pgv_x_adjust", "1"); - adapter_params.values.emplace("use_down_pgv", "false"); - controller_.clearRecords(); - - const auto result = agv_->navigateToStation( - "AP1", - options, - adapter_params); - - ASSERT_TRUE(result.ok()) << result.message; - const auto records = controller_.records(); - ASSERT_EQ(records.size(), 2U); - EXPECT_EQ(records[0].command, kRobotConfigLock); - EXPECT_EQ(records[1].command, kRobotTaskGoTarget); - - const auto payload = parsePayload(records[1]); - EXPECT_EQ(payloadValue(payload, "source_id").asString(), "LM2"); - EXPECT_EQ(payloadValue(payload, "id").asString(), "AP1"); - EXPECT_TRUE(payloadValue(payload, "use_pgv").isBool()); - EXPECT_TRUE(payloadValue(payload, "use_pgv").asBool()); - EXPECT_TRUE(payloadValue(payload, "use_down_pgv").isBool()); - EXPECT_FALSE(payloadValue(payload, "use_down_pgv").asBool()); - EXPECT_TRUE(payloadValue(payload, "pgv_adjust_dist").isNumeric()); - EXPECT_TRUE(payloadValue(payload, "pgv_adjust_cx").isNumeric()); - EXPECT_TRUE(payloadValue(payload, "pgv_adjust_cy").isNumeric()); - EXPECT_TRUE(payloadValue(payload, "pgv_x_adjust").isNumeric()); - EXPECT_DOUBLE_EQ(payloadValue(payload, "pgv_adjust_dist").asDouble(), 0.3); - EXPECT_DOUBLE_EQ(payloadValue(payload, "pgv_adjust_cx").asDouble(), -0.3); - EXPECT_DOUBLE_EQ(payloadValue(payload, "pgv_adjust_cy").asDouble(), 0.0); - EXPECT_DOUBLE_EQ(payloadValue(payload, "pgv_x_adjust").asDouble(), 1.0); - EXPECT_FALSE(payloadHas(payload, "pgv_adjustuse_pgv_dist")); - EXPECT_FALSE(payloadHas(payload, "pgv_ajdust_cy")); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToStationNormalizesVendorDocumentPgvCyAlias) -{ - AgvMotionOptions options; - options.asynchronous = true; - AgvAdapterParams adapter_params; - adapter_params.values.emplace("use_pgv", "true"); - adapter_params.values.emplace("pgv_ajdust_cy", "-0.2"); - controller_.clearRecords(); - - const auto result = agv_->navigateToStation( - "AP1", - options, - adapter_params); - - ASSERT_TRUE(result.ok()) << result.message; - const auto records = controller_.records(); - ASSERT_EQ(records.size(), 2U); - const auto payload = parsePayload(records[1]); - EXPECT_TRUE(payloadValue(payload, "pgv_adjust_cy").isNumeric()); - EXPECT_DOUBLE_EQ(payloadValue(payload, "pgv_adjust_cy").asDouble(), -0.2); - EXPECT_FALSE(payloadHas(payload, "pgv_ajdust_cy")); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigateToStationRejectsInvalidPgvAdjustmentBeforeAcquiringAuthority) -{ - struct InvalidPgvCase { - const char* key; - const char* value; - const char* expected_detail; - }; - const InvalidPgvCase cases[] = { - {"use_pgv", "enabled", "must be a boolean string"}, - {"pgv_adjust_dist", "-0.1", "must be non-negative"}, - {"pgv_adjust_cx", "nan", "must be a complete finite number"}, - {"pgv_x_adjust", "0.5m", "must be a complete finite number"}, - {"pgv_ajdust_cy", "inf", "must be a complete finite number"}, - {"pgv_adjustuse_pgv_dist", "0.3", "vendor-document typo"}, - }; - - AgvMotionOptions options; - options.asynchronous = true; - for (const auto& test_case : cases) { - SCOPED_TRACE(test_case.key); - AgvAdapterParams adapter_params; - adapter_params.values.emplace(test_case.key, test_case.value); - controller_.clearRecords(); - - const auto result = agv_->navigateToStation( - "AP1", - options, - adapter_params); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::InvalidArgument); - EXPECT_NE( - result.message.find(test_case.expected_detail), - std::string::npos); - EXPECT_TRUE(controller_.records().empty()); - } - - AgvAdapterParams ambiguous_adapter_params; - ambiguous_adapter_params.values.emplace("pgv_adjust_cy", "0.1"); - ambiguous_adapter_params.values.emplace("pgv_ajdust_cy", "0.2"); - controller_.clearRecords(); - - const auto ambiguous_result = agv_->navigateToStation( - "AP1", - options, - ambiguous_adapter_params); - - EXPECT_FALSE(ambiguous_result.ok()); - EXPECT_EQ(ambiguous_result.code, AgvErrorCode::InvalidArgument); - EXPECT_NE( - ambiguous_result.message.find("must not both be set"), - std::string::npos); - EXPECT_TRUE(controller_.records().empty()); - - AgvAdapterParams mixed_action_adapter_params; - mixed_action_adapter_params.values.emplace("use_pgv", "true"); - mixed_action_adapter_params.values.emplace("operation", "JackHeight"); - mixed_action_adapter_params.values.emplace("jack_height", "0.5"); - controller_.clearRecords(); - - const auto mixed_action_result = agv_->navigateToStation( - "AP1", - options, - mixed_action_adapter_params); - - EXPECT_FALSE(mixed_action_result.ok()); - EXPECT_EQ(mixed_action_result.code, AgvErrorCode::InvalidArgument); - EXPECT_NE( - mixed_action_result.message.find( - "PGV adjustment must not be combined with adapter field"), - std::string::npos); - EXPECT_TRUE(controller_.records().empty()); -} - -TEST_F(SeerRobokitControlAuthorityTest, SetVelocityUsesOnlyDocumentedNumericFields) -{ - controller_.clearRecords(); - - const auto result = agv_->setVelocity(AgvVelocity{0.1, -0.2, 0.3}); - - ASSERT_TRUE(result.ok()) << result.message; - auto records = controller_.records(); - ASSERT_EQ(records.size(), 2U); - EXPECT_EQ(records[0].command, kRobotConfigLock); - EXPECT_EQ(records[1].command, kRobotControlMotion); - - auto payload = parsePayload(records[1]); - EXPECT_TRUE(payloadValue(payload, "vx").isNumeric()); - EXPECT_TRUE(payloadValue(payload, "vy").isNumeric()); - EXPECT_TRUE(payloadValue(payload, "w").isNumeric()); - EXPECT_DOUBLE_EQ(payloadValue(payload, "vx").asDouble(), 0.1); - EXPECT_DOUBLE_EQ(payloadValue(payload, "vy").asDouble(), -0.2); - EXPECT_DOUBLE_EQ(payloadValue(payload, "w").asDouble(), 0.3); - EXPECT_FALSE(payloadHas(payload, "duration")); - - controller_.clearRecords(); - const auto stop_result = agv_->stopVelocityControl(); - - ASSERT_TRUE(stop_result.ok()) << stop_result.message; - records = controller_.records(); - ASSERT_EQ(records.size(), 2U); - EXPECT_EQ(records[1].command, kRobotControlMotion); - payload = parsePayload(records[1]); - EXPECT_TRUE(payloadValue(payload, "vx").isNumeric()); - EXPECT_TRUE(payloadValue(payload, "vy").isNumeric()); - EXPECT_TRUE(payloadValue(payload, "w").isNumeric()); - EXPECT_DOUBLE_EQ(payloadValue(payload, "vx").asDouble(), 0.0); - EXPECT_DOUBLE_EQ(payloadValue(payload, "vy").asDouble(), 0.0); - EXPECT_DOUBLE_EQ(payloadValue(payload, "w").asDouble(), 0.0); - EXPECT_FALSE(payloadHas(payload, "duration")); -} - -TEST_F(SeerRobokitControlAuthorityTest, ControllerErrorCodeIsPreservedInResultMessage) -{ - controller_.setResponseCode(kRobotControlMotion, 41200); - controller_.clearRecords(); - - const auto result = agv_->setVelocity(AgvVelocity{0.1, 0.0, 0.0}); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, AgvErrorCode::CommandFailed); - EXPECT_NE(result.message.find("ret_code=41200"), std::string::npos); - EXPECT_NE(result.message.find("err_msg=simulated command failure"), std::string::npos); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - MapModeCommandsSupersedeTrackedFreeNavigation) -{ - auto result = - agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - ASSERT_TRUE(result.ok()) << result.message; - ASSERT_TRUE(SeerRobokitAgvTestPeer::hasTrackedPoseTask(*agv_)); - - result = agv_->switchMap("map-1"); - ASSERT_TRUE(result.ok()) << result.message; - EXPECT_FALSE(SeerRobokitAgvTestPeer::hasTrackedPoseTask(*agv_)); - - result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - ASSERT_TRUE(result.ok()) << result.message; - ASSERT_TRUE(SeerRobokitAgvTestPeer::hasTrackedPoseTask(*agv_)); - - result = agv_->startMapping(); - ASSERT_TRUE(result.ok()) << result.message; - EXPECT_FALSE(SeerRobokitAgvTestPeer::hasTrackedPoseTask(*agv_)); - - result = agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - ASSERT_TRUE(result.ok()) << result.message; - ASSERT_TRUE(SeerRobokitAgvTestPeer::hasTrackedPoseTask(*agv_)); - - result = agv_->stopMapping(); - ASSERT_TRUE(result.ok()) << result.message; - EXPECT_FALSE(SeerRobokitAgvTestPeer::hasTrackedPoseTask(*agv_)); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - PauseResumeAndStopVelocityPreserveTrackedFreeNavigation) -{ - auto result = - agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - ASSERT_TRUE(result.ok()) << result.message; - ASSERT_TRUE(SeerRobokitAgvTestPeer::hasTrackedPoseTask(*agv_)); - - result = agv_->pauseNavigation(); - ASSERT_TRUE(result.ok()) << result.message; - EXPECT_TRUE(SeerRobokitAgvTestPeer::hasTrackedPoseTask(*agv_)); - - result = agv_->resumeNavigation(); - ASSERT_TRUE(result.ok()) << result.message; - EXPECT_TRUE(SeerRobokitAgvTestPeer::hasTrackedPoseTask(*agv_)); - - result = agv_->stopVelocityControl(); - ASSERT_TRUE(result.ok()) << result.message; - EXPECT_TRUE(SeerRobokitAgvTestPeer::hasTrackedPoseTask(*agv_)); - - controller_.clearRecords(); - const auto status = agv_->navigationStatus(); - EXPECT_EQ(status.state, AgvTaskState::Running); - EXPECT_EQ(status.type, AgvTaskType::NavigateToPose); - const auto records = controller_.records(); - ASSERT_EQ(records.size(), 1U); - EXPECT_EQ(records[0].command, kRobotStatusTaskPackage); -} - -TEST_F(SeerRobokitControlAuthorityTest, NavigationStatusQueriesTrackedPoseTaskPackage) -{ - AgvAdapterParams adapter_params; - adapter_params.values.emplace("task_id", "pose-task-current"); - const auto navigate_result = agv_->navigateToPose( - math::Pose2d{1.0, 2.0, 0.5}, - asynchronousMotionOptions(), - adapter_params); - ASSERT_TRUE(navigate_result.ok()) << navigate_result.message; - const auto navigate_records = controller_.records(); - ASSERT_GE(navigate_records.size(), 2U); - const auto navigate_payload = parsePayload(navigate_records[1]); - const std::string generated_task_id = - payloadValue(navigate_payload, "task_id").asString(); - ASSERT_FALSE(generated_task_id.empty()); - - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"create_on":"2026-07-31T10:00:01Z","err_msg":"","task_status_package":{"percentage":42.5,"distance":0.7,"info":"operator pause","task_status_list":[{"task_id":"${TASK_ID}","status":3,"type":1}]}})"); - controller_.clearRecords(); - - const auto status = agv_->navigationStatus(); - - EXPECT_EQ(status.state, AgvTaskState::Paused); - EXPECT_EQ(status.type, AgvTaskType::NavigateToPose); - EXPECT_DOUBLE_EQ(status.progress, 42.5); - EXPECT_NE(status.message.find("task_id=" + generated_task_id), std::string::npos); - EXPECT_NE(status.message.find("operator pause"), std::string::npos); - EXPECT_NE(status.message.find("create_on=2026-07-31T10:00:01Z"), std::string::npos); - const auto records = controller_.records(); - ASSERT_EQ(records.size(), 1U); - EXPECT_EQ(records[0].command, kRobotStatusTaskPackage); - const auto payload = parsePayload(records[0]); - const auto& task_ids = payloadValue(payload, "task_ids"); - ASSERT_TRUE(task_ids.isArray()); - ASSERT_EQ(task_ids.size(), 1U); - EXPECT_EQ(task_ids[0].asString(), generated_task_id); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigationStatusMapsControllerTaskStatusSevenToFailed) -{ - const auto navigate_result = agv_->navigateToPose( - math::Pose2d{1.0, 2.0, 0.5}, - asynchronousMotionOptions()); - ASSERT_TRUE(navigate_result.ok()) << navigate_result.message; - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"info":"controller terminated tracked pose","task_status_list":[{"task_id":"${TASK_ID}","status":7,"type":1}]}})"); - controller_.clearRecords(); - - const auto status = agv_->navigationStatus(); - - EXPECT_EQ(status.state, AgvTaskState::Failed); - EXPECT_EQ(status.type, AgvTaskType::NavigateToPose); - EXPECT_NE(status.message.find("controller terminated tracked pose"), std::string::npos); - EXPECT_NE(status.message.find("task_status=7"), std::string::npos); - EXPECT_FALSE(SeerRobokitAgvTestPeer::hasTrackedPoseTask(*agv_)); - const auto records = controller_.records(); - ASSERT_EQ(records.size(), 1U); - EXPECT_EQ(records[0].command, kRobotStatusTaskPackage); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigationStatusReturnsControllerFaultWhileTaskStillReportsRunning) -{ - const auto navigate_result = - agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - ASSERT_TRUE(navigate_result.ok()) << navigate_result.message; - - Json::Value fault_push(Json::objectValue); - Json::Value errors(Json::arrayValue); - errors.append("E_RUNNING_STATUS_52: collision input active"); - *fault_push.demand("errors", "errors" + std::strlen("errors")) = errors; - *fault_push.demand("fatals", "fatals" + std::strlen("fatals")) = - Json::Value(Json::arrayValue); - SeerRobokitAgvTestPeer::cacheRuntimeState(*agv_, fault_push); - controller_.clearRecords(); - - const auto status = agv_->navigationStatus(); - - EXPECT_EQ(status.state, AgvTaskState::Failed); - EXPECT_EQ(status.type, AgvTaskType::NavigateToPose); - EXPECT_NE(status.message.find("controller_task_state=2"), std::string::npos); - EXPECT_NE(status.message.find("E_RUNNING_STATUS_52"), std::string::npos); - EXPECT_TRUE(SeerRobokitAgvTestPeer::hasTrackedPoseTask(*agv_)); - const auto records = controller_.records(); - ASSERT_EQ(records.size(), 1U); - EXPECT_EQ(records[0].command, kRobotStatusTaskPackage); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigationStatusPreservesFaultWhenTrackedTaskDisappears) -{ - const auto navigate_result = - agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - ASSERT_TRUE(navigate_result.ok()) << navigate_result.message; - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"info":"task vanished","task_status_list":[]}})"); - controller_.clearRecords(); - AgvNavigationStatus status; - - std::thread status_thread([this, &status]() { - status = agv_->navigationStatus(); - }); - - bool status_query_observed = false; - for (int attempt = 0; attempt < 200; ++attempt) { - const auto records = controller_.records(); - status_query_observed = std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }); - if (status_query_observed) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_TRUE(status_query_observed); - - Json::Value fault_push(Json::objectValue); - Json::Value errors(Json::arrayValue); - errors.append("E_TASK_GONE_54: controller removed failed task"); - *fault_push.demand("errors", "errors" + std::strlen("errors")) = errors; - *fault_push.demand("fatals", "fatals" + std::strlen("fatals")) = - Json::Value(Json::arrayValue); - SeerRobokitAgvTestPeer::cacheRuntimeState(*agv_, fault_push); - status_thread.join(); - - EXPECT_EQ(status.state, AgvTaskState::Failed); - EXPECT_EQ(status.type, AgvTaskType::NavigateToPose); - EXPECT_NE(status.message.find("task disappeared"), std::string::npos); - EXPECT_NE(status.message.find("E_TASK_GONE_54"), std::string::npos); - EXPECT_FALSE(SeerRobokitAgvTestPeer::hasTrackedPoseTask(*agv_)); - const auto records = controller_.records(); - EXPECT_FALSE(std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTask; - })); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigationStatusRejectsFaultArrivingDuringCompletedPoseVerification) -{ - const auto navigate_result = - agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - ASSERT_TRUE(navigate_result.ok()) << navigate_result.message; - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"info":"controller says complete","task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusLoc, - R"({"ret_code":0,"x":1.0,"y":2.0,"angle":0.5})"); - controller_.setResponseDelay( - kRobotStatusLoc, - std::chrono::milliseconds(300)); - controller_.clearRecords(); - AgvNavigationStatus status; - - std::thread status_thread([this, &status]() { - status = agv_->navigationStatus(); - }); - - bool location_query_observed = false; - for (int attempt = 0; attempt < 700; ++attempt) { - const auto records = controller_.records(); - location_query_observed = std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusLoc; - }); - if (location_query_observed) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_TRUE(location_query_observed); - - Json::Value fault_push(Json::objectValue); - Json::Value errors(Json::arrayValue); - errors.append("E_STATUS_VERIFY_53: fault during completed pose check"); - *fault_push.demand("errors", "errors" + std::strlen("errors")) = errors; - *fault_push.demand("fatals", "fatals" + std::strlen("fatals")) = - Json::Value(Json::arrayValue); - SeerRobokitAgvTestPeer::cacheRuntimeState(*agv_, fault_push); - status_thread.join(); - - EXPECT_EQ(status.state, AgvTaskState::Failed); - EXPECT_EQ(status.type, AgvTaskType::NavigateToPose); - EXPECT_NE(status.message.find("target verification"), std::string::npos); - EXPECT_NE(status.message.find("E_STATUS_VERIFY_53"), std::string::npos); - EXPECT_FALSE(SeerRobokitAgvTestPeer::hasTrackedPoseTask(*agv_)); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigationStatusRejectsCompletedPoseWhenTargetWasNotReached) -{ - const auto navigate_result = - agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - ASSERT_TRUE(navigate_result.ok()) << navigate_result.message; - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"info":"controller says complete","task_status_list":[{"task_id":"${TASK_ID}","status":4,"type":1}]}})"); - controller_.setResponsePayload( - kRobotStatusLoc, - R"({"ret_code":0,"x":0.0,"y":0.0,"angle":0.0})"); - controller_.clearRecords(); - - const auto status = agv_->navigationStatus(); - - EXPECT_EQ(status.state, AgvTaskState::Failed); - EXPECT_EQ(status.type, AgvTaskType::NavigateToPose); - EXPECT_NE( - status.message.find("requested target was not reached"), - std::string::npos); - EXPECT_NE(status.message.find("distance_error"), std::string::npos); - EXPECT_FALSE(SeerRobokitAgvTestPeer::hasTrackedPoseTask(*agv_)); - const auto records = controller_.records(); - ASSERT_EQ(records.size(), 2U); - EXPECT_EQ(records[0].command, kRobotStatusTaskPackage); - EXPECT_EQ(records[1].command, kRobotStatusLoc); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigationStatusWaitsBrieflyForLateControllerFaultDetail) -{ - const auto navigate_result = - agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - ASSERT_TRUE(navigate_result.ok()) << navigate_result.message; - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"info":"planner failed","task_status_list":[{"task_id":"${TASK_ID}","status":5,"type":1}]}})"); - controller_.clearRecords(); - AgvNavigationStatus status; - - std::thread status_thread([this, &status]() { - status = agv_->navigationStatus(); - }); - - bool status_query_observed = false; - for (int attempt = 0; attempt < 200; ++attempt) { - const auto records = controller_.records(); - status_query_observed = std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }); - if (status_query_observed) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_TRUE(status_query_observed); - - Json::Value fault_push(Json::objectValue); - Json::Value fatals(Json::arrayValue); - fatals.append("E_LATE_77: localization alarm"); - *fault_push.demand("fatals", "fatals" + std::strlen("fatals")) = fatals; - SeerRobokitAgvTestPeer::cacheRuntimeState(*agv_, fault_push); - status_thread.join(); - - EXPECT_EQ(status.state, AgvTaskState::Failed); - EXPECT_EQ(status.type, AgvTaskType::NavigateToPose); - EXPECT_NE(status.message.find("planner failed"), std::string::npos); - EXPECT_NE(status.message.find("E_LATE_77"), std::string::npos); - EXPECT_NE(status.message.find("localization alarm"), std::string::npos); - EXPECT_FALSE(SeerRobokitAgvTestPeer::hasTrackedPoseTask(*agv_)); -} - -TEST_F( - SeerRobokitControlAuthorityTest, - NavigationStatusDoesNotReturnOldPoseTaskAfterStationSupersedesIt) -{ - const auto navigate_result = - agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - ASSERT_TRUE(navigate_result.ok()) << navigate_result.message; - - controller_.setResponsePayload( - kRobotStatusTaskPackage, - R"({"ret_code":0,"task_status_package":{"info":"old pose paused","task_status_list":[{"task_id":"${TASK_ID}","status":3,"type":1}]}})"); - controller_.setResponseDelay( - kRobotStatusTaskPackage, - std::chrono::milliseconds(300)); - controller_.setResponsePayload( - kRobotStatusTask, - R"({"ret_code":0,"err_msg":"","task_status":2,"task_type":2,"move_status_info":"station task running"})"); - controller_.clearRecords(); - AgvNavigationStatus status; - - std::thread status_thread([this, &status]() { - status = agv_->navigationStatus(); - }); - - bool status_query_observed = false; - for (int attempt = 0; attempt < 500; ++attempt) { - const auto records = controller_.records(); - status_query_observed = std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTaskPackage; - }); - if (status_query_observed) { - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_TRUE(status_query_observed); - - const auto station_result = agv_->navigateToStation("station-1", asynchronousMotionOptions()); - status_thread.join(); - - ASSERT_TRUE(station_result.ok()) << station_result.message; - EXPECT_EQ(status.state, AgvTaskState::Running); - EXPECT_EQ(status.type, AgvTaskType::NavigateToStation); - EXPECT_EQ(status.message, "station task running"); - const auto records = controller_.records(); - EXPECT_TRUE(std::any_of( - records.begin(), - records.end(), - [](const CommandRecord& record) { - return record.command == kRobotStatusTask; - })); -} - -TEST_F(SeerRobokitControlAuthorityTest, DisconnectClearsTrackedPoseTask) -{ - const auto navigate_result = - agv_->navigateToPose(math::Pose2d{1.0, 2.0, 0.5}, asynchronousMotionOptions()); - ASSERT_TRUE(navigate_result.ok()) << navigate_result.message; - ASSERT_TRUE(SeerRobokitAgvTestPeer::hasTrackedPoseTask(*agv_)); - - const auto disconnect_result = SeerRobokitAgvTestPeer::disconnect(*agv_); - - ASSERT_TRUE(disconnect_result.ok()) << disconnect_result.message; - EXPECT_FALSE(SeerRobokitAgvTestPeer::hasTrackedPoseTask(*agv_)); -} - -TEST_F(SeerRobokitControlAuthorityTest, RuntimeStatePreservesCachedControllerFaultDetail) -{ - Json::Value push_payload(Json::objectValue); - Json::Value errors(Json::arrayValue); - Json::Value error(Json::objectValue); - *error.demand("code", "code" + std::strlen("code")) = "E_NAV_42"; - *error.demand("message", "message" + std::strlen("message")) = "planner alarm"; - errors.append(error); - *push_payload.demand("errors", "errors" + std::strlen("errors")) = errors; - SeerRobokitAgvTestPeer::cacheRuntimeState(*agv_, push_payload); - SeerRobokitAgvTestPeer::setAdapterError( - *agv_, - "SEER Robokit map file is empty after stripping the transport header"); - controller_.clearRecords(); - - const auto state = agv_->runtimeState(); - - EXPECT_TRUE(state.connected); - EXPECT_TRUE(state.fault); - EXPECT_EQ(state.mode, AgvMode::Fault); - EXPECT_NE(state.last_error.find("E_NAV_42"), std::string::npos); - EXPECT_NE(state.last_error.find("planner alarm"), std::string::npos); - EXPECT_NE(state.last_error.find("adapter_error="), std::string::npos); - EXPECT_NE(state.last_error.find("map file is empty"), std::string::npos); - EXPECT_TRUE(controller_.records().empty()); -} - -TEST_F(SeerRobokitControlAuthorityTest, NavigationStatusPreservesControllerErrorCode) -{ - controller_.setResponseCode(kRobotStatusTask, 51020); - controller_.clearRecords(); - - const auto status = agv_->navigationStatus(); - - EXPECT_EQ(status.state, AgvTaskState::Failed); - EXPECT_NE(status.message.find("ret_code=51020"), std::string::npos); - EXPECT_NE(status.message.find("err_msg=simulated command failure"), std::string::npos); - const auto records = controller_.records(); - ASSERT_EQ(records.size(), 1U); - EXPECT_EQ(records[0].command, kRobotStatusTask); -} - -} // namespace -} // namespace cmvr::device diff --git a/cmvr-es/devices/arm/aubo_arm/CMakeLists.txt b/cmvr-es/devices/arm/aubo_arm/CMakeLists.txt index d52da874..2b3231c6 100644 --- a/cmvr-es/devices/arm/aubo_arm/CMakeLists.txt +++ b/cmvr-es/devices/arm/aubo_arm/CMakeLists.txt @@ -54,88 +54,3 @@ target_link_libraries(aubo_arm add_library(cmvr_es::device::aubo_arm ALIAS aubo_arm) install(TARGETS aubo_arm LIBRARY DESTINATION lib) - -if(BUILD_TESTING) - enable_testing() - add_executable(aubo_arm_motion_result_test - tests/aubo_arm_motion_result_test.cpp - ) - target_include_directories(aubo_arm_motion_result_test - PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ) - add_test( - NAME aubo_arm_motion_result_test - COMMAND aubo_arm_motion_result_test - ) - set_tests_properties(aubo_arm_motion_result_test PROPERTIES TIMEOUT 10) - - add_executable(aubo_motion_state_test - tests/aubo_motion_state_test.cpp - ) - target_include_directories(aubo_motion_state_test - PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ) - add_test( - NAME aubo_motion_state_test - COMMAND aubo_motion_state_test - ) - set_tests_properties(aubo_motion_state_test PROPERTIES TIMEOUT 10) - - add_executable(aubo_safety_state_test - tests/aubo_safety_state_test.cpp - ) - target_include_directories(aubo_safety_state_test - PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ) - add_test( - NAME aubo_safety_state_test - COMMAND aubo_safety_state_test - ) - set_tests_properties(aubo_safety_state_test PROPERTIES TIMEOUT 10) - - add_executable(aubo_arm_json_command_test - tests/aubo_arm_json_command_test.cpp - ) - target_link_libraries(aubo_arm_json_command_test - PRIVATE - cmvr_es::device::aubo_arm - cmvr_es::proto - ) - add_test( - NAME aubo_arm_json_command_test - COMMAND aubo_arm_json_command_test - ) - set_tests_properties(aubo_arm_json_command_test PROPERTIES - TIMEOUT 10 - ENVIRONMENT "LD_LIBRARY_PATH=${CMVR_TEST_EXTERNAL_LIBRARY_PATH}" - ) - if(UNIX AND NOT APPLE) - # The imported AUBO target still contributes its vendor directory to - # direct consumers' build-tree RUNPATH. Put the system runtime first - # for this test; installed artifacts exclude the vendor libstdc++. - execute_process( - COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=libstdc++.so.6 - OUTPUT_VARIABLE AUBO_TEST_SYSTEM_LIBSTDCXX - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - if(EXISTS "${AUBO_TEST_SYSTEM_LIBSTDCXX}") - get_filename_component( - AUBO_TEST_SYSTEM_LIBSTDCXX_REAL - "${AUBO_TEST_SYSTEM_LIBSTDCXX}" - REALPATH - ) - get_filename_component( - AUBO_TEST_SYSTEM_LIBSTDCXX_DIR - "${AUBO_TEST_SYSTEM_LIBSTDCXX_REAL}" - DIRECTORY - ) - set_property( - TARGET aubo_arm_json_command_test - PROPERTY BUILD_RPATH "${AUBO_TEST_SYSTEM_LIBSTDCXX_DIR}" - ) - endif() - endif() -endif() diff --git a/cmvr-es/devices/arm/aubo_arm/README.md b/cmvr-es/devices/arm/aubo_arm/README.md index f895c6cd..0d8c752a 100644 --- a/cmvr-es/devices/arm/aubo_arm/README.md +++ b/cmvr-es/devices/arm/aubo_arm/README.md @@ -12,7 +12,6 @@ ## 代码与配置 - 实现:[`aubo_arm.h`](aubo_arm.h)、[`aubo_arm.cpp`](aubo_arm.cpp) -- 测试:[`tests/aubo_arm_json_command_test.cpp`](tests/aubo_arm_json_command_test.cpp) - 设备配置:[`../../../config/devices/arm/aubo_arm.pb.txt`](../../../config/devices/arm/aubo_arm.pb.txt) - DeviceManager 配置: [`../../../config/manager/device_manager.pb.txt`](../../../config/manager/device_manager.pb.txt) @@ -136,18 +135,3 @@ cmake --install build - 模拟量 IO 涉及 domain、单位和量程,当前 JSON 接口不开放; - gRPC/JSON 返回成功不代表目标 IO 具备功能安全等级; - 真实写测试前应确认通道用途、负载、电气隔离、默认电平和控制器程序所有权。 - -## 测试 - -```bash -cmake --build build --target \ - aubo_safety_state_test \ - aubo_motion_state_test \ - aubo_arm_json_command_test -j4 -ctest --test-dir build \ - -R 'aubo_(safety_state|motion_state|arm_json_command)_test' \ - --output-on-failure -``` - -该测试覆盖 JSON 校验和无硬件错误路径,不代表已在真实 AUBO 控制柜完成 DI/DO -读取、写入或 runstate 拒绝验证。 diff --git a/cmvr-es/devices/arm/aubo_arm/tests/aubo_arm_json_command_test.cpp b/cmvr-es/devices/arm/aubo_arm/tests/aubo_arm_json_command_test.cpp deleted file mode 100644 index d31683f6..00000000 --- a/cmvr-es/devices/arm/aubo_arm/tests/aubo_arm_json_command_test.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "devices/arm/aubo_arm/aubo_arm.h" - -#include -#include - -namespace { - -#define CHECK_TRUE(condition) \ - do { \ - if (!(condition)) { \ - std::cerr << "CHECK_TRUE failed at line " << __LINE__ << ": " \ - << #condition << std::endl; \ - return 1; \ - } \ - } while (false) - -bool contains(const std::string& value, const std::string& expected) -{ - return value.find(expected) != std::string::npos; -} - -cmvr::config::RobotArmConfig makeConfig() -{ - cmvr::config::RobotArmConfig config; - config.set_id("aubo_arm_json_test"); - auto* vendor = config.mutable_vendor(); - vendor->set_brand(cmvr::config::VENDOR_ROBOT_ARM_BRAND_AUBO_ARM); - vendor->set_model("AuboTest"); - vendor->set_dof(6); - return config; -} - -} // namespace - -int main() -{ - cmvr::device::AuboArm arm(makeConfig()); - cmvr::device::AbstractDevice* device = &arm; - std::string response; - - CHECK_TRUE(!device->executeJsonCommand("{", response)); - CHECK_TRUE(contains(response, R"("error_code":"invalid_json")")); - - CHECK_TRUE(!device->executeJsonCommand("[]", response)); - CHECK_TRUE(contains(response, R"("error_code":"invalid_json")")); - - CHECK_TRUE(!device->executeJsonCommand( - R"({"command":"ptz","operation":"get_di","index":0})", response)); - CHECK_TRUE(contains(response, R"("error_code":"unsupported_command")")); - - CHECK_TRUE(!device->executeJsonCommand( - R"({"command":"cabinet_io","operation":"get_ai","index":0})", response)); - CHECK_TRUE(contains(response, R"("error_code":"invalid_operation")")); - - CHECK_TRUE(!device->executeJsonCommand( - R"({"command":"cabinet_io","operation":"get_di","index":-1})", response)); - CHECK_TRUE(contains(response, R"("error_code":"invalid_argument")")); - - CHECK_TRUE(!device->executeJsonCommand( - R"({"command":"cabinet_io","operation":"set_do","index":0,"value":1})", - response)); - CHECK_TRUE(contains(response, R"("error_code":"invalid_argument")")); - - CHECK_TRUE(!device->executeJsonCommand( - R"({"command":"cabinet_io","operation":"set_do","index":0})", response)); - CHECK_TRUE(contains(response, R"("error_code":"invalid_argument")")); - - CHECK_TRUE(!device->executeJsonCommand( - R"({"command":"cabinet_io","operation":"get_di","index":0})", response)); - CHECK_TRUE(contains(response, R"("error_code":"not_connected")")); - - CHECK_TRUE(!device->executeJsonCommand( - R"({"command":"cabinet_io","operation":"get_do","index":0})", response)); - CHECK_TRUE(contains(response, R"("operation":"get_do")")); - CHECK_TRUE(contains(response, R"("error_code":"not_connected")")); - - CHECK_TRUE(!device->executeJsonCommand( - R"({"command":"cabinet_io","operation":"set_do","index":0,"value":true})", - response)); - CHECK_TRUE(contains(response, R"("operation":"set_do")")); - CHECK_TRUE(contains(response, R"("error_code":"not_connected")")); - - return 0; -} diff --git a/cmvr-es/devices/arm/aubo_arm/tests/aubo_arm_motion_result_test.cpp b/cmvr-es/devices/arm/aubo_arm/tests/aubo_arm_motion_result_test.cpp deleted file mode 100644 index 57bca235..00000000 --- a/cmvr-es/devices/arm/aubo_arm/tests/aubo_arm_motion_result_test.cpp +++ /dev/null @@ -1,158 +0,0 @@ -#include "devices/arm/aubo_arm/aubo_motion_result.h" -#include "devices/arm/aubo_arm/aubo_torque_on_result.h" - -#include -#include -#include -#include - -namespace { - -#define CHECK_TRUE(condition) \ - do { \ - if (!(condition)) { \ - std::cerr << "CHECK_TRUE failed at line " << __LINE__ << ": " \ - << #condition << std::endl; \ - return 1; \ - } \ - } while (false) - -} // namespace - -int main() -{ - using cmvr::device::aubo_internal::MotionCommandOutcome; - using cmvr::device::aubo_internal::MotionWaitResult; - using cmvr::device::aubo_internal::preservePrimaryTorqueOnFailure; - using cmvr::device::aubo_internal::resolveMotionCommand; - using cmvr::device::aubo_internal::runTorqueOnControllerMutation; - - constexpr int success_code = 0; - constexpr int request_ignore_code = 13; - - int wait_calls = 0; - const auto wait_succeeded = [&wait_calls]() { - ++wait_calls; - return MotionWaitResult::Completed; - }; - CHECK_TRUE(resolveMotionCommand( - success_code, - success_code, - request_ignore_code, - wait_succeeded) == MotionCommandOutcome::CompletedAfterMotion); - CHECK_TRUE(wait_calls == 1); - - wait_calls = 0; - CHECK_TRUE(resolveMotionCommand( - request_ignore_code, - success_code, - request_ignore_code, - wait_succeeded) == MotionCommandOutcome::CompletedWithoutMotion); - CHECK_TRUE(wait_calls == 0); - - const int submit_failures[] = {1, 2, 3, -request_ignore_code}; - for (const int return_code : submit_failures) { - wait_calls = 0; - CHECK_TRUE(resolveMotionCommand( - return_code, - success_code, - request_ignore_code, - wait_succeeded) == MotionCommandOutcome::SubmitFailed); - CHECK_TRUE(wait_calls == 0); - } - - wait_calls = 0; - const auto wait_failed = [&wait_calls]() { - ++wait_calls; - return MotionWaitResult::Failed; - }; - CHECK_TRUE(resolveMotionCommand( - success_code, - success_code, - request_ignore_code, - wait_failed) == MotionCommandOutcome::CompletionFailed); - CHECK_TRUE(wait_calls == 1); - - wait_calls = 0; - const auto wait_cancelled = [&wait_calls]() { - ++wait_calls; - return MotionWaitResult::Cancelled; - }; - CHECK_TRUE(resolveMotionCommand( - success_code, - success_code, - request_ignore_code, - wait_cancelled) == MotionCommandOutcome::Cancelled); - CHECK_TRUE(wait_calls == 1); - - using cmvr::device::ArmErrorCode; - using cmvr::device::Result; - std::vector mutation_trace; - const auto failed_mutation = runTorqueOnControllerMutation( - success_code, - [&mutation_trace] { - mutation_trace.push_back("mutation"); - return 42; - }, - [&mutation_trace](const int return_code) { - mutation_trace.push_back("primary-failure"); - return Result::failure( - ArmErrorCode::CommandFailed, - "vendor failure ret=" + std::to_string(return_code)); - }, - [&mutation_trace]() -> std::optional { - mutation_trace.push_back("cancellation-cleanup"); - return Result::failure( - ArmErrorCode::CommandRejected, - "controller safety termination confirmed"); - }); - CHECK_TRUE(failed_mutation.has_value()); - CHECK_TRUE(failed_mutation->code == ArmErrorCode::CommandFailed); - CHECK_TRUE( - failed_mutation->message.find("vendor failure ret=42") != - std::string::npos); - CHECK_TRUE( - failed_mutation->message.find( - "controller safety termination confirmed") != - std::string::npos); - CHECK_TRUE(mutation_trace.size() == 3); - CHECK_TRUE(mutation_trace[0] == "mutation"); - CHECK_TRUE(mutation_trace[1] == "primary-failure"); - CHECK_TRUE(mutation_trace[2] == "cancellation-cleanup"); - - const auto cleanup_failed = preservePrimaryTorqueOnFailure( - Result::failure( - ArmErrorCode::CommandFailed, - "vendor exception"), - std::optional{Result::failure( - ArmErrorCode::CommandFailed, - "safety termination failed")}); - CHECK_TRUE(cleanup_failed.code == ArmErrorCode::CommandFailed); - CHECK_TRUE( - cleanup_failed.message.find("vendor exception") != - std::string::npos); - CHECK_TRUE( - cleanup_failed.message.find("safety termination failed") != - std::string::npos); - - int successful_cancellation_checks = 0; - const auto cancelled_after_success = runTorqueOnControllerMutation( - success_code, - [] { return 0; }, - [](const int) { - return Result::failure( - ArmErrorCode::CommandFailed, "must not be used"); - }, - [&successful_cancellation_checks]() -> std::optional { - ++successful_cancellation_checks; - return Result::failure( - ArmErrorCode::CommandRejected, - "cancelled after successful mutation"); - }); - CHECK_TRUE(cancelled_after_success.has_value()); - CHECK_TRUE( - cancelled_after_success->code == ArmErrorCode::CommandRejected); - CHECK_TRUE(successful_cancellation_checks == 1); - - return 0; -} diff --git a/cmvr-es/devices/arm/aubo_arm/tests/aubo_motion_state_test.cpp b/cmvr-es/devices/arm/aubo_arm/tests/aubo_motion_state_test.cpp deleted file mode 100644 index 6f68937d..00000000 --- a/cmvr-es/devices/arm/aubo_arm/tests/aubo_motion_state_test.cpp +++ /dev/null @@ -1,213 +0,0 @@ -#include "devices/arm/aubo_arm/aubo_motion_state.h" - -#include -#include -#include -#include - -namespace { - -#define CHECK_TRUE(condition) \ - do { \ - if (!(condition)) { \ - std::cerr << "CHECK_TRUE failed at line " << __LINE__ << ": " \ - << #condition << std::endl; \ - return 1; \ - } \ - } while (false) - -} // namespace - -int main() -{ - using namespace cmvr::device::aubo_internal; - - MotionState state; - CHECK_TRUE(state.begin(MotionKind::None).status == - MotionStartStatus::Invalid); - const auto joint = state.begin(MotionKind::Joint); - CHECK_TRUE(joint.started()); - CHECK_TRUE(state.busy()); - CHECK_TRUE(state.begin(MotionKind::Linear).status == - MotionStartStatus::Busy); - - const auto stop_joint = state.beginStop(); - CHECK_TRUE(stop_joint.started()); - CHECK_TRUE(stop_joint.kind == MotionKind::Joint); - CHECK_TRUE(stop_joint.active_token.generation == - joint.token.generation); - CHECK_TRUE(stop_joint.tracked_motion); - CHECK_TRUE(state.cancelled(joint.token)); - const auto joined_stop_joint = state.beginStop(); - CHECK_TRUE(joined_stop_joint.status == - StopStartStatus::AlreadyStopping); - CHECK_TRUE( - state.waitForStopCompletion( - joined_stop_joint, std::chrono::milliseconds(1)) == - StopWaitStatus::Timeout); - CHECK_TRUE(state.begin(MotionKind::Linear).status == - MotionStartStatus::Stopping); - CHECK_TRUE(!state.waitForOwnerExit( - joint.token, std::chrono::milliseconds(1))); - CHECK_TRUE(!state.completeStop()); - - state.finish(joint.token); - CHECK_TRUE(state.waitForOwnerExit( - joint.token, std::chrono::milliseconds(1))); - CHECK_TRUE(state.completeStop()); - CHECK_TRUE( - state.waitForStopCompletion( - joined_stop_joint, std::chrono::milliseconds(1)) == - StopWaitStatus::Completed); - CHECK_TRUE(!state.busy()); - - const auto linear = state.begin(MotionKind::Linear); - CHECK_TRUE(linear.started()); - CHECK_TRUE(!state.cancelled(linear.token)); - // A delayed guard from the cancelled command must not release a newer one. - state.finish(joint.token); - CHECK_TRUE(state.busy()); - state.finish(linear.token, MotionFinishMode::Clear); - CHECK_TRUE(!state.busy()); - - const auto speed_joint = state.begin(MotionKind::Joint); - CHECK_TRUE(speed_joint.started()); - state.finish(speed_joint.token, MotionFinishMode::Retain); - CHECK_TRUE(state.busy()); - CHECK_TRUE(state.begin(MotionKind::Linear).status == - MotionStartStatus::Busy); - const auto rejected_speed_update = - state.begin(MotionKind::Joint, true); - CHECK_TRUE(rejected_speed_update.started()); - state.finish( - rejected_speed_update.token, - MotionFinishMode::RestorePrevious); - const auto stop_speed = state.beginStop(); - CHECK_TRUE(stop_speed.started()); - CHECK_TRUE(stop_speed.kind == MotionKind::Joint); - CHECK_TRUE(stop_speed.tracked_motion); - CHECK_TRUE(state.completeStop()); - CHECK_TRUE(!state.busy()); - - const auto idle_stop = state.beginStop(); - CHECK_TRUE(idle_stop.kind == MotionKind::None); - CHECK_TRUE(!idle_stop.tracked_motion); - const auto joined_idle_stop = state.beginStop(); - CHECK_TRUE(joined_idle_stop.status == - StopStartStatus::AlreadyStopping); - state.failStop(); - CHECK_TRUE( - state.waitForStopCompletion( - joined_idle_stop, std::chrono::milliseconds(1)) == - StopWaitStatus::Failed); - const auto retry_idle_stop = state.beginStop(); - CHECK_TRUE(retry_idle_stop.kind == MotionKind::None); - CHECK_TRUE(!retry_idle_stop.tracked_motion); - CHECK_TRUE(state.completeStop()); - - const auto mismatched_stop_motion = state.begin(MotionKind::Linear); - CHECK_TRUE(mismatched_stop_motion.started()); - const auto mismatched_stop = state.beginStop(MotionKind::Joint); - CHECK_TRUE(mismatched_stop.kind == MotionKind::Linear); - state.finish(mismatched_stop_motion.token); - CHECK_TRUE(state.completeStop()); - - const auto uncertain_motion = state.begin(MotionKind::Joint); - CHECK_TRUE(uncertain_motion.started()); - state.failMotion(uncertain_motion.token); - CHECK_TRUE(state.busy()); - CHECK_TRUE(state.begin(MotionKind::Linear).status == - MotionStartStatus::Blocked); - const auto stop_uncertain = state.beginStop(); - CHECK_TRUE(stop_uncertain.kind == MotionKind::Joint); - CHECK_TRUE(stop_uncertain.tracked_motion); - CHECK_TRUE(state.completeStop()); - - const auto failed_stop_motion = state.begin(MotionKind::Linear); - CHECK_TRUE(failed_stop_motion.started()); - const auto failed_stop = state.beginStop(); - CHECK_TRUE(failed_stop.kind == MotionKind::Linear); - state.failStop(); - CHECK_TRUE(state.busy()); - CHECK_TRUE(state.begin(MotionKind::Joint).status == - MotionStartStatus::Blocked); - state.finish(failed_stop_motion.token); - - const auto retry = state.beginStop(); - CHECK_TRUE(retry.started()); - CHECK_TRUE(retry.kind == MotionKind::Linear); - CHECK_TRUE(state.completeStop()); - const auto recovered = state.begin(MotionKind::Joint); - CHECK_TRUE(recovered.started()); - state.finish(recovered.token, MotionFinishMode::Clear); - - const auto safety_motion = state.begin(MotionKind::Linear); - CHECK_TRUE(safety_motion.started()); - const auto safety_cancel = state.cancelActiveForSafety(); - CHECK_TRUE(safety_cancel.kind == MotionKind::Linear); - CHECK_TRUE(safety_cancel.tracked_motion); - CHECK_TRUE(state.cancelled(safety_motion.token)); - CHECK_TRUE(state.begin(MotionKind::Joint).status == - MotionStartStatus::Blocked); - state.finish(safety_motion.token); - const auto safety_stop = state.beginStop(); - CHECK_TRUE(safety_stop.started()); - CHECK_TRUE(safety_stop.kind == MotionKind::Linear); - CHECK_TRUE(state.completeStop()); - - const auto retained_speed = state.begin(MotionKind::Joint); - CHECK_TRUE(retained_speed.started()); - state.finish(retained_speed.token, MotionFinishMode::Retain); - const auto retained_cancel = state.cancelActiveForSafety(); - CHECK_TRUE(retained_cancel.kind == MotionKind::Joint); - CHECK_TRUE(retained_cancel.tracked_motion); - CHECK_TRUE(!retained_cancel.active_token.valid()); - CHECK_TRUE(state.begin(MotionKind::Linear).status == - MotionStartStatus::Blocked); - const auto retained_stop = state.beginStop(); - CHECK_TRUE(retained_stop.started()); - CHECK_TRUE(retained_stop.kind == MotionKind::Joint); - CHECK_TRUE(retained_stop.tracked_motion); - CHECK_TRUE(state.completeStop()); - - // A waiter keeps the completion for the stop it joined even when another - // stop starts and finishes before the waiter is scheduled again. - const auto concurrent_first_stop = state.beginStop(); - CHECK_TRUE(concurrent_first_stop.started()); - const auto concurrent_first_join = state.beginStop(); - CHECK_TRUE(concurrent_first_join.status == - StopStartStatus::AlreadyStopping); - std::atomic waiter_entered{false}; - std::atomic first_wait_result{ - StopWaitStatus::Timeout}; - std::thread first_waiter([&]() { - waiter_entered.store(true, std::memory_order_release); - first_wait_result.store( - state.waitForStopCompletion( - concurrent_first_join, - std::chrono::milliseconds(500)), - std::memory_order_release); - }); - while (!waiter_entered.load(std::memory_order_acquire)) { - std::this_thread::yield(); - } - - const bool concurrent_first_completed = state.completeStop(); - const auto concurrent_second_stop = state.beginStop(); - const auto concurrent_second_join = state.beginStop(); - state.failStop(); - first_waiter.join(); - - CHECK_TRUE(concurrent_first_completed); - CHECK_TRUE(concurrent_second_stop.started()); - CHECK_TRUE(concurrent_second_join.status == - StopStartStatus::AlreadyStopping); - CHECK_TRUE(first_wait_result.load(std::memory_order_acquire) == - StopWaitStatus::Completed); - CHECK_TRUE( - state.waitForStopCompletion( - concurrent_second_join, std::chrono::milliseconds(1)) == - StopWaitStatus::Failed); - - return 0; -} diff --git a/cmvr-es/devices/arm/aubo_arm/tests/aubo_safety_state_test.cpp b/cmvr-es/devices/arm/aubo_arm/tests/aubo_safety_state_test.cpp deleted file mode 100644 index 1d350990..00000000 --- a/cmvr-es/devices/arm/aubo_arm/tests/aubo_safety_state_test.cpp +++ /dev/null @@ -1,156 +0,0 @@ -#include "devices/arm/aubo_arm/aubo_safety_state.h" - -#include - -namespace { - -#define CHECK_TRUE(condition) \ - do { \ - if (!(condition)) { \ - std::cerr << "CHECK_TRUE failed at line " << __LINE__ << ": " \ - << #condition << std::endl; \ - return 1; \ - } \ - } while (false) - -} // namespace - -int main() -{ - using namespace cmvr::device::aubo_internal; - - SafetyState state; - CHECK_TRUE(!state.tryPermit().has_value()); - - state.observe(SafetyCondition::Normal); - const auto initial_permit = state.tryPermit(); - CHECK_TRUE(initial_permit.has_value()); - CHECK_TRUE(state.validate(*initial_permit)); - - CHECK_TRUE(effectiveSafetyCondition(SafetyCondition::Normal, 1) == - SafetyCondition::RobotEmergencyStop); - CHECK_TRUE(effectiveSafetyCondition(SafetyCondition::Normal, -1) == - SafetyCondition::Unknown); - CHECK_TRUE(effectiveSafetyCondition(SafetyCondition::Reduced, 0) == - SafetyCondition::Reduced); - CHECK_TRUE(needsProtectiveUnlock(SafetyCondition::ProtectiveStop)); - CHECK_TRUE(needsProtectiveUnlock(SafetyCondition::Violation)); - CHECK_TRUE(!needsProtectiveUnlock(SafetyCondition::SafeguardStop)); - CHECK_TRUE(needsInterfaceBoardRestart( - SafetyCondition::RobotEmergencyStop)); - CHECK_TRUE(needsInterfaceBoardRestart( - SafetyCondition::SystemEmergencyStop)); - CHECK_TRUE(needsInterfaceBoardRestart(SafetyCondition::Fault)); - CHECK_TRUE(!needsInterfaceBoardRestart(SafetyCondition::Recovery)); - - state.observe(SafetyCondition::RobotEmergencyStop); - CHECK_TRUE(!state.validate(*initial_permit)); - CHECK_TRUE(state.snapshot().latched); - CHECK_TRUE(!state.beginRecovery(state.snapshot().epoch).has_value()); - - // The observed level alone does not unlock motion. The monitor must first - // prove the old controller operation is fully quiescent. - state.observe(SafetyCondition::Normal); - CHECK_TRUE(state.snapshot().latched); - CHECK_TRUE(!state.tryPermit().has_value()); - CHECK_TRUE(!shouldAutoRecoverHardwareEmergencyStop( - state.snapshot(), false, 0, true, false)); - CHECK_TRUE(shouldAutoRecoverHardwareEmergencyStop( - state.snapshot(), true, 0, true, false)); - CHECK_TRUE(!shouldAutoRecoverHardwareEmergencyStop( - state.snapshot(), true, 0, false, false)); - CHECK_TRUE(!shouldAutoRecoverHardwareEmergencyStop( - state.snapshot(), true, 0, true, true)); - - const auto recovery = state.beginRecovery(state.snapshot().epoch); - CHECK_TRUE(recovery.has_value()); - CHECK_TRUE(!state.completeRecovery(*recovery, true, true, false)); - state.failRecovery(*recovery); - - const auto retry = state.beginRecovery(state.snapshot().epoch); - CHECK_TRUE(retry.has_value()); - // Automatic release is not committed at Idle/PowerOn. The controller - // must have completed startup and reached Running first. - CHECK_TRUE(!state.completeHardwareEmergencyStopRecovery( - *retry, false, true, true)); - CHECK_TRUE(!state.completeHardwareEmergencyStopRecovery( - *retry, true, false, true)); - CHECK_TRUE(state.completeHardwareEmergencyStopRecovery( - *retry, true, true, true)); - const auto recovered_permit = state.tryPermit(); - CHECK_TRUE(recovered_permit.has_value()); - CHECK_TRUE(state.validate(*recovered_permit)); - - // Some AUBO cabinets drop the SDK connection while the physical E-stop is - // pressed. Losing the monitor sample must not erase the hardware E-stop - // latch; otherwise releasing the switch back to Normal would never trigger - // automatic power-on. - state.observe(SafetyCondition::RobotEmergencyStop); - const auto estop_epoch = state.snapshot().epoch; - state.observe(SafetyCondition::Unknown); - CHECK_TRUE(state.snapshot().latched); - CHECK_TRUE(state.snapshot().latched_reason == - SafetyCondition::RobotEmergencyStop); - CHECK_TRUE(state.snapshot().epoch == estop_epoch); - state.observe(SafetyCondition::Normal); - CHECK_TRUE(shouldAutoRecoverHardwareEmergencyStop( - state.snapshot(), true, 0, true, false)); - const auto disconnected_recovery = state.beginRecovery( - state.snapshot().epoch); - CHECK_TRUE(disconnected_recovery.has_value()); - CHECK_TRUE(state.completeHardwareEmergencyStopRecovery( - *disconnected_recovery, true, true, true)); - - // Releasing a real E-stop must never clear a software-triggered stop that - // was latched while the hardware input was active. - state.observe(SafetyCondition::RobotEmergencyStop); - state.observe(SafetyCondition::SoftwareEmergencyStop); - // The hardware monitor continues publishing the physical E-stop level - // until the switch is released. It must not overwrite the software latch. - state.observe(SafetyCondition::RobotEmergencyStop); - state.observe(SafetyCondition::Normal); - CHECK_TRUE(!shouldAutoRecoverHardwareEmergencyStop( - state.snapshot(), true, 0, true, false)); - CHECK_TRUE(state.snapshot().software_emergency_stop_latched); - CHECK_TRUE(state.snapshot().latched_reason == - SafetyCondition::SoftwareEmergencyStop); - const auto software_recovery = state.beginRecovery( - state.snapshot().epoch); - CHECK_TRUE(software_recovery.has_value()); - CHECK_TRUE(!state.completeHardwareEmergencyStopRecovery( - *software_recovery, true, true, true)); - state.failRecovery(*software_recovery); - const auto explicit_software_recovery = state.beginRecovery( - state.snapshot().epoch); - CHECK_TRUE(explicit_software_recovery.has_value()); - CHECK_TRUE(state.completeRecovery( - *explicit_software_recovery, true, true, true)); - CHECK_TRUE(!state.snapshot().software_emergency_stop_latched); - - // A new safety event invalidates an in-flight recovery token. - state.observe(SafetyCondition::ProtectiveStop); - state.observe(SafetyCondition::Reduced); - const auto stale_recovery = state.beginRecovery( - state.snapshot().epoch); - CHECK_TRUE(stale_recovery.has_value()); - CHECK_TRUE(!state.completeHardwareEmergencyStopRecovery( - *stale_recovery, true, true, true)); - state.failRecovery(*stale_recovery); - const auto explicit_recovery = state.beginRecovery( - state.snapshot().epoch); - CHECK_TRUE(explicit_recovery.has_value()); - state.observe(SafetyCondition::SafeguardStop); - state.observe(SafetyCondition::Normal); - CHECK_TRUE(!state.completeRecovery( - *explicit_recovery, true, true, true)); - CHECK_TRUE(state.snapshot().latched); - - // An old API call must not begin recovery for a newer safety event. - const auto stale_epoch = state.snapshot().epoch; - state.observe(SafetyCondition::RobotEmergencyStop); - state.observe(SafetyCondition::Normal); - CHECK_TRUE(!state.beginRecovery(stale_epoch).has_value()); - CHECK_TRUE(!state.snapshot().recovery_in_progress); - - return 0; -} diff --git a/cmvr-es/devices/arm/huayan_arm/CMakeLists.txt b/cmvr-es/devices/arm/huayan_arm/CMakeLists.txt index 6001a5d7..ca88f4fc 100644 --- a/cmvr-es/devices/arm/huayan_arm/CMakeLists.txt +++ b/cmvr-es/devices/arm/huayan_arm/CMakeLists.txt @@ -29,49 +29,3 @@ add_library(cmvr_es::device::huayan_arm ALIAS huayan_arm) install(TARGETS huayan_arm LIBRARY DESTINATION lib) install(FILES ${HUAYAN_ARM_SDK_DIR}/lib/libHR_Pro.so DESTINATION lib) - -if(BUILD_TESTING) - add_executable(huayan_lifecycle_state_test - tests/huayan_lifecycle_state_test.cpp - ) - target_include_directories(huayan_lifecycle_state_test - PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ) - target_link_libraries(huayan_lifecycle_state_test - PRIVATE - Threads::Threads - ) - add_test( - NAME huayan_lifecycle_state_test - COMMAND huayan_lifecycle_state_test - ) - set_tests_properties(huayan_lifecycle_state_test PROPERTIES TIMEOUT 10) - - if(UNIX AND NOT APPLE) - add_executable(huayan_arm_sdk_test - tests/huayan_arm_sdk_test.cpp - ) - target_include_directories(huayan_arm_sdk_test - PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ${HUAYAN_ARM_SDK_DIR}/include - ) - target_link_libraries(huayan_arm_sdk_test - PRIVATE - cmvr_es::device::huayan_arm - Threads::Threads - ) - # Export the fake HRIF_* definitions so libhuayan_arm resolves its SDK - # calls to the deterministic test controller instead of real hardware. - target_link_options(huayan_arm_sdk_test PRIVATE -Wl,--export-dynamic) - add_test( - NAME huayan_arm_sdk_test - COMMAND huayan_arm_sdk_test - ) - set_tests_properties(huayan_arm_sdk_test PROPERTIES - TIMEOUT 20 - ENVIRONMENT "LD_LIBRARY_PATH=${CMVR_TEST_EXTERNAL_LIBRARY_PATH}" - ) - endif() -endif() diff --git a/cmvr-es/devices/arm/huayan_arm/tests/huayan_arm_sdk_test.cpp b/cmvr-es/devices/arm/huayan_arm/tests/huayan_arm_sdk_test.cpp deleted file mode 100644 index 00cb8e27..00000000 --- a/cmvr-es/devices/arm/huayan_arm/tests/huayan_arm_sdk_test.cpp +++ /dev/null @@ -1,874 +0,0 @@ -#include "devices/arm/huayan_arm/huayan_arm.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "HR_Pro.h" - -namespace { - -using Clock = std::chrono::steady_clock; -using namespace std::chrono_literals; - -constexpr double kPi = 3.14159265358979323846; - -double radToDeg(const double value) -{ - return value * 180.0 / kPi; -} - -struct FakeSdkState final { - std::mutex mutex; - bool connected{false}; - bool enabled{true}; - bool electrified{true}; - bool robot_error{false}; - bool paused{false}; - bool emergency_input{false}; - bool emergency_signal_fault{false}; - bool safeguard_input{false}; - bool safeguard_signal_fault{false}; - bool software_safeguard{false}; - - bool motion_active{false}; - bool motion_is_joint{true}; - bool stop_pending{false}; - bool hold_next_motion{false}; - bool stale_done_once{false}; - Clock::time_point completion_at{}; - Clock::time_point stop_complete_at{}; - std::array joint_position_deg{}; - std::array joint_target_deg{}; - std::array tcp_position_hr{}; - std::array tcp_target_hr{}; - std::string waypoint_id; - - bool servo_started{false}; - bool program_running{false}; - std::string selected_program; - - int move_j_calls{0}; - int move_l_calls{0}; - int speed_j_calls{0}; - int speed_l_calls{0}; - int group_stop_calls{0}; - int group_reset_calls{0}; - int start_servo_calls{0}; - int stop_script_calls{0}; - int idle_velocity_reads_after_stop{0}; - bool count_idle_reads{false}; - - void refreshLocked() - { - const auto now = Clock::now(); - const bool safety_active = emergency_input || safeguard_input || - software_safeguard; - - if (stop_pending && now >= stop_complete_at) { - stop_pending = false; - motion_active = false; - stale_done_once = false; - count_idle_reads = true; - } - - if (motion_active && !stop_pending && !safety_active && - completion_at != Clock::time_point{} && now >= completion_at) { - motion_active = false; - stale_done_once = false; - if (motion_is_joint) { - joint_position_deg = joint_target_deg; - } else { - tcp_position_hr = tcp_target_hr; - } - } - } - - bool movingLocked() - { - refreshLocked(); - return motion_active && !emergency_input && !safeguard_input && - !software_safeguard; - } - - bool doneLocked() - { - refreshLocked(); - return !motion_active; - } - - void startMotionLocked(const bool joint) - { - motion_active = true; - motion_is_joint = joint; - stop_pending = false; - count_idle_reads = false; - stale_done_once = true; - if (hold_next_motion) { - // The fallback deadline keeps a failed test from leaving a worker - // blocked for the production 60 second timeout. - completion_at = Clock::now() + 3s; - hold_next_motion = false; - } else { - completion_at = Clock::now() + 120ms; - } - } -}; - -FakeSdkState g_sdk; - -void resetFakeSdk() -{ - std::lock_guard lock(g_sdk.mutex); - g_sdk.connected = false; - g_sdk.enabled = true; - g_sdk.electrified = true; - g_sdk.robot_error = false; - g_sdk.paused = false; - g_sdk.emergency_input = false; - g_sdk.emergency_signal_fault = false; - g_sdk.safeguard_input = false; - g_sdk.safeguard_signal_fault = false; - g_sdk.software_safeguard = false; - g_sdk.motion_active = false; - g_sdk.motion_is_joint = true; - g_sdk.stop_pending = false; - g_sdk.hold_next_motion = false; - g_sdk.stale_done_once = false; - g_sdk.completion_at = {}; - g_sdk.stop_complete_at = {}; - g_sdk.joint_position_deg = {}; - g_sdk.joint_target_deg = {}; - g_sdk.tcp_position_hr = {}; - g_sdk.tcp_target_hr = {}; - g_sdk.waypoint_id.clear(); - g_sdk.servo_started = false; - g_sdk.program_running = false; - g_sdk.selected_program.clear(); - g_sdk.move_j_calls = 0; - g_sdk.move_l_calls = 0; - g_sdk.speed_j_calls = 0; - g_sdk.speed_l_calls = 0; - g_sdk.group_stop_calls = 0; - g_sdk.group_reset_calls = 0; - g_sdk.start_servo_calls = 0; - g_sdk.stop_script_calls = 0; - g_sdk.idle_velocity_reads_after_stop = 0; - g_sdk.count_idle_reads = false; -} - -void holdNextMotion() -{ - std::lock_guard lock(g_sdk.mutex); - g_sdk.hold_next_motion = true; -} - -void setHardwareEmergencyStop(const bool active) -{ - std::lock_guard lock(g_sdk.mutex); - g_sdk.emergency_input = active; - // If the wrapper never sends a real group Stop, releasing the switch makes - // the pending fake waypoint move again. This models the field failure. -} - -void setEmergencySignalFault(const bool active) -{ - std::lock_guard lock(g_sdk.mutex); - g_sdk.emergency_signal_fault = active; -} - -void dropFakeTransport() -{ - std::lock_guard lock(g_sdk.mutex); - g_sdk.connected = false; -} - -template -bool waitUntil(Predicate&& predicate, - const std::chrono::milliseconds timeout = 2s) -{ - const auto deadline = Clock::now() + timeout; - while (Clock::now() < deadline) { - if (predicate()) { - return true; - } - std::this_thread::sleep_for(10ms); - } - return predicate(); -} - -cmvr::config::RobotArmConfig makeConfig() -{ - cmvr::config::RobotArmConfig cfg; - cfg.set_id("huayan_fake_sdk"); - auto* vendor = cfg.mutable_vendor(); - vendor->set_brand(cmvr::config::VENDOR_ROBOT_ARM_BRAND_HUAYAN_ARM); - vendor->set_ip("127.0.0.1"); - vendor->set_port(10003); - vendor->set_model("HuayanFake"); - vendor->set_dof(6); - vendor->set_base_frame("Base"); - vendor->set_tool_frame("TCP"); - for (int i = 1; i <= 6; ++i) { - vendor->add_joint_names("joint_" + std::to_string(i)); - } - return cfg; -} - -int failures = 0; - -#define CHECK_TRUE(condition) \ - do { \ - if (!(condition)) { \ - std::cerr << "CHECK_TRUE failed at line " << __LINE__ << ": " \ - << #condition << std::endl; \ - ++failures; \ - } \ - } while (false) - -} // namespace - -// The test executable exports these strong symbols. On ELF platforms they -// interpose the real SDK definitions used by libhuayan_arm, giving the test a -// deterministic controller without opening a network connection. -extern "C" { - -int HRIF_Connect(unsigned int, const char*, unsigned short) -{ - std::lock_guard lock(g_sdk.mutex); - g_sdk.connected = true; - return 0; -} - -int HRIF_DisConnect(unsigned int) -{ - std::lock_guard lock(g_sdk.mutex); - g_sdk.connected = false; - g_sdk.motion_active = false; - return 0; -} - -bool HRIF_IsConnected(unsigned int) -{ - std::lock_guard lock(g_sdk.mutex); - return g_sdk.connected; -} - -int HRIF_GetErrorCodeStr(unsigned int, int error_code, std::string& message) -{ - message = "fake SDK error " + std::to_string(error_code); - return 0; -} - -int HRIF_GrpEnable(unsigned int, unsigned int) -{ - std::lock_guard lock(g_sdk.mutex); - if (g_sdk.emergency_input || g_sdk.safeguard_input || - g_sdk.software_safeguard) { - return 101; - } - g_sdk.enabled = true; - g_sdk.electrified = true; - return 0; -} - -int HRIF_GrpDisable(unsigned int, unsigned int) -{ - std::lock_guard lock(g_sdk.mutex); - g_sdk.enabled = false; - g_sdk.electrified = false; - return 0; -} - -int HRIF_GrpReset(unsigned int, unsigned int) -{ - std::lock_guard lock(g_sdk.mutex); - ++g_sdk.group_reset_calls; - if (g_sdk.emergency_input || g_sdk.safeguard_input || - g_sdk.software_safeguard) { - return 102; - } - g_sdk.robot_error = false; - return 0; -} - -int HRIF_GrpStop(unsigned int, unsigned int) -{ - std::lock_guard lock(g_sdk.mutex); - ++g_sdk.group_stop_calls; - g_sdk.idle_velocity_reads_after_stop = 0; - g_sdk.count_idle_reads = false; - if (g_sdk.motion_active) { - g_sdk.stop_pending = true; - g_sdk.stop_complete_at = Clock::now() + 120ms; - g_sdk.completion_at = {}; - } else { - g_sdk.stop_pending = false; - g_sdk.count_idle_reads = true; - } - g_sdk.servo_started = false; - return 0; -} - -int HRIF_SetOverride(unsigned int, unsigned int, double) -{ - return 0; -} - -int HRIF_ReadRobotState(unsigned int, unsigned int, - int& moving, int& enabled, int& error, - int& error_code, int& error_axis, int& brake, - int& paused, int& emergency_stop, int& safeguard, - int& electrified, int& connected_to_box, - int& blending_done, int& in_position) -{ - std::lock_guard lock(g_sdk.mutex); - if (!g_sdk.connected) { - return 201; - } - moving = g_sdk.movingLocked() ? 1 : 0; - enabled = g_sdk.enabled ? 1 : 0; - error = g_sdk.robot_error ? 1 : 0; - error_code = g_sdk.robot_error ? 9001 : 0; - error_axis = 0; - brake = g_sdk.enabled ? 1 : 0; - paused = g_sdk.paused ? 1 : 0; - emergency_stop = g_sdk.emergency_input ? 1 : 0; - safeguard = (g_sdk.safeguard_input || g_sdk.software_safeguard) ? 1 : 0; - electrified = g_sdk.electrified ? 1 : 0; - connected_to_box = 1; - blending_done = moving == 0 ? 1 : 0; - in_position = g_sdk.doneLocked() ? 1 : 0; - return 0; -} - -int HRIF_ReadEmergencyInfo(unsigned int, unsigned int, - int& emergency_signal_fault, - int& emergency_input, - int& safeguard_signal_fault, - int& safeguard_input) -{ - std::lock_guard lock(g_sdk.mutex); - if (!g_sdk.connected) { - return 202; - } - emergency_signal_fault = g_sdk.emergency_signal_fault ? 1 : 0; - emergency_input = g_sdk.emergency_input ? 1 : 0; - safeguard_signal_fault = g_sdk.safeguard_signal_fault ? 1 : 0; - safeguard_input = - (g_sdk.safeguard_input || g_sdk.software_safeguard) ? 1 : 0; - return 0; -} - -int HRIF_ReadCurWaypointID(unsigned int, unsigned int, std::string& waypoint) -{ - std::lock_guard lock(g_sdk.mutex); - waypoint = g_sdk.waypoint_id; - return 0; -} - -int HRIF_IsMotionDone(unsigned int, unsigned int, bool& done) -{ - std::lock_guard lock(g_sdk.mutex); - if (g_sdk.stale_done_once) { - g_sdk.stale_done_once = false; - done = true; - } else { - done = g_sdk.doneLocked(); - } - return 0; -} - -int HRIF_ReadActJointPos(unsigned int, unsigned int, - double& j1, double& j2, double& j3, - double& j4, double& j5, double& j6) -{ - std::lock_guard lock(g_sdk.mutex); - g_sdk.refreshLocked(); - j1 = g_sdk.joint_position_deg[0]; - j2 = g_sdk.joint_position_deg[1]; - j3 = g_sdk.joint_position_deg[2]; - j4 = g_sdk.joint_position_deg[3]; - j5 = g_sdk.joint_position_deg[4]; - j6 = g_sdk.joint_position_deg[5]; - return 0; -} - -int HRIF_ReadActJointVel(unsigned int, unsigned int, - double& j1, double& j2, double& j3, - double& j4, double& j5, double& j6) -{ - std::lock_guard lock(g_sdk.mutex); - const double velocity = g_sdk.movingLocked() ? 5.0 : 0.0; - j1 = j2 = j3 = j4 = j5 = j6 = velocity; - if (velocity == 0.0 && g_sdk.count_idle_reads) { - ++g_sdk.idle_velocity_reads_after_stop; - } - return 0; -} - -int HRIF_ReadActTcpPos(unsigned int, unsigned int, - double& x, double& y, double& z, - double& rx, double& ry, double& rz) -{ - std::lock_guard lock(g_sdk.mutex); - g_sdk.refreshLocked(); - x = g_sdk.tcp_position_hr[0]; - y = g_sdk.tcp_position_hr[1]; - z = g_sdk.tcp_position_hr[2]; - rx = g_sdk.tcp_position_hr[3]; - ry = g_sdk.tcp_position_hr[4]; - rz = g_sdk.tcp_position_hr[5]; - return 0; -} - -int HRIF_ReadActTcpVel(unsigned int, unsigned int, - double& x, double& y, double& z, - double& rx, double& ry, double& rz) -{ - std::lock_guard lock(g_sdk.mutex); - const double velocity = g_sdk.movingLocked() ? 5.0 : 0.0; - x = y = z = rx = ry = rz = velocity; - return 0; -} - -int HRIF_MoveJ(unsigned int, unsigned int, - double, double, double, double, double, double, - double j1, double j2, double j3, - double j4, double j5, double j6, - std::string, std::string, double, double, double, - int, int, int, int, std::string command_id) -{ - std::lock_guard lock(g_sdk.mutex); - ++g_sdk.move_j_calls; - g_sdk.joint_target_deg = {j1, j2, j3, j4, j5, j6}; - g_sdk.waypoint_id = std::move(command_id); - g_sdk.startMotionLocked(true); - return 0; -} - -int HRIF_MoveL(unsigned int, unsigned int, - double x, double y, double z, - double rx, double ry, double rz, - double, double, double, double, double, double, - std::string, std::string, double, double, double, - int, int, int, std::string command_id) -{ - std::lock_guard lock(g_sdk.mutex); - ++g_sdk.move_l_calls; - g_sdk.tcp_target_hr = {x, y, z, rx, ry, rz}; - g_sdk.waypoint_id = std::move(command_id); - g_sdk.startMotionLocked(false); - return 0; -} - -int HRIF_SpeedJ(unsigned int, unsigned int, - double, double, double, double, double, double, - double, double) -{ - std::lock_guard lock(g_sdk.mutex); - ++g_sdk.speed_j_calls; - g_sdk.startMotionLocked(true); - return 0; -} - -int HRIF_SpeedL(unsigned int, unsigned int, - double, double, double, double, double, double, - double, double, double) -{ - std::lock_guard lock(g_sdk.mutex); - ++g_sdk.speed_l_calls; - g_sdk.startMotionLocked(false); - return 0; -} - -int HRIF_StartServo(unsigned int, unsigned int, double, double) -{ - std::lock_guard lock(g_sdk.mutex); - ++g_sdk.start_servo_calls; - g_sdk.servo_started = true; - return 0; -} - -int HRIF_PushServoJ(unsigned int, unsigned int, - double j1, double j2, double j3, - double j4, double j5, double j6) -{ - std::lock_guard lock(g_sdk.mutex); - if (!g_sdk.servo_started) { - return 301; - } - g_sdk.joint_position_deg = {j1, j2, j3, j4, j5, j6}; - return 0; -} - -int HRIF_PushServoP(unsigned int, unsigned int, - std::vector& coord, - std::vector&, - std::vector&) -{ - std::lock_guard lock(g_sdk.mutex); - if (!g_sdk.servo_started || coord.size() < 6) { - return 302; - } - std::copy_n(coord.begin(), 6, g_sdk.tcp_position_hr.begin()); - return 0; -} - -int HRIF_SwitchScript(unsigned int, unsigned int, std::string script_name) -{ - std::lock_guard lock(g_sdk.mutex); - if (script_name.empty()) { - return 401; - } - g_sdk.selected_program = std::move(script_name); - return 0; -} - -int HRIF_StartScript(unsigned int) -{ - std::lock_guard lock(g_sdk.mutex); - if (g_sdk.selected_program.empty()) { - return 402; - } - g_sdk.program_running = true; - g_sdk.paused = false; - return 0; -} - -int HRIF_PauseScript(unsigned int) -{ - std::lock_guard lock(g_sdk.mutex); - if (!g_sdk.program_running) { - return 403; - } - g_sdk.paused = true; - return 0; -} - -int HRIF_StopScript(unsigned int) -{ - std::lock_guard lock(g_sdk.mutex); - ++g_sdk.stop_script_calls; - g_sdk.program_running = false; - g_sdk.paused = false; - return 0; -} - -int HRIF_EnterSafetyGuard(unsigned int, unsigned int, int flag) -{ - std::lock_guard lock(g_sdk.mutex); - g_sdk.software_safeguard = flag != 0; - return 0; -} - -int HRIF_ShutdownRobot(unsigned int) -{ - std::lock_guard lock(g_sdk.mutex); - g_sdk.connected = false; - g_sdk.enabled = false; - g_sdk.electrified = false; - return 0; -} - -} // extern "C" - -int main() -{ - using namespace cmvr::device; - - resetFakeSdk(); - HuayanRobot arm(makeConfig()); - CHECK_TRUE(arm.connect("127.0.0.1", 10003).ok()); - - MotionOptions options; - options.velocity = 0.4; - options.acceleration = 0.8; - CHECK_TRUE(arm.supportsActionQueueMotion()); - - JointPositionCommand joint_a{{0.10, -0.05, 0.08, 0.0, 0.02, -0.03}}; - MotionOptions cancelled_options = options; - cancelled_options.cancellation_requested = []() { return true; }; - CHECK_TRUE(!arm.moveJ(joint_a, cancelled_options).ok()); - CartesianPose cancelled_pose; - cancelled_pose.x = 0.20; - cancelled_pose.z = 0.30; - CHECK_TRUE(!arm.moveL(cancelled_pose, cancelled_options).ok()); - { - std::lock_guard lock(g_sdk.mutex); - CHECK_TRUE(g_sdk.move_j_calls == 0); - CHECK_TRUE(g_sdk.move_l_calls == 0); - } - - // Once a command has been accepted, caller cancellation returns promptly - // but retains the typed motion barrier until Stop confirms controller idle. - std::atomic cancel_during_wait{false}; - MotionOptions cancellable_options = options; - cancellable_options.cancellation_requested = [&cancel_during_wait]() { - return cancel_during_wait.load(); - }; - JointPositionCommand cancelled_in_wait{ - {0.05, -0.02, 0.04, 0.01, 0.0, -0.01}}; - holdNextMotion(); - auto cancelled_motion = std::async(std::launch::async, [&]() { - return arm.moveJ(cancelled_in_wait, cancellable_options); - }); - CHECK_TRUE(waitUntil([&]() { - std::lock_guard lock(g_sdk.mutex); - return g_sdk.move_j_calls > 0; - })); - cancel_during_wait.store(true); - CHECK_TRUE(cancelled_motion.wait_for(1s) == std::future_status::ready); - if (cancelled_motion.wait_for(0ms) == std::future_status::ready) { - CHECK_TRUE(!cancelled_motion.get().ok()); - } - CHECK_TRUE(arm.busy()); - CHECK_TRUE(arm.stopMotion().ok()); - CHECK_TRUE(!arm.busy()); - - // The first IsMotionDone read intentionally reports the preceding idle - // state. Completion must be correlated with the command/target. Once the - // target is reached, an identical command is an idempotent no-op. - CHECK_TRUE(arm.moveJ(joint_a, options).ok()); - int move_j_after_first = 0; - { - std::lock_guard lock(g_sdk.mutex); - move_j_after_first = g_sdk.move_j_calls; - } - CHECK_TRUE(arm.moveJ(joint_a, options).ok()); - { - std::lock_guard lock(g_sdk.mutex); - CHECK_TRUE(g_sdk.move_j_calls == move_j_after_first); - } - - CartesianPose pose_a; - pose_a.x = 0.31; - pose_a.y = -0.12; - pose_a.z = 0.42; - pose_a.rx = 0.08; - pose_a.ry = -0.04; - pose_a.rz = 0.12; - CHECK_TRUE(arm.moveL(pose_a, options).ok()); - int move_l_after_first = 0; - { - std::lock_guard lock(g_sdk.mutex); - move_l_after_first = g_sdk.move_l_calls; - } - CHECK_TRUE(arm.moveL(pose_a, options).ok()); - { - std::lock_guard lock(g_sdk.mutex); - CHECK_TRUE(g_sdk.move_l_calls == move_l_after_first); - } - - // Stop must cancel the old owner and wait until the controller reports - // stable idle; clearing the owner immediately after GrpStop would fail the - // elapsed-time and consecutive-idle checks below. - JointPositionCommand joint_b{{0.22, -0.08, 0.14, 0.03, 0.04, -0.01}}; - holdNextMotion(); - const int before_held_move = move_j_after_first; - auto held_move = std::async(std::launch::async, [&]() { - return arm.moveJ(joint_b, options); - }); - CHECK_TRUE(waitUntil([&]() { - std::lock_guard lock(g_sdk.mutex); - return g_sdk.move_j_calls > before_held_move; - })); - const auto stop_started = Clock::now(); - CHECK_TRUE(arm.stopMotion().ok()); - const auto stop_elapsed = Clock::now() - stop_started; - CHECK_TRUE(stop_elapsed >= 100ms); - CHECK_TRUE(held_move.wait_for(1s) == std::future_status::ready); - if (held_move.wait_for(0ms) == std::future_status::ready) { - CHECK_TRUE(!held_move.get().ok()); - } - CHECK_TRUE(!arm.busy()); - { - std::lock_guard lock(g_sdk.mutex); - CHECK_TRUE(g_sdk.idle_velocity_reads_after_stop >= 3); - } - CHECK_TRUE(arm.moveJ(joint_b, options).ok()); - - // A hardware E-stop cancels and terminates the active waypoint. Releasing - // the switch does not clear the software latch or grant a new permit. - JointPositionCommand joint_c{{0.34, -0.02, 0.09, 0.05, -0.02, 0.07}}; - holdNextMotion(); - int before_estop_move = 0; - int before_estop_stop = 0; - { - std::lock_guard lock(g_sdk.mutex); - before_estop_move = g_sdk.move_j_calls; - before_estop_stop = g_sdk.group_stop_calls; - } - auto estop_move = std::async(std::launch::async, [&]() { - return arm.moveJ(joint_c, options); - }); - CHECK_TRUE(waitUntil([&]() { - std::lock_guard lock(g_sdk.mutex); - return g_sdk.move_j_calls > before_estop_move; - })); - setHardwareEmergencyStop(true); - CHECK_TRUE(waitUntil([&]() { - std::lock_guard lock(g_sdk.mutex); - return g_sdk.group_stop_calls > before_estop_stop; - })); - CHECK_TRUE(estop_move.wait_for(2s) == std::future_status::ready); - if (estop_move.wait_for(0ms) == std::future_status::ready) { - CHECK_TRUE(!estop_move.get().ok()); - } - setHardwareEmergencyStop(false); - std::this_thread::sleep_for(150ms); - - int move_count_while_latched = 0; - { - std::lock_guard lock(g_sdk.mutex); - move_count_while_latched = g_sdk.move_j_calls; - } - const auto rejected_while_latched = arm.moveJ(joint_a, options); - CHECK_TRUE(!rejected_while_latched.ok()); - { - std::lock_guard lock(g_sdk.mutex); - CHECK_TRUE(g_sdk.move_j_calls == move_count_while_latched); - } - CHECK_TRUE(arm.clearFault().ok()); - CHECK_TRUE(arm.torqueOn().ok()); - CHECK_TRUE(arm.moveJ(joint_a, options).ok()); - - // Speed commands own the controller while waiting. A different motion is - // rejected, and Stop releases ownership only after termination. - holdNextMotion(); - JointVelocityCommand speed{{0.1, 0.0, 0.0, 0.0, 0.0, 0.0}}; - int speed_calls_before = 0; - { - std::lock_guard lock(g_sdk.mutex); - speed_calls_before = g_sdk.speed_j_calls; - } - auto speed_motion = std::async(std::launch::async, [&]() { - return arm.speedJ(speed, 0.5, 2.0); - }); - CHECK_TRUE(waitUntil([&]() { - std::lock_guard lock(g_sdk.mutex); - return g_sdk.speed_j_calls > speed_calls_before; - })); - CHECK_TRUE(!arm.moveL(pose_a, options).ok()); - CHECK_TRUE(arm.stopMotion().ok()); - CHECK_TRUE(speed_motion.wait_for(1s) == std::future_status::ready); - if (speed_motion.wait_for(0ms) == std::future_status::ready) { - CHECK_TRUE(!speed_motion.get().ok()); - } - CHECK_TRUE(!arm.busy()); - - // SpeedL used to hold the SDK mutex while waiting, which deadlocked its - // own timeout/Stop path. A concurrent Stop must cancel it, settle the - // controller, and allow a genuinely new Move command afterwards. - holdNextMotion(); - CartesianVelocity line_speed; - line_speed.vx = 0.05; - int speed_l_calls_before = 0; - { - std::lock_guard lock(g_sdk.mutex); - speed_l_calls_before = g_sdk.speed_l_calls; - } - auto line_speed_motion = std::async(std::launch::async, [&]() { - return arm.speedL(line_speed, 0.5, 2.0, FrameType::Base); - }); - CHECK_TRUE(waitUntil([&]() { - std::lock_guard lock(g_sdk.mutex); - return g_sdk.speed_l_calls > speed_l_calls_before; - })); - CHECK_TRUE(arm.stopMotion().ok()); - CHECK_TRUE(line_speed_motion.wait_for(1s) == std::future_status::ready); - if (line_speed_motion.wait_for(0ms) == std::future_status::ready) { - CHECK_TRUE(!line_speed_motion.get().ok()); - } - CHECK_TRUE(!arm.busy()); - CHECK_TRUE(arm.moveJ(joint_b, options).ok()); - - // A dual-channel emergency input mismatch is a typed emergency latch. It - // remains blocked after the wiring level is healthy and is recovered only - // through the emergency recovery path. - int stops_before_signal_fault = 0; - { - std::lock_guard lock(g_sdk.mutex); - stops_before_signal_fault = g_sdk.group_stop_calls; - } - setEmergencySignalFault(true); - CHECK_TRUE(waitUntil([&]() { - std::lock_guard lock(g_sdk.mutex); - return g_sdk.group_stop_calls > stops_before_signal_fault; - })); - setEmergencySignalFault(false); - std::this_thread::sleep_for(100ms); - CHECK_TRUE(!arm.moveJ(joint_c, options).ok()); - CHECK_TRUE(arm.torqueOn().ok()); - CHECK_TRUE(arm.moveJ(joint_c, options).ok()); - - // Power-off holds a terminal barrier through GrpDisable. Motion remains - // denied until an explicit enable confirms the powered state again. - CHECK_TRUE(arm.torqueOff().ok()); - CHECK_TRUE(!arm.moveJ(joint_a, options).ok()); - CHECK_TRUE(arm.torqueOn().ok()); - CHECK_TRUE(arm.moveJ(joint_a, options).ok()); - - // Servo and program modes retain ownership beyond the start call. Stop of - // a retained program must use StopScript as well as the group stop path. - ServoOptions servo_options; - CHECK_TRUE(arm.startServoMode(servo_options).ok()); - CHECK_TRUE(!arm.moveJ(joint_b, options).ok()); - CHECK_TRUE(arm.servoJ(joint_b).ok()); - CHECK_TRUE(arm.stopServoMode().ok()); - CHECK_TRUE(!arm.busy()); - - CHECK_TRUE(arm.loadProgram("fake_program.script").ok()); - CHECK_TRUE(arm.playProgram().ok()); - CHECK_TRUE(!arm.moveJ(joint_c, options).ok()); - int stop_script_calls_before = 0; - { - std::lock_guard lock(g_sdk.mutex); - stop_script_calls_before = g_sdk.stop_script_calls; - } - CHECK_TRUE(arm.stopMotion().ok()); - { - std::lock_guard lock(g_sdk.mutex); - CHECK_TRUE(g_sdk.stop_script_calls > stop_script_calls_before); - } - CHECK_TRUE(!arm.busy()); - - // Retire an in-flight stale generation after transport loss before - // reconnecting; no old waiter may issue SDK reads into the new session. - holdNextMotion(); - int moves_before_transport_loss = 0; - { - std::lock_guard lock(g_sdk.mutex); - moves_before_transport_loss = g_sdk.move_j_calls; - } - auto transport_lost_move = std::async(std::launch::async, [&]() { - return arm.moveJ(joint_c, options); - }); - CHECK_TRUE(waitUntil([&]() { - std::lock_guard lock(g_sdk.mutex); - return g_sdk.move_j_calls > moves_before_transport_loss; - })); - dropFakeTransport(); - CHECK_TRUE(arm.connect("127.0.0.1", 10003).ok()); - CHECK_TRUE(transport_lost_move.wait_for(1s) == std::future_status::ready); - if (transport_lost_move.wait_for(0ms) == std::future_status::ready) { - CHECK_TRUE(!transport_lost_move.get().ok()); - } - CHECK_TRUE(arm.moveJ(joint_b, options).ok()); - CHECK_TRUE(arm.disconnect().ok()); - - resetFakeSdk(); - HuayanRobot shutdown_arm(makeConfig()); - CHECK_TRUE(shutdown_arm.connect("127.0.0.1", 10003).ok()); - CHECK_TRUE(shutdown_arm.shutdown().ok()); - CHECK_TRUE(!shutdown_arm.isConnected()); - return failures == 0 ? 0 : 1; -} diff --git a/cmvr-es/devices/arm/huayan_arm/tests/huayan_lifecycle_state_test.cpp b/cmvr-es/devices/arm/huayan_arm/tests/huayan_lifecycle_state_test.cpp deleted file mode 100644 index 8bb93ff7..00000000 --- a/cmvr-es/devices/arm/huayan_arm/tests/huayan_lifecycle_state_test.cpp +++ /dev/null @@ -1,232 +0,0 @@ -#include "devices/arm/huayan_arm/huayan_lifecycle_state.h" - -#include -#include - -namespace { - -#define CHECK_TRUE(condition) \ - do { \ - if (!(condition)) { \ - std::cerr << "CHECK_TRUE failed at line " << __LINE__ << ": " \ - << #condition << std::endl; \ - return 1; \ - } \ - } while (false) - -} // namespace - -int main() -{ - using namespace cmvr::device::huayan_internal; - - MotionState motion; - CHECK_TRUE(motion.begin(MotionKind::None).status == - MotionStartStatus::Invalid); - - // A completed target does not poison an identical subsequent command, - // while an actually concurrent command is rejected. - const auto first_joint = motion.begin(MotionKind::Joint); - CHECK_TRUE(first_joint.started()); - CHECK_TRUE(motion.begin(MotionKind::Joint).status == - MotionStartStatus::Busy); - CHECK_TRUE(motion.begin(MotionKind::Linear).status == - MotionStartStatus::Busy); - motion.finish(first_joint.token); - const auto repeated_joint = motion.begin(MotionKind::Joint); - CHECK_TRUE(repeated_joint.started()); - CHECK_TRUE(repeated_joint.token.generation > - first_joint.token.generation); - motion.finish(first_joint.token); - CHECK_TRUE(motion.ownerActive(repeated_joint.token)); - motion.finish(repeated_joint.token); - CHECK_TRUE(!motion.busy()); - - // Stop cancels the current generation and cannot complete before its - // owner exits. - const auto linear = motion.begin(MotionKind::Linear); - CHECK_TRUE(linear.started()); - const auto stop_linear = motion.beginStop(); - CHECK_TRUE(stop_linear.started()); - CHECK_TRUE(stop_linear.kind == MotionKind::Linear); - CHECK_TRUE(stop_linear.active_token.generation == - linear.token.generation); - CHECK_TRUE(stop_linear.tracked_motion); - CHECK_TRUE(motion.cancelled(linear.token)); - CHECK_TRUE(motion.beginStop().status == - StopStartStatus::AlreadyStopping); - CHECK_TRUE(motion.begin(MotionKind::Joint).status == - MotionStartStatus::Stopping); - CHECK_TRUE(!motion.waitForOwnerExit( - linear.token, std::chrono::milliseconds(1))); - CHECK_TRUE(!motion.completeStop()); - motion.finish(linear.token); - CHECK_TRUE(motion.waitForOwnerExit( - linear.token, std::chrono::milliseconds(1))); - CHECK_TRUE(motion.completeStop()); - CHECK_TRUE(!motion.busy()); - - // An uncertain submission/completion remains fail-closed until a - // positively acknowledged Stop clears it. - const auto failed_speed = motion.begin(MotionKind::SpeedLinear); - CHECK_TRUE(failed_speed.started()); - motion.failMotion(failed_speed.token); - CHECK_TRUE(motion.snapshot().blocked); - CHECK_TRUE(motion.begin(MotionKind::Joint).status == - MotionStartStatus::Blocked); - const auto stop_failed_speed = motion.beginStop(); - CHECK_TRUE(stop_failed_speed.kind == MotionKind::SpeedLinear); - CHECK_TRUE(stop_failed_speed.tracked_motion); - CHECK_TRUE(motion.completeStop()); - - const auto failed_stop_motion = motion.begin(MotionKind::Joint); - CHECK_TRUE(failed_stop_motion.started()); - const auto failed_stop = motion.beginStop(); - CHECK_TRUE(failed_stop.kind == MotionKind::Joint); - motion.failStop(); - CHECK_TRUE(motion.snapshot().blocked); - CHECK_TRUE(motion.begin(MotionKind::Linear).status == - MotionStartStatus::Blocked); - motion.finish(failed_stop_motion.token); - const auto retry_failed_stop = motion.beginStop(); - CHECK_TRUE(retry_failed_stop.kind == MotionKind::Joint); - CHECK_TRUE(motion.completeStop()); - - // Servo and program modes remain owned after their start RPC returns. - const auto servo = motion.begin(MotionKind::Servo); - CHECK_TRUE(servo.started()); - motion.finish(servo.token, MotionFinishMode::Retain); - CHECK_TRUE(motion.snapshot().retained_kind == MotionKind::Servo); - CHECK_TRUE(motion.begin(MotionKind::Program).status == - MotionStartStatus::Busy); - const auto servo_update = motion.begin(MotionKind::Servo, true); - CHECK_TRUE(servo_update.started()); - motion.finish(servo_update.token); - CHECK_TRUE(motion.snapshot().retained_kind == MotionKind::Servo); - const auto stop_servo = motion.beginStop(); - CHECK_TRUE(stop_servo.kind == MotionKind::Servo); - CHECK_TRUE(stop_servo.tracked_motion); - CHECK_TRUE(motion.completeStop()); - - const auto program = motion.begin(MotionKind::Program); - CHECK_TRUE(program.started()); - motion.finish(program.token, MotionFinishMode::Retain); - const auto cancelled_program = motion.cancelActiveForSafety(); - CHECK_TRUE(cancelled_program.kind == MotionKind::Program); - CHECK_TRUE(cancelled_program.tracked_motion); - CHECK_TRUE(!cancelled_program.active_token.valid()); - CHECK_TRUE(motion.begin(MotionKind::Joint).status == - MotionStartStatus::Blocked); - const auto stop_program = motion.beginStop(); - CHECK_TRUE(stop_program.kind == MotionKind::Program); - CHECK_TRUE(motion.completeStop()); - - const auto safety_move = motion.begin(MotionKind::SpeedJoint); - CHECK_TRUE(safety_move.started()); - const auto cancelled_move = motion.cancelActiveForSafety(); - CHECK_TRUE(cancelled_move.kind == MotionKind::SpeedJoint); - CHECK_TRUE(cancelled_move.active_token.generation == - safety_move.token.generation); - CHECK_TRUE(motion.cancelled(safety_move.token)); - motion.finish(safety_move.token); - const auto stop_safety_move = motion.beginStop(); - CHECK_TRUE(stop_safety_move.kind == MotionKind::SpeedJoint); - CHECK_TRUE(motion.completeStop()); - - RawSafetyState raw; - CHECK_TRUE(classifySafetyCondition(raw) == SafetyCondition::Unknown); - raw.valid = true; - CHECK_TRUE(classifySafetyCondition(raw) == SafetyCondition::Normal); - raw.software_protective_stop = true; - CHECK_TRUE(classifySafetyCondition(raw) == - SafetyCondition::SoftwareProtectiveStop); - raw.software_emergency_stop = true; - CHECK_TRUE(classifySafetyCondition(raw) == - SafetyCondition::SoftwareEmergencyStop); - raw.robot_fault = 1; - CHECK_TRUE(classifySafetyCondition(raw) == - SafetyCondition::RobotFault); - raw.safeguard_stop = 1; - CHECK_TRUE(classifySafetyCondition(raw) == - SafetyCondition::SafeguardStop); - raw.emergency_stop = 1; - CHECK_TRUE(classifySafetyCondition(raw) == - SafetyCondition::EmergencyStop); - raw.safeguard_signal_fault = 1; - CHECK_TRUE(classifySafetyCondition(raw) == - SafetyCondition::SafeguardSignalFault); - raw.emergency_signal_fault = 1; - CHECK_TRUE(classifySafetyCondition(raw) == - SafetyCondition::EmergencySignalFault); - - SafetyState safety; - CHECK_TRUE(!safety.tryPermit().has_value()); - safety.observe(SafetyCondition::Normal); - const auto initial_permit = safety.tryPermit(); - CHECK_TRUE(initial_permit.has_value()); - CHECK_TRUE(safety.validate(*initial_permit)); - - safety.observe(SafetyCondition::EmergencyStop); - CHECK_TRUE(safety.snapshot().latched); - CHECK_TRUE(!safety.validate(*initial_permit)); - CHECK_TRUE(!safety.beginRecovery(safety.snapshot().epoch).has_value()); - const auto first_emergency_epoch = safety.snapshot().epoch; - safety.observe(SafetyCondition::EmergencyStop); - safety.observe(SafetyCondition::EmergencyStop); - CHECK_TRUE(safety.snapshot().epoch == first_emergency_epoch); - - // Releasing the hardware switch only changes the observed level; it does - // not clear the event latch or issue a new motion permit. - safety.observe(SafetyCondition::Normal); - CHECK_TRUE(safety.snapshot().latched); - CHECK_TRUE(!safety.tryPermit().has_value()); - - const auto not_ready = safety.beginRecovery(safety.snapshot().epoch); - CHECK_TRUE(not_ready.has_value()); - CHECK_TRUE(!safety.completeRecovery(*not_ready, false, true, true)); - CHECK_TRUE(safety.snapshot().latched); - safety.failRecovery(*not_ready); - - const auto not_idle = safety.beginRecovery(safety.snapshot().epoch); - CHECK_TRUE(not_idle.has_value()); - CHECK_TRUE(!safety.completeRecovery(*not_idle, true, false, true)); - CHECK_TRUE(safety.snapshot().latched); - safety.failRecovery(*not_idle); - - const auto not_cancelled = - safety.beginRecovery(safety.snapshot().epoch); - CHECK_TRUE(not_cancelled.has_value()); - CHECK_TRUE(!safety.completeRecovery(*not_cancelled, true, true, false)); - CHECK_TRUE(safety.snapshot().latched); - safety.failRecovery(*not_cancelled); - - const auto recovery_retry = - safety.beginRecovery(safety.snapshot().epoch); - CHECK_TRUE(recovery_retry.has_value()); - CHECK_TRUE(safety.completeRecovery( - *recovery_retry, true, true, true)); - const auto recovered_permit = safety.tryPermit(); - CHECK_TRUE(recovered_permit.has_value()); - CHECK_TRUE(safety.validate(*recovered_permit)); - - // A second safety event, including the same physical E-stop being pressed - // again, invalidates an older recovery token atomically. - safety.observe(SafetyCondition::EmergencyStop); - safety.observe(SafetyCondition::Normal); - const auto stale_recovery = - safety.beginRecovery(safety.snapshot().epoch); - CHECK_TRUE(stale_recovery.has_value()); - safety.observe(SafetyCondition::EmergencyStop); - safety.observe(SafetyCondition::Normal); - CHECK_TRUE(!safety.completeRecovery( - *stale_recovery, true, true, true)); - CHECK_TRUE(safety.snapshot().latched); - CHECK_TRUE(!safety.snapshot().recovery_in_progress); - - const auto stale_epoch = safety.snapshot().epoch; - safety.observe(SafetyCondition::SafeguardStop); - safety.observe(SafetyCondition::Normal); - CHECK_TRUE(!safety.beginRecovery(stale_epoch).has_value()); - - return 0; -} diff --git a/cmvr-es/devices/arm/ume_robot_arm/CMakeLists.txt b/cmvr-es/devices/arm/ume_robot_arm/CMakeLists.txt index f92b6ecd..17c4ff22 100644 --- a/cmvr-es/devices/arm/ume_robot_arm/CMakeLists.txt +++ b/cmvr-es/devices/arm/ume_robot_arm/CMakeLists.txt @@ -21,72 +21,3 @@ target_link_libraries(ume_robot_arm add_library(cmvr_es::device::ume_robot_arm ALIAS ume_robot_arm) install(TARGETS ume_robot_arm LIBRARY DESTINATION lib) - -if(BUILD_TESTING) - add_executable(damiao_mit_codec_test - tests/damiao_mit_codec_test.cpp - ) - target_link_libraries(damiao_mit_codec_test - PRIVATE - cmvr_es::device::ume_robot_arm - gtest - gtest_main - pthread - ) - add_test( - NAME damiao_mit_codec_test - COMMAND damiao_mit_codec_test - ) - set(_ume_robot_arm_test_environment - "LD_LIBRARY_PATH=${CMVR_TEST_EXTERNAL_LIBRARY_PATH}" - ) - if(CMVR_TEST_SYSTEM_LIBSTDCXX) - list(APPEND _ume_robot_arm_test_environment - "LD_PRELOAD=${CMVR_TEST_SYSTEM_LIBSTDCXX}") - endif() - set_tests_properties(damiao_mit_codec_test PROPERTIES - TIMEOUT 10 - ENVIRONMENT "${_ume_robot_arm_test_environment}" - ) - - add_executable(damiao_can_fd_chain_test - tests/damiao_can_fd_chain_test.cpp - ) - target_link_libraries(damiao_can_fd_chain_test - PRIVATE - cmvr_es::device::ume_robot_arm - gtest - gtest_main - pthread - ) - add_test( - NAME damiao_can_fd_chain_test - COMMAND damiao_can_fd_chain_test - ) - set_tests_properties(damiao_can_fd_chain_test PROPERTIES - TIMEOUT 10 - ENVIRONMENT "${_ume_robot_arm_test_environment}" - ) - - add_executable(ume_robot_arm_test - tests/ume_robot_arm_test.cpp - ) - target_link_libraries(ume_robot_arm_test - PRIVATE - cmvr_es::device::ume_robot_arm - gtest - gtest_main - pthread - ) - target_compile_definitions(ume_robot_arm_test PRIVATE - CMVR_UME_ARM_CONFIG_PATH="${PROJECT_SOURCE_DIR}/cmvr-es/config/devices/arm/ume_arms.pb.txt" - ) - add_test( - NAME ume_robot_arm_test - COMMAND ume_robot_arm_test - ) - set_tests_properties(ume_robot_arm_test PROPERTIES - TIMEOUT 10 - ENVIRONMENT "${_ume_robot_arm_test_environment}" - ) -endif() diff --git a/cmvr-es/devices/arm/ume_robot_arm/tests/damiao_can_fd_chain_test.cpp b/cmvr-es/devices/arm/ume_robot_arm/tests/damiao_can_fd_chain_test.cpp deleted file mode 100644 index 782ce46c..00000000 --- a/cmvr-es/devices/arm/ume_robot_arm/tests/damiao_can_fd_chain_test.cpp +++ /dev/null @@ -1,407 +0,0 @@ -#include "arm/ume_robot_arm/include/damiao_can_fd_chain.h" - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "canbus/abstract_canbus.h" - -namespace cmvr::device { -namespace { - -class FakeCanbus final : public AbstractCanbus { -public: - std::string typeName() const override { return "FakeCanbus"; } - bool init() override - { - initialized = true; - return init_result; - } - bool start() override - { - started = start_result; - is_started_ = started; - return started; - } - bool stop() override - { - stopped = true; - started = false; - is_started_ = false; - return true; - } - - msgs::ErrorCode send(const std::vector& frames, - int32_t* frame_num) override - { - if (!started || !frame_num || - *frame_num != static_cast(frames.size())) { - return msgs::ErrorCode::CAN_CLIENT_ERROR_SEND_FAILED; - } - if (!send_result) { - return msgs::ErrorCode::CAN_CLIENT_ERROR_SEND_FAILED; - } - sent_batches.push_back(frames); - if (!scheduled_replies.empty()) { - for (const auto& reply : scheduled_replies.front()) { - replies.push_back(reply); - } - scheduled_replies.pop_front(); - } - return msgs::ErrorCode::OK; - } - - msgs::ErrorCode receive(std::vector* frames, - int32_t* frame_num) override - { - if (!started || !frames || !frame_num || replies.empty()) { - return msgs::ErrorCode::CAN_CLIENT_ERROR_RECV_FAILED; - } - frames->clear(); - frames->push_back(replies.front()); - replies.pop_front(); - *frame_num = 1; - return msgs::ErrorCode::OK; - } - - bool discardPendingFrames() override - { - ++drain_calls; - if (drain_delay > std::chrono::microseconds::zero()) { - std::this_thread::sleep_for(drain_delay); - } - replies.clear(); - return drain_result; - } - - std::string getErrorString(int32_t) override { return {}; } - - void enqueueReplies(std::vector batch) - { - scheduled_replies.push_back(std::move(batch)); - } - - bool init_result{true}; - bool start_result{true}; - bool initialized{false}; - bool started{false}; - bool stopped{false}; - bool drain_result{true}; - bool send_result{true}; - std::size_t drain_calls{0}; - std::chrono::microseconds drain_delay{0}; - std::vector> sent_batches; - std::deque replies; - std::deque> scheduled_replies; -}; - -DamiaoJointSpec joint(std::string name, - std::uint32_t command_id, - std::uint32_t feedback_id, - std::uint8_t reported_id, - int direction = 1) -{ - DamiaoJointSpec spec; - spec.joint_name = std::move(name); - spec.command_id = command_id; - spec.feedback_id = feedback_id; - spec.reported_motor_id = reported_id; - spec.model = DamiaoMotorModel::DM4310; - spec.direction = direction; - spec.zero_offset_rad = direction == 1 ? 0.1 : -0.2; - spec.joint_lower_rad = -2.0; - spec.joint_upper_rad = 2.0; - spec.max_velocity_rad_s = 3.0; - spec.max_torque_nm = 2.0; - spec.healthy_status_mask = 1U << 0U; - spec.max_driver_temperature_raw = 80U; - spec.max_motor_temperature_raw = 90U; - return spec; -} - -CanFrame feedback(std::uint32_t id, - std::uint8_t reported_id, - std::uint8_t status = 0U) -{ - CanFrame frame; - frame.id = id; - frame.len = 8; - frame.is_fd = true; - frame.bitrate_switch = true; - frame.rx_monotonic_ns = 100; - frame.data[0] = - static_cast((status << 4U) | reported_id); - frame.data[1] = 0x80; - frame.data[2] = 0x00; - frame.data[3] = 0x80; - frame.data[4] = 0x08; - frame.data[5] = 0x00; - frame.data[6] = 30U; - frame.data[7] = 35U; - return frame; -} - -std::chrono::steady_clock::time_point soon() -{ - return std::chrono::steady_clock::now() + - std::chrono::milliseconds(20); -} - -std::size_t countLifecycleByte( - const std::vector>& batches, - const std::uint8_t value) -{ - std::size_t count = 0; - for (const auto& batch : batches) { - for (const auto& frame : batch) { - if (frame.len == 8 && - frame.data[0] == 0xFF && - frame.data[7] == value) { - ++count; - } - } - } - return count; -} - -TEST(DamiaoCanFdChainTest, PassiveOpenNeverEnablesHardware) -{ - auto bus = std::make_shared(); - DamiaoCanFdChain chain( - bus, {joint("J1", 1, 0x11, 1)}, - DamiaoChainOptions{true, true, false}); - - ASSERT_TRUE(chain.init().ok()); - ASSERT_TRUE(chain.openPassive().ok()); - EXPECT_EQ(chain.state(), DamiaoChainState::Passive); - EXPECT_TRUE(bus->sent_batches.empty()); - - const auto arm_result = chain.arm(soon()); - EXPECT_FALSE(arm_result.ok()); - EXPECT_EQ(arm_result.code, ArmErrorCode::CommandRejected); - EXPECT_TRUE(bus->sent_batches.empty()); -} - -TEST(DamiaoCanFdChainTest, ExplicitArmAndExchangeUseUniqueConfiguredFeedback) -{ - auto bus = std::make_shared(); - DamiaoCanFdChain chain( - bus, - {joint("J1", 1, 0x11, 1), - joint("J2", 2, 0x12, 2, -1)}, - DamiaoChainOptions{true, true, true}); - ASSERT_TRUE(chain.init().ok()); - ASSERT_TRUE(chain.openPassive().ok()); - - // A stale invalid frame is already queued before this request. The drain - // must remove it; only replies generated by the subsequent send may be - // accepted. - bus->replies.push_back(feedback(0x11, 1, 2)); - bus->enqueueReplies({ - feedback(0x12, 2), - feedback(0x11, 1), - }); - ASSERT_TRUE(chain.arm(soon()).ok()); - EXPECT_EQ(chain.state(), DamiaoChainState::Armed); - EXPECT_EQ(countLifecycleByte(bus->sent_batches, 0xFC), 2U); - - bus->enqueueReplies({ - feedback(0x11, 1), - feedback(0x12, 2), - }); - DamiaoMitCommand commands[2]{}; - commands[0].tau_ff_nm = 1.0; - commands[1].tau_ff_nm = -1.0; - DamiaoJointFeedback states[2]{}; - ASSERT_TRUE(chain.exchange( - commands, 2, states, 2, soon()).ok()); - EXPECT_EQ(chain.state(), DamiaoChainState::Active); - EXPECT_TRUE(states[0].valid); - EXPECT_TRUE(states[1].valid); - // J2 has direction=-1 and offset=-0.2. - EXPECT_NEAR(states[1].q_rad, -0.2003814697265625, 1e-12); - EXPECT_NEAR(states[1].dq_rad_s, -0.0146484375, 1e-12); - EXPECT_NEAR(states[1].tau_nm, -0.0048828125, 1e-12); -} - -TEST(DamiaoCanFdChainTest, MissedFeedbackLatchesFaultAndNeverReenables) -{ - auto bus = std::make_shared(); - DamiaoCanFdChain chain( - bus, {joint("J1", 1, 0x11, 1)}, - DamiaoChainOptions{true, true, true}); - ASSERT_TRUE(chain.init().ok()); - ASSERT_TRUE(chain.openPassive().ok()); - bus->enqueueReplies({feedback(0x11, 1)}); - ASSERT_TRUE(chain.arm(soon()).ok()); - - DamiaoMitCommand command; - DamiaoJointFeedback state; - const auto result = chain.exchange( - &command, 1, &state, 1, - std::chrono::steady_clock::now() + - std::chrono::milliseconds(1)); - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, ArmErrorCode::Timeout); - EXPECT_EQ(chain.state(), DamiaoChainState::FaultLatched); - EXPECT_EQ(countLifecycleByte(bus->sent_batches, 0xFC), 1U); - EXPECT_GE(countLifecycleByte(bus->sent_batches, 0xFD), 1U); - - // Clearing the fault is explicit and leaves the chain passive. - bus->enqueueReplies({feedback(0x11, 1)}); - ASSERT_TRUE(chain.clearFault(soon()).ok()); - EXPECT_EQ(chain.state(), DamiaoChainState::Passive); - EXPECT_EQ(countLifecycleByte(bus->sent_batches, 0xFC), 1U); -} - -TEST(DamiaoCanFdChainTest, DuplicateFeedbackCannotSatisfyAGroupCycle) -{ - auto bus = std::make_shared(); - DamiaoCanFdChain chain( - bus, - {joint("J1", 1, 0x11, 1), - joint("J2", 2, 0x12, 2)}, - DamiaoChainOptions{true, true, true}); - ASSERT_TRUE(chain.init().ok()); - ASSERT_TRUE(chain.openPassive().ok()); - bus->enqueueReplies({ - feedback(0x11, 1), - feedback(0x12, 2), - }); - ASSERT_TRUE(chain.arm(soon()).ok()); - - bus->enqueueReplies({ - feedback(0x11, 1), - feedback(0x11, 1), - }); - DamiaoMitCommand commands[2]{}; - DamiaoJointFeedback states[2]{}; - EXPECT_FALSE(chain.exchange( - commands, 2, states, 2, - std::chrono::steady_clock::now() + - std::chrono::milliseconds(1)).ok()); - EXPECT_EQ(chain.state(), DamiaoChainState::FaultLatched); - EXPECT_EQ(chain.statistics().duplicate_feedback, 1U); -} - -TEST(DamiaoCanFdChainTest, RejectsUnreviewedStatusAndClassicFrame) -{ - auto bus = std::make_shared(); - DamiaoCanFdChain chain( - bus, {joint("J1", 1, 0x11, 1)}, - DamiaoChainOptions{true, true, true}); - ASSERT_TRUE(chain.init().ok()); - ASSERT_TRUE(chain.openPassive().ok()); - bus->enqueueReplies({feedback(0x11, 1)}); - ASSERT_TRUE(chain.arm(soon()).ok()); - - bus->enqueueReplies({feedback(0x11, 1, 2)}); - DamiaoMitCommand command; - DamiaoJointFeedback state; - EXPECT_FALSE(chain.exchange( - &command, 1, &state, 1, soon()).ok()); - EXPECT_EQ(chain.state(), DamiaoChainState::FaultLatched); - - auto second_bus = std::make_shared(); - DamiaoCanFdChain second( - second_bus, {joint("J1", 1, 0x11, 1)}, - DamiaoChainOptions{true, true, true}); - ASSERT_TRUE(second.init().ok()); - ASSERT_TRUE(second.openPassive().ok()); - auto classic = feedback(0x11, 1); - classic.is_fd = false; - classic.bitrate_switch = false; - second_bus->enqueueReplies({classic}); - EXPECT_FALSE(second.arm(soon()).ok()); - EXPECT_EQ(second.state(), DamiaoChainState::FaultLatched); - - auto third_bus = std::make_shared(); - DamiaoCanFdChain third( - third_bus, {joint("J1", 1, 0x11, 1)}, - DamiaoChainOptions{true, true, true}); - ASSERT_TRUE(third.init().ok()); - ASSERT_TRUE(third.openPassive().ok()); - auto error_passive = feedback(0x11, 1); - error_passive.error_state_indicator = true; - third_bus->enqueueReplies({error_passive}); - EXPECT_FALSE(third.arm(soon()).ok()); - EXPECT_EQ(third.state(), DamiaoChainState::FaultLatched); -} - -TEST(DamiaoCanFdChainTest, HardwareEnableRequiresReviewedHealthContract) -{ - auto bus = std::make_shared(); - auto unreviewed = joint("J1", 1, 0x11, 1); - unreviewed.healthy_status_mask = 0U; - DamiaoCanFdChain chain( - bus, {unreviewed}, - DamiaoChainOptions{true, true, true}); - - const auto result = chain.init(); - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, ArmErrorCode::InvalidArgument); - EXPECT_FALSE(bus->initialized); -} - -TEST(DamiaoCanFdChainTest, DisableReportsUnconfirmedSafetyFrames) -{ - auto bus = std::make_shared(); - DamiaoCanFdChain chain( - bus, {joint("J1", 1, 0x11, 1)}, - DamiaoChainOptions{true, true, true}); - ASSERT_TRUE(chain.init().ok()); - ASSERT_TRUE(chain.openPassive().ok()); - bus->enqueueReplies({feedback(0x11, 1)}); - ASSERT_TRUE(chain.arm(soon()).ok()); - - bus->send_result = false; - const auto result = chain.disable(); - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, ArmErrorCode::CommandFailed); - EXPECT_EQ(chain.state(), DamiaoChainState::FaultLatched); -} - -TEST(DamiaoCanFdChainTest, ExpiredDeadlineAfterDrainNeverCommitsEnable) -{ - auto bus = std::make_shared(); - DamiaoCanFdChain chain( - bus, {joint("J1", 1, 0x11, 1)}, - DamiaoChainOptions{true, true, true}); - ASSERT_TRUE(chain.init().ok()); - ASSERT_TRUE(chain.openPassive().ok()); - - bus->drain_delay = std::chrono::milliseconds(3); - bus->enqueueReplies({feedback(0x11, 1)}); - const auto result = chain.arm( - std::chrono::steady_clock::now() + - std::chrono::milliseconds(1)); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, ArmErrorCode::Timeout); - EXPECT_EQ(chain.state(), DamiaoChainState::FaultLatched); - EXPECT_EQ(countLifecycleByte(bus->sent_batches, 0xFC), 0U); - EXPECT_GE(countLifecycleByte(bus->sent_batches, 0xFD), 1U); -} - -TEST(DamiaoCanFdChainTest, ConfigurationRejectsAmbiguousMappings) -{ - auto bus = std::make_shared(); - DamiaoCanFdChain chain( - bus, - {joint("J1", 1, 0x11, 1), - joint("J1", 2, 0x12, 2)}, - DamiaoChainOptions{true, true, false}); - const auto result = chain.init(); - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, ArmErrorCode::InvalidArgument); - EXPECT_FALSE(bus->initialized); -} - -} // namespace -} // namespace cmvr::device diff --git a/cmvr-es/devices/arm/ume_robot_arm/tests/damiao_mit_codec_test.cpp b/cmvr-es/devices/arm/ume_robot_arm/tests/damiao_mit_codec_test.cpp deleted file mode 100644 index 5a3bcef1..00000000 --- a/cmvr-es/devices/arm/ume_robot_arm/tests/damiao_mit_codec_test.cpp +++ /dev/null @@ -1,150 +0,0 @@ -#include "arm/ume_robot_arm/include/damiao_mit_codec.h" - -#include -#include -#include - -#include - -namespace cmvr::device { -namespace { - -void expectPayload(const CanFrame& frame, - const std::array& expected) -{ - ASSERT_EQ(frame.len, expected.size()); - for (std::size_t i = 0; i < expected.size(); ++i) { - EXPECT_EQ(frame.data[i], expected[i]) << "byte " << i; - } -} - -TEST(DamiaoMitCodecTest, MatchesLegacyPythonGoldenVectors) -{ - CanFrame frame; - DamiaoMitCommand zero; - auto result = DamiaoMitCodec::encodeMit( - 1, DamiaoMotorModel::DM4310, zero, true, true, frame); - ASSERT_TRUE(result); - EXPECT_EQ(result.saturation_mask, DAMIAO_SATURATION_NONE); - EXPECT_TRUE(frame.is_fd); - EXPECT_TRUE(frame.bitrate_switch); - expectPayload(frame, {0x7F, 0xFF, 0x7F, 0xF0, - 0x00, 0x00, 0x07, 0xFF}); - - DamiaoMitCommand nontrivial; - nontrivial.kp = 100.0; - nontrivial.kd = 1.0; - nontrivial.q_rad = 1.25; - nontrivial.dq_rad_s = -2.5; - nontrivial.tau_ff_nm = 3.0; - result = DamiaoMitCodec::encodeMit( - 1, DamiaoMotorModel::DM4310, nontrivial, false, false, frame); - ASSERT_TRUE(result); - expectPayload(frame, {0x8C, 0xCC, 0x75, 0x43, - 0x33, 0x33, 0x3A, 0x65}); -} - -TEST(DamiaoMitCodecTest, ReportsProtocolSaturationWithoutHidingIt) -{ - DamiaoMitCommand command; - command.q_rad = 100.0; - command.dq_rad_s = -100.0; - command.kp = 600.0; - command.kd = -1.0; - command.tau_ff_nm = 100.0; - CanFrame frame; - const auto result = DamiaoMitCodec::encodeMit( - 2, DamiaoMotorModel::DM4310, command, false, false, frame); - ASSERT_TRUE(result); - EXPECT_EQ( - result.saturation_mask, - DAMIAO_SATURATION_Q | DAMIAO_SATURATION_DQ | - DAMIAO_SATURATION_KP | DAMIAO_SATURATION_KD | - DAMIAO_SATURATION_TAU); -} - -TEST(DamiaoMitCodecTest, RejectsNonFiniteInput) -{ - DamiaoMitCommand command; - command.tau_ff_nm = std::numeric_limits::quiet_NaN(); - CanFrame frame; - const auto result = DamiaoMitCodec::encodeMit( - 1, DamiaoMotorModel::DM4310, command, false, false, frame); - EXPECT_FALSE(result); - EXPECT_EQ(result.error, DamiaoCodecError::NonFiniteInput); -} - -TEST(DamiaoMitCodecTest, EncodesLifecycleFramesWithoutEnablingImplicitly) -{ - CanFrame frame; - ASSERT_EQ(DamiaoMitCodec::encodeMode( - 3, DamiaoMode::Enable, true, true, frame), - DamiaoCodecError::None); - expectPayload(frame, {0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC}); - - ASSERT_EQ(DamiaoMitCodec::encodeMode( - 3, DamiaoMode::Disable, true, true, frame), - DamiaoCodecError::None); - EXPECT_EQ(frame.data[7], 0xFD); - ASSERT_EQ(DamiaoMitCodec::encodeMode( - 3, DamiaoMode::SetZero, true, true, frame), - DamiaoCodecError::None); - EXPECT_EQ(frame.data[7], 0xFE); - ASSERT_EQ(DamiaoMitCodec::encodeMode( - 3, DamiaoMode::ClearFault, true, true, frame), - DamiaoCodecError::None); - EXPECT_EQ(frame.data[7], 0xFB); -} - -TEST(DamiaoMitCodecTest, DecodesLegacyFeedbackAndRequiresConfiguredId) -{ - CanFrame frame; - frame.id = 0x11; - frame.len = 8; - frame.is_fd = true; - frame.bitrate_switch = true; - frame.rx_monotonic_ns = 1234567; - frame.data[0] = 0xA1; - frame.data[1] = 0x80; - frame.data[2] = 0x00; - frame.data[3] = 0x80; - frame.data[4] = 0x08; - frame.data[5] = 0x00; - frame.data[6] = 40; - frame.data[7] = 41; - - DamiaoJointFeedback feedback; - EXPECT_EQ(DamiaoMitCodec::decodeFeedback( - frame, 0x12, DamiaoMotorModel::DM4310, feedback), - DamiaoCodecError::UnexpectedFeedbackId); - EXPECT_FALSE(feedback.valid); - - ASSERT_EQ(DamiaoMitCodec::decodeFeedback( - frame, 0x11, DamiaoMotorModel::DM4310, feedback), - DamiaoCodecError::None); - EXPECT_TRUE(feedback.valid); - EXPECT_EQ(feedback.reported_motor_id, 1); - EXPECT_EQ(feedback.status, 0x0A); - EXPECT_EQ(feedback.driver_temperature_raw, 40); - EXPECT_EQ(feedback.motor_temperature_raw, 41); - EXPECT_EQ(feedback.rx_monotonic_ns, 1234567); - EXPECT_NEAR(feedback.q_rad, 0.0003814697265625, 1e-12); - EXPECT_NEAR(feedback.dq_rad_s, 0.0146484375, 1e-12); - EXPECT_NEAR(feedback.tau_nm, 0.0048828125, 1e-12); -} - -TEST(DamiaoMitCodecTest, ContainsAllLegacyMotorRanges) -{ - EXPECT_DOUBLE_EQ( - DamiaoMitCodec::limitsFor(DamiaoMotorModel::DM8009).tau_max_nm, - 54.0); - EXPECT_DOUBLE_EQ( - DamiaoMitCodec::limitsFor(DamiaoMotorModel::DMH3510).dq_max_rad_s, - 280.0); - EXPECT_FALSE( - DamiaoMitCodec::limitsFor(DamiaoMotorModel::Unknown).valid()); -} - -} // namespace -} // namespace cmvr::device diff --git a/cmvr-es/devices/arm/ume_robot_arm/tests/ume_robot_arm_test.cpp b/cmvr-es/devices/arm/ume_robot_arm/tests/ume_robot_arm_test.cpp deleted file mode 100644 index e7241ebc..00000000 --- a/cmvr-es/devices/arm/ume_robot_arm/tests/ume_robot_arm_test.cpp +++ /dev/null @@ -1,338 +0,0 @@ -#include "arm/ume_robot_arm/include/ume_robot_arm.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "canbus/abstract_canbus.h" -#include "common/io/proto_file_io.h" - -#ifndef CMVR_UME_ARM_CONFIG_PATH -#define CMVR_UME_ARM_CONFIG_PATH "" -#endif - -namespace cmvr::device { -namespace { - -class LoopbackDamiaoBus final : public AbstractCanbus { -public: - std::string typeName() const override { return "LoopbackDamiaoBus"; } - bool init() override - { - std::lock_guard lock(mutex); - initialized = true; - return true; - } - bool start() override - { - std::lock_guard lock(mutex); - started = true; - is_started_ = true; - return true; - } - bool stop() override - { - std::lock_guard lock(mutex); - started = false; - is_started_ = false; - return true; - } - - msgs::ErrorCode send( - const std::vector& frames, - int32_t* frame_num) override - { - std::lock_guard lock(mutex); - if (!started || !frame_num || - *frame_num != static_cast(frames.size())) { - return msgs::ErrorCode::CAN_CLIENT_ERROR_SEND_FAILED; - } - if (!send_result) { - return msgs::ErrorCode::CAN_CLIENT_ERROR_SEND_FAILED; - } - sent_batches.push_back(frames); - for (const auto& frame : frames) { - if (frame.id < 1U || frame.id > 8U) { - continue; - } - CanFrame reply; - reply.id = 0x10U + frame.id; - reply.len = 8U; - reply.is_fd = true; - reply.bitrate_switch = true; - reply.rx_monotonic_ns = - std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count(); - reply.data[0] = static_cast(frame.id); - reply.data[1] = 0x80U; - reply.data[2] = 0x00U; - reply.data[3] = 0x80U; - reply.data[4] = 0x08U; - reply.data[5] = 0x00U; - replies.push_back(reply); - } - return msgs::ErrorCode::OK; - } - - msgs::ErrorCode receive( - std::vector* frames, - int32_t* frame_num) override - { - std::lock_guard lock(mutex); - if (!started || !frames || !frame_num || replies.empty()) { - return msgs::ErrorCode::CAN_CLIENT_ERROR_RECV_FAILED; - } - frames->clear(); - frames->push_back(replies.front()); - replies.pop_front(); - *frame_num = 1; - return msgs::ErrorCode::OK; - } - - bool discardPendingFrames() override - { - std::lock_guard lock(mutex); - replies.clear(); - return started; - } - - std::string getErrorString(int32_t) override { return {}; } - - void setSendResult(const bool result) - { - std::lock_guard lock(mutex); - send_result = result; - } - - std::size_t lifecycleCount(const std::uint8_t byte) const - { - std::lock_guard lock(mutex); - std::size_t count = 0; - for (const auto& batch : sent_batches) { - for (const auto& frame : batch) { - if (frame.len == 8U && - frame.data[0] == 0xFFU && - frame.data[7] == byte) { - ++count; - } - } - } - return count; - } - - bool initialized{false}; - bool started{false}; - bool send_result{true}; - std::deque replies; - std::vector> sent_batches; - mutable std::mutex mutex; -}; - -config::RobotArmConfig configFor(const bool hardware_enabled) -{ - config::RobotArmConfig cfg; - cfg.set_id("ume_right"); - auto* ume = cfg.mutable_ume(); - ume->set_hardware_enabled(hardware_enabled); - ume->set_control_frequency_hz(800U); - ume->set_cycle_deadline_us(1000U); - ume->set_feedback_watchdog_ms(20U); - auto* can = ume->mutable_can(); - can->set_interface_name("fake-can"); - can->set_enable_fd(true); - can->set_bitrate_switch(true); - can->set_send_timeout_us(100U); - can->set_receive_timeout_us(100U); - can->set_receive_own_messages(false); - for (std::uint32_t i = 1; i <= 8U; ++i) { - auto* joint = ume->add_joints(); - joint->set_joint_name("RJ" + std::to_string(i)); - joint->set_command_id(i); - joint->set_feedback_id(0x10U + i); - joint->set_reported_motor_id(i); - joint->set_model(config::DAMIAO_MOTOR_MODEL_DM4310); - joint->set_direction(1); - joint->set_joint_lower_rad(-2.0); - joint->set_joint_upper_rad(2.0); - joint->set_max_velocity_rad_s(3.0); - joint->set_max_torque_nm(2.0); - joint->add_healthy_feedback_status(0U); - joint->set_max_driver_temperature_raw(80U); - joint->set_max_motor_temperature_raw(90U); - } - return cfg; -} - -bool waitUntil( - const std::function& predicate, - const std::chrono::milliseconds timeout) -{ - const auto deadline = std::chrono::steady_clock::now() + timeout; - while (std::chrono::steady_clock::now() < deadline) { - if (predicate()) { - return true; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - return predicate(); -} - -TEST(UmeRobotArmTest, LifecycleIsPassiveUntilExplicitFreshTorqueCommand) -{ - auto bus = std::make_shared(); - UmeRobotArm arm(configFor(true), bus); - - ASSERT_TRUE(arm.init()); - EXPECT_EQ(bus->lifecycleCount(0xFCU), 0U); - ASSERT_TRUE(arm.start()); - EXPECT_EQ(bus->lifecycleCount(0xFCU), 0U); - - TorqueServoOptions options; - options.period = 0.00125; - options.command_watchdog_ms = 100U; - ASSERT_TRUE(arm.startTorqueMode(options).ok()); - JointTorqueCommand command; - command.torque.assign(8U, 0.0); - ASSERT_TRUE(arm.servoTorque(command).ok()); - ASSERT_TRUE(arm.torqueOn().ok()); - - ASSERT_TRUE(waitUntil( - [&arm] { return arm.getJointState().sequence > 0U; }, - std::chrono::milliseconds(30))); - const auto state = arm.getJointState(); - EXPECT_TRUE(state.position_valid); - EXPECT_TRUE(state.velocity_valid); - EXPECT_TRUE(state.effort_valid); - EXPECT_EQ(state.position.size(), 8U); - EXPECT_EQ(bus->lifecycleCount(0xFCU), 8U); - EXPECT_EQ(arm.getControlMode(), ControlMode::Torque); - - EXPECT_TRUE(arm.stop()); - EXPECT_GE(bus->lifecycleCount(0xFDU), 8U); -} - -TEST(UmeRobotArmTest, StaleCommandLatchesFaultAndNeverReenables) -{ - auto bus = std::make_shared(); - UmeRobotArm arm(configFor(true), bus); - ASSERT_TRUE(arm.init()); - ASSERT_TRUE(arm.start()); - - TorqueServoOptions options; - options.period = 0.001; - options.command_watchdog_ms = 2U; - ASSERT_TRUE(arm.startTorqueMode(options).ok()); - JointTorqueCommand command; - command.torque.assign(8U, 0.0); - ASSERT_TRUE(arm.servoTorque(command).ok()); - ASSERT_TRUE(arm.torqueOn().ok()); - ASSERT_TRUE(waitUntil( - [&arm] { return arm.isFault(); }, - std::chrono::milliseconds(50))); - - EXPECT_FALSE(arm.busy()); - EXPECT_EQ(bus->lifecycleCount(0xFCU), 8U); - EXPECT_GE(bus->lifecycleCount(0xFDU), 8U); - EXPECT_EQ(arm.healthSnapshot().state, DeviceHealthState::Fault); -} - -TEST(UmeRobotArmTest, HardwareGateRejectsEnableWithoutWritingIt) -{ - auto bus = std::make_shared(); - UmeRobotArm arm(configFor(false), bus); - ASSERT_TRUE(arm.init()); - ASSERT_TRUE(arm.start()); - ASSERT_TRUE(arm.startTorqueMode(TorqueServoOptions{}).ok()); - JointTorqueCommand command; - command.torque.assign(8U, 0.0); - ASSERT_TRUE(arm.servoTorque(command).ok()); - - const auto result = arm.torqueOn(); - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, ArmErrorCode::CommandRejected); - EXPECT_EQ(bus->lifecycleCount(0xFCU), 0U); -} - -TEST(UmeRobotArmTest, PositionServoIsExplicitlyUnsupported) -{ - auto bus = std::make_shared(); - UmeRobotArm arm(configFor(false), bus); - JointPositionCommand command; - command.position.assign(8U, 0.0); - const auto result = arm.servoJ(command); - EXPECT_EQ(result.code, ArmErrorCode::UnsupportedCommand); -} - -TEST(UmeRobotArmTest, RejectsCycleDeadlineLongerThanControlPeriod) -{ - auto cfg = configFor(false); - cfg.mutable_ume()->set_cycle_deadline_us(2000U); - auto bus = std::make_shared(); - UmeRobotArm arm(cfg, bus); - - EXPECT_FALSE(arm.init()); - EXPECT_FALSE(bus->initialized); - EXPECT_EQ( - arm.healthSnapshot().state, - DeviceHealthState::Fault); -} - -TEST(UmeRobotArmTest, RejectsReportedMotorIdBeforeNarrowingConversion) -{ - auto cfg = configFor(false); - cfg.mutable_ume()->mutable_joints(0)->set_reported_motor_id(257U); - auto bus = std::make_shared(); - UmeRobotArm arm(cfg, bus); - - EXPECT_FALSE(arm.init()); - EXPECT_FALSE(bus->initialized); - EXPECT_EQ(arm.healthSnapshot().state, DeviceHealthState::Fault); -} - -TEST(UmeRobotArmTest, EmergencyStopReportsUnconfirmedDisable) -{ - auto bus = std::make_shared(); - UmeRobotArm arm(configFor(true), bus); - ASSERT_TRUE(arm.init()); - ASSERT_TRUE(arm.start()); - - bus->setSendResult(false); - const auto result = arm.emergencyStop(); - - EXPECT_FALSE(result.ok()); - EXPECT_EQ(result.code, ArmErrorCode::CommandFailed); - EXPECT_TRUE(arm.isEmergencyStopped()); - EXPECT_TRUE(arm.isFault()); - EXPECT_NE( - arm.healthSnapshot().error_message.find("zero/disable failed"), - std::string::npos); -} - -TEST(UmeRobotArmTest, CheckedInDualArmConfigParsesAndKeepsHardwareDisabled) -{ - config::ArmRootConfig root; - ASSERT_TRUE(ProtoMessageIo::getProtoFromAsciiFile( - CMVR_UME_ARM_CONFIG_PATH, &root)); - ASSERT_EQ(root.arm().robot_arms_size(), 2); - for (const auto& arm : root.arm().robot_arms()) { - ASSERT_TRUE(arm.has_ume()); - EXPECT_EQ(arm.ume().joints_size(), 8); - EXPECT_FALSE(arm.ume().hardware_enabled()); - EXPECT_TRUE(arm.ume().can().enable_fd()); - EXPECT_TRUE(arm.ume().can().bitrate_switch()); - EXPECT_GT(arm.ume().can().send_timeout_us(), 0U); - EXPECT_FALSE(arm.ume().can().receive_own_messages()); - } -} - -} // namespace -} // namespace cmvr::device diff --git a/cmvr-es/devices/canbus/can_client/pcan/pcan_client.cc b/cmvr-es/devices/canbus/can_client/pcan/pcan_client.cc deleted file mode 100644 index 0dc99860..00000000 --- a/cmvr-es/devices/canbus/can_client/pcan/pcan_client.cc +++ /dev/null @@ -1,205 +0,0 @@ -#include "common/base/logging/logger.h" -#include "pcan_client.h" - -#include -#include -#include -#include -#include "cmvr/msgs/error_code.pb.h" -#include "cstdio" - -namespace cmvr { - namespace device { -#define CAN_ID_MASK 0x1FFFF800U // can_filter mask -#define CAN_STANDARD_MAX_ID 0x7FFU - - using cmvr::msgs::ErrorCode; - using cmvr::msgs::CANCardParameter; - PcanClient::PcanClient(const config::SocketCanConfig &cfg) { - port_ = static_cast(cfg.channel_id()); - interface_ = CANCardParameter::NATIVE; - enable_can_err_check_ = false; - } - - PcanClient::~PcanClient() { - stop(); - } - - bool PcanClient::init() { - - -#define LPCSTR const char* - /// - /// Sets a TPCANDevice value. The input can be numeric, in hexadecimal or decimal format, or as string denoting - /// a TPCANDevice value name. - /// - LPCSTR DeviceType = "PCAN_PCI"; - /// - /// Sets value in range of a double. The input can be hexadecimal or decimal format. - /// - LPCSTR DeviceID = ""; - /// - /// Sets a zero-based index value in range of a double. The input can be hexadecimal or decimal format. - /// - LPCSTR ControllerNumber = ""; - /// - /// Sets a valid Internet Protocol address - /// - LPCSTR IPAddress = ""; - /// - /// Sets a valid GUID for a PCAN device - /// - LPCSTR DeviceGUID = ""; - - - char sParameters[260]; - if (DeviceType != "") - snprintf(sParameters, sizeof(sParameters), "%s=%s", LOOKUP_DEVICE_TYPE, DeviceType); - if (DeviceID != "") - { - if (sParameters != "") - snprintf(sParameters, sizeof(sParameters), "%s, ", sParameters); - snprintf(sParameters, sizeof(sParameters), "%s%s=%s", sParameters, LOOKUP_DEVICE_ID, DeviceID); - } - if (ControllerNumber != "") - { - if (sParameters != "") - snprintf(sParameters, sizeof(sParameters), "%s, ", sParameters); - snprintf(sParameters, sizeof(sParameters), "%s%s=%s", sParameters, LOOKUP_CONTROLLER_NUMBER, ControllerNumber); - } - if (IPAddress != "") - { - if (sParameters != "") - snprintf(sParameters, sizeof(sParameters), "%s, ", sParameters); - snprintf(sParameters, sizeof(sParameters), "%s%s=%s", sParameters, LOOKUP_IP_ADDRESS, IPAddress); - } - - if (DeviceGUID != "") - { - if (sParameters != "") - snprintf(sParameters, sizeof(sParameters), "%s, ", sParameters); - snprintf(sParameters, sizeof(sParameters), "%s%s=%s", sParameters, LOOKUP_DEVICE_GUID, DeviceGUID); - } - - TPCANHandle handle; - TPCANStatus stsResult = CAN_LookUpChannel((LPSTR)sParameters, &handle); - TPCANStatus ret = CAN_Initialize(PcanHandle, Bitrate); - if (ret != PCAN_ERROR_OK) { - CMVR_LOG(ERROR) << "send message failed, error code: " << ret; - return false; - } - - TPCANStatus state = CAN_GetStatus(PcanHandle); - if (state & PCAN_ERROR_BUSOFF) { - // 进入 bus-off,尝试复位总线 - CMVR_LOG(ERROR) << "send message failed, error code: " << ret; - return false; - } - - return true; - } - - bool PcanClient::start() { - is_started_ = true; - return true; - } - - bool PcanClient::stop() { - if (is_started_) { - is_started_ = false; - CAN_Uninitialize(dev_handler_); - CMVR_LOG(INFO) << "close socket can ok. port:" << port_; - } - return true; - } - - cmvr::msgs::ErrorCode PcanClient::send(const std::vector &frames, int32_t *const frame_num) { - if (frame_num == nullptr) { - CMVR_LOG(FATAL) << "frame_num is null"; - } - if (frames.size() != static_cast(*frame_num)) { - CMVR_LOG(FATAL) << "frames size does not match frame_num"; - } - - if (!is_started_) { - CMVR_LOG(ERROR) << "Nvidia can client has not been initiated! Please init first!"; - return ErrorCode::CAN_CLIENT_ERROR_SEND_FAILED; - } - for (size_t i = 0; i < frames.size() && i < MAX_CAN_SEND_FRAME_LEN; ++i) { - if (frames[i].len > CANBUS_MESSAGE_LENGTH || frames[i].len < 0) { - CMVR_LOG(ERROR) << "frames[" << i << "].len = " << frames[i].len - << ", which is not equal to can message data length (" - << CANBUS_MESSAGE_LENGTH << ")."; - return ErrorCode::CAN_CLIENT_ERROR_SEND_FAILED; - } - if (frames[i].id > CAN_STANDARD_MAX_ID) { - send_frames_[i].ID = (frames[i].id & CAN_EFF_MASK) | CAN_EFF_FLAG; - } else { - send_frames_[i].ID = (frames[i].id & CAN_SFF_MASK); - } - // CMVR_LOG(INFO) << "send can id is " << send_frames_[i].can_id; - send_frames_[i].LEN = frames[i].len; - std::memcpy(send_frames_[i].DATA, frames[i].data, frames[i].len); - send_frames_[i].MSGTYPE = PCAN_MESSAGE_EXTENDED; - // Synchronous transmission of CAN messages - TPCANStatus ret = CAN_Write(PcanHandle, &send_frames_[i]); - if (ret != PCAN_ERROR_OK) { - CMVR_LOG(ERROR) << "send message failed, error code: " << ret; - return ErrorCode::CAN_CLIENT_ERROR_BASE; - } - } - - return ErrorCode::OK; - } - - cmvr::msgs::ErrorCode PcanClient::receive(std::vector *const frames, int32_t *const frame_num) { - if (!is_started_) { - CMVR_LOG(ERROR) << "Nvidia can client is not init! Please init first!"; - return ErrorCode::CAN_CLIENT_ERROR_RECV_FAILED; - } - - if (*frame_num > MAX_CAN_RECV_FRAME_LEN || *frame_num < 0) { - CMVR_LOG(ERROR) << "recv can frame num not in range[0, " << MAX_CAN_RECV_FRAME_LEN - << "], frame_num:" << *frame_num; - // TODO(Authors): check the difference of returning frame_num/error_code - return ErrorCode::CAN_CLIENT_ERROR_FRAME_NUM; - } - TPCANTimestamp CANTimeStamp; - for (int32_t i = 0; i < *frame_num && i < MAX_CAN_RECV_FRAME_LEN; ++i) { - CanFrame cf; - - // We execute the "Read" function of the PCANBasic - TPCANStatus ret = CAN_Read(PcanHandle, &recv_frames_[i], &CANTimeStamp); - if (ret != PCAN_ERROR_OK) { - - CMVR_LOG(ERROR) << "receive message failed, error code: " << ret; - return ErrorCode::CAN_CLIENT_ERROR_BASE; - } - if (recv_frames_[i].LEN > CANBUS_MESSAGE_LENGTH || - recv_frames_[i].LEN < 0) { - CMVR_LOG(ERROR) << "recv_frames_[" << i - << "].can_dlc = " << recv_frames_[i].LEN - << ", which is not equal to can message data length (" - << CANBUS_MESSAGE_LENGTH << ")."; - return ErrorCode::CAN_CLIENT_ERROR_RECV_FAILED; - } - if (recv_frames_[i].ID > CAN_STANDARD_MAX_ID) { - cf.id = enable_can_err_check_ - ? recv_frames_[i].ID & CAN_EFF_MASK | CAN_ERR_FLAG - : recv_frames_[i].ID & CAN_EFF_MASK; - } else { - cf.id = (recv_frames_[i].ID & CAN_SFF_MASK); - } - CMVR_LOG(INFO) << "Socket can receive can id is " << recv_frames_[i].ID; - cf.len = recv_frames_[i].LEN; - std::memcpy(cf.data, recv_frames_[i].DATA, recv_frames_[i].LEN); - frames->push_back(cf); - } - return ErrorCode::OK; - } - - std::string PcanClient::getErrorString(const int32_t status) { - return ""; - } - } // namespace device -} // namespace cmvr diff --git a/cmvr-es/devices/canbus/can_client/pcan/pcan_client.h b/cmvr-es/devices/canbus/can_client/pcan/pcan_client.h deleted file mode 100644 index 94401e65..00000000 --- a/cmvr-es/devices/canbus/can_client/pcan/pcan_client.h +++ /dev/null @@ -1,86 +0,0 @@ -// -// Created by lgv on 2025/8/7. -// - -/** - * @file - * @brief Defines the SocketCanClientRaw class which inherits AbstractCanbus. - */ -#pragma once - -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include "cmvr/msgs/error_code.pb.h" -#include "cmvr/msgs/can_card_parameter.pb.h" -#include "cmvr/config/motor_config/motor_config.pb.h" - -#include "gflags/gflags.h" -#include "../../abstract_canbus.h" -#include "canbus/common/canbus_consts.h" - -#include - -namespace cmvr { - namespace device { - - class PcanClient final : public AbstractCanbus { - public: - explicit PcanClient(const config::SocketCanConfig &cfg); - ~PcanClient(); - std::string typeName() const override { return "PcanClient"; } - bool init() override; - bool start() override; - bool stop() override; - - /** - * @brief Send messages - * @param frames The messages to send. - * @param frame_num The amount of messages to send. - * @return The status of the sending action - */ - cmvr::msgs::ErrorCode send(const std::vector &frames, - int32_t *const frame_num) override; - - /** - * @brief Receive messages - * @param frames The messages to receive. - * @param frame_num The amount of messages to receive. - * @return The status of the receiving action - */ - cmvr::msgs::ErrorCode receive(std::vector *const frames, - int32_t *const frame_num) override; - - /** - * @brief Get the error string. - * @param status The status to get the error string. - */ - std::string getErrorString(const int32_t status) override; - private: - int dev_handler_ = 0; - cmvr::msgs::CANCardParameter::CANChannelId port_; - cmvr::msgs::CANCardParameter::CANInterface interface_; - TPCANMsg send_frames_[MAX_CAN_SEND_FRAME_LEN]; - TPCANMsg recv_frames_[MAX_CAN_RECV_FRAME_LEN]; - - - // - bool enable_can_err_check_{false}; - const TPCANHandle PcanHandle = PCAN_USBBUS1; - const TPCANBaudrate Bitrate = PCAN_BAUD_1M; - }; - } -} diff --git a/cmvr-es/devices/canbus/can_client/pcan/pcan_client_test.cpp b/cmvr-es/devices/canbus/can_client/pcan/pcan_client_test.cpp deleted file mode 100644 index e493b851..00000000 --- a/cmvr-es/devices/canbus/can_client/pcan/pcan_client_test.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "common/base/logging/logger.h" -// -// Created by lgv on 2025/8/7. -// -#include "cmvr/msgs/error_code.pb.h" -#include "cmvr/msgs/can_card_parameter.pb.h" -#include "canbus/can_client/pcan/pcan_client.h" -#include "gtest/gtest.h" -namespace cmvr { - namespace device { - using cmvr::msgs::ErrorCode; - using cmvr::msgs::CANCardParameter; - - TEST(PcanClienTest, simple_test) { - CANCardParameter param; - param.set_brand(CANCardParameter::SOCKET_CAN_RAW); - param.set_channel_id(CANCardParameter::CHANNEL_ID_ZERO); - - config::SocketCanConfig cfg; - cfg.set_channel_id(0); - PcanClient socket_can_client(cfg); - - socket_can_client.init(); - - // EXPECT_EQ(socket_can_client.start(), ErrorCode::CAN_CLIENT_ERROR_BASE); - socket_can_client.start(); - std::vector frames; - // int32_t num = 0; - // EXPECT_EQ(socket_can_client.send(frames, &num), - // ErrorCode::OK); - // ++num; - // EXPECT_EQ(socket_can_client.receive(&frames, &num), - // ErrorCode::OK); - // CMVR_LOG(INFO) << frames.at(0).CanFrameString(); - CanFrame can_frame; - can_frame.id = 0x123; - can_frame.len = 8; - memset(can_frame.data, 0xA3, sizeof(can_frame.data)); - frames.clear(); - frames.push_back(can_frame); - EXPECT_EQ(socket_can_client.sendSingleFrame(frames), - ErrorCode::OK); - socket_can_client.stop(); - } - } -} diff --git a/cmvr-es/devices/dexhand/rh56dftp_dexhand/CMakeLists.txt b/cmvr-es/devices/dexhand/rh56dftp_dexhand/CMakeLists.txt index 0c340a57..1e522d43 100644 --- a/cmvr-es/devices/dexhand/rh56dftp_dexhand/CMakeLists.txt +++ b/cmvr-es/devices/dexhand/rh56dftp_dexhand/CMakeLists.txt @@ -7,30 +7,3 @@ add_library(cmvr_es::device::rh56dftp_dexhand ALIAS rh56dftp_dexhand) target_link_libraries(rh56dftp_dexhand PRIVATE cmvr_es::hardware cmvr_es::proto -lmodbus) install(TARGETS rh56dftp_dexhand LIBRARY DESTINATION lib) - -if(BUILD_TESTING) - add_executable(rh56dftp_dexhand_stop_all_test - tests/rh56dftp_dexhand_stop_all_test.cpp - ) - target_link_libraries(rh56dftp_dexhand_stop_all_test PRIVATE - cmvr_es::device::rh56dftp_dexhand - gtest - gtest_main - pthread - ) - add_test( - NAME rh56dftp_dexhand_stop_all_test - COMMAND rh56dftp_dexhand_stop_all_test - ) - set(_rh56_stop_all_test_environment - "LD_LIBRARY_PATH=${CMVR_TEST_EXTERNAL_LIBRARY_PATH}" - ) - if(CMVR_TEST_SYSTEM_LIBSTDCXX) - list(APPEND _rh56_stop_all_test_environment - "LD_PRELOAD=${CMVR_TEST_SYSTEM_LIBSTDCXX}") - endif() - set_tests_properties(rh56dftp_dexhand_stop_all_test PROPERTIES - TIMEOUT 10 - ENVIRONMENT "${_rh56_stop_all_test_environment}" - ) -endif() diff --git a/cmvr-es/devices/dexhand/rh56dftp_dexhand/tests/rh56dftp_dexhand_stop_all_test.cpp b/cmvr-es/devices/dexhand/rh56dftp_dexhand/tests/rh56dftp_dexhand_stop_all_test.cpp deleted file mode 100644 index 9414588c..00000000 --- a/cmvr-es/devices/dexhand/rh56dftp_dexhand/tests/rh56dftp_dexhand_stop_all_test.cpp +++ /dev/null @@ -1,348 +0,0 @@ -#include "devices/dexhand/rh56dftp_dexhand/include/rh56dftp_dexhand.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace cmvr::device { -namespace { - -using namespace std::chrono_literals; - -class FakeModbusController final : public ModbusController { -public: - bool open(const std::string&, int) override - { - std::lock_guard lock(mutex_); - open_ = true; - return true; - } - - void close() override - { - std::lock_guard lock(mutex_); - open_ = false; - } - - bool isOpen() const override - { - std::lock_guard lock(mutex_); - return open_; - } - - bool writeRegisters( - int, - const uint16_t* values, - const int count) override - { - std::unique_lock lock(mutex_); - ++write_calls_; - write_started_ = true; - condition_.notify_all(); - condition_.wait(lock, [this] { return !block_write_; }); - if (!write_succeeds_) { - return false; - } - actual_angles_.assign(values, values + count); - return true; - } - - bool readRegisterBlock( - const int address, - const int count, - std::vector& values) override - { - std::unique_lock lock(mutex_); - ++read_calls_; - read_started_ = true; - condition_.notify_all(); - condition_.wait(lock, [this] { return !block_read_; }); - const std::vector* source = &actual_angles_; - std::vector sampled_angles; - if (address == 1546 && !actual_angle_samples_.empty()) { - const auto sample = actual_angle_samples_.front(); - actual_angle_samples_.pop_front(); - sampled_angles.assign(sample.begin(), sample.end()); - source = &sampled_angles; - } - values.assign(static_cast(count), 0U); - for (std::size_t index = 0; - index < values.size() && index < source->size(); - ++index) { - values[index] = (*source)[index]; - } - return read_succeeds_; - } - - void setActualAngles(const std::array& values) - { - std::lock_guard lock(mutex_); - actual_angles_.assign(values.begin(), values.end()); - actual_angle_samples_.clear(); - } - - void setActualAngleSamples( - std::deque> samples) - { - std::lock_guard lock(mutex_); - actual_angle_samples_ = std::move(samples); - } - - void setWriteSucceeds(const bool succeeds) - { - std::lock_guard lock(mutex_); - write_succeeds_ = succeeds; - } - - void blockNextRead() - { - std::lock_guard lock(mutex_); - block_read_ = true; - read_started_ = false; - } - - void releaseRead() - { - { - std::lock_guard lock(mutex_); - block_read_ = false; - } - condition_.notify_all(); - } - - bool waitForRead(const std::chrono::milliseconds timeout) - { - std::unique_lock lock(mutex_); - return condition_.wait_for( - lock, timeout, [this] { return read_started_; }); - } - - bool waitForReadCalls( - const int expected, - const std::chrono::milliseconds timeout) - { - std::unique_lock lock(mutex_); - return condition_.wait_for( - lock, timeout, [this, expected] { return read_calls_ >= expected; }); - } - - void blockNextWrite() - { - std::lock_guard lock(mutex_); - block_write_ = true; - write_started_ = false; - } - - void releaseWrite() - { - { - std::lock_guard lock(mutex_); - block_write_ = false; - } - condition_.notify_all(); - } - - bool waitForWrite(const std::chrono::milliseconds timeout) - { - std::unique_lock lock(mutex_); - return condition_.wait_for( - lock, timeout, [this] { return write_started_; }); - } - - int readCalls() const - { - std::lock_guard lock(mutex_); - return read_calls_; - } - - int writeCalls() const - { - std::lock_guard lock(mutex_); - return write_calls_; - } - -private: - mutable std::mutex mutex_; - std::condition_variable condition_; - std::vector actual_angles_{6U, 0U}; - std::deque> actual_angle_samples_; - bool open_{false}; - bool block_read_{false}; - bool block_write_{false}; - bool read_started_{false}; - bool write_started_{false}; - bool read_succeeds_{true}; - bool write_succeeds_{true}; - int read_calls_{0}; - int write_calls_{0}; -}; - -struct TestHand { - TestHand() - { - config.set_id("rh56-test"); - config.set_ip("fake-modbus"); - auto controller = std::make_unique(); - fake = controller.get(); - hand = std::make_unique( - config, std::move(controller)); - EXPECT_TRUE(hand->init()); - } - - ~TestHand() - { - if (hand) { - hand->stop(); - } - } - - config::RH56DFTPDexHandConfig config; - FakeModbusController* fake{nullptr}; - std::unique_ptr hand; -}; - -TEST(RH56DFTPDexhandStopAllTest, IdleTactileDeviceStopsWithoutClosingLifecycle) -{ - TestHand fixture; - - EXPECT_TRUE(fixture.hand->stopOperationalActivity()); - EXPECT_EQ(fixture.hand->state(), AbstractDexHand::Status::INITIALIZED); - EXPECT_TRUE(fixture.fake->isOpen()); - - const int reads_before = fixture.fake->readCalls(); - (void)fixture.hand->getSensorData( - AbstractDexHand::FingerType::INDEX, - AbstractDexHand::TactileRegion::TIP); - EXPECT_EQ(fixture.fake->readCalls(), reads_before); -} - -TEST(RH56DFTPDexhandStopAllTest, UnreachedAngleTargetFailsClosedThenRecovers) -{ - TestHand fixture; - const std::vector target{100, 200, 300, 400, 500, 600}; - - fixture.hand->setAngles(target); - fixture.fake->setActualAngles({0, 0, 0, 0, 0, 0}); - EXPECT_FALSE(fixture.hand->stopOperationalActivity()); - - fixture.fake->setActualAngles({100, 200, 300, 400, 500, 600}); - EXPECT_TRUE(fixture.hand->stopOperationalActivity()); - EXPECT_TRUE(fixture.fake->isOpen()); -} - -TEST(RH56DFTPDexhandStopAllTest, MovingSampleAtTargetDoesNotConfirmStop) -{ - TestHand fixture; - const std::vector target{100, 200, 300, 400, 500, 600}; - - fixture.hand->setAngles(target); - fixture.fake->setActualAngleSamples({ - {100, 200, 300, 400, 500, 600}, - {103, 203, 303, 403, 503, 603}, - {106, 206, 306, 406, 506, 606}, - }); - EXPECT_FALSE(fixture.hand->stopOperationalActivity()); - - fixture.fake->setActualAngles({100, 200, 300, 400, 500, 600}); - EXPECT_TRUE(fixture.hand->stopOperationalActivity()); -} - -TEST(RH56DFTPDexhandStopAllTest, FailedAngleWriteRemainsUnconfirmed) -{ - TestHand fixture; - fixture.fake->setActualAngles({0, 0, 0, 0, 0, 0}); - fixture.fake->setWriteSucceeds(false); - - fixture.hand->setAngles({100, 200, 300, 400, 500, 600}); - - EXPECT_FALSE(fixture.hand->stopOperationalActivity()); -} - -TEST(RH56DFTPDexhandStopAllTest, StopWaitsForAdmittedAngleWrite) -{ - TestHand fixture; - fixture.fake->blockNextWrite(); - const std::vector target{100, 200, 300, 400, 500, 600}; - auto command = std::async(std::launch::async, [&] { - fixture.hand->setAngles(target); - }); - ASSERT_TRUE(fixture.fake->waitForWrite(500ms)); - - auto stop = std::async(std::launch::async, [&] { - return fixture.hand->stopOperationalActivity(); - }); - EXPECT_EQ(stop.wait_for(20ms), std::future_status::timeout); - - fixture.fake->releaseWrite(); - EXPECT_EQ(command.wait_for(500ms), std::future_status::ready); - command.get(); - ASSERT_EQ(stop.wait_for(500ms), std::future_status::ready); - EXPECT_TRUE(stop.get()); - - const int writes_before = fixture.fake->writeCalls(); - fixture.hand->setAngles(target); - EXPECT_EQ(fixture.fake->writeCalls(), writes_before); - EXPECT_TRUE(fixture.hand->resumeOperationalActivity()); - fixture.hand->setAngles(target); - EXPECT_EQ(fixture.fake->writeCalls(), writes_before + 1); -} - -TEST(RH56DFTPDexhandStopAllTest, StopWaitsForAdmittedTactileRead) -{ - TestHand fixture; - fixture.fake->blockNextRead(); - auto read = std::async(std::launch::async, [&] { - return fixture.hand->getSensorData( - AbstractDexHand::FingerType::INDEX, - AbstractDexHand::TactileRegion::TIP); - }); - ASSERT_TRUE(fixture.fake->waitForRead(500ms)); - - auto stop = std::async(std::launch::async, [&] { - return fixture.hand->stopOperationalActivity(); - }); - EXPECT_EQ(stop.wait_for(20ms), std::future_status::timeout); - - fixture.fake->releaseRead(); - EXPECT_EQ(read.wait_for(500ms), std::future_status::ready); - (void)read.get(); - ASSERT_EQ(stop.wait_for(500ms), std::future_status::ready); - EXPECT_TRUE(stop.get()); -} - -TEST(RH56DFTPDexhandStopAllTest, StopDrainsAndPausesBackgroundTactilePolling) -{ - TestHand fixture; - ASSERT_TRUE(fixture.hand->start()); - - const int reads_before_block = fixture.fake->readCalls(); - fixture.fake->blockNextRead(); - ASSERT_TRUE(fixture.fake->waitForReadCalls(reads_before_block + 1, 500ms)); - - auto stop = std::async(std::launch::async, [&] { - return fixture.hand->stopOperationalActivity(); - }); - EXPECT_EQ(stop.wait_for(20ms), std::future_status::timeout); - - fixture.fake->releaseRead(); - ASSERT_EQ(stop.wait_for(500ms), std::future_status::ready); - EXPECT_TRUE(stop.get()); - - const int reads_after_stop = fixture.fake->readCalls(); - std::this_thread::sleep_for(30ms); - EXPECT_EQ(fixture.fake->readCalls(), reads_after_stop); - - ASSERT_TRUE(fixture.hand->resumeOperationalActivity()); - EXPECT_TRUE(fixture.fake->waitForReadCalls(reads_after_stop + 1, 500ms)); -} - -} // namespace -} // namespace cmvr::device diff --git a/cmvr-es/devices/motor/README.md b/cmvr-es/devices/motor/README.md index 46949387..46f4e279 100644 --- a/cmvr-es/devices/motor/README.md +++ b/cmvr-es/devices/motor/README.md @@ -34,14 +34,3 @@ RobotArm 和业务 Task 只依赖 `MotorManager`/`AbstractMotor` 的稳定接口 - 软件 `emergencyStop` 和 Quick Stop 不具备功能安全等级; - 真实设备必须具有经风险评估确定的硬接线急停、安全继电器和驱动器安全链; - 新硬件配置保持 `enable: false`,完成方向、限位和故障注入验证后才能启用。 - -## 测试 - -```bash -cmake --build build --target grpc_motor_service_test -j4 -ctest --test-dir build \ - -R '^grpc_motor_service_test$' \ - --output-on-failure -``` - -该测试使用 fake motor,不替代真实总线、驱动器或安全链验证。 diff --git a/cmvr-es/devices/speaker/ffmpeg_speaker/CMakeLists.txt b/cmvr-es/devices/speaker/ffmpeg_speaker/CMakeLists.txt index c37d546c..7ff77300 100644 --- a/cmvr-es/devices/speaker/ffmpeg_speaker/CMakeLists.txt +++ b/cmvr-es/devices/speaker/ffmpeg_speaker/CMakeLists.txt @@ -7,32 +7,3 @@ add_library(cmvr_es::device::ffmpeg_speaker ALIAS ffmpeg_speaker) target_link_libraries(ffmpeg_speaker PRIVATE -lpulse-simple -lpulse cmvr_es::proto) install(TARGETS ffmpeg_speaker LIBRARY DESTINATION lib) - -if(BUILD_TESTING) - add_executable(ffmpeg_speaker_lifecycle_test - tests/ffmpeg_speaker_lifecycle_test.cpp - ) - target_link_libraries(ffmpeg_speaker_lifecycle_test - PRIVATE - cmvr_es::device::ffmpeg_speaker - avcodec - avformat - avutil - swresample - ) - add_test( - NAME ffmpeg_speaker_lifecycle_test - COMMAND ffmpeg_speaker_lifecycle_test - ) - set(_ffmpeg_speaker_test_environment - "LD_LIBRARY_PATH=${CMVR_TEST_EXTERNAL_LIBRARY_PATH}" - ) - if(CMVR_TEST_SYSTEM_LIBSTDCXX) - list(APPEND _ffmpeg_speaker_test_environment - "LD_PRELOAD=${CMVR_TEST_SYSTEM_LIBSTDCXX}") - endif() - set_tests_properties(ffmpeg_speaker_lifecycle_test PROPERTIES - TIMEOUT 10 - ENVIRONMENT "${_ffmpeg_speaker_test_environment}" - ) -endif() diff --git a/cmvr-es/devices/speaker/ffmpeg_speaker/tests/ffmpeg_speaker_lifecycle_test.cpp b/cmvr-es/devices/speaker/ffmpeg_speaker/tests/ffmpeg_speaker_lifecycle_test.cpp deleted file mode 100644 index 432a82a6..00000000 --- a/cmvr-es/devices/speaker/ffmpeg_speaker/tests/ffmpeg_speaker_lifecycle_test.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "include/ffmpeg_speaker.h" - -#include - -namespace { - -bool check(const bool condition, const char* expression, const int line) -{ - if (condition) { - return true; - } - std::cerr << "CHECK failed at line " << line << ": " << expression << '\n'; - return false; -} - -#define CHECK_TRUE(expression) \ - do { \ - if (!check(static_cast(expression), #expression, __LINE__)) { \ - return 1; \ - } \ - } while (false) - -} // namespace - -int main() -{ - cmvr::config::FFMpegSpeakerConfig config; - config.set_id("lifecycle-test-speaker"); - cmvr::device::ffmpegSpeaker speaker(config); - cmvr::device::SpeakerState state{}; - - CHECK_TRUE(speaker.init()); - speaker.getState(state); - CHECK_TRUE(state.is_initialized); - - speaker.resetPlayState(); - speaker.getState(state); - CHECK_TRUE(state.is_initialized); - - CHECK_TRUE(speaker.stopPlayback()); - speaker.getState(state); - CHECK_TRUE(state.is_initialized); - - speaker.stopStreaming(); - speaker.getState(state); - CHECK_TRUE(state.is_initialized); - - CHECK_TRUE(speaker.stop()); - speaker.getState(state); - CHECK_TRUE(!state.is_initialized); - - std::cout << "ffmpeg_speaker_lifecycle_test: PASS\n"; - return 0; -} diff --git a/cmvr-es/manager/README.md b/cmvr-es/manager/README.md index 620a6288..95b2cd5c 100644 --- a/cmvr-es/manager/README.md +++ b/cmvr-es/manager/README.md @@ -229,16 +229,6 @@ ring generation 不等于 `TrackDescriptor::generation`,ring 的 `ReadResult.s ## 测试 -MediaSourceManager: - -```bash -cmake --build build --target media_source_manager_test -ctest \ - --test-dir build \ - -R '^media_source_manager_test$' \ - --output-on-failure -``` - DeviceManager 已有 `device_manager_snapshot_test`,覆盖全量状态表、生命周期失败、 异常限长、排序和值快照并发读取。TaskManager 仍缺少独立 CTest。修改其行为时 至少补充: diff --git a/cmvr-es/manager/control_authority_manager/CMakeLists.txt b/cmvr-es/manager/control_authority_manager/CMakeLists.txt index f69da862..115d0698 100644 --- a/cmvr-es/manager/control_authority_manager/CMakeLists.txt +++ b/cmvr-es/manager/control_authority_manager/CMakeLists.txt @@ -12,23 +12,3 @@ add_library( ALIAS control_authority_manager ) install(TARGETS control_authority_manager ARCHIVE DESTINATION lib) - -if(BUILD_TESTING) - add_executable(control_authority_manager_test - tests/control_authority_manager_test.cpp - ) - target_link_libraries(control_authority_manager_test - PRIVATE - cmvr_es::control_authority_manager - gtest - gtest_main - pthread - ) - add_test( - NAME control_authority_manager_test - COMMAND control_authority_manager_test - ) - set_tests_properties(control_authority_manager_test PROPERTIES - TIMEOUT 10 - ) -endif() diff --git a/cmvr-es/manager/control_authority_manager/tests/control_authority_manager_test.cpp b/cmvr-es/manager/control_authority_manager/tests/control_authority_manager_test.cpp deleted file mode 100644 index f0703b7b..00000000 --- a/cmvr-es/manager/control_authority_manager/tests/control_authority_manager_test.cpp +++ /dev/null @@ -1,923 +0,0 @@ -#include "manager/control_authority_manager/include/control_authority_manager.h" - -#include -#include -#include - -#include - -namespace cmvr::control { -namespace { - -using namespace std::chrono_literals; - -class ControlAuthorityManagerTest : public ::testing::Test { -protected: - void SetUp() override - { - ControlAuthorityManager::instance().clear(); - } - - void TearDown() override - { - ControlAuthorityManager::instance().clear(); - } -}; - -TEST_F(ControlAuthorityManagerTest, LeaseIsExclusiveAndExactReleaseRestoresAccess) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto first = - manager.tryAcquire("right_arm", "session-a", 100ms); - ASSERT_TRUE(first.acquired); - EXPECT_TRUE(manager.validate(first.token)); - EXPECT_TRUE(manager.isLeased("right_arm")); - - const auto conflict = - manager.tryAcquire("right_arm", "session-b", 100ms); - EXPECT_FALSE(conflict.acquired); - - manager.release(first.token); - EXPECT_FALSE(manager.isLeased("right_arm")); - EXPECT_TRUE( - manager.tryAcquire("right_arm", "session-b", 100ms) - .acquired); -} - -TEST_F(ControlAuthorityManagerTest, StaleGenerationCannotReleaseNewLease) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto old = - manager.tryAcquire("right_arm", "session-a", 100ms); - ASSERT_TRUE(old.acquired); - manager.release(old.token); - const auto current = - manager.tryAcquire("right_arm", "session-a", 100ms); - ASSERT_TRUE(current.acquired); - ASSERT_NE( - old.token.generation, - current.token.generation); - - manager.release(old.token); - EXPECT_TRUE(manager.validate(current.token)); -} - -TEST_F(ControlAuthorityManagerTest, - SafetyBarrierAtomicallyPreemptsControlAndRejectsOtherOwners) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto control = - manager.tryAcquire("right_arm", "move-session", 100ms); - ASSERT_TRUE(control.acquired); - - const auto barrier = manager.preemptAcquire( - "right_arm", "stop-operation", 100ms); - ASSERT_TRUE(barrier.acquired) << barrier.detail; - EXPECT_FALSE(manager.validate(control.token)); - EXPECT_TRUE(manager.validate(barrier.token)); - - const auto move_during_stop = - manager.tryAcquire("right_arm", "new-move", 100ms); - EXPECT_FALSE(move_during_stop.acquired); - const auto second_stop = manager.preemptAcquire( - "right_arm", "second-stop", 100ms); - ASSERT_TRUE(second_stop.acquired) << second_stop.detail; - - manager.release(control.token); - EXPECT_TRUE(manager.validate(barrier.token)); - manager.release(barrier.token); - EXPECT_TRUE(manager.validate(second_stop.token)); - EXPECT_FALSE( - manager.tryAcquire("right_arm", "new-move", 100ms) - .acquired); - manager.release(second_stop.token); - EXPECT_FALSE(manager.isLeased("right_arm")); -} - -TEST_F(ControlAuthorityManagerTest, - SafetyPreemptionReturnsWhileDispatchIsInFlightAndWaitsForBoth) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto control = - manager.tryAcquire("right_arm", "move-session", 1s); - ASSERT_TRUE(control.acquired); - - auto dispatch = manager.tryBeginDispatch(control.token); - ASSERT_TRUE(dispatch.acquired()); - auto pending_barrier = std::async( - std::launch::async, - [&manager]() { - return manager.preemptAcquire( - "right_arm", "stop-operation", 1s); - }); - - const auto preempt_status = pending_barrier.wait_for(100ms); - if (preempt_status != std::future_status::ready) { - dispatch = {}; - const auto cleanup_barrier = pending_barrier.get(); - if (cleanup_barrier.acquired) { - manager.release(cleanup_barrier.token); - } - FAIL() << "safety preemption waited for an in-flight dispatch"; - return; - } - - const auto acquired_barrier = pending_barrier.get(); - ASSERT_TRUE(acquired_barrier.acquired) - << acquired_barrier.detail; - EXPECT_FALSE(manager.validate(control.token)); - EXPECT_FALSE(manager.tryBeginDispatch(control.token).acquired()); - - EXPECT_FALSE(manager.waitForPreemptedRelease( - acquired_barrier.token, 10ms)); - manager.release(control.token); - EXPECT_FALSE(manager.waitForPreemptedRelease( - acquired_barrier.token, 10ms)); - - dispatch = {}; - EXPECT_TRUE(manager.waitForPreemptedRelease( - acquired_barrier.token, 10ms)); - manager.release(acquired_barrier.token); -} - -TEST_F(ControlAuthorityManagerTest, - DispatchOnOneResourceDoesNotDelaySafetyPreemptionOnAnother) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto right_control = - manager.tryAcquire("right_arm", "right-move", 1s); - const auto left_control = - manager.tryAcquire("left_arm", "left-move", 1s); - ASSERT_TRUE(right_control.acquired); - ASSERT_TRUE(left_control.acquired); - - auto right_dispatch = manager.tryBeginDispatch(right_control.token); - ASSERT_TRUE(right_dispatch.acquired()); - auto pending_left_barrier = std::async( - std::launch::async, - [&manager]() { - return manager.preemptAcquire( - "left_arm", "left-stop", 1s); - }); - - const auto preempt_status = pending_left_barrier.wait_for(100ms); - if (preempt_status != std::future_status::ready) { - right_dispatch = {}; - const auto cleanup_barrier = pending_left_barrier.get(); - if (cleanup_barrier.acquired) { - manager.release(cleanup_barrier.token); - } - FAIL() << "one resource's dispatch blocked another resource's stop"; - return; - } - - const auto left_barrier = pending_left_barrier.get(); - ASSERT_TRUE(left_barrier.acquired) << left_barrier.detail; - manager.release(left_control.token); - EXPECT_TRUE(manager.waitForPreemptedRelease( - left_barrier.token, 0ms)); - manager.release(left_barrier.token); - - EXPECT_TRUE(right_dispatch.acquired()); - right_dispatch = {}; - manager.release(right_control.token); -} - -TEST_F(ControlAuthorityManagerTest, - DispatchGuardDestructorReleasesTheInFlightFence) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto control = - manager.tryAcquire("right_arm", "move-session", 1s); - ASSERT_TRUE(control.acquired); - - ControlAcquireResult barrier; - { - auto dispatch = manager.tryBeginDispatch(control.token); - ASSERT_TRUE(dispatch.acquired()); - barrier = manager.preemptAcquire( - "right_arm", "stop-operation", 1s); - ASSERT_TRUE(barrier.acquired) << barrier.detail; - manager.release(control.token); - EXPECT_FALSE(manager.waitForPreemptedRelease( - barrier.token, 0ms)); - } - - EXPECT_TRUE(manager.waitForPreemptedRelease(barrier.token, 0ms)); - manager.release(barrier.token); -} - -TEST_F(ControlAuthorityManagerTest, - DispatchGuardMoveAssignmentReleasesOnlyItsPreviousFence) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto right_control = - manager.tryAcquire("right_arm", "right-move", 1s); - const auto left_control = - manager.tryAcquire("left_arm", "left-move", 1s); - ASSERT_TRUE(right_control.acquired); - ASSERT_TRUE(left_control.acquired); - - auto right_dispatch = manager.tryBeginDispatch(right_control.token); - auto left_dispatch = manager.tryBeginDispatch(left_control.token); - ASSERT_TRUE(right_dispatch.acquired()); - ASSERT_TRUE(left_dispatch.acquired()); - const auto right_barrier = manager.preemptAcquire( - "right_arm", "right-stop", 1s); - const auto left_barrier = manager.preemptAcquire( - "left_arm", "left-stop", 1s); - ASSERT_TRUE(right_barrier.acquired) << right_barrier.detail; - ASSERT_TRUE(left_barrier.acquired) << left_barrier.detail; - manager.release(right_control.token); - manager.release(left_control.token); - - right_dispatch = std::move(left_dispatch); - EXPECT_TRUE(right_dispatch.acquired()); - EXPECT_FALSE(left_dispatch.acquired()); - EXPECT_TRUE(manager.waitForPreemptedRelease( - right_barrier.token, 0ms)); - EXPECT_FALSE(manager.waitForPreemptedRelease( - left_barrier.token, 0ms)); - - right_dispatch = {}; - EXPECT_TRUE(manager.waitForPreemptedRelease( - left_barrier.token, 0ms)); - manager.release(right_barrier.token); - manager.release(left_barrier.token); -} - -TEST_F(ControlAuthorityManagerTest, - RevokeKeepsAnInFlightDispatchFencedFromNormalSuccessors) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto control = - manager.tryAcquire("right_arm", "move-session", 1s); - ASSERT_TRUE(control.acquired); - auto dispatch = manager.tryBeginDispatch(control.token); - ASSERT_TRUE(dispatch.acquired()); - - manager.revoke("right_arm"); - EXPECT_FALSE(manager.validate(control.token)); - EXPECT_TRUE(manager.isLeased("right_arm")); - EXPECT_FALSE( - manager.tryAcquire("right_arm", "successor", 1s).acquired); - manager.release(control.token); - EXPECT_FALSE( - manager.tryAcquire("right_arm", "successor", 1s).acquired); - - dispatch = {}; - const auto successor = - manager.tryAcquire("right_arm", "successor", 1s); - ASSERT_TRUE(successor.acquired) << successor.detail; - manager.release(successor.token); -} - -TEST_F(ControlAuthorityManagerTest, - ClearKeepsInFlightDispatchesWhileErasingIdleEntries) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto active = - manager.tryAcquire("right_arm", "move-session", 1s); - ASSERT_TRUE(active.acquired); - ASSERT_TRUE(manager.tryAcquire("idle_arm", "idle-session", 1s).acquired); - auto dispatch = manager.tryBeginDispatch(active.token); - ASSERT_TRUE(dispatch.acquired()); - - manager.clear(); - EXPECT_FALSE( - manager.tryAcquire("right_arm", "successor", 1s).acquired); - const auto idle_successor = - manager.tryAcquire("idle_arm", "idle-successor", 1s); - ASSERT_TRUE(idle_successor.acquired) << idle_successor.detail; - manager.release(idle_successor.token); - - dispatch = {}; - const auto active_successor = - manager.tryAcquire("right_arm", "successor", 1s); - ASSERT_TRUE(active_successor.acquired) << active_successor.detail; - manager.release(active_successor.token); -} - -TEST_F(ControlAuthorityManagerTest, - ExpiredLeaseKeepsInFlightDispatchFencedFromNormalSuccessors) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto control = - manager.tryAcquire("right_arm", "move-session", 10ms); - ASSERT_TRUE(control.acquired); - auto dispatch = manager.tryBeginDispatch(control.token); - ASSERT_TRUE(dispatch.acquired()); - std::this_thread::sleep_for(20ms); - - EXPECT_FALSE(manager.validate(control.token)); - EXPECT_FALSE( - manager.tryAcquire("right_arm", "successor", 1s).acquired); - manager.release(control.token); - EXPECT_FALSE( - manager.tryAcquire("right_arm", "successor", 1s).acquired); - - dispatch = {}; - const auto successor = - manager.tryAcquire("right_arm", "successor", 1s); - ASSERT_TRUE(successor.acquired) << successor.detail; - manager.release(successor.token); -} - -TEST_F(ControlAuthorityManagerTest, - DispatchGuardSurvivesAuthorityMapRehash) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto control = - manager.tryAcquire("right_arm", "move-session", 1s); - ASSERT_TRUE(control.acquired); - auto dispatch = manager.tryBeginDispatch(control.token); - ASSERT_TRUE(dispatch.acquired()); - - for (int index = 0; index < 512; ++index) { - ASSERT_TRUE(manager.tryAcquire( - "rehash-resource-" + std::to_string(index), - "rehash-owner", - 1s).acquired); - } - - const auto barrier = manager.preemptAcquire( - "right_arm", "stop-operation", 1s); - ASSERT_TRUE(barrier.acquired) << barrier.detail; - manager.release(control.token); - EXPECT_FALSE(manager.waitForPreemptedRelease(barrier.token, 0ms)); - dispatch = {}; - EXPECT_TRUE(manager.waitForPreemptedRelease(barrier.token, 0ms)); - manager.release(barrier.token); -} - -TEST_F(ControlAuthorityManagerTest, - StaleLeaseCannotBeginDispatchAfterSafetyPreemption) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto control = - manager.tryAcquire("right_arm", "move-session", 1s); - ASSERT_TRUE(control.acquired); - const auto barrier = manager.preemptAcquire( - "right_arm", "stop-operation", 1s); - ASSERT_TRUE(barrier.acquired) << barrier.detail; - - EXPECT_FALSE(manager.tryBeginDispatch(control.token).acquired()); - manager.release(barrier.token); -} - -TEST_F(ControlAuthorityManagerTest, - ReleasedLastSafetyBarrierKeepsPreemptedHandlerFenced) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto control = - manager.tryAcquire("right_arm", "move-session", 1s); - ASSERT_TRUE(control.acquired); - const auto barrier = manager.preemptAcquire( - "right_arm", "stop-operation", 1s); - ASSERT_TRUE(barrier.acquired) << barrier.detail; - - manager.release(barrier.token); - EXPECT_TRUE(manager.isLeased("right_arm")); - EXPECT_FALSE( - manager.tryAcquire("right_arm", "new-move", 1s).acquired); - - manager.release(control.token); - EXPECT_FALSE(manager.isLeased("right_arm")); - EXPECT_TRUE( - manager.tryAcquire("right_arm", "new-move", 1s).acquired); -} - -TEST_F(ControlAuthorityManagerTest, - SafetyBarrierWaitsForPreemptedNormalLeaseRelease) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto control = - manager.tryAcquire("right_arm", "move-session", 1s); - ASSERT_TRUE(control.acquired); - const auto barrier = manager.preemptAcquire( - "right_arm", "stop-operation", 1s); - ASSERT_TRUE(barrier.acquired) << barrier.detail; - - auto wait_result = std::async( - std::launch::async, - [&manager, token = barrier.token]() { - return manager.waitForPreemptedRelease(token, 1s); - }); - EXPECT_EQ( - wait_result.wait_for(30ms), - std::future_status::timeout); - - manager.release(control.token); - EXPECT_TRUE(wait_result.get()); - EXPECT_TRUE(manager.validate(barrier.token)); - manager.release(barrier.token); -} - -TEST_F(ControlAuthorityManagerTest, - ConditionalSafetyBarrierTracksPreemptedNormalLeaseRelease) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto control = - manager.tryAcquire("right_arm", "move-session", 1s); - ASSERT_TRUE(control.acquired); - auto dispatch = manager.tryBeginDispatch(control.token); - ASSERT_TRUE(dispatch.acquired()); - const auto barrier = manager.preemptAcquireIfCurrent( - control.token, "timed-out-action", 1s); - ASSERT_TRUE(barrier.acquired) << barrier.detail; - - EXPECT_FALSE( - manager.waitForPreemptedRelease(barrier.token, 10ms)); - dispatch = {}; - EXPECT_FALSE( - manager.waitForPreemptedRelease(barrier.token, 10ms)); - manager.release(control.token); - EXPECT_TRUE( - manager.waitForPreemptedRelease(barrier.token, 10ms)); - manager.release(barrier.token); -} - -TEST_F(ControlAuthorityManagerTest, - ReleasedSafetyHolderStopsWaitingWithoutAffectingOtherHolder) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto control = - manager.tryAcquire("right_arm", "move-session", 1s); - ASSERT_TRUE(control.acquired); - const auto first_barrier = manager.preemptAcquire( - "right_arm", "first-stop", 1s); - ASSERT_TRUE(first_barrier.acquired) << first_barrier.detail; - const auto second_barrier = manager.preemptAcquire( - "right_arm", "second-stop", 1s); - ASSERT_TRUE(second_barrier.acquired) << second_barrier.detail; - - auto first_wait = std::async( - std::launch::async, - [&manager, token = first_barrier.token]() { - return manager.waitForPreemptedRelease(token, 1s); - }); - auto second_wait = std::async( - std::launch::async, - [&manager, token = second_barrier.token]() { - return manager.waitForPreemptedRelease(token, 1s); - }); - EXPECT_EQ(first_wait.wait_for(30ms), std::future_status::timeout); - EXPECT_EQ(second_wait.wait_for(30ms), std::future_status::timeout); - - manager.release(first_barrier.token); - EXPECT_FALSE(first_wait.get()); - EXPECT_EQ(second_wait.wait_for(30ms), std::future_status::timeout); - manager.release(control.token); - EXPECT_TRUE(second_wait.get()); - manager.release(second_barrier.token); -} - -TEST_F(ControlAuthorityManagerTest, - PreemptedReleaseRequiresExactNormalLeaseToken) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto control = - manager.tryAcquire("right_arm", "move-session", 1s); - ASSERT_TRUE(control.acquired); - const auto barrier = manager.preemptAcquire( - "right_arm", "stop-operation", 1s); - ASSERT_TRUE(barrier.acquired) << barrier.detail; - - auto forged = control.token; - forged.owner_id = "different-owner"; - manager.release(forged); - EXPECT_FALSE( - manager.waitForPreemptedRelease(barrier.token, 10ms)); - - manager.release(control.token); - EXPECT_TRUE( - manager.waitForPreemptedRelease(barrier.token, 0ms)); - manager.release(barrier.token); -} - -TEST_F(ControlAuthorityManagerTest, - ClearWakesPreemptedReleaseWaiterAndInvalidatesSafetyHolder) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto control = - manager.tryAcquire("right_arm", "move-session", 1s); - ASSERT_TRUE(control.acquired); - const auto barrier = manager.preemptAcquire( - "right_arm", "stop-operation", 1s); - ASSERT_TRUE(barrier.acquired) << barrier.detail; - - auto wait_result = std::async( - std::launch::async, - [&manager, token = barrier.token]() { - return manager.waitForPreemptedRelease(token, 1s); - }); - EXPECT_EQ( - wait_result.wait_for(30ms), - std::future_status::timeout); - - manager.clear(); - EXPECT_FALSE(wait_result.get()); - manager.release(control.token); -} - -TEST_F(ControlAuthorityManagerTest, - RevokeWakesPreemptedReleaseWaiterAndInvalidatesSafetyHolder) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto control = - manager.tryAcquire("right_arm", "move-session", 1s); - ASSERT_TRUE(control.acquired); - const auto barrier = manager.preemptAcquire( - "right_arm", "stop-operation", 1s); - ASSERT_TRUE(barrier.acquired) << barrier.detail; - - auto wait_result = std::async( - std::launch::async, - [&manager, token = barrier.token]() { - return manager.waitForPreemptedRelease(token, 1s); - }); - EXPECT_EQ( - wait_result.wait_for(30ms), - std::future_status::timeout); - - manager.revoke("right_arm"); - EXPECT_FALSE(wait_result.get()); - manager.release(control.token); -} - -TEST_F(ControlAuthorityManagerTest, - ExpiredNormalLeaseStillRequiresHandlerReleaseAfterPreemption) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto control = - manager.tryAcquire("right_arm", "move-session", 10ms); - ASSERT_TRUE(control.acquired); - std::this_thread::sleep_for(20ms); - - const auto barrier = manager.preemptAcquire( - "right_arm", "stop-operation", 1s); - ASSERT_TRUE(barrier.acquired) << barrier.detail; - EXPECT_FALSE( - manager.waitForPreemptedRelease(barrier.token, 10ms)); - - manager.release(control.token); - EXPECT_TRUE( - manager.waitForPreemptedRelease(barrier.token, 0ms)); - manager.release(barrier.token); -} - -TEST_F(ControlAuthorityManagerTest, - QuarantinedFallbackTracksOriginalNormalHandlerRelease) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto control = - manager.tryAcquire("right_arm", "move-session", 1s); - ASSERT_TRUE(control.acquired); - ASSERT_TRUE(manager.quarantineIfCurrent(control.token)); - - const auto barrier = manager.preemptAcquire( - "right_arm", "stop-operation", 1s); - ASSERT_TRUE(barrier.acquired) << barrier.detail; - EXPECT_FALSE( - manager.waitForPreemptedRelease(barrier.token, 10ms)); - - manager.release(control.token); - EXPECT_TRUE( - manager.waitForPreemptedRelease(barrier.token, 0ms)); - manager.release(barrier.token); - EXPECT_TRUE(manager.isLeased("right_arm")); - - manager.revoke("right_arm"); -} - -TEST_F(ControlAuthorityManagerTest, - WaitRejectsStaleSafetyTokenForSuccessorEntry) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto old_control = - manager.tryAcquire("right_arm", "old-move", 1s); - ASSERT_TRUE(old_control.acquired); - const auto old_barrier = manager.preemptAcquire( - "right_arm", "old-stop", 1s); - ASSERT_TRUE(old_barrier.acquired) << old_barrier.detail; - manager.release(old_barrier.token); - - EXPECT_FALSE( - manager.tryAcquire("right_arm", "new-move", 1s).acquired); - manager.release(old_control.token); - - const auto successor = - manager.tryAcquire("right_arm", "new-move", 1s); - ASSERT_TRUE(successor.acquired); - const auto current_barrier = manager.preemptAcquire( - "right_arm", "new-stop", 1s); - ASSERT_TRUE(current_barrier.acquired) << current_barrier.detail; - - EXPECT_FALSE(manager.waitForPreemptedRelease( - old_barrier.token, 0ms)); - EXPECT_FALSE(manager.waitForPreemptedRelease( - current_barrier.token, 10ms)); - - manager.release(successor.token); - EXPECT_TRUE(manager.waitForPreemptedRelease( - current_barrier.token, 0ms)); - manager.release(current_barrier.token); -} - -TEST_F(ControlAuthorityManagerTest, - ConditionalSafetyBarrierPreemptsMatchingCurrentLease) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto control = - manager.tryAcquire("right_arm", "move-session", 100ms); - ASSERT_TRUE(control.acquired); - - const auto barrier = manager.preemptAcquireIfCurrent( - control.token, "timed-out-action", 100ms); - ASSERT_TRUE(barrier.acquired) << barrier.detail; - EXPECT_FALSE(manager.validate(control.token)); - EXPECT_TRUE(manager.validate(barrier.token)); - manager.release(control.token); - EXPECT_TRUE(manager.validate(barrier.token)); - EXPECT_FALSE( - manager.tryAcquire("right_arm", "new-move", 100ms) - .acquired); - - manager.release(barrier.token); - EXPECT_FALSE(manager.isLeased("right_arm")); -} - -TEST_F(ControlAuthorityManagerTest, - ConditionalSafetyBarrierDoesNotPreemptSuccessorForStaleToken) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto old = - manager.tryAcquire("right_arm", "move-session", 100ms); - ASSERT_TRUE(old.acquired); - const auto direct_stop = manager.preemptAcquire( - "right_arm", "direct-stop", 100ms); - ASSERT_TRUE(direct_stop.acquired) << direct_stop.detail; - manager.release(direct_stop.token); - EXPECT_FALSE( - manager.tryAcquire("right_arm", "move-session", 100ms).acquired); - manager.release(old.token); - const auto successor = - manager.tryAcquire("right_arm", "move-session", 100ms); - ASSERT_TRUE(successor.acquired); - ASSERT_NE(old.token.generation, successor.token.generation); - - const auto barrier = manager.preemptAcquireIfCurrent( - old.token, "delayed-stop", 100ms); - EXPECT_FALSE(barrier.acquired); - EXPECT_FALSE(barrier.token.valid()); - EXPECT_TRUE(manager.validate(successor.token)); - EXPECT_FALSE( - manager.tryAcquire("right_arm", "competing-move", 100ms) - .acquired); - - manager.release(successor.token); - EXPECT_FALSE(manager.isLeased("right_arm")); -} - -TEST_F(ControlAuthorityManagerTest, - ConditionalSafetyBarrierDoesNotJoinExistingSafetyBarrier) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto control = - manager.tryAcquire("right_arm", "move-session", 100ms); - ASSERT_TRUE(control.acquired); - const auto existing_barrier = manager.preemptAcquire( - "right_arm", "direct-stop", 100ms); - ASSERT_TRUE(existing_barrier.acquired) << existing_barrier.detail; - - const auto delayed_barrier = manager.preemptAcquireIfCurrent( - control.token, "delayed-action-stop", 100ms); - EXPECT_FALSE(delayed_barrier.acquired); - EXPECT_FALSE(delayed_barrier.token.valid()); - EXPECT_TRUE(manager.validate(existing_barrier.token)); - - manager.release(existing_barrier.token); - EXPECT_TRUE(manager.isLeased("right_arm")); - manager.release(control.token); - EXPECT_FALSE(manager.isLeased("right_arm")); - EXPECT_TRUE( - manager.tryAcquire("right_arm", "new-move", 100ms) - .acquired); -} - -TEST_F(ControlAuthorityManagerTest, - QuarantineSurvivesNormalAndTemporarySafetyTokenRelease) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto control = - manager.tryAcquire("right_arm", "move-session", 20ms); - ASSERT_TRUE(control.acquired); - - ASSERT_TRUE(manager.quarantineIfCurrent(control.token)); - EXPECT_FALSE(manager.validate(control.token)); - EXPECT_TRUE(manager.isLeased("right_arm")); - - manager.release(control.token); - std::this_thread::sleep_for(30ms); - EXPECT_TRUE(manager.isLeased("right_arm")); - EXPECT_FALSE( - manager.tryAcquire("right_arm", "new-move", 100ms) - .acquired); - - const auto temporary_stop = manager.preemptAcquire( - "right_arm", "temporary-stop", 100ms); - ASSERT_TRUE(temporary_stop.acquired) << temporary_stop.detail; - EXPECT_TRUE(manager.validate(temporary_stop.token)); - manager.release(temporary_stop.token); - - EXPECT_TRUE(manager.isLeased("right_arm")); - EXPECT_FALSE( - manager.tryAcquire("right_arm", "new-move", 100ms) - .acquired); - - manager.revoke("right_arm"); - EXPECT_FALSE(manager.isLeased("right_arm")); -} - -TEST_F(ControlAuthorityManagerTest, - QuarantineWithStaleTokenDoesNotAffectSuccessor) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto old = - manager.tryAcquire("right_arm", "move-session", 100ms); - ASSERT_TRUE(old.acquired); - manager.release(old.token); - const auto successor = - manager.tryAcquire("right_arm", "move-session", 100ms); - ASSERT_TRUE(successor.acquired); - ASSERT_NE(old.token.generation, successor.token.generation); - - EXPECT_FALSE(manager.quarantineIfCurrent(old.token)); - EXPECT_TRUE(manager.validate(successor.token)); - EXPECT_FALSE( - manager.tryAcquire("right_arm", "competing-move", 100ms) - .acquired); - - manager.release(successor.token); - EXPECT_FALSE(manager.isLeased("right_arm")); -} - -TEST_F(ControlAuthorityManagerTest, - RetiredSafetyHolderStaysFailClosedUntilConfirmedRecovery) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto control = - manager.tryAcquire("right_arm", "move-session", 1s); - ASSERT_TRUE(control.acquired); - const auto failed_stop = manager.preemptAcquire( - "right_arm", "failed-stop", 1s); - ASSERT_TRUE(failed_stop.acquired) << failed_stop.detail; - - manager.release(control.token); - ASSERT_TRUE(manager.waitForPreemptedRelease( - failed_stop.token, 0ms)); - ASSERT_TRUE(manager.retireSafetyHolder(failed_stop.token)); - EXPECT_FALSE(manager.validate(failed_stop.token)); - - // A delayed destructor release cannot undo the retained fail-closed state. - manager.release(failed_stop.token); - EXPECT_TRUE(manager.isLeased("right_arm")); - EXPECT_FALSE( - manager.tryAcquire("right_arm", "new-move", 1s).acquired); - - const auto recovery = manager.preemptAcquire( - "right_arm", "confirmed-recovery", 1s); - ASSERT_TRUE(recovery.acquired) << recovery.detail; - ASSERT_TRUE(manager.waitForPreemptedRelease(recovery.token, 0ms)); - ASSERT_TRUE(manager.recoverRetiredSafetyHolders(recovery.token)); - EXPECT_TRUE(manager.validate(recovery.token)); - - manager.release(recovery.token); - EXPECT_FALSE(manager.isLeased("right_arm")); -} - -TEST_F(ControlAuthorityManagerTest, - RecoveryWaitsForPreemptedNormalHandlerToRelease) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto control = - manager.tryAcquire("right_arm", "move-session", 1s); - ASSERT_TRUE(control.acquired); - const auto failed_stop = manager.preemptAcquire( - "right_arm", "failed-stop", 1s); - ASSERT_TRUE(failed_stop.acquired) << failed_stop.detail; - ASSERT_TRUE(manager.retireSafetyHolder(failed_stop.token)); - - const auto recovery = manager.preemptAcquire( - "right_arm", "confirmed-recovery", 1s); - ASSERT_TRUE(recovery.acquired) << recovery.detail; - EXPECT_FALSE(manager.recoverRetiredSafetyHolders(recovery.token)); - EXPECT_FALSE(manager.waitForPreemptedRelease(recovery.token, 10ms)); - - manager.release(control.token); - ASSERT_TRUE(manager.waitForPreemptedRelease(recovery.token, 0ms)); - ASSERT_TRUE(manager.recoverRetiredSafetyHolders(recovery.token)); - manager.release(recovery.token); - EXPECT_FALSE(manager.isLeased("right_arm")); -} - -TEST_F(ControlAuthorityManagerTest, - RecoveryPreservesEveryOtherActiveSafetyHolder) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto retired = manager.preemptAcquire( - "right_arm", "failed-stop", 1s); - ASSERT_TRUE(retired.acquired) << retired.detail; - ASSERT_TRUE(manager.retireSafetyHolder(retired.token)); - - const auto independent_stop = manager.preemptAcquire( - "right_arm", "independent-stop", 1s); - const auto recovery = manager.preemptAcquire( - "right_arm", "confirmed-recovery", 1s); - ASSERT_TRUE(independent_stop.acquired) << independent_stop.detail; - ASSERT_TRUE(recovery.acquired) << recovery.detail; - - ASSERT_TRUE(manager.recoverRetiredSafetyHolders(recovery.token)); - EXPECT_TRUE(manager.validate(independent_stop.token)); - EXPECT_TRUE(manager.validate(recovery.token)); - EXPECT_FALSE(manager.validate(retired.token)); - - manager.release(recovery.token); - EXPECT_TRUE(manager.isLeased("right_arm")); - EXPECT_TRUE(manager.validate(independent_stop.token)); - manager.release(independent_stop.token); - EXPECT_FALSE(manager.isLeased("right_arm")); -} - -TEST_F(ControlAuthorityManagerTest, - RetiredOrForgedSafetyTokenCannotAuthorizeRecovery) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto retired = manager.preemptAcquire( - "right_arm", "failed-stop", 1s); - ASSERT_TRUE(retired.acquired) << retired.detail; - ASSERT_TRUE(manager.retireSafetyHolder(retired.token)); - EXPECT_FALSE(manager.recoverRetiredSafetyHolders(retired.token)); - - const auto recovery = manager.preemptAcquire( - "right_arm", "confirmed-recovery", 1s); - ASSERT_TRUE(recovery.acquired) << recovery.detail; - auto forged = recovery.token; - forged.owner_id = "different-owner"; - EXPECT_FALSE(manager.recoverRetiredSafetyHolders(forged)); - EXPECT_TRUE(manager.isLeased("right_arm")); - - ASSERT_TRUE(manager.recoverRetiredSafetyHolders(recovery.token)); - manager.release(recovery.token); - EXPECT_FALSE(manager.isLeased("right_arm")); -} - -TEST_F(ControlAuthorityManagerTest, - ConfirmedRecoveryCanClearTokenlessQuarantine) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto control = - manager.tryAcquire("right_arm", "move-session", 1s); - ASSERT_TRUE(control.acquired); - ASSERT_TRUE(manager.quarantineIfCurrent(control.token)); - - const auto recovery = manager.preemptAcquire( - "right_arm", "confirmed-recovery", 1s); - ASSERT_TRUE(recovery.acquired) << recovery.detail; - EXPECT_FALSE(manager.recoverRetiredSafetyHolders(recovery.token)); - - manager.release(control.token); - ASSERT_TRUE(manager.waitForPreemptedRelease(recovery.token, 0ms)); - ASSERT_TRUE(manager.recoverRetiredSafetyHolders(recovery.token)); - manager.release(recovery.token); - EXPECT_FALSE(manager.isLeased("right_arm")); -} - -TEST_F(ControlAuthorityManagerTest, ExpiryAndRenewUseMonotonicLocalTime) -{ - auto& manager = ControlAuthorityManager::instance(); - const auto lease = - manager.tryAcquire("right_arm", "session-a", 20ms); - ASSERT_TRUE(lease.acquired); - std::this_thread::sleep_for(10ms); - ASSERT_TRUE(manager.renew(lease.token, 30ms)); - std::this_thread::sleep_for(20ms); - EXPECT_TRUE(manager.validate(lease.token)); - std::this_thread::sleep_for(20ms); - EXPECT_FALSE(manager.validate(lease.token)); - EXPECT_FALSE(manager.isLeased("right_arm")); -} - -TEST_F(ControlAuthorityManagerTest, DifferentArmsCanBeLeasedIndependently) -{ - auto& manager = ControlAuthorityManager::instance(); - EXPECT_TRUE( - manager.tryAcquire("right_arm", "session-a", 100ms) - .acquired); - EXPECT_TRUE( - manager.tryAcquire("left_arm", "session-b", 100ms) - .acquired); -} - -} // namespace -} // namespace cmvr::control diff --git a/cmvr-es/manager/device_manager/CMakeLists.txt b/cmvr-es/manager/device_manager/CMakeLists.txt index 5183fced..195be88f 100644 --- a/cmvr-es/manager/device_manager/CMakeLists.txt +++ b/cmvr-es/manager/device_manager/CMakeLists.txt @@ -56,27 +56,4 @@ if(BUILD_TESTING) ) endif() - add_executable(device_manager_lifecycle_test - tests/device_manager_lifecycle_test.cpp - ) - target_link_libraries(device_manager_lifecycle_test PRIVATE - cmvr_es::device_manager - gtest - gtest_main - pthread - ) - add_test( - NAME device_manager_lifecycle_test - COMMAND device_manager_lifecycle_test - ) - set(_device_manager_lifecycle_test_environment - "LD_LIBRARY_PATH=${CMVR_TEST_EXTERNAL_LIBRARY_PATH}") - if(CMVR_TEST_SYSTEM_LIBSTDCXX) - list(APPEND _device_manager_lifecycle_test_environment - "LD_PRELOAD=${CMVR_TEST_SYSTEM_LIBSTDCXX}") - endif() - set_tests_properties(device_manager_lifecycle_test PROPERTIES - TIMEOUT 10 - ENVIRONMENT "${_device_manager_lifecycle_test_environment}" - ) endif() diff --git a/cmvr-es/manager/device_manager/tests/device_manager_lifecycle_test.cpp b/cmvr-es/manager/device_manager/tests/device_manager_lifecycle_test.cpp deleted file mode 100644 index 4149a835..00000000 --- a/cmvr-es/manager/device_manager/tests/device_manager_lifecycle_test.cpp +++ /dev/null @@ -1,153 +0,0 @@ -#include "manager/device_manager/include/device_manager.h" - -#include - -#include - -namespace { - -class LifecycleDevice final : public cmvr::device::AbstractDevice { -public: - explicit LifecycleDevice(const std::string& id) - : AbstractDevice(id) - { - } - - cmvr::device::DeviceKind kind() const noexcept override - { - return cmvr::device::DeviceKind::Camera; - } - - std::string typeName() const override { return "LifecycleDevice"; } - - bool start() override - { - ++start_calls; - if (throw_on_start) { - throw std::runtime_error("start failure"); - } - return start_result; - } - - bool stop() override - { - ++stop_calls; - return true; - } - - bool start_result{true}; - bool throw_on_start{false}; - int start_calls{0}; - int stop_calls{0}; -}; - -class DeviceManagerLifecycleTest : public ::testing::Test { -protected: - void SetUp() override - { - cmvr::device::DeviceManager::destroyInstance(); - } - - void TearDown() override - { - cmvr::device::DeviceManager::destroyInstance(); - } -}; - -TEST_F(DeviceManagerLifecycleTest, - EnabledDeviceCreationFailureMarksInitializationFailed) -{ - cmvr::config::DeviceManagerConfig config; - auto* entry = config.add_devices(); - entry->set_id("unsupported"); - entry->set_type( - cmvr::config::DeviceConfigEntry::DEVICE_TYPE_UNKNOWN); - entry->set_enable(true); - - auto& manager = - cmvr::device::DeviceManager::getInstance(config); - EXPECT_FALSE(manager.initialized()); - EXPECT_FALSE(manager.start()); -} - -TEST_F(DeviceManagerLifecycleTest, DisabledInvalidDeviceIsIgnored) -{ - cmvr::config::DeviceManagerConfig config; - auto* entry = config.add_devices(); - entry->set_id("disabled"); - entry->set_type( - cmvr::config::DeviceConfigEntry::DEVICE_TYPE_UNKNOWN); - entry->set_enable(false); - - auto& manager = - cmvr::device::DeviceManager::getInstance(config); - EXPECT_TRUE(manager.initialized()); - EXPECT_TRUE(manager.start()); -} - -TEST_F(DeviceManagerLifecycleTest, - DeviceStartFailureIsReturnedAndTriggersStop) -{ - cmvr::config::DeviceManagerConfig config; - auto& manager = - cmvr::device::DeviceManager::getInstance(config); - ASSERT_TRUE(manager.initialized()); - - auto device = - std::make_shared("start_failure"); - device->start_result = false; - manager.registerDevice(device); - - EXPECT_FALSE(manager.start()); - EXPECT_EQ(device->start_calls, 1); - EXPECT_EQ(device->stop_calls, 1); -} - -TEST_F(DeviceManagerLifecycleTest, - DeviceStartExceptionIsReturnedAndTriggersStop) -{ - cmvr::config::DeviceManagerConfig config; - auto& manager = - cmvr::device::DeviceManager::getInstance(config); - ASSERT_TRUE(manager.initialized()); - - auto device = - std::make_shared("start_exception"); - device->throw_on_start = true; - manager.registerDevice(device); - - EXPECT_FALSE(manager.start()); - EXPECT_EQ(device->start_calls, 1); - EXPECT_EQ(device->stop_calls, 1); -} - -TEST_F(DeviceManagerLifecycleTest, - EnforceSelectedCannotStartWithMissingConfiguredTarget) -{ - cmvr::config::DeviceManagerConfig config; - auto* safety = config.mutable_safety(); - safety->set_mode( - cmvr::config::SafetyManagerConfig::ENFORCE_SELECTED); - safety->add_enforced_device_ids("missing-arm"); - - auto& manager = cmvr::device::DeviceManager::getInstance(config); - ASSERT_TRUE(manager.initialized()); - EXPECT_FALSE(manager.start()); - EXPECT_EQ( - manager.safetyManager().snapshot().system_state, - cmvr::safety::SystemAdmissionState::Starting); -} - -TEST_F(DeviceManagerLifecycleTest, - EnforceSelectedCannotSilentlyCoverNoDevices) -{ - cmvr::config::DeviceManagerConfig config; - config.mutable_safety()->set_mode( - cmvr::config::SafetyManagerConfig::ENFORCE_SELECTED); - - auto& manager = cmvr::device::DeviceManager::getInstance(config); - ASSERT_TRUE(manager.initialized()); - EXPECT_FALSE(manager.start()); -} - -} // namespace diff --git a/cmvr-es/manager/media_source_manager/CMakeLists.txt b/cmvr-es/manager/media_source_manager/CMakeLists.txt index b5369f7c..4d80215a 100644 --- a/cmvr-es/manager/media_source_manager/CMakeLists.txt +++ b/cmvr-es/manager/media_source_manager/CMakeLists.txt @@ -1,7 +1,6 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) cmake_minimum_required(VERSION 3.22) project(cmvr_media_source_manager LANGUAGES CXX) - enable_testing() add_subdirectory( ${CMAKE_CURRENT_SOURCE_DIR}/../../service/grpc/stop_all ${CMAKE_CURRENT_BINARY_DIR}/stop_all @@ -43,55 +42,4 @@ if(NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) ) add_library(cmvr_es::device_media_source_adapter ALIAS device_media_source_adapter) - if(BUILD_TESTING) - add_executable(device_media_source_adapter_test - tests/device_media_source_adapter_test.cpp - ) - target_compile_features(device_media_source_adapter_test PRIVATE cxx_std_17) - target_link_libraries(device_media_source_adapter_test - PRIVATE - cmvr_es::device_media_source_adapter - gtest - gtest_main - ) - add_test( - NAME device_media_source_adapter_test - COMMAND device_media_source_adapter_test - ) - set(_device_media_source_adapter_test_environment - "LD_LIBRARY_PATH=${CMVR_TEST_EXTERNAL_LIBRARY_PATH}") - if(CMVR_TEST_SYSTEM_LIBSTDCXX) - list(APPEND _device_media_source_adapter_test_environment - "LD_PRELOAD=${CMVR_TEST_SYSTEM_LIBSTDCXX}") - endif() - set_tests_properties(device_media_source_adapter_test PROPERTIES - ENVIRONMENT - "${_device_media_source_adapter_test_environment}" - ) - endif() -endif() - -option(CMVR_MEDIA_SOURCE_MANAGER_BUILD_TESTS - "Build the standalone MediaSourceManager self-test" - ${PROJECT_IS_TOP_LEVEL}) - -if(CMVR_MEDIA_SOURCE_MANAGER_BUILD_TESTS) - find_package(Threads REQUIRED) - add_executable(media_source_manager_test - tests/media_source_manager_test.cpp - ) - target_compile_features(media_source_manager_test PRIVATE cxx_std_17) - target_link_libraries(media_source_manager_test - PRIVATE - cmvr_es::media_source_manager - Threads::Threads - ) - # This self-test only links the static Hub and pthreads. In the root build, - # the project-wide third-party RUNPATH can otherwise make the loader pick up - # a vendor libstdc++.so (for example from the AUBO SDK), even though the test - # has no dependency on that SDK. - set_target_properties(media_source_manager_test PROPERTIES - SKIP_BUILD_RPATH TRUE - ) - add_test(NAME media_source_manager_test COMMAND media_source_manager_test) endif() diff --git a/cmvr-es/manager/media_source_manager/tests/device_media_source_adapter_test.cpp b/cmvr-es/manager/media_source_manager/tests/device_media_source_adapter_test.cpp deleted file mode 100644 index 0c007166..00000000 --- a/cmvr-es/manager/media_source_manager/tests/device_media_source_adapter_test.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include "manager/media_source_manager/include/device_media_source_adapter.h" - -#include -#include -#include -#include - -#include - -#include "manager/safety_manager/include/device_safety_endpoint.h" - -namespace cmvr::media { -namespace { - -class FakeSensorEndpoint final : public safety::DeviceSafetyEndpoint { -public: - explicit FakeSensorEndpoint(std::string device_id) - { - descriptor_.device_id = std::move(device_id); - descriptor_.kind = device::DeviceKind::Camera; - descriptor_.default_policy = safety::SafetyPolicyFamily::Sensor; - descriptor_.maximum_snapshot_age = std::chrono::seconds(1); - descriptor_.supports_active_refresh = true; - } - - safety::DeviceSafetyDescriptor descriptor() const override - { - return descriptor_; - } - - void bindPublisher(safety::SafetySnapshotPublisher publisher) override - { - publisher_ = std::move(publisher); - } - - void requestSafetyRefresh() noexcept override - { - if (!publisher_) { - return; - } - safety::DeviceSafetySnapshot snapshot; - snapshot.device_id = descriptor_.device_id; - snapshot.condition = safety::SafetyCondition::Nominal; - snapshot.device_generation = 1; - snapshot.sample_sequence = ++sequence_; - snapshot.observed_at = safety::SafetyClock::now(); - snapshot.connected = safety::TriState::True; - snapshot.operational_ready = safety::TriState::True; - snapshot.quiescent = safety::TriState::True; - snapshot.motion_active = safety::TriState::False; - snapshot.actuator_enabled = safety::TriState::False; - snapshot.emergency_stop_active = safety::TriState::False; - snapshot.protective_stop_active = safety::TriState::False; - snapshot.fault_active = safety::TriState::False; - (void)publisher_(std::move(snapshot)); - } - - safety::HardwareCheckResult validateBeforeDispatch( - const safety::AdmissionPermit& permit) override - { - ++hardware_checks; - last_intent = permit.intent; - return {true, safety::SafetyReason::None, {}}; - } - - safety::RecoveryCheckResult reconcileAdmissionState( - const safety::RecoveryContext&) override - { - return {true, safety::SafetyReason::None, {}}; - } - - std::atomic hardware_checks{0}; - safety::CommandIntent last_intent{safety::CommandIntent::Observe}; - -private: - safety::DeviceSafetyDescriptor descriptor_; - safety::SafetySnapshotPublisher publisher_; - std::atomic sequence_{0}; -}; - -TEST(DeviceMediaSourceAdapterTest, - SensorStartUsesFinalCheckAndQuarantineRejectsRestart) -{ - safety::SafetyManagerConfig config; - config.enforcement_mode = safety::EnforcementMode::EnforceAll; - safety::SafetyManager coordinator(config); - auto endpoint = std::make_shared("camera"); - ASSERT_TRUE(coordinator.registerDevice( - {endpoint->descriptor(), endpoint, {}})); - endpoint->requestSafetyRefresh(); - coordinator.updateDeviceRuntimeState( - "camera", - device::ManagedDeviceState::Running, - {device::DeviceHealthState::Healthy, {}}); - coordinator.markStartupComplete(); - - { - auto dispatch = beginMediaSourceStartDispatch(coordinator, "camera"); - ASSERT_TRUE(dispatch.acquired()); - EXPECT_EQ(endpoint->hardware_checks.load(), 1); - EXPECT_EQ(endpoint->last_intent, safety::CommandIntent::StartActivity); - } - - coordinator.quarantineDevice( - "camera", safety::SafetyReason::OutcomeUnknown, - "uncertain-media-start"); - auto rejected = beginMediaSourceStartDispatch(coordinator, "camera"); - EXPECT_FALSE(rejected.acquired()); - EXPECT_EQ(endpoint->hardware_checks.load(), 1); -} - -} // namespace -} // namespace cmvr::media diff --git a/cmvr-es/manager/media_source_manager/tests/media_source_manager_test.cpp b/cmvr-es/manager/media_source_manager/tests/media_source_manager_test.cpp deleted file mode 100644 index a7fd3907..00000000 --- a/cmvr-es/manager/media_source_manager/tests/media_source_manager_test.cpp +++ /dev/null @@ -1,1338 +0,0 @@ -#include "manager/media_source_manager/include/media_source_manager.h" -#include "service/grpc/stop_all/include/stop_all_admission_gate.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace { - -using namespace std::chrono_literals; -using cmvr::media::Codec; -using cmvr::media::MediaFrame; -using cmvr::media::MediaFramePtr; -using cmvr::media::MediaKind; -using cmvr::media::MediaSourceManager; -using cmvr::media::PayloadFormat; -using cmvr::media::Rational; -using cmvr::media::TrackDescriptor; -using cmvr::media::TrackDescriptorPtr; - -static_assert(!std::is_copy_assignable::value, "MediaFrame must be immutable"); -static_assert(!std::is_copy_assignable::value, "TrackDescriptor must be immutable"); -static_assert(std::is_same::value, - "MediaFramePtr must share const frames"); - -int failures = 0; - -#define CHECK_TRUE(expression) \ - do { \ - if (!(expression)) { \ - std::cerr << __FILE__ << ':' << __LINE__ << " check failed: " #expression << '\n'; \ - ++failures; \ - } \ - } while (false) - -TrackDescriptorPtr makeVideoDescriptor( - const Codec codec, - const uint64_t generation, - std::vector codec_config = {}, - std::string track_id = "camera.front.video", - std::string source_id = "camera.front") { - TrackDescriptor::Config config; - config.id = std::move(track_id); - config.source_id = std::move(source_id); - config.kind = MediaKind::VIDEO; - config.codec = codec; - config.payload_format = codec == Codec::UNKNOWN ? PayloadFormat::UNKNOWN : PayloadFormat::ANNEX_B; - config.time_base = Rational{1, 90000}; - config.width = 640; - config.height = 360; - config.nominal_rate = 30; - config.generation = generation; - config.codec_config = std::move(codec_config); - return cmvr::media::makeTrackDescriptor(std::move(config)); -} - -MediaFramePtr makeFrame( - TrackDescriptorPtr descriptor, - const uint64_t sequence, - const uint8_t marker) { - MediaFrame::Config config; - config.descriptor = std::move(descriptor); - config.payload = {marker, static_cast(marker + 1)}; - config.sequence = sequence; - config.pts = static_cast(sequence * 3000); - config.dts = config.pts; - config.duration = 3000; - config.capture_time_ns = sequence * 1000000; - config.capture_utc_ns = 1700000000000000000LL + static_cast(sequence); - config.key_frame = sequence == 0; - return cmvr::media::makeMediaFrame(std::move(config)); -} - -void testMediaMetadataValidation() { - TrackDescriptor::Config invalid; - invalid.id = "invalid.video"; - invalid.source_id = "invalid"; - invalid.kind = MediaKind::VIDEO; - invalid.time_base = Rational{0, 1}; - bool rejected = false; - try { - (void)cmvr::media::makeTrackDescriptor(std::move(invalid)); - } catch (const std::invalid_argument&) { - rejected = true; - } - CHECK_TRUE(rejected); - - const auto frame = makeFrame(makeVideoDescriptor(Codec::H264, 1), 7, 1); - CHECK_TRUE(frame->capture_time_ns == 7000000); - CHECK_TRUE(frame->capture_utc_ns == 1700000000000000007LL); - CHECK_TRUE(frame->duration == 3000); -} - -void testLegacySpmcCompatibility() { - bool ring_zero_capacity_rejected = false; - try { - RingBuffer invalid_ring(0); - } catch (const std::invalid_argument&) { - ring_zero_capacity_rejected = true; - } - CHECK_TRUE(ring_zero_capacity_rejected); - - bool spmc_zero_capacity_rejected = false; - try { - SPMCRingBuffer invalid_ring(0); - } catch (const std::invalid_argument&) { - spmc_zero_capacity_rejected = true; - } - CHECK_TRUE(spmc_zero_capacity_rejected); - - SPMCRingBuffer ring(2); - ring.push(10); - ring.push(20); - CHECK_TRUE(ring.size() == 2); - CHECK_TRUE(ring.getHead() == 2); - CHECK_TRUE(ring.getTail() == 0); - CHECK_TRUE(ring.getLast().has_value() && *ring.getLast() == 20); - - size_t reader = 0; - CHECK_TRUE(ring.pop(reader).has_value()); - ring.push(30); - ring.push(40); - CHECK_TRUE(!ring.pop(reader).has_value()); - CHECK_TRUE(reader == ring.getTail()); - CHECK_TRUE(ring.pop(reader).has_value()); - - ring.clear(); - CHECK_TRUE(ring.empty()); - CHECK_TRUE(ring.getHead() == 4); - ring.push(50); - CHECK_TRUE(!ring.pop(reader).has_value()); - const auto after_clear = ring.pop(reader); - CHECK_TRUE(after_clear.has_value() && *after_clear == 50); -} - -void testBroadcastFrameRing() { - using Ring = BroadcastFrameRing; - Ring ring(2); - const auto descriptor = makeVideoDescriptor(Codec::H264, 1, {1, 2, 3}); - auto cursor = ring.makeCursor(Ring::StartPosition::OLDEST_AVAILABLE); - - CHECK_TRUE(ring.publish(makeFrame(descriptor, 0, 10)).value() == 0); - CHECK_TRUE(ring.publish(makeFrame(descriptor, 1, 20)).value() == 1); - CHECK_TRUE(ring.publish(makeFrame(descriptor, 2, 30)).value() == 2); - - const auto first = ring.tryRead(cursor); - CHECK_TRUE(first.has_value()); - CHECK_TRUE(first->sequence == 1); - CHECK_TRUE(first->value->sequence == 1); - CHECK_TRUE(first->dropped_count == 1); - CHECK_TRUE(first->dropped_since_last_read == 1); - CHECK_TRUE(ring.stats().dropped_count == 1); - - const auto second = ring.tryRead(cursor); - CHECK_TRUE(second.has_value() && second->sequence == 2); - CHECK_TRUE(second->dropped_since_last_read == 0); - - auto waiting_cursor = ring.makeCursor(Ring::StartPosition::NEXT_PUBLISHED); - auto waiting_read = std::async(std::launch::async, [&ring, &waiting_cursor] { - return ring.waitRead(waiting_cursor, 1s); - }); - std::this_thread::sleep_for(10ms); - ring.publish(makeFrame(descriptor, 3, 40)); - CHECK_TRUE(waiting_read.wait_for(500ms) == std::future_status::ready); - CHECK_TRUE(waiting_read.get().has_value()); - - const uint64_t next_generation = ring.reset(); - CHECK_TRUE(next_generation == 2); - ring.publish(makeFrame(descriptor, 4, 50)); - const auto after_reset = ring.tryRead(cursor); - CHECK_TRUE(after_reset.has_value()); - CHECK_TRUE(after_reset->generation == 2); - CHECK_TRUE(after_reset->sequence == 0); - CHECK_TRUE(after_reset->generation_changed); - - auto close_cursor = ring.makeCursor(Ring::StartPosition::NEXT_PUBLISHED); - auto close_wait = std::async(std::launch::async, [&ring, &close_cursor] { - return ring.waitRead(close_cursor, 2s); - }); - ring.close(); - CHECK_TRUE(close_wait.wait_for(500ms) == std::future_status::ready); - CHECK_TRUE(!close_wait.get().has_value()); - CHECK_TRUE(!ring.publish(makeFrame(descriptor, 5, 60)).has_value()); -} - -void testBroadcastDiscardPending() { - using Ring = BroadcastFrameRing; - const auto descriptor = makeVideoDescriptor(Codec::H264, 1, {1, 2, 3}); - - { - Ring ring(8); - auto cursor = ring.makeCursor(Ring::StartPosition::OLDEST_AVAILABLE); - ring.publish(makeFrame(descriptor, 0, 10)); - ring.publish(makeFrame(descriptor, 1, 20)); - - CHECK_TRUE(ring.discardPendingIfExceeds(cursor, 2) == 0); - const auto first = ring.tryRead(cursor); - CHECK_TRUE(first.has_value()); - CHECK_TRUE(first->sequence == 0); - CHECK_TRUE(first->dropped_since_last_read == 0); - } - - { - Ring ring(8); - auto cursor = ring.makeCursor(Ring::StartPosition::OLDEST_AVAILABLE); - ring.publish(makeFrame(descriptor, 0, 10)); - ring.publish(makeFrame(descriptor, 1, 20)); - ring.publish(makeFrame(descriptor, 2, 30)); - - CHECK_TRUE(ring.discardPendingIfExceeds(cursor, 2) == 3); - CHECK_TRUE(!ring.tryRead(cursor).has_value()); - - ring.publish(makeFrame(descriptor, 3, 40)); - const auto after_discard = ring.tryRead(cursor); - CHECK_TRUE(after_discard.has_value()); - CHECK_TRUE(after_discard->sequence == 3); - CHECK_TRUE(after_discard->dropped_count == 3); - CHECK_TRUE(after_discard->dropped_since_last_read == 3); - } - - { - // Two frames are overwritten before the explicit three-frame discard. - // Both kinds of loss must be reported by the next successful read. - Ring ring(3); - auto cursor = ring.makeCursor(Ring::StartPosition::OLDEST_AVAILABLE); - for (uint64_t sequence = 0; sequence < 5; ++sequence) { - ring.publish(makeFrame( - descriptor, - sequence, - static_cast(sequence))); - } - - CHECK_TRUE(ring.discardPendingIfExceeds(cursor, 2) == 3); - CHECK_TRUE(cursor.dropped_count == 5); - ring.publish(makeFrame(descriptor, 5, 50)); - const auto after_overwrite_and_discard = ring.tryRead(cursor); - CHECK_TRUE(after_overwrite_and_discard.has_value()); - CHECK_TRUE(after_overwrite_and_discard->sequence == 5); - CHECK_TRUE(after_overwrite_and_discard->dropped_count == 5); - CHECK_TRUE(after_overwrite_and_discard->dropped_since_last_read == 5); - } - - { - // An old-generation OLDEST_AVAILABLE cursor adopts the reset generation - // before deciding whether that generation's pending frames are excessive. - Ring ring(4); - auto cursor = ring.makeCursor(Ring::StartPosition::OLDEST_AVAILABLE); - ring.publish(makeFrame(descriptor, 0, 10)); - ring.reset(); - ring.publish(makeFrame(descriptor, 1, 20)); - ring.publish(makeFrame(descriptor, 2, 30)); - - CHECK_TRUE(ring.discardPendingIfExceeds(cursor, 1) == 2); - ring.publish(makeFrame(descriptor, 3, 40)); - const auto after_reset = ring.tryRead(cursor); - CHECK_TRUE(after_reset.has_value()); - CHECK_TRUE(after_reset->generation == 2); - CHECK_TRUE(after_reset->sequence == 2); - CHECK_TRUE(after_reset->generation_changed); - CHECK_TRUE(after_reset->dropped_since_last_read == 2); - } -} - -void testBroadcastDiscardConcurrentPublish() { - using Ring = BroadcastFrameRing; - constexpr uint64_t frame_count = 4000; - Ring ring(64); - auto cursor = ring.makeCursor(Ring::StartPosition::NEXT_PUBLISHED); - std::atomic start{false}; - std::atomic publisher_done{false}; - - std::thread publisher([&] { - while (!start.load(std::memory_order_acquire)) { - std::this_thread::yield(); - } - for (uint64_t sequence = 0; sequence < frame_count; ++sequence) { - ring.publish(std::make_shared(static_cast(sequence))); - if ((sequence & 7U) == 0U) { - std::this_thread::yield(); - } - } - publisher_done.store(true, std::memory_order_release); - }); - - uint64_t read_count = 0; - uint64_t actively_discarded = 0; - start.store(true, std::memory_order_release); - while (true) { - actively_discarded += ring.discardPendingIfExceeds(cursor, 8); - if (ring.tryRead(cursor)) { - ++read_count; - continue; - } - if (publisher_done.load(std::memory_order_acquire)) { - actively_discarded += ring.discardPendingIfExceeds(cursor, 8); - if (ring.tryRead(cursor)) { - ++read_count; - continue; - } - break; - } - std::this_thread::yield(); - } - publisher.join(); - - CHECK_TRUE(read_count + cursor.dropped_count == frame_count); - CHECK_TRUE(actively_discarded <= cursor.dropped_count); -} - -void testBroadcastConcurrency() { - using Ring = BroadcastFrameRing; - constexpr uint64_t frame_count = 500; - Ring ring(frame_count); - const auto descriptor = makeVideoDescriptor(Codec::H264, 1, {1, 2, 3}); - auto first_cursor = ring.makeCursor(Ring::StartPosition::OLDEST_AVAILABLE); - auto second_cursor = ring.makeCursor(Ring::StartPosition::OLDEST_AVAILABLE); - - auto consume = [&ring](Ring::Cursor& cursor) { - uint64_t expected = 0; - while (expected < frame_count) { - const auto result = ring.waitRead(cursor, 1s); - if (!result || result->sequence != expected || result->value->sequence != expected) { - return false; - } - ++expected; - } - return cursor.dropped_count == 0; - }; - - auto first_consumer = std::async(std::launch::async, consume, std::ref(first_cursor)); - auto second_consumer = std::async(std::launch::async, consume, std::ref(second_cursor)); - std::thread producer([&ring, &descriptor] { - for (uint64_t sequence = 0; sequence < frame_count; ++sequence) { - ring.publish(makeFrame(descriptor, sequence, static_cast(sequence))); - } - }); - - producer.join(); - CHECK_TRUE(first_consumer.get()); - CHECK_TRUE(second_consumer.get()); -} - -void testHubLifecycleAndDescriptorRefresh() { - MediaSourceManager hub; - const auto initial_descriptor = makeVideoDescriptor(Codec::UNKNOWN, 1); - std::atomic start_count{0}; - std::atomic stop_count{0}; - std::atomic key_frame_requests{0}; - std::mutex sink_mutex; - MediaSourceManager::FrameSink sink; - - MediaSourceManager::SourceCallbacks callbacks; - callbacks.start = [&](const MediaSourceManager::FrameSink& callback_sink, - const MediaSourceManager::CancelPredicate&) { - { - std::lock_guard lock(sink_mutex); - sink = callback_sink; - } - ++start_count; - return true; - }; - callbacks.stop = [&] { - ++stop_count; - std::lock_guard lock(sink_mutex); - sink = {}; - }; - callbacks.request_key_frame = [&] { - ++key_frame_requests; - return true; - }; - - CHECK_TRUE(hub.registerSource(initial_descriptor, callbacks, 4)); - CHECK_TRUE(!hub.registerSource(initial_descriptor, callbacks, 4)); - CHECK_TRUE(hub.hasSource(initial_descriptor->id)); - CHECK_TRUE(hub.listTracks().size() == 1); - - auto first = hub.subscribe(initial_descriptor->id); - auto second = hub.subscribe(initial_descriptor->id); - CHECK_TRUE(first.valid() && second.valid()); - CHECK_TRUE(hub.requestKeyFrame(initial_descriptor->id)); - CHECK_TRUE(key_frame_requests == 1); - CHECK_TRUE(start_count == 1); - CHECK_TRUE(hub.subscriberCount(initial_descriptor->id) == 2); - CHECK_TRUE(first.descriptor()->codec == Codec::UNKNOWN); - CHECK_TRUE(!hub.unregisterSource(initial_descriptor->id)); - - // Content changes at the same generation must atomically replace the initial descriptor. - const auto actual_descriptor = makeVideoDescriptor(Codec::H264, 1, {0, 0, 0, 1, 0x67}); - MediaSourceManager::FrameSink producer; - { - std::lock_guard lock(sink_mutex); - producer = sink; - } - CHECK_TRUE(static_cast(producer)); - const auto shared_frame = makeFrame(actual_descriptor, 0, 70); - producer(shared_frame); - - const auto first_read = first.waitRead(500ms); - const auto second_read = second.waitRead(500ms); - CHECK_TRUE(first_read.has_value() && first_read->value == shared_frame); - CHECK_TRUE(second_read.has_value() && second_read->value == shared_frame); - CHECK_TRUE(first.descriptor() == actual_descriptor); - CHECK_TRUE(second.descriptor()->codec_config == actual_descriptor->codec_config); - - first.reset(); - CHECK_TRUE(stop_count == 0); - CHECK_TRUE(hub.subscriberCount(initial_descriptor->id) == 1); - second.reset(); - CHECK_TRUE(stop_count == 1); - CHECK_TRUE(!hub.requestKeyFrame(initial_descriptor->id)); - CHECK_TRUE(hub.subscriberCount(initial_descriptor->id) == 0); - - { - auto restarted = hub.subscribe(initial_descriptor->id); - CHECK_TRUE(restarted.valid()); - CHECK_TRUE(start_count == 2); - } - CHECK_TRUE(stop_count == 2); - CHECK_TRUE(hub.unregisterSource(initial_descriptor->id)); - CHECK_TRUE(!hub.hasSource(initial_descriptor->id)); -} - -void testSubscriptionDiscardPending() { - MediaSourceManager hub; - const auto descriptor = makeVideoDescriptor(Codec::H264, 1); - std::mutex sink_mutex; - MediaSourceManager::FrameSink sink; - - MediaSourceManager::SourceCallbacks callbacks; - callbacks.start = [&](const MediaSourceManager::FrameSink& callback_sink, - const MediaSourceManager::CancelPredicate&) { - std::lock_guard lock(sink_mutex); - sink = callback_sink; - return true; - }; - callbacks.stop = [&] { - std::lock_guard lock(sink_mutex); - sink = {}; - }; - - CHECK_TRUE(hub.registerSource(descriptor, std::move(callbacks), 8)); - auto subscription = hub.subscribe(descriptor->id); - CHECK_TRUE(subscription.valid()); - - MediaSourceManager::FrameSink producer; - { - std::lock_guard lock(sink_mutex); - producer = sink; - } - CHECK_TRUE(static_cast(producer)); - producer(makeFrame(descriptor, 0, 10)); - producer(makeFrame(descriptor, 1, 20)); - producer(makeFrame(descriptor, 2, 30)); - - CHECK_TRUE(subscription.discardPendingIfExceeds(2) == 3); - CHECK_TRUE(!subscription.tryRead().has_value()); - producer(makeFrame(descriptor, 3, 40)); - const auto next = subscription.tryRead(); - CHECK_TRUE(next.has_value()); - CHECK_TRUE(next->value->sequence == 3); - CHECK_TRUE(next->dropped_since_last_read == 3); - CHECK_TRUE(subscription.droppedCount() == 3); -} - -void testHubFailedStartAndShutdown() { - MediaSourceManager hub; - const auto descriptor = makeVideoDescriptor(Codec::UNKNOWN, 1); - std::atomic start_attempts{0}; - std::atomic retry_stop_count{0}; - MediaSourceManager::SourceCallbacks failed_callbacks; - failed_callbacks.start = [&](const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate&) { - return ++start_attempts >= 2; - }; - failed_callbacks.stop = [&] { ++retry_stop_count; }; - CHECK_TRUE(hub.registerSource(descriptor, std::move(failed_callbacks), 2)); - auto failed = hub.subscribe(descriptor->id); - CHECK_TRUE(!failed.valid()); - auto retry = hub.subscribe(descriptor->id); - CHECK_TRUE(retry.valid()); - retry.reset(); - CHECK_TRUE(start_attempts == 2); - CHECK_TRUE(retry_stop_count == 1); - CHECK_TRUE(hub.unregisterSource(descriptor->id)); - - std::atomic stop_count{0}; - MediaSourceManager::SourceCallbacks callbacks; - callbacks.start = [](const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate&) { - return true; - }; - callbacks.stop = [&] { ++stop_count; }; - CHECK_TRUE(hub.registerSource(descriptor, std::move(callbacks), 2)); - auto live = hub.subscribe(descriptor->id); - CHECK_TRUE(live.valid()); - hub.shutdown(); - CHECK_TRUE(stop_count == 1); - CHECK_TRUE(!live.valid()); - CHECK_TRUE(!live.waitRead(50ms).has_value()); -} - -void testHubStopAllSourcesAllowsReregistration() { - MediaSourceManager hub; - const auto first_descriptor = makeVideoDescriptor(Codec::H264, 1); - std::atomic first_stop_count{0}; - - MediaSourceManager::SourceCallbacks first_callbacks; - first_callbacks.start = [](const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate&) { - return true; - }; - first_callbacks.stop = [&] { ++first_stop_count; }; - CHECK_TRUE(hub.registerSource(first_descriptor, std::move(first_callbacks), 2)); - auto old_subscription = hub.subscribe(first_descriptor->id); - CHECK_TRUE(old_subscription.valid()); - - auto blocked_read = std::async(std::launch::async, [&] { - return old_subscription.waitRead(2s); - }); - CHECK_TRUE(hub.stopAllSources()); - - CHECK_TRUE(first_stop_count.load(std::memory_order_acquire) == 1); - CHECK_TRUE(!hub.hasSource(first_descriptor->id)); - CHECK_TRUE(!old_subscription.valid()); - CHECK_TRUE(blocked_read.wait_for(500ms) == std::future_status::ready); - if (blocked_read.wait_for(0ms) == std::future_status::ready) { - CHECK_TRUE(!blocked_read.get().has_value()); - } - - const auto second_descriptor = makeVideoDescriptor(Codec::H264, 2); - std::atomic second_start_count{0}; - std::atomic second_stop_count{0}; - MediaSourceManager::SourceCallbacks second_callbacks; - second_callbacks.start = [&](const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate&) { - ++second_start_count; - return true; - }; - second_callbacks.stop = [&] { ++second_stop_count; }; - - CHECK_TRUE(hub.registerSource(second_descriptor, std::move(second_callbacks), 2)); - auto new_subscription = hub.subscribe(second_descriptor->id); - CHECK_TRUE(new_subscription.valid()); - CHECK_TRUE(new_subscription.descriptor()->generation == 2); - CHECK_TRUE(second_start_count.load(std::memory_order_acquire) == 1); - - old_subscription.reset(); - CHECK_TRUE(second_stop_count.load(std::memory_order_acquire) == 0); - new_subscription.reset(); - CHECK_TRUE(second_stop_count.load(std::memory_order_acquire) == 1); -} - -void testStopAllSourcesReportsAndRetriesUnconfirmedStop() { - MediaSourceManager hub; - const auto descriptor = makeVideoDescriptor(Codec::H264, 1); - std::atomic stop_attempts{0}; - - MediaSourceManager::SourceCallbacks callbacks; - callbacks.start = [](const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate&) { - return true; - }; - callbacks.stop_confirmed = [&] { - return ++stop_attempts >= 2; - }; - CHECK_TRUE(hub.registerSource(descriptor, std::move(callbacks), 2)); - auto subscription = hub.subscribe(descriptor->id); - CHECK_TRUE(subscription.valid()); - - std::vector stop_failures; - CHECK_TRUE(!hub.stopAllSources(&stop_failures)); - CHECK_TRUE(stop_failures.size() == 1); - CHECK_TRUE(stop_failures.front() == descriptor->id); - CHECK_TRUE(hub.hasSource(descriptor->id)); - CHECK_TRUE(!subscription.valid()); - - stop_failures.clear(); - CHECK_TRUE(hub.stopAllSources(&stop_failures)); - CHECK_TRUE(stop_failures.empty()); - CHECK_TRUE(!hub.hasSource(descriptor->id)); - CHECK_TRUE(stop_attempts.load(std::memory_order_acquire) == 2); -} - -void testStopSourcesForDeviceIsSelectiveAndRetriesFailures() { - MediaSourceManager hub; - const auto front_video = makeVideoDescriptor( - Codec::H264, 1, {}, "front.video", "camera.front"); - const auto front_depth = makeVideoDescriptor( - Codec::H264, 1, {}, "front.depth", "camera.front"); - const auto rear_video = makeVideoDescriptor( - Codec::H264, 1, {}, "rear.video", "camera.rear"); - - std::atomic front_video_stops{0}; - std::atomic front_depth_stops{0}; - std::atomic rear_stops{0}; - auto register_source = [&]( - const TrackDescriptorPtr& descriptor, - std::function stop_confirmed) { - MediaSourceManager::SourceCallbacks callbacks; - callbacks.start = []( - const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate&) { return true; }; - callbacks.stop_confirmed = std::move(stop_confirmed); - return hub.registerSource(descriptor, std::move(callbacks), 2); - }; - - CHECK_TRUE(register_source(front_video, [&] { - return ++front_video_stops >= 2; - })); - CHECK_TRUE(register_source(front_depth, [&] { - ++front_depth_stops; - return true; - })); - CHECK_TRUE(register_source(rear_video, [&] { - ++rear_stops; - return true; - })); - CHECK_TRUE( - hub.trackedSourceIds() == - (std::vector{"camera.front", "camera.rear"})); - - auto front_video_subscription = hub.subscribe(front_video->id); - auto front_depth_subscription = hub.subscribe(front_depth->id); - auto rear_subscription = hub.subscribe(rear_video->id); - CHECK_TRUE(front_video_subscription.valid()); - CHECK_TRUE(front_depth_subscription.valid()); - CHECK_TRUE(rear_subscription.valid()); - - std::vector stop_failures; - CHECK_TRUE(!hub.stopSourcesForDevice("camera.front", &stop_failures)); - CHECK_TRUE(stop_failures.size() == 1U); - CHECK_TRUE(stop_failures.front() == front_video->id); - CHECK_TRUE(hub.hasSource(front_video->id)); - CHECK_TRUE(!hub.hasSource(front_depth->id)); - CHECK_TRUE(hub.hasSource(rear_video->id)); - CHECK_TRUE( - hub.trackedSourceIds() == - (std::vector{"camera.front", "camera.rear"})); - CHECK_TRUE(!front_video_subscription.valid()); - CHECK_TRUE(!front_depth_subscription.valid()); - CHECK_TRUE(rear_subscription.valid()); - CHECK_TRUE(rear_stops.load(std::memory_order_acquire) == 0); - - CHECK_TRUE(hub.stopSourcesForDevice("camera.front", &stop_failures)); - CHECK_TRUE(stop_failures.empty()); - CHECK_TRUE(!hub.hasSource(front_video->id)); - CHECK_TRUE(hub.hasSource(rear_video->id)); - CHECK_TRUE( - hub.trackedSourceIds() == - (std::vector{"camera.rear"})); - CHECK_TRUE(front_video_stops.load(std::memory_order_acquire) == 2); - CHECK_TRUE(front_depth_stops.load(std::memory_order_acquire) == 1); - CHECK_TRUE(rear_stops.load(std::memory_order_acquire) == 0); - - rear_subscription.reset(); - CHECK_TRUE(rear_stops.load(std::memory_order_acquire) == 1); -} - -void testDeviceStopsRunConcurrentlyAndSerializeMatchingRegistration() { - MediaSourceManager hub; - const auto first = makeVideoDescriptor( - Codec::H264, 1, {}, "first.video", "camera.first"); - const auto second = makeVideoDescriptor( - Codec::H264, 1, {}, "second.video", "camera.second"); - - std::atomic first_stop_entered{false}; - std::atomic second_stop_entered{false}; - std::atomic release_stops{false}; - auto register_blocking_source = [&]( - const TrackDescriptorPtr& descriptor, - std::atomic& entered) { - MediaSourceManager::SourceCallbacks callbacks; - callbacks.start = []( - const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate&) { return true; }; - callbacks.stop = [&entered, &release_stops] { - entered.store(true, std::memory_order_release); - while (!release_stops.load(std::memory_order_acquire)) { - std::this_thread::sleep_for(1ms); - } - }; - return hub.registerSource(descriptor, std::move(callbacks), 2); - }; - - CHECK_TRUE(register_blocking_source(first, first_stop_entered)); - CHECK_TRUE(register_blocking_source(second, second_stop_entered)); - auto first_subscription = hub.subscribe(first->id); - auto second_subscription = hub.subscribe(second->id); - CHECK_TRUE(first_subscription.valid()); - CHECK_TRUE(second_subscription.valid()); - - auto first_stop = std::async(std::launch::async, [&] { - return hub.stopSourcesForDevice(first->source_id); - }); - const auto first_deadline = std::chrono::steady_clock::now() + 500ms; - while (!first_stop_entered.load(std::memory_order_acquire) && - std::chrono::steady_clock::now() < first_deadline) { - std::this_thread::sleep_for(1ms); - } - CHECK_TRUE(first_stop_entered.load(std::memory_order_acquire)); - CHECK_TRUE( - hub.trackedSourceIds() == - (std::vector{"camera.first", "camera.second"})); - - auto second_stop = std::async(std::launch::async, [&] { - return hub.stopSourcesForDevice(second->source_id); - }); - const auto second_deadline = std::chrono::steady_clock::now() + 500ms; - while (!second_stop_entered.load(std::memory_order_acquire) && - std::chrono::steady_clock::now() < second_deadline) { - std::this_thread::sleep_for(1ms); - } - CHECK_TRUE(second_stop_entered.load(std::memory_order_acquire)); - - MediaSourceManager::SourceCallbacks replacement_callbacks; - replacement_callbacks.start = []( - const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate&) { return true; }; - replacement_callbacks.stop = [] {}; - auto matching_registration = std::async(std::launch::async, [&] { - return hub.registerSource( - makeVideoDescriptor( - Codec::H264, - 2, - {}, - "first.replacement", - "camera.first"), - std::move(replacement_callbacks), - 2); - }); - CHECK_TRUE( - matching_registration.wait_for(20ms) == std::future_status::timeout); - - release_stops.store(true, std::memory_order_release); - CHECK_TRUE(first_stop.wait_for(500ms) == std::future_status::ready); - CHECK_TRUE(second_stop.wait_for(500ms) == std::future_status::ready); - if (first_stop.wait_for(0ms) == std::future_status::ready) { - CHECK_TRUE(first_stop.get()); - } - if (second_stop.wait_for(0ms) == std::future_status::ready) { - CHECK_TRUE(second_stop.get()); - } - CHECK_TRUE( - matching_registration.wait_for(500ms) == std::future_status::ready); - if (matching_registration.wait_for(0ms) == std::future_status::ready) { - CHECK_TRUE(matching_registration.get()); - } - CHECK_TRUE(hub.hasSource("first.replacement")); - CHECK_TRUE( - hub.trackedSourceIds() == - (std::vector{"camera.first"})); -} - -void testStopAllWaitsForDeviceStopAndRetainsItsConcurrentRegistrationRule() { - MediaSourceManager hub; - const auto first = makeVideoDescriptor( - Codec::H264, 1, {}, "first.video", "camera.first"); - const auto other = makeVideoDescriptor( - Codec::H264, 1, {}, "other.video", "camera.other"); - std::atomic first_stop_entered{false}; - std::atomic release_first_stop{false}; - std::atomic other_stops{0}; - - MediaSourceManager::SourceCallbacks first_callbacks; - first_callbacks.start = []( - const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate&) { return true; }; - first_callbacks.stop = [&] { - first_stop_entered.store(true, std::memory_order_release); - while (!release_first_stop.load(std::memory_order_acquire)) { - std::this_thread::sleep_for(1ms); - } - }; - CHECK_TRUE(hub.registerSource(first, std::move(first_callbacks), 2)); - auto first_subscription = hub.subscribe(first->id); - CHECK_TRUE(first_subscription.valid()); - - auto device_stop = std::async(std::launch::async, [&] { - return hub.stopSourcesForDevice(first->source_id); - }); - const auto stop_deadline = std::chrono::steady_clock::now() + 500ms; - while (!first_stop_entered.load(std::memory_order_acquire) && - std::chrono::steady_clock::now() < stop_deadline) { - std::this_thread::sleep_for(1ms); - } - CHECK_TRUE(first_stop_entered.load(std::memory_order_acquire)); - - auto stop_all = std::async(std::launch::async, [&] { - return hub.stopAllSources(); - }); - CHECK_TRUE(stop_all.wait_for(20ms) == std::future_status::timeout); - - MediaSourceManager::SourceCallbacks other_callbacks; - other_callbacks.start = []( - const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate&) { return true; }; - other_callbacks.stop = [&] { ++other_stops; }; - CHECK_TRUE(hub.registerSource(other, std::move(other_callbacks), 2)); - auto other_subscription = hub.subscribe(other->id); - CHECK_TRUE(other_subscription.valid()); - - release_first_stop.store(true, std::memory_order_release); - CHECK_TRUE(device_stop.wait_for(500ms) == std::future_status::ready); - if (device_stop.wait_for(0ms) == std::future_status::ready) { - CHECK_TRUE(device_stop.get()); - } - CHECK_TRUE(stop_all.wait_for(500ms) == std::future_status::ready); - if (stop_all.wait_for(0ms) == std::future_status::ready) { - CHECK_TRUE(stop_all.get()); - } - CHECK_TRUE(!hub.hasSource(first->id)); - CHECK_TRUE(!hub.hasSource(other->id)); - CHECK_TRUE(hub.trackedSourceIds().empty()); - CHECK_TRUE(!other_subscription.valid()); - CHECK_TRUE(other_stops.load(std::memory_order_acquire) == 1); -} - -void testConcurrentRegistrationWaitsForStopAllSources() { - MediaSourceManager hub; - const auto descriptor = makeVideoDescriptor(Codec::H264, 1); - std::atomic stop_entered{false}; - std::atomic release_stop{false}; - std::atomic old_stop_count{0}; - - MediaSourceManager::SourceCallbacks old_callbacks; - old_callbacks.start = [](const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate&) { - return true; - }; - old_callbacks.stop = [&] { - stop_entered.store(true, std::memory_order_release); - while (!release_stop.load(std::memory_order_acquire)) { - std::this_thread::sleep_for(1ms); - } - ++old_stop_count; - }; - CHECK_TRUE(hub.registerSource(descriptor, std::move(old_callbacks), 2)); - auto old_subscription = hub.subscribe(descriptor->id); - CHECK_TRUE(old_subscription.valid()); - - auto stop_all = std::async( - std::launch::async, [&] { return hub.stopAllSources(); }); - const auto stop_deadline = std::chrono::steady_clock::now() + 500ms; - while (!stop_entered.load(std::memory_order_acquire) && - std::chrono::steady_clock::now() < stop_deadline) { - std::this_thread::sleep_for(1ms); - } - CHECK_TRUE(stop_entered.load(std::memory_order_acquire)); - - std::atomic new_start_count{0}; - MediaSourceManager::SourceCallbacks new_callbacks; - new_callbacks.start = [&](const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate&) { - ++new_start_count; - return true; - }; - new_callbacks.stop = [] {}; - auto registration = std::async(std::launch::async, [&] { - return hub.registerSource( - makeVideoDescriptor(Codec::H264, 2), std::move(new_callbacks), 2); - }); - - CHECK_TRUE(registration.wait_for(20ms) == std::future_status::timeout); - release_stop.store(true, std::memory_order_release); - CHECK_TRUE(stop_all.wait_for(500ms) == std::future_status::ready); - if (stop_all.wait_for(0ms) == std::future_status::ready) { - CHECK_TRUE(stop_all.get()); - } - CHECK_TRUE(registration.wait_for(500ms) == std::future_status::ready); - const bool registered = registration.wait_for(0ms) == std::future_status::ready && - registration.get(); - CHECK_TRUE(registered); - CHECK_TRUE(old_stop_count.load(std::memory_order_acquire) == 1); - CHECK_TRUE(hub.hasSource(descriptor->id)); - - auto new_subscription = hub.subscribe(descriptor->id); - CHECK_TRUE(new_subscription.valid()); - CHECK_TRUE(new_subscription.descriptor()->generation == 2); - CHECK_TRUE(new_start_count.load(std::memory_order_acquire) == 1); -} - -void testSystemStopAllAdmissionFencesRegistrationAndStartup() { - cmvr::service::StopAllAdmissionGate admission_gate; - MediaSourceManager hub(&admission_gate); - const auto dormant = makeVideoDescriptor( - Codec::H264, 1, {}, "dormant.video", "camera.dormant"); - const auto new_source = makeVideoDescriptor( - Codec::H264, 1, {}, "new.video", "camera.new"); - std::atomic dormant_starts{0}; - std::atomic new_starts{0}; - - MediaSourceManager::SourceCallbacks dormant_callbacks; - dormant_callbacks.start = [&]( - const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate&) { - ++dormant_starts; - return true; - }; - dormant_callbacks.stop = [] {}; - CHECK_TRUE(hub.registerSource( - dormant, std::move(dormant_callbacks), 2)); - - const auto stop_ticket = admission_gate.beginStopAll(); - CHECK_TRUE(stop_ticket.valid()); - - MediaSourceManager::SourceCallbacks rejected_callbacks; - rejected_callbacks.start = [&]( - const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate&) { - ++new_starts; - return true; - }; - rejected_callbacks.stop = [] {}; - CHECK_TRUE(!hub.registerSource( - new_source, std::move(rejected_callbacks), 2)); - auto rejected_subscription = hub.subscribe(dormant->id); - CHECK_TRUE(!rejected_subscription.valid()); - CHECK_TRUE(dormant_starts.load(std::memory_order_acquire) == 0); - CHECK_TRUE(new_starts.load(std::memory_order_acquire) == 0); - - CHECK_TRUE(admission_gate.finishStopAll(stop_ticket, true)); - - MediaSourceManager::SourceCallbacks recovered_callbacks; - recovered_callbacks.start = [&]( - const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate&) { - ++new_starts; - return true; - }; - recovered_callbacks.stop = [] {}; - CHECK_TRUE(hub.registerSource( - new_source, std::move(recovered_callbacks), 2)); - - auto dormant_subscription = hub.subscribe(dormant->id); - auto new_subscription = hub.subscribe(new_source->id); - CHECK_TRUE(dormant_subscription.valid()); - CHECK_TRUE(new_subscription.valid()); - CHECK_TRUE(dormant_starts.load(std::memory_order_acquire) == 1); - CHECK_TRUE(new_starts.load(std::memory_order_acquire) == 1); -} - -void testSystemStopAllRejectsRegistrationWaitingForLocalStop() { - cmvr::service::StopAllAdmissionGate admission_gate; - MediaSourceManager hub(&admission_gate); - const auto old_source = makeVideoDescriptor( - Codec::H264, 1, {}, "old.video", "camera.shared"); - const auto replacement = makeVideoDescriptor( - Codec::H264, 2, {}, "replacement.video", "camera.shared"); - std::atomic stop_entered{false}; - std::atomic release_stop{false}; - - MediaSourceManager::SourceCallbacks old_callbacks; - old_callbacks.start = []( - const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate&) { return true; }; - old_callbacks.stop = [&] { - stop_entered.store(true, std::memory_order_release); - while (!release_stop.load(std::memory_order_acquire)) { - std::this_thread::sleep_for(1ms); - } - }; - CHECK_TRUE(hub.registerSource( - old_source, std::move(old_callbacks), 2)); - auto old_subscription = hub.subscribe(old_source->id); - CHECK_TRUE(old_subscription.valid()); - - auto local_stop = std::async(std::launch::async, [&] { - return hub.stopSourcesForDevice(old_source->source_id); - }); - const auto stop_deadline = std::chrono::steady_clock::now() + 500ms; - while (!stop_entered.load(std::memory_order_acquire) && - std::chrono::steady_clock::now() < stop_deadline) { - std::this_thread::sleep_for(1ms); - } - CHECK_TRUE(stop_entered.load(std::memory_order_acquire)); - - auto make_replacement_callbacks = [] { - MediaSourceManager::SourceCallbacks callbacks; - callbacks.start = []( - const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate&) { return true; }; - callbacks.stop = [] {}; - return callbacks; - }; - auto waiting_registration = std::async(std::launch::async, [&] { - return hub.registerSource( - replacement, make_replacement_callbacks(), 2); - }); - CHECK_TRUE( - waiting_registration.wait_for(20ms) == - std::future_status::timeout); - - const auto stop_ticket = admission_gate.beginStopAll(); - release_stop.store(true, std::memory_order_release); - CHECK_TRUE(local_stop.wait_for(500ms) == std::future_status::ready); - if (local_stop.wait_for(0ms) == std::future_status::ready) { - CHECK_TRUE(local_stop.get()); - } - CHECK_TRUE( - waiting_registration.wait_for(500ms) == - std::future_status::ready); - if (waiting_registration.wait_for(0ms) == std::future_status::ready) { - CHECK_TRUE(!waiting_registration.get()); - } - CHECK_TRUE(!hub.hasSource(replacement->id)); - - CHECK_TRUE(admission_gate.finishStopAll(stop_ticket, true)); - CHECK_TRUE(hub.registerSource( - replacement, make_replacement_callbacks(), 2)); - auto recovered = hub.subscribe(replacement->id); - CHECK_TRUE(recovered.valid()); -} - -void testSystemStopAllRejectsSubscriptionWaitingForLocalStop() { - cmvr::service::StopAllAdmissionGate admission_gate; - MediaSourceManager hub(&admission_gate); - const auto descriptor = makeVideoDescriptor( - Codec::H264, 1, {}, "waiting.video", "camera.waiting"); - std::atomic stop_entered{false}; - std::atomic release_stop{false}; - std::atomic starts{0}; - - MediaSourceManager::SourceCallbacks callbacks; - callbacks.start = [&]( - const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate&) { - ++starts; - return true; - }; - callbacks.stop = [&] { - stop_entered.store(true, std::memory_order_release); - while (!release_stop.load(std::memory_order_acquire)) { - std::this_thread::sleep_for(1ms); - } - }; - CHECK_TRUE(hub.registerSource( - descriptor, std::move(callbacks), 2)); - auto active = hub.subscribe(descriptor->id); - CHECK_TRUE(active.valid()); - - auto local_stop = std::async(std::launch::async, [&] { - active.reset(); - }); - const auto stop_deadline = std::chrono::steady_clock::now() + 500ms; - while (!stop_entered.load(std::memory_order_acquire) && - std::chrono::steady_clock::now() < stop_deadline) { - std::this_thread::sleep_for(1ms); - } - CHECK_TRUE(stop_entered.load(std::memory_order_acquire)); - - auto waiting_subscription = std::async(std::launch::async, [&] { - return hub.subscribe(descriptor->id); - }); - CHECK_TRUE( - waiting_subscription.wait_for(20ms) == - std::future_status::timeout); - - const auto stop_ticket = admission_gate.beginStopAll(); - release_stop.store(true, std::memory_order_release); - CHECK_TRUE(local_stop.wait_for(500ms) == std::future_status::ready); - if (local_stop.wait_for(0ms) == std::future_status::ready) { - local_stop.get(); - } - CHECK_TRUE( - waiting_subscription.wait_for(500ms) == - std::future_status::ready); - if (waiting_subscription.wait_for(0ms) == std::future_status::ready) { - CHECK_TRUE(!waiting_subscription.get().valid()); - } - CHECK_TRUE(starts.load(std::memory_order_acquire) == 1); - - CHECK_TRUE(admission_gate.finishStopAll(stop_ticket, true)); - auto recovered = hub.subscribe(descriptor->id); - CHECK_TRUE(recovered.valid()); - CHECK_TRUE(starts.load(std::memory_order_acquire) == 2); -} - -void testStopAllSourcesCancelsStartingSourceBeforeReuse() { - MediaSourceManager hub; - const auto descriptor = makeVideoDescriptor(Codec::UNKNOWN, 1); - std::atomic old_start_entered{false}; - std::atomic release_old_start{false}; - std::atomic old_stop_count{0}; - - MediaSourceManager::SourceCallbacks old_callbacks; - old_callbacks.start = [&](const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate& cancelled) { - old_start_entered.store(true, std::memory_order_release); - while (!release_old_start.load(std::memory_order_acquire)) { - if (cancelled()) { - break; - } - std::this_thread::sleep_for(1ms); - } - // Deliberately report a late success to exercise the abandoned-start - // stop path after stopAllSources has unregistered this source. - return true; - }; - old_callbacks.stop = [&] { ++old_stop_count; }; - CHECK_TRUE(hub.registerSource(descriptor, std::move(old_callbacks), 2)); - - auto old_subscription = std::async(std::launch::async, [&] { - return hub.subscribe(descriptor->id); - }); - const auto start_deadline = std::chrono::steady_clock::now() + 500ms; - while (!old_start_entered.load(std::memory_order_acquire) && - std::chrono::steady_clock::now() < start_deadline) { - std::this_thread::sleep_for(1ms); - } - CHECK_TRUE(old_start_entered.load(std::memory_order_acquire)); - - CHECK_TRUE(!hub.stopAllSources()); - CHECK_TRUE(hub.hasSource(descriptor->id)); - CHECK_TRUE(old_subscription.wait_for(500ms) == std::future_status::ready); - if (old_subscription.wait_for(0ms) == std::future_status::ready) { - CHECK_TRUE(!old_subscription.get().valid()); - } - - release_old_start.store(true, std::memory_order_release); - const auto old_stop_deadline = std::chrono::steady_clock::now() + 500ms; - while (old_stop_count.load(std::memory_order_acquire) != 1 && - std::chrono::steady_clock::now() < old_stop_deadline) { - std::this_thread::sleep_for(1ms); - } - CHECK_TRUE(old_stop_count.load(std::memory_order_acquire) == 1); - CHECK_TRUE(hub.stopAllSources()); - - std::atomic new_start_count{0}; - MediaSourceManager::SourceCallbacks new_callbacks; - new_callbacks.start = [&](const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate&) { - ++new_start_count; - return true; - }; - new_callbacks.stop = [] {}; - CHECK_TRUE(hub.registerSource( - makeVideoDescriptor(Codec::H264, 2), std::move(new_callbacks), 2)); - auto new_subscription = hub.subscribe(descriptor->id); - CHECK_TRUE(new_subscription.valid()); - CHECK_TRUE(new_start_count.load(std::memory_order_acquire) == 1); - CHECK_TRUE(new_subscription.valid()); -} - -void testKeyFrameRequestIsOrderedBeforeStop() { - MediaSourceManager hub; - const auto descriptor = makeVideoDescriptor(Codec::H264, 1); - std::atomic key_frame_entered{false}; - std::atomic release_key_frame{false}; - std::atomic stop_count{0}; - - MediaSourceManager::SourceCallbacks callbacks; - callbacks.start = [](const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate&) { - return true; - }; - callbacks.stop = [&] { ++stop_count; }; - callbacks.request_key_frame = [&] { - key_frame_entered.store(true, std::memory_order_release); - while (!release_key_frame.load(std::memory_order_acquire)) { - std::this_thread::sleep_for(1ms); - } - return true; - }; - CHECK_TRUE(hub.registerSource(descriptor, std::move(callbacks), 2)); - auto subscription = hub.subscribe(descriptor->id); - CHECK_TRUE(subscription.valid()); - - auto key_frame = std::async(std::launch::async, [&] { - return hub.requestKeyFrame(descriptor->id); - }); - const auto enter_deadline = std::chrono::steady_clock::now() + 500ms; - while (!key_frame_entered.load(std::memory_order_acquire) && - std::chrono::steady_clock::now() < enter_deadline) { - std::this_thread::sleep_for(1ms); - } - CHECK_TRUE(key_frame_entered.load(std::memory_order_acquire)); - - auto stop = std::async(std::launch::async, [&] { subscription.reset(); }); - CHECK_TRUE(stop.wait_for(20ms) == std::future_status::timeout); - CHECK_TRUE(stop_count.load(std::memory_order_acquire) == 0); - - release_key_frame.store(true, std::memory_order_release); - CHECK_TRUE(key_frame.get()); - CHECK_TRUE(stop.wait_for(500ms) == std::future_status::ready); - stop.get(); - CHECK_TRUE(stop_count.load(std::memory_order_acquire) == 1); - CHECK_TRUE(!hub.requestKeyFrame(descriptor->id)); -} - -void testHubCancelsBlockedStartWithoutBlockingShutdown() { - MediaSourceManager hub; - const auto descriptor = makeVideoDescriptor(Codec::UNKNOWN, 1); - std::atomic start_entered{false}; - std::atomic start_exited{false}; - - MediaSourceManager::SourceCallbacks callbacks; - callbacks.start = [&](const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate& cancelled) { - start_entered.store(true, std::memory_order_release); - while (!cancelled()) { - std::this_thread::sleep_for(2ms); - } - start_exited.store(true, std::memory_order_release); - return false; - }; - CHECK_TRUE(hub.registerSource(descriptor, std::move(callbacks), 2)); - - auto subscription_future = std::async(std::launch::async, [&] { - return hub.subscribe(descriptor->id); - }); - const auto start_deadline = std::chrono::steady_clock::now() + 500ms; - while (!start_entered.load(std::memory_order_acquire) && - std::chrono::steady_clock::now() < start_deadline) { - std::this_thread::sleep_for(2ms); - } - - auto shutdown_future = std::async(std::launch::async, [&] { hub.shutdown(); }); - const bool shutdown_completed = shutdown_future.wait_for(500ms) == - std::future_status::ready; - if (shutdown_completed) shutdown_future.get(); - const bool subscribe_completed = subscription_future.wait_for(500ms) == - std::future_status::ready; - bool invalid_subscription = false; - if (subscribe_completed) { - invalid_subscription = !subscription_future.get().valid(); - } - const auto exit_deadline = std::chrono::steady_clock::now() + 500ms; - while (!start_exited.load(std::memory_order_acquire) && - std::chrono::steady_clock::now() < exit_deadline) { - std::this_thread::sleep_for(2ms); - } - - CHECK_TRUE(start_entered.load(std::memory_order_acquire)); - CHECK_TRUE(shutdown_completed); - CHECK_TRUE(subscribe_completed); - CHECK_TRUE(invalid_subscription); - CHECK_TRUE(start_exited.load(std::memory_order_acquire)); -} - -void testHubQuarantinesNonCooperativeStart() { - MediaSourceManager hub; - const auto descriptor = makeVideoDescriptor(Codec::UNKNOWN, 1); - std::atomic start_entered{false}; - std::atomic release_start{false}; - std::atomic start_exited{false}; - std::atomic stop_count{0}; - - MediaSourceManager::SourceCallbacks callbacks; - callbacks.start = [&](const MediaSourceManager::FrameSink&, - const MediaSourceManager::CancelPredicate&) { - start_entered.store(true, std::memory_order_release); - while (!release_start.load(std::memory_order_acquire)) { - std::this_thread::sleep_for(2ms); - } - start_exited.store(true, std::memory_order_release); - return true; - }; - callbacks.stop = [&] { ++stop_count; }; - CHECK_TRUE(hub.registerSource(descriptor, std::move(callbacks), 2)); - - auto subscription_future = std::async(std::launch::async, [&] { - return hub.subscribe(descriptor->id); - }); - const auto start_deadline = std::chrono::steady_clock::now() + 500ms; - while (!start_entered.load(std::memory_order_acquire) && - std::chrono::steady_clock::now() < start_deadline) { - std::this_thread::sleep_for(2ms); - } - - const auto shutdown_started = std::chrono::steady_clock::now(); - hub.shutdown(); - const bool shutdown_was_bounded = - std::chrono::steady_clock::now() - shutdown_started < 500ms; - const bool subscribe_completed = subscription_future.wait_for(500ms) == - std::future_status::ready; - bool invalid_subscription = false; - if (subscribe_completed) { - invalid_subscription = !subscription_future.get().valid(); - } - - // Release the deliberately non-cooperative test callback before its stack - // captures go out of scope. Late successful startup must be stopped once. - release_start.store(true, std::memory_order_release); - const auto exit_deadline = std::chrono::steady_clock::now() + 500ms; - while ((!start_exited.load(std::memory_order_acquire) || stop_count.load() != 1) && - std::chrono::steady_clock::now() < exit_deadline) { - std::this_thread::sleep_for(2ms); - } - - CHECK_TRUE(start_entered.load(std::memory_order_acquire)); - CHECK_TRUE(shutdown_was_bounded); - CHECK_TRUE(subscribe_completed); - CHECK_TRUE(invalid_subscription); - CHECK_TRUE(start_exited.load(std::memory_order_acquire)); - CHECK_TRUE(stop_count.load() == 1); -} - -} // namespace - -int main() { - testMediaMetadataValidation(); - testLegacySpmcCompatibility(); - testBroadcastFrameRing(); - testBroadcastDiscardPending(); - testBroadcastDiscardConcurrentPublish(); - testBroadcastConcurrency(); - testHubLifecycleAndDescriptorRefresh(); - testSubscriptionDiscardPending(); - testHubFailedStartAndShutdown(); - testHubStopAllSourcesAllowsReregistration(); - testStopAllSourcesReportsAndRetriesUnconfirmedStop(); - testStopSourcesForDeviceIsSelectiveAndRetriesFailures(); - testDeviceStopsRunConcurrentlyAndSerializeMatchingRegistration(); - testStopAllWaitsForDeviceStopAndRetainsItsConcurrentRegistrationRule(); - testConcurrentRegistrationWaitsForStopAllSources(); - testSystemStopAllAdmissionFencesRegistrationAndStartup(); - testSystemStopAllRejectsRegistrationWaitingForLocalStop(); - testSystemStopAllRejectsSubscriptionWaitingForLocalStop(); - testStopAllSourcesCancelsStartingSourceBeforeReuse(); - testKeyFrameRequestIsOrderedBeforeStop(); - testHubCancelsBlockedStartWithoutBlockingShutdown(); - testHubQuarantinesNonCooperativeStart(); - - if (failures != 0) { - std::cerr << failures << " media_source_manager checks failed\n"; - return 1; - } - std::cout << "media_source_manager self-test passed\n"; - return 0; -} diff --git a/cmvr-es/manager/safety_manager/CMakeLists.txt b/cmvr-es/manager/safety_manager/CMakeLists.txt index f647fb1e..2c704db1 100644 --- a/cmvr-es/manager/safety_manager/CMakeLists.txt +++ b/cmvr-es/manager/safety_manager/CMakeLists.txt @@ -16,50 +16,3 @@ target_link_libraries(safety_manager PUBLIC add_library(cmvr_es::safety_manager ALIAS safety_manager) install(TARGETS safety_manager LIBRARY DESTINATION lib) - -if(BUILD_TESTING) - add_executable(safety_snapshot_store_test - tests/safety_snapshot_store_test.cpp - ) - target_link_libraries(safety_snapshot_store_test PRIVATE - cmvr_es::safety_manager - gtest - gtest_main - pthread - ) - add_test( - NAME safety_snapshot_store_test - COMMAND safety_snapshot_store_test - ) - set_tests_properties(safety_snapshot_store_test PROPERTIES TIMEOUT 10) - - add_executable(command_ledger_test - tests/command_ledger_test.cpp - ) - target_link_libraries(command_ledger_test PRIVATE - cmvr_es::safety_manager - gtest - gtest_main - pthread - ) - add_test( - NAME command_ledger_test - COMMAND command_ledger_test - ) - set_tests_properties(command_ledger_test PROPERTIES TIMEOUT 10) - - add_executable(safety_manager_test - tests/safety_manager_test.cpp - ) - target_link_libraries(safety_manager_test PRIVATE - cmvr_es::safety_manager - gtest - gtest_main - pthread - ) - add_test( - NAME safety_manager_test - COMMAND safety_manager_test - ) - set_tests_properties(safety_manager_test PROPERTIES TIMEOUT 15) -endif() diff --git a/cmvr-es/manager/safety_manager/include/safety_manager.h b/cmvr-es/manager/safety_manager/include/safety_manager.h index 20661939..9c0fa3da 100644 --- a/cmvr-es/manager/safety_manager/include/safety_manager.h +++ b/cmvr-es/manager/safety_manager/include/safety_manager.h @@ -13,7 +13,6 @@ #include "manager/safety_manager/include/command_ledger.h" #include "manager/safety_manager/include/device_safety_endpoint.h" #include "manager/safety_manager/include/safety_participant.h" -#include "manager/safety_manager/include/safety_snapshot_store.h" namespace cmvr::safety { @@ -174,7 +173,6 @@ public: SafetyManager& operator=(const SafetyManager&) = delete; bool registerDevice(DeviceSafetyRegistration registration); - bool unregisterDevice(const std::string& device_id); bool registerParticipant(std::shared_ptr participant); bool unregisterParticipant(const std::string& participant_id); @@ -182,15 +180,12 @@ public: const std::string& device_id, device::ManagedDeviceState lifecycle, device::DeviceHealthSnapshot health = {}); - bool publishSafetySnapshot(DeviceSafetySnapshot snapshot); std::optional advanceDeviceGeneration( const std::string& device_id); StartupCoverageResult validateStartupCoverage( SafetyClock::time_point deadline); void markStartupComplete(); - void beginShutdown() noexcept; - AdmissionDecision evaluate(const AdmissionRequest& request) const; AdmissionResult admit(const AdmissionRequest& request); // Lightweight session check. This validates the coordinator-owned epoch, // generation, freshness, and admission state without calling the device @@ -208,16 +203,16 @@ public: RecoveryResult recover(const RecoveryRequest& request); SafetyManagerSnapshot snapshot() const; - SafetySnapshotStore& snapshotStore() noexcept; - const SafetySnapshotStore& snapshotStore() const noexcept; CommandLedger& commandLedger() noexcept; - const CommandLedger& commandLedger() const noexcept; const std::string& serviceInstanceId() const noexcept; const SafetyManagerConfig& config() const noexcept; private: friend class DispatchGuard; struct Impl; + bool publishSafetySnapshot(DeviceSafetySnapshot snapshot); + void beginShutdown() noexcept; + AdmissionDecision evaluate(const AdmissionRequest& request) const; void endDispatch_(const std::string& device_id) noexcept; std::unique_ptr impl_; }; diff --git a/cmvr-es/manager/safety_manager/src/safety_manager.cpp b/cmvr-es/manager/safety_manager/src/safety_manager.cpp index 10d3c42e..69e1e917 100644 --- a/cmvr-es/manager/safety_manager/src/safety_manager.cpp +++ b/cmvr-es/manager/safety_manager/src/safety_manager.cpp @@ -1,4 +1,5 @@ #include "manager/safety_manager/include/safety_manager.h" +#include "manager/safety_manager/include/safety_snapshot_store.h" #include #include @@ -531,51 +532,6 @@ bool SafetyManager::registerDevice(DeviceSafetyRegistration registration) return true; } -bool SafetyManager::unregisterDevice(const std::string& device_id) -{ - std::shared_ptr endpoint; - std::string participant_id; - { - std::lock_guard lock(impl_->mutex); - const auto found = impl_->devices.find(device_id); - if (found == impl_->devices.end()) { - return false; - } - if (found->second.in_flight_dispatches != 0) { - return false; - } - found->second.publisher_binding->active.store( - false, std::memory_order_release); - endpoint = found->second.endpoint; - if (found->second.participant) { - participant_id = - found->second.participant->descriptor().participant_id; - impl_->participants.erase(participant_id); - const auto runtime = - impl_->participant_runtime.find(participant_id); - if (runtime != impl_->participant_runtime.end()) { - runtime->second.registered = false; - if (!runtime->second.barrier_active && - impl_->retained_barriers.count(participant_id) == 0U) { - impl_->participant_runtime.erase(runtime); - } - } - } - found->second.admission_state = DeviceAdmissionState::Removed; - impl_->devices.erase(found); - impl_->addEventLocked( - SafetyReason::DeviceUnavailable, - device_id, - {}, - "device safety capability unregistered"); - } - if (endpoint) { - endpoint->bindPublisher({}); - } - impl_->snapshots.unregisterDevice(device_id); - return true; -} - bool SafetyManager::registerParticipant( std::shared_ptr participant) { @@ -2529,26 +2485,11 @@ SafetyManagerSnapshot SafetyManager::snapshot() const return result; } -SafetySnapshotStore& SafetyManager::snapshotStore() noexcept -{ - return impl_->snapshots; -} - -const SafetySnapshotStore& SafetyManager::snapshotStore() const noexcept -{ - return impl_->snapshots; -} - CommandLedger& SafetyManager::commandLedger() noexcept { return impl_->ledger; } -const CommandLedger& SafetyManager::commandLedger() const noexcept -{ - return impl_->ledger; -} - const std::string& SafetyManager::serviceInstanceId() const noexcept { return impl_->service_instance_id; diff --git a/cmvr-es/manager/safety_manager/tests/command_ledger_test.cpp b/cmvr-es/manager/safety_manager/tests/command_ledger_test.cpp deleted file mode 100644 index bad8e503..00000000 --- a/cmvr-es/manager/safety_manager/tests/command_ledger_test.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include "manager/safety_manager/include/command_ledger.h" - -#include -#include -#include -#include - -#include - -namespace cmvr::safety { -namespace { - -CommandKey key(const std::string& id) -{ - return {"anonymous", id}; -} - -CommandOutcome completedOutcome() -{ - CommandOutcome outcome; - outcome.lifecycle = CommandLifecycle::Completed; - outcome.reason = SafetyReason::None; - outcome.serialized_response = "done"; - return outcome; -} - -TEST(CommandLedgerTest, SameIdJoinsAndDifferentPayloadConflicts) -{ - CommandLedger ledger; - const auto first = ledger.reserve(key("command-1"), "payload-a"); - ASSERT_EQ(first.status, CommandReservationStatus::AcceptedNew); - EXPECT_EQ( - ledger.reserve(key("command-1"), "payload-a").status, - CommandReservationStatus::JoinedInFlight); - EXPECT_EQ( - ledger.reserve(key("command-1"), "payload-b").status, - CommandReservationStatus::CommandIdConflict); - - ASSERT_TRUE(ledger.complete(first.ticket, completedOutcome())); - const auto cached = ledger.reserve(key("command-1"), "payload-a"); - ASSERT_EQ(cached.status, CommandReservationStatus::CachedResult); - ASSERT_TRUE(cached.cached_outcome.has_value()); - EXPECT_EQ(cached.cached_outcome->serialized_response, "done"); -} - -TEST(CommandLedgerTest, ConcurrentCallersNeverCreateASecondReservation) -{ - CommandLedger ledger; - std::atomic accepted{0}; - std::vector workers; - for (int index = 0; index < 16; ++index) { - workers.emplace_back([&] { - const auto result = ledger.reserve(key("shared"), "payload"); - if (result.status == CommandReservationStatus::AcceptedNew) { - accepted.fetch_add(1); - } - }); - } - for (auto& worker : workers) { - worker.join(); - } - EXPECT_EQ(accepted.load(), 1); - EXPECT_EQ(ledger.acceptedIdCount(), 1U); -} - -TEST(CommandLedgerTest, OutcomeUnknownIsCachedAndNeverReservedAgain) -{ - CommandLedger ledger; - const auto first = ledger.reserve(key("uncertain"), "payload"); - ASSERT_EQ(first.status, CommandReservationStatus::AcceptedNew); - - CommandOutcome outcome; - outcome.lifecycle = CommandLifecycle::OutcomeUnknown; - outcome.reason = SafetyReason::OutcomeUnknown; - outcome.hardware_submission_possible = true; - ASSERT_TRUE(ledger.complete(first.ticket, outcome)); - - const auto retry = ledger.reserve(key("uncertain"), "payload"); - ASSERT_EQ(retry.status, CommandReservationStatus::CachedResult); - ASSERT_TRUE(retry.cached_outcome.has_value()); - EXPECT_EQ( - retry.cached_outcome->lifecycle, CommandLifecycle::OutcomeUnknown); - EXPECT_TRUE(retry.cached_outcome->hardware_submission_possible); -} - -TEST(CommandLedgerTest, EvictedResultLeavesAnExactTombstone) -{ - CommandLedger ledger({1, 3}); - auto first = ledger.reserve(key("first"), "payload-1"); - ASSERT_TRUE(ledger.complete(first.ticket, completedOutcome())); - auto second = ledger.reserve(key("second"), "payload-2"); - ASSERT_TRUE(ledger.complete(second.ticket, completedOutcome())); - - EXPECT_EQ( - ledger.reserve(key("first"), "payload-1").status, - CommandReservationStatus::ResultEvicted); - EXPECT_EQ( - ledger.reserve(key("first"), "different").status, - CommandReservationStatus::CommandIdConflict); - - auto third = ledger.reserve(key("third"), "payload-3"); - ASSERT_EQ(third.status, CommandReservationStatus::AcceptedNew); - EXPECT_EQ( - ledger.reserve(key("fourth"), "payload-4").status, - CommandReservationStatus::LedgerExhausted); -} - -TEST(CommandLedgerTest, WaitTimesOutWithoutChangingExecution) -{ - CommandLedger ledger; - const auto reservation = ledger.reserve(key("slow"), "payload"); - ASSERT_EQ(reservation.status, CommandReservationStatus::AcceptedNew); - EXPECT_FALSE(ledger.wait( - reservation.ticket, - SafetyClock::now() + std::chrono::milliseconds(5)).has_value()); - EXPECT_EQ( - ledger.reserve(key("slow"), "payload").status, - CommandReservationStatus::JoinedInFlight); -} - -} // namespace -} // namespace cmvr::safety diff --git a/cmvr-es/manager/safety_manager/tests/safety_manager_test.cpp b/cmvr-es/manager/safety_manager/tests/safety_manager_test.cpp deleted file mode 100644 index 04fd32c2..00000000 --- a/cmvr-es/manager/safety_manager/tests/safety_manager_test.cpp +++ /dev/null @@ -1,782 +0,0 @@ -#include "manager/safety_manager/include/safety_manager.h" - -#include -#include -#include -#include - -#include - -namespace cmvr::safety { -namespace { - -DeviceSafetyDescriptor controlDescriptor(std::string device_id = "arm") -{ - DeviceSafetyDescriptor descriptor; - descriptor.device_id = std::move(device_id); - descriptor.kind = device::DeviceKind::Arm; - descriptor.default_policy = SafetyPolicyFamily::Control; - descriptor.maximum_snapshot_age = std::chrono::seconds(1); - descriptor.requires_safe_stop = true; - descriptor.supports_active_refresh = true; - return descriptor; -} - -class FakeEndpoint final : public DeviceSafetyEndpoint { -public: - explicit FakeEndpoint(DeviceSafetyDescriptor descriptor) - : descriptor_(std::move(descriptor)) - { - } - - DeviceSafetyDescriptor descriptor() const override - { - return descriptor_; - } - - void bindPublisher(SafetySnapshotPublisher publisher) override - { - publisher_ = std::move(publisher); - } - - void requestSafetyRefresh() noexcept override - { - if (!publisher_ || !publish_on_refresh) { - return; - } - DeviceSafetySnapshot snapshot; - snapshot.device_id = descriptor_.device_id; - snapshot.condition = condition; - snapshot.device_generation = generation; - snapshot.sample_sequence = ++sequence; - snapshot.observed_at = SafetyClock::now(); - snapshot.connected = connected; - snapshot.operational_ready = ready; - snapshot.quiescent = quiescent; - snapshot.motion_active = - quiescent == TriState::True ? TriState::False : TriState::Unknown; - snapshot.emergency_stop_active = emergency_stop; - snapshot.protective_stop_active = protective_stop; - snapshot.fault_active = fault; - (void)publisher_(std::move(snapshot)); - } - - HardwareCheckResult validateBeforeDispatch( - const AdmissionPermit&) override - { - ++hardware_checks; - return final_check; - } - - RecoveryCheckResult reconcileAdmissionState( - const RecoveryContext&) override - { - ++recoveries; - return recovery_check; - } - - RecoveryCheckResult restoreOperationalState( - const RecoveryContext&) override - { - ++operational_restores; - if (operational_restore_check.reconciled && - restore_to_nominal_on_success) { - condition = SafetyCondition::Nominal; - connected = TriState::True; - ready = TriState::True; - quiescent = TriState::True; - emergency_stop = TriState::False; - protective_stop = TriState::False; - fault = TriState::False; - } - return operational_restore_check; - } - - DeviceSafetyDescriptor descriptor_; - SafetySnapshotPublisher publisher_; - SafetyCondition condition{SafetyCondition::Nominal}; - TriState connected{TriState::True}; - TriState ready{TriState::True}; - TriState quiescent{TriState::True}; - TriState emergency_stop{TriState::False}; - TriState protective_stop{TriState::False}; - TriState fault{TriState::False}; - HardwareCheckResult final_check{true, SafetyReason::None, {}}; - RecoveryCheckResult recovery_check{true, SafetyReason::None, {}}; - RecoveryCheckResult operational_restore_check{ - true, SafetyReason::None, {}}; - std::uint64_t generation{1}; - std::uint64_t sequence{0}; - bool publish_on_refresh{true}; - std::atomic hardware_checks{0}; - std::atomic recoveries{0}; - std::atomic operational_restores{0}; - bool restore_to_nominal_on_success{true}; -}; - -class FakeParticipant final : public SafetyParticipant { -public: - ParticipantDescriptor descriptor() const override - { - return {"arm", ParticipantPhase::Actuator, true, - std::chrono::milliseconds(100)}; - } - - BarrierToken beginBarrier( - const SafetyOperationContext& context) override - { - ++barriers; - return {"arm", context.operation_id, context.safety_epoch, - static_cast(barriers.load())}; - } - - ParticipantResult requestQuiesce( - const BarrierToken&, - const SafetyOperationContext&) override - { - ++stop_requests; - return stop_result; - } - - ParticipantResult verifyQuiescent( - const BarrierToken&, - const SafetyOperationContext&) override - { - ++verifications; - return verify_result; - } - - RecoveryCheckResult recoverAdmission( - const BarrierToken&, - const RecoveryContext&) override - { - ++recoveries; - return recovery_result; - } - - ParticipantResult releaseBarrier( - const BarrierToken&) noexcept override - { - ++releases; - return release_result; - } - - ParticipantResult stop_result{true, SafetyReason::None, {}}; - ParticipantResult verify_result{true, SafetyReason::None, {}}; - RecoveryCheckResult recovery_result{true, SafetyReason::None, {}}; - ParticipantResult release_result{true, SafetyReason::None, {}}; - std::atomic barriers{0}; - std::atomic stop_requests{0}; - std::atomic verifications{0}; - std::atomic recoveries{0}; - std::atomic releases{0}; -}; - -AdmissionRequest actuateRequest() -{ - AdmissionRequest request; - request.command = { - "/cmvr.api.ArmService/moveJ", - CommandIntent::Actuate, - SafetyPolicyFamily::Control, - true, - false}; - request.device_id = "arm"; - request.command_id = "command-1"; - request.deadline = SafetyClock::now() + std::chrono::seconds(1); - return request; -} - -TEST(SafetyManagerTest, ShadowReportsDenyWithoutChangingLegacyBehavior) -{ - SafetyManager coordinator; - ASSERT_TRUE(coordinator.registerDevice({controlDescriptor(), {}, {}})); - coordinator.markStartupComplete(); - - const auto result = coordinator.admit(actuateRequest()); - EXPECT_TRUE(result.decision.allowed); - EXPECT_FALSE(result.decision.policy_allowed); - EXPECT_FALSE(result.decision.enforced); - EXPECT_EQ(result.decision.reason, SafetyReason::SafetyStateMissing); - EXPECT_TRUE(result.permit.has_value()); -} - -TEST(SafetyManagerTest, - EnforceSelectedStartupRejectsEmptyOrUnknownCoverage) -{ - SafetyManagerConfig empty_config; - empty_config.enforcement_mode = EnforcementMode::EnforceSelected; - SafetyManager empty(empty_config); - const auto empty_result = empty.validateStartupCoverage( - SafetyClock::now() + std::chrono::milliseconds(10)); - ASSERT_FALSE(empty_result.ready); - ASSERT_EQ(empty_result.issues.size(), 1U); - EXPECT_EQ(empty_result.issues.front().reason, SafetyReason::InvalidArgument); - - SafetyManagerConfig missing_config; - missing_config.enforcement_mode = EnforcementMode::EnforceSelected; - missing_config.enforced_device_ids.insert("missing-arm"); - SafetyManager missing(missing_config); - const auto missing_result = missing.validateStartupCoverage( - SafetyClock::now() + std::chrono::milliseconds(10)); - ASSERT_FALSE(missing_result.ready); - ASSERT_EQ(missing_result.issues.size(), 1U); - EXPECT_EQ(missing_result.issues.front().target_id, "missing-arm"); - EXPECT_EQ(missing_result.issues.front().reason, SafetyReason::DeviceNotFound); -} - -TEST(SafetyManagerTest, - EnforceAllStartupRequiresEndpointParticipantAndFreshSnapshot) -{ - SafetyManagerConfig config; - config.enforcement_mode = EnforcementMode::EnforceAll; - - SafetyManager missing_capability(config); - ASSERT_TRUE(missing_capability.registerDevice( - {controlDescriptor(), {}, {}})); - const auto structural = missing_capability.validateStartupCoverage( - SafetyClock::now() + std::chrono::milliseconds(10)); - EXPECT_FALSE(structural.ready); - EXPECT_EQ(structural.issues.size(), 2U); - - SafetyManager missing_sample(config); - auto silent_endpoint = - std::make_shared(controlDescriptor()); - silent_endpoint->publish_on_refresh = false; - ASSERT_TRUE(missing_sample.registerDevice({ - controlDescriptor(), - silent_endpoint, - std::make_shared()})); - const auto stale = missing_sample.validateStartupCoverage( - SafetyClock::now() + std::chrono::milliseconds(10)); - ASSERT_FALSE(stale.ready); - ASSERT_EQ(stale.issues.size(), 1U); - EXPECT_EQ(stale.issues.front().reason, SafetyReason::SafetyStateMissing); -} - -TEST(SafetyManagerTest, - HardwareUnsafeSnapshotBlocksAdmissionButNotStructuralStartup) -{ - SafetyManagerConfig config; - config.enforcement_mode = EnforcementMode::EnforceAll; - SafetyManager coordinator(config); - auto endpoint = std::make_shared(controlDescriptor()); - endpoint->condition = SafetyCondition::Unsafe; - endpoint->emergency_stop = TriState::True; - ASSERT_TRUE(coordinator.registerDevice({ - controlDescriptor(), endpoint, std::make_shared()})); - coordinator.updateDeviceRuntimeState( - "arm", device::ManagedDeviceState::Running, - {device::DeviceHealthState::Healthy, {}}); - - const auto coverage = coordinator.validateStartupCoverage( - SafetyClock::now() + std::chrono::milliseconds(50)); - EXPECT_TRUE(coverage.ready); - coordinator.markStartupComplete(); - const auto admission = coordinator.admit(actuateRequest()); - EXPECT_FALSE(admission.decision.allowed); - EXPECT_EQ( - admission.decision.reason, SafetyReason::EmergencyStopActive); -} - -TEST(SafetyManagerTest, EnforceAllFailsClosedOnUnknownControlState) -{ - SafetyManagerConfig config; - config.enforcement_mode = EnforcementMode::EnforceAll; - SafetyManager coordinator(config); - ASSERT_TRUE(coordinator.registerDevice({controlDescriptor(), {}, {}})); - coordinator.markStartupComplete(); - - const auto result = coordinator.admit(actuateRequest()); - EXPECT_FALSE(result.decision.allowed); - EXPECT_FALSE(result.decision.policy_allowed); - EXPECT_TRUE(result.decision.enforced); - EXPECT_FALSE(result.permit.has_value()); -} - -TEST(SafetyManagerTest, ControlSafetyBitsMustBeExplicitlyFalse) -{ - SafetyManagerConfig config; - config.enforcement_mode = EnforcementMode::EnforceAll; - SafetyManager coordinator(config); - auto endpoint = std::make_shared(controlDescriptor()); - endpoint->protective_stop = TriState::Unknown; - ASSERT_TRUE(coordinator.registerDevice( - {controlDescriptor(), endpoint, {}})); - coordinator.updateDeviceRuntimeState( - "arm", device::ManagedDeviceState::Running, - {device::DeviceHealthState::Healthy, {}}); - coordinator.markStartupComplete(); - - const auto result = coordinator.admit(actuateRequest()); - EXPECT_FALSE(result.decision.allowed); - EXPECT_EQ(result.decision.reason, SafetyReason::ProtectiveStopActive); - ASSERT_EQ(coordinator.snapshot().devices.size(), 1U); - EXPECT_EQ( - coordinator.snapshot().devices.front().admission_state, - DeviceAdmissionState::Blocked); -} - -TEST(SafetyManagerTest, EnforcedDispatchRunsFinalHardwareCheck) -{ - SafetyManagerConfig config; - config.enforcement_mode = EnforcementMode::EnforceAll; - SafetyManager coordinator(config); - auto endpoint = std::make_shared(controlDescriptor()); - ASSERT_TRUE(coordinator.registerDevice( - {controlDescriptor(), endpoint, {}})); - coordinator.updateDeviceRuntimeState( - "arm", device::ManagedDeviceState::Running, - {device::DeviceHealthState::Healthy, {}}); - coordinator.markStartupComplete(); - - auto admission = coordinator.admit(actuateRequest()); - ASSERT_TRUE(admission.decision.allowed) << admission.decision.detail; - ASSERT_TRUE(admission.permit.has_value()); - auto dispatch = coordinator.beginDispatch(*admission.permit); - EXPECT_TRUE(dispatch.acquired()); - EXPECT_EQ(endpoint->hardware_checks.load(), 1); -} - -TEST(SafetyManagerTest, - StartActivityMayEnterFromRestrictedButActuationMayNot) -{ - SafetyManagerConfig config; - config.enforcement_mode = EnforcementMode::EnforceAll; - SafetyManager coordinator(config); - auto endpoint = std::make_shared(controlDescriptor()); - endpoint->condition = SafetyCondition::Restricted; - endpoint->ready = TriState::False; - ASSERT_TRUE(coordinator.registerDevice( - {controlDescriptor(), endpoint, {}})); - coordinator.updateDeviceRuntimeState( - "arm", device::ManagedDeviceState::Running, - {device::DeviceHealthState::Healthy, {}}); - coordinator.markStartupComplete(); - - auto start = actuateRequest(); - start.command.intent = CommandIntent::StartActivity; - const auto start_result = coordinator.admit(start); - ASSERT_TRUE(start_result.decision.allowed) - << start_result.decision.detail; - ASSERT_TRUE(start_result.permit.has_value()); - EXPECT_TRUE(coordinator.beginDispatch(*start_result.permit).acquired()); - - const auto actuation = coordinator.admit(actuateRequest()); - EXPECT_FALSE(actuation.decision.allowed); - EXPECT_EQ(actuation.decision.reason, SafetyReason::HardwareUnsafe); -} - -TEST(SafetyManagerTest, SuccessfulStopInvalidatesOldPermitAndReopens) -{ - SafetyManagerConfig config; - config.enforcement_mode = EnforcementMode::EnforceAll; - SafetyManager coordinator(config); - auto endpoint = std::make_shared(controlDescriptor()); - auto participant = std::make_shared(); - ASSERT_TRUE(coordinator.registerDevice( - {controlDescriptor(), endpoint, participant})); - coordinator.updateDeviceRuntimeState( - "arm", device::ManagedDeviceState::Running, - {device::DeviceHealthState::Healthy, {}}); - coordinator.markStartupComplete(); - - auto admission = coordinator.admit(actuateRequest()); - ASSERT_TRUE(admission.permit.has_value()); - const auto old_epoch = admission.permit->safety_epoch; - const auto stopped = coordinator.stopAll( - "stop-1", SafetyClock::now() + std::chrono::seconds(1)); - ASSERT_TRUE(stopped.success); - EXPECT_EQ(stopped.system_state, SystemAdmissionState::Open); - EXPECT_GT(stopped.current_safety_epoch, old_epoch); - const auto revalidated = - coordinator.revalidatePermit(*admission.permit); - EXPECT_FALSE(revalidated.safe); - EXPECT_EQ(revalidated.reason, SafetyReason::SafetyLatched); - EXPECT_FALSE(coordinator.beginDispatch(*admission.permit).acquired()); - EXPECT_EQ(participant->stop_requests.load(), 1); - EXPECT_EQ(participant->verifications.load(), 1); - const auto snapshot = coordinator.snapshot(); - ASSERT_EQ(snapshot.participants.size(), 1U); - EXPECT_EQ(snapshot.participants.front().descriptor.participant_id, "arm"); - EXPECT_FALSE(snapshot.participants.front().barrier_active); - EXPECT_FALSE(snapshot.participants.front().barrier_retained); - EXPECT_TRUE(snapshot.participants.front().last_request.recorded); - EXPECT_TRUE(snapshot.participants.front().last_request.success); - EXPECT_TRUE(snapshot.participants.front().last_verify.recorded); - EXPECT_TRUE(snapshot.participants.front().last_verify.success); - EXPECT_TRUE(snapshot.participants.front().last_release.recorded); - EXPECT_TRUE(snapshot.participants.front().last_release.success); -} - -TEST(SafetyManagerTest, FailedStopRequiresVerifiedRecovery) -{ - SafetyManagerConfig config; - config.enforcement_mode = EnforcementMode::EnforceAll; - SafetyManager coordinator(config); - auto endpoint = std::make_shared(controlDescriptor()); - auto participant = std::make_shared(); - participant->verify_result = { - false, SafetyReason::StopUnconfirmed, "motion not confirmed"}; - ASSERT_TRUE(coordinator.registerDevice( - {controlDescriptor(), endpoint, participant})); - coordinator.updateDeviceRuntimeState( - "arm", device::ManagedDeviceState::Running, - {device::DeviceHealthState::Healthy, {}}); - coordinator.markStartupComplete(); - - const auto stopped = coordinator.stopAll( - "stop-failed", SafetyClock::now() + std::chrono::seconds(1)); - ASSERT_FALSE(stopped.success); - ASSERT_EQ(stopped.system_state, SystemAdmissionState::Latched); - const auto latched = coordinator.snapshot(); - ASSERT_EQ(latched.participants.size(), 1U); - EXPECT_TRUE(latched.participants.front().barrier_active); - EXPECT_TRUE(latched.participants.front().barrier_retained); - EXPECT_TRUE(latched.participants.front().last_verify.recorded); - EXPECT_FALSE(latched.participants.front().last_verify.success); - EXPECT_FALSE(latched.participants.front().last_release.recorded); - - participant->verify_result = {true, SafetyReason::None, {}}; - RecoveryRequest request; - request.recovery_id = "recovery-1"; - request.all_devices = true; - request.expected_safety_epoch = stopped.current_safety_epoch; - request.verify_only = false; - request.reason = "operator confirmed work cell is clear"; - request.deadline = SafetyClock::now() + std::chrono::seconds(1); - const auto recovered = coordinator.recover(request); - EXPECT_EQ(recovered.result, RecoveryResultCode::Recovered); - EXPECT_EQ(recovered.system_state, SystemAdmissionState::Open); - EXPECT_EQ(endpoint->recoveries.load(), 1); - EXPECT_EQ(participant->recoveries.load(), 1); - const auto reopened = coordinator.snapshot(); - ASSERT_EQ(reopened.participants.size(), 1U); - EXPECT_FALSE(reopened.participants.front().barrier_active); - EXPECT_FALSE(reopened.participants.front().barrier_retained); - EXPECT_TRUE(reopened.participants.front().last_release.recorded); - EXPECT_TRUE(reopened.participants.front().last_release.success); -} - -TEST(SafetyManagerTest, RecoveryCannotIgnoreEmergencyStop) -{ - SafetyManager coordinator; - auto endpoint = std::make_shared(controlDescriptor()); - auto participant = std::make_shared(); - ASSERT_TRUE(coordinator.registerDevice( - {controlDescriptor(), endpoint, participant})); - coordinator.markStartupComplete(); - coordinator.quarantineDevice("arm", SafetyReason::OutcomeUnknown); - const auto before = coordinator.snapshot(); - - endpoint->emergency_stop = TriState::True; - RecoveryRequest request; - request.recovery_id = "recovery-estop"; - request.all_devices = true; - request.expected_safety_epoch = before.safety_epoch; - request.verify_only = false; - request.reason = "test"; - request.deadline = SafetyClock::now() + std::chrono::seconds(1); - const auto recovered = coordinator.recover(request); - EXPECT_EQ(recovered.result, RecoveryResultCode::BlockerRemains); - EXPECT_EQ(recovered.system_state, SystemAdmissionState::Latched); - ASSERT_FALSE(recovered.targets.empty()); - EXPECT_EQ( - recovered.targets.front().reason, - SafetyReason::EmergencyStopActive); - EXPECT_EQ(endpoint->recoveries.load(), 0); -} - -TEST(SafetyManagerTest, - OperationalRestoreClearsRecoverableHardwareAndSoftwareState) -{ - SafetyManager coordinator; - auto endpoint = std::make_shared(controlDescriptor()); - endpoint->condition = SafetyCondition::Unsafe; - endpoint->ready = TriState::False; - endpoint->protective_stop = TriState::True; - endpoint->quiescent = TriState::True; - ASSERT_TRUE(coordinator.registerDevice( - {controlDescriptor(), endpoint, {}})); - coordinator.markStartupComplete(); - coordinator.quarantineDevice("arm", SafetyReason::OutcomeUnknown); - const auto before = coordinator.snapshot(); - - RecoveryRequest request; - request.recovery_id = "restore-operational"; - request.all_devices = true; - request.expected_safety_epoch = before.safety_epoch; - request.verify_only = false; - request.restore_operational_state = true; - request.reason = "operator confirmed the work cell is clear"; - request.deadline = SafetyClock::now() + std::chrono::seconds(1); - request.authorize_clear = [] { return true; }; - - const auto restored = coordinator.recover(request); - - EXPECT_EQ(restored.result, RecoveryResultCode::Recovered); - EXPECT_EQ(restored.system_state, SystemAdmissionState::Open); - ASSERT_EQ(restored.targets.size(), 1U); - EXPECT_TRUE(restored.targets.front().success) - << restored.targets.front().detail; - EXPECT_EQ(endpoint->operational_restores.load(), 1); - EXPECT_EQ(endpoint->recoveries.load(), 1); - EXPECT_EQ( - coordinator.snapshot().devices.front().admission_state, - DeviceAdmissionState::Open); -} - -TEST(SafetyManagerTest, OperationalRestoreFailsClosedOnActiveEmergencyStop) -{ - SafetyManager coordinator; - auto endpoint = std::make_shared(controlDescriptor()); - endpoint->condition = SafetyCondition::Unsafe; - endpoint->ready = TriState::False; - endpoint->emergency_stop = TriState::True; - endpoint->quiescent = TriState::True; - endpoint->operational_restore_check = { - false, - SafetyReason::EmergencyStopActive, - "hardware emergency-stop input is still active"}; - ASSERT_TRUE(coordinator.registerDevice( - {controlDescriptor(), endpoint, {}})); - coordinator.markStartupComplete(); - coordinator.quarantineDevice("arm", SafetyReason::OutcomeUnknown); - const auto before = coordinator.snapshot(); - - RecoveryRequest request; - request.recovery_id = "restore-active-estop"; - request.all_devices = true; - request.expected_safety_epoch = before.safety_epoch; - request.verify_only = false; - request.restore_operational_state = true; - request.reason = "operator requested recovery"; - request.deadline = SafetyClock::now() + std::chrono::seconds(1); - request.authorize_clear = [] { return true; }; - - const auto restored = coordinator.recover(request); - - EXPECT_EQ(restored.result, RecoveryResultCode::BlockerRemains); - EXPECT_EQ(restored.system_state, SystemAdmissionState::Latched); - ASSERT_EQ(restored.targets.size(), 1U); - EXPECT_FALSE(restored.targets.front().success); - EXPECT_EQ( - restored.targets.front().reason, - SafetyReason::EmergencyStopActive); - EXPECT_EQ(endpoint->operational_restores.load(), 0); - EXPECT_EQ(endpoint->recoveries.load(), 0); -} - -TEST(SafetyManagerTest, OperationalRestoreDoesNotRecoverAnActiveDevice) -{ - SafetyManager coordinator; - auto endpoint = std::make_shared(controlDescriptor()); - endpoint->condition = SafetyCondition::Unsafe; - endpoint->ready = TriState::False; - endpoint->quiescent = TriState::False; - endpoint->fault = TriState::True; - ASSERT_TRUE(coordinator.registerDevice( - {controlDescriptor(), endpoint, {}})); - coordinator.markStartupComplete(); - coordinator.quarantineDevice("arm", SafetyReason::OutcomeUnknown); - - RecoveryRequest request; - request.recovery_id = "restore-active-device"; - request.all_devices = true; - request.expected_safety_epoch = coordinator.snapshot().safety_epoch; - request.verify_only = false; - request.restore_operational_state = true; - request.reason = "operator requested recovery"; - request.deadline = SafetyClock::now() + std::chrono::seconds(1); - request.authorize_clear = [] { return true; }; - - const auto restored = coordinator.recover(request); - - EXPECT_EQ(restored.result, RecoveryResultCode::BlockerRemains); - ASSERT_EQ(restored.targets.size(), 1U); - EXPECT_EQ( - restored.targets.front().reason, - SafetyReason::DeviceStillMoving); - EXPECT_EQ(endpoint->operational_restores.load(), 0); - EXPECT_EQ(endpoint->recoveries.load(), 0); -} - -TEST(SafetyManagerTest, OperationalRestoreAuditFailurePreventsDeviceRecovery) -{ - SafetyManager coordinator; - auto endpoint = std::make_shared(controlDescriptor()); - endpoint->condition = SafetyCondition::Unsafe; - endpoint->ready = TriState::False; - endpoint->protective_stop = TriState::True; - ASSERT_TRUE(coordinator.registerDevice( - {controlDescriptor(), endpoint, {}})); - coordinator.markStartupComplete(); - coordinator.quarantineDevice("arm", SafetyReason::OutcomeUnknown); - - RecoveryRequest request; - request.recovery_id = "restore-audit-failure"; - request.all_devices = true; - request.expected_safety_epoch = coordinator.snapshot().safety_epoch; - request.verify_only = false; - request.restore_operational_state = true; - request.reason = "operator requested recovery"; - request.deadline = SafetyClock::now() + std::chrono::seconds(1); - request.authorize_clear = [] { return false; }; - - const auto restored = coordinator.recover(request); - - EXPECT_EQ(restored.result, RecoveryResultCode::BlockerRemains); - ASSERT_EQ(restored.targets.size(), 1U); - EXPECT_EQ( - restored.targets.front().reason, - SafetyReason::RecoveryAuditFailed); - EXPECT_EQ(endpoint->operational_restores.load(), 0); - EXPECT_EQ(endpoint->recoveries.load(), 0); -} - -TEST(SafetyManagerTest, OperationalRestoreRequiresExplicitAuthorization) -{ - SafetyManager coordinator; - auto endpoint = std::make_shared(controlDescriptor()); - ASSERT_TRUE(coordinator.registerDevice( - {controlDescriptor(), endpoint, {}})); - coordinator.markStartupComplete(); - - RecoveryRequest request; - request.recovery_id = "restore-without-authorization"; - request.all_devices = true; - request.expected_safety_epoch = coordinator.snapshot().safety_epoch; - request.verify_only = false; - request.restore_operational_state = true; - request.reason = "operator requested recovery"; - - const auto restored = coordinator.recover(request); - - EXPECT_EQ(restored.result, RecoveryResultCode::Failed); - ASSERT_EQ(restored.targets.size(), 1U); - EXPECT_EQ( - restored.targets.front().reason, - SafetyReason::InvalidArgument); - EXPECT_EQ(endpoint->operational_restores.load(), 0); -} - -TEST(SafetyManagerTest, - OperationalRestoreAuditFailureWithNoDevicesRemainsLatched) -{ - SafetyManager coordinator; - coordinator.markStartupComplete(); - - RecoveryRequest request; - request.recovery_id = "empty-restore-audit-failure"; - request.all_devices = true; - request.expected_safety_epoch = coordinator.snapshot().safety_epoch; - request.verify_only = false; - request.restore_operational_state = true; - request.reason = "operator requested recovery"; - request.deadline = SafetyClock::now() + std::chrono::seconds(1); - request.authorize_clear = [] { return false; }; - - const auto restored = coordinator.recover(request); - - EXPECT_EQ(restored.result, RecoveryResultCode::BlockerRemains); - EXPECT_EQ(restored.system_state, SystemAdmissionState::Latched); - ASSERT_EQ(restored.targets.size(), 1U); - EXPECT_EQ(restored.targets.front().target_id, "system"); - EXPECT_EQ( - restored.targets.front().reason, - SafetyReason::RecoveryAuditFailed); -} - -TEST(SafetyManagerTest, - OperationalRestoreDoesNotPartiallyReleaseSoftwareAdmission) -{ - SafetyManager coordinator; - auto first = std::make_shared( - controlDescriptor("arm-first")); - first->condition = SafetyCondition::Unsafe; - first->ready = TriState::False; - first->protective_stop = TriState::True; - auto second = std::make_shared( - controlDescriptor("arm-second")); - second->condition = SafetyCondition::Unsafe; - second->ready = TriState::False; - second->fault = TriState::True; - second->operational_restore_check = { - false, SafetyReason::DeviceFault, "fault reset failed"}; - ASSERT_TRUE(coordinator.registerDevice( - {controlDescriptor("arm-first"), first, {}})); - ASSERT_TRUE(coordinator.registerDevice( - {controlDescriptor("arm-second"), second, {}})); - coordinator.markStartupComplete(); - coordinator.quarantineDevice( - "arm-first", SafetyReason::OutcomeUnknown); - coordinator.quarantineDevice( - "arm-second", SafetyReason::OutcomeUnknown); - - RecoveryRequest request; - request.recovery_id = "restore-partial-failure"; - request.all_devices = true; - request.expected_safety_epoch = coordinator.snapshot().safety_epoch; - request.verify_only = false; - request.restore_operational_state = true; - request.reason = "operator requested recovery"; - request.deadline = SafetyClock::now() + std::chrono::seconds(1); - request.authorize_clear = [] { return true; }; - - const auto restored = coordinator.recover(request); - - EXPECT_EQ(restored.result, RecoveryResultCode::BlockerRemains); - EXPECT_EQ(restored.system_state, SystemAdmissionState::Latched); - EXPECT_EQ(first->operational_restores.load(), 1); - EXPECT_EQ(second->operational_restores.load(), 1); - EXPECT_EQ(first->recoveries.load(), 0); - EXPECT_EQ(second->recoveries.load(), 0); - const auto snapshot = coordinator.snapshot(); - ASSERT_EQ(snapshot.devices.size(), 2U); - for (const auto& device : snapshot.devices) { - EXPECT_EQ( - device.admission_state, - DeviceAdmissionState::Quarantined) - << device.descriptor.device_id; - } -} - -TEST(SafetyManagerTest, RecoveryAuditFailureCannotReleaseLatch) -{ - SafetyManager coordinator; - auto endpoint = std::make_shared(controlDescriptor()); - auto participant = std::make_shared(); - participant->verify_result = { - false, SafetyReason::StopUnconfirmed, "motion not confirmed"}; - ASSERT_TRUE(coordinator.registerDevice( - {controlDescriptor(), endpoint, participant})); - coordinator.markStartupComplete(); - - const auto stopped = coordinator.stopAll( - "stop-audit", SafetyClock::now() + std::chrono::seconds(1)); - ASSERT_FALSE(stopped.success); - participant->verify_result = {true, SafetyReason::None, {}}; - - RecoveryRequest request; - request.recovery_id = "recovery-audit"; - request.all_devices = true; - request.expected_safety_epoch = stopped.current_safety_epoch; - request.verify_only = false; - request.reason = "operator inspected the work cell"; - request.deadline = SafetyClock::now() + std::chrono::seconds(1); - request.authorize_clear = [] { return false; }; - const auto recovered = coordinator.recover(request); - - EXPECT_EQ(recovered.result, RecoveryResultCode::BlockerRemains); - EXPECT_EQ(recovered.system_state, SystemAdmissionState::Latched); - ASSERT_FALSE(recovered.targets.empty()); - EXPECT_EQ( - recovered.targets.front().reason, - SafetyReason::RecoveryAuditFailed); - EXPECT_EQ(endpoint->recoveries.load(), 0); - EXPECT_EQ(participant->recoveries.load(), 0); - EXPECT_EQ(participant->releases.load(), 0); -} - -} // namespace -} // namespace cmvr::safety diff --git a/cmvr-es/manager/safety_manager/tests/safety_snapshot_store_test.cpp b/cmvr-es/manager/safety_manager/tests/safety_snapshot_store_test.cpp deleted file mode 100644 index 7d2c93d6..00000000 --- a/cmvr-es/manager/safety_manager/tests/safety_snapshot_store_test.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include "manager/safety_manager/include/safety_snapshot_store.h" - -#include -#include -#include - -#include - -namespace cmvr::safety { -namespace { - -DeviceSafetyDescriptor descriptor() -{ - DeviceSafetyDescriptor result; - result.device_id = "arm"; - result.kind = device::DeviceKind::Arm; - result.default_policy = SafetyPolicyFamily::Control; - result.maximum_snapshot_age = std::chrono::milliseconds(50); - result.requires_safe_stop = true; - return result; -} - -DeviceSafetySnapshot sample( - const std::uint64_t generation, - const std::uint64_t sequence, - const SafetyClock::time_point observed_at = SafetyClock::now()) -{ - DeviceSafetySnapshot result; - result.device_id = "arm"; - result.condition = SafetyCondition::Nominal; - result.device_generation = generation; - result.sample_sequence = sequence; - result.observed_at = observed_at; - result.connected = TriState::True; - result.operational_ready = TriState::True; - result.quiescent = TriState::True; - result.motion_active = TriState::False; - result.emergency_stop_active = TriState::False; - result.protective_stop_active = TriState::False; - result.fault_active = TriState::False; - return result; -} - -TEST(SafetySnapshotStoreTest, RejectsOldGenerationAndSequence) -{ - SafetySnapshotStore store; - ASSERT_TRUE(store.registerDevice(descriptor(), 3)); - EXPECT_FALSE(store.publish(sample(2, 1))); - ASSERT_TRUE(store.publish(sample(3, 2))); - EXPECT_FALSE(store.publish(sample(3, 2))); - EXPECT_FALSE(store.publish(sample(3, 1))); - EXPECT_TRUE(store.publish(sample(4, 1))); - - const auto view = store.get("arm"); - ASSERT_TRUE(view.registered); - EXPECT_EQ(view.snapshot.device_generation, 4U); - EXPECT_EQ(view.snapshot.sample_sequence, 1U); -} - -TEST(SafetySnapshotStoreTest, FreshnessUsesMonotonicObservationTime) -{ - SafetySnapshotStore store; - ASSERT_TRUE(store.registerDevice(descriptor())); - const auto observed = SafetyClock::now(); - ASSERT_TRUE(store.publish(sample(1, 1, observed))); - - EXPECT_TRUE(store.get( - "arm", observed + std::chrono::milliseconds(49)).fresh); - const auto stale = store.get( - "arm", observed + std::chrono::milliseconds(51)); - EXPECT_FALSE(stale.fresh); - EXPECT_EQ(stale.sample_age, std::chrono::milliseconds(51)); -} - -TEST(SafetySnapshotStoreTest, BumpGenerationRequiresANewSample) -{ - SafetySnapshotStore store; - ASSERT_TRUE(store.registerDevice(descriptor())); - ASSERT_TRUE(store.publish(sample(1, 8))); - ASSERT_EQ(store.bumpGeneration("arm"), 2U); - - const auto view = store.get("arm"); - EXPECT_FALSE(view.has_sample); - EXPECT_FALSE(view.fresh); - EXPECT_EQ(view.snapshot.device_generation, 2U); - EXPECT_FALSE(store.publish(sample(1, 9))); - EXPECT_TRUE(store.publish(sample(2, 1))); -} - -TEST(SafetySnapshotStoreTest, WaiterObservesOnlyANewerSample) -{ - SafetySnapshotStore store; - ASSERT_TRUE(store.registerDevice(descriptor())); - ASSERT_TRUE(store.publish(sample(1, 1))); - - std::atomic published{false}; - std::thread writer([&] { - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - published.store(store.publish(sample(1, 2))); - }); - - SafetySnapshotView view; - EXPECT_TRUE(store.waitForNewerSample( - "arm", 1, SafetyClock::now() + std::chrono::seconds(1), view)); - writer.join(); - EXPECT_TRUE(published.load()); - EXPECT_EQ(view.snapshot.sample_sequence, 2U); -} - -} // namespace -} // namespace cmvr::safety diff --git a/cmvr-es/manager/task_manager/CMakeLists.txt b/cmvr-es/manager/task_manager/CMakeLists.txt index 6f4185a8..bbc08858 100644 --- a/cmvr-es/manager/task_manager/CMakeLists.txt +++ b/cmvr-es/manager/task_manager/CMakeLists.txt @@ -16,30 +16,3 @@ target_link_libraries(task_manager add_library(cmvr_es::task_manager ALIAS task_manager) install(TARGETS task_manager LIBRARY DESTINATION lib) - -if(BUILD_TESTING) - add_executable(task_manager_lifecycle_test - tests/task_manager_lifecycle_test.cpp - ) - target_link_libraries(task_manager_lifecycle_test PRIVATE - cmvr_es::task_manager - cmvr_es::stop_all_admission_gate - gtest - gtest_main - pthread - ) - add_test( - NAME task_manager_lifecycle_test - COMMAND task_manager_lifecycle_test - ) - set(_task_manager_lifecycle_test_environment - "LD_LIBRARY_PATH=${CMVR_TEST_EXTERNAL_LIBRARY_PATH}") - if(CMVR_TEST_SYSTEM_LIBSTDCXX) - list(APPEND _task_manager_lifecycle_test_environment - "LD_PRELOAD=${CMVR_TEST_SYSTEM_LIBSTDCXX}") - endif() - set_tests_properties(task_manager_lifecycle_test PROPERTIES - TIMEOUT 10 - ENVIRONMENT "${_task_manager_lifecycle_test_environment}" - ) -endif() diff --git a/cmvr-es/manager/task_manager/tests/task_manager_lifecycle_test.cpp b/cmvr-es/manager/task_manager/tests/task_manager_lifecycle_test.cpp deleted file mode 100644 index bc7a4bf8..00000000 --- a/cmvr-es/manager/task_manager/tests/task_manager_lifecycle_test.cpp +++ /dev/null @@ -1,428 +0,0 @@ -#include "manager/task_manager/include/task_manager.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "service/grpc/stop_all/include/stop_all_admission_gate.h" -#include "task/task_factory.h" - -namespace { - -struct TaskBehavior { - bool init_result{true}; - bool start_result{true}; - bool throw_on_start{false}; - bool stop_activity_result{true}; - bool block_start{false}; - bool query_snapshot_on_stop{false}; -}; - -TaskBehavior task_behavior; -std::vector stop_order; - -class LifecycleTask final : public cmvr::task::Task { -public: - explicit LifecycleTask( - std::string id, - const cmvr::task::TaskShutdownPhase shutdown_phase = - cmvr::task::TaskShutdownPhase::DEPENDENT_ACTIVITY) - : id_(std::move(id)), - shutdown_phase_(shutdown_phase) - { - } - - const std::string& id() const override { return id_; } - cmvr::task::TaskRunMode runMode() const override - { - return cmvr::task::TaskRunMode::BLOCKING_SERVICE; - } - cmvr::task::TaskShutdownPhase shutdownPhase() const override - { - return shutdown_phase_; - } - - bool init() override - { - ++init_calls; - state_ = task_behavior.init_result - ? cmvr::task::TaskState::IDLE - : cmvr::task::TaskState::FAILED; - return task_behavior.init_result; - } - - bool start() override - { - ++start_calls; - { - std::unique_lock lock(start_mutex); - start_entered = true; - start_condition.notify_all(); - start_condition.wait(lock, [] { - return !task_behavior.block_start; - }); - } - if (task_behavior.throw_on_start) { - throw std::runtime_error("start failure"); - } - state_ = task_behavior.start_result - ? cmvr::task::TaskState::RUNNING - : cmvr::task::TaskState::FAILED; - return task_behavior.start_result; - } - - bool step(double) override { return true; } - - void stop() override - { - ++stop_calls; - if (task_behavior.query_snapshot_on_stop) { - (void)cmvr::task::TaskManager::activitySnapshotIfInitialized(); - } - stop_order.push_back(id_); - state_ = cmvr::task::TaskState::STOPPED; - } - - bool stopActivity() override - { - ++stop_activity_calls; - return task_behavior.stop_activity_result; - } - - cmvr::task::TaskState state() const override { return state_; } - bool isBusy() const override - { - return state_ == cmvr::task::TaskState::RUNNING; - } - bool isFinished() const override - { - return state_ == cmvr::task::TaskState::STOPPED; - } - bool isFailed() const override - { - return state_ == cmvr::task::TaskState::FAILED; - } - std::string stateString() const override - { - return cmvr::task::taskStateToString(state_); - } - std::string detailStatusString() const override - { - return stateString(); - } - - int init_calls{0}; - int start_calls{0}; - int stop_calls{0}; - int stop_activity_calls{0}; - std::mutex start_mutex; - std::condition_variable start_condition; - bool start_entered{false}; - -private: - std::string id_; - cmvr::task::TaskShutdownPhase shutdown_phase_; - cmvr::task::TaskState state_{ - cmvr::task::TaskState::UNINITIALIZED}; -}; - -std::shared_ptr created_task; -std::shared_ptr created_ingress_task; - -cmvr::config::TaskManagerConfig enabledTaskConfig() -{ - cmvr::config::TaskManagerConfig config; - auto* entry = config.add_tasks(); - entry->set_id("lifecycle_task"); - entry->set_type( - cmvr::config::TaskConfigEntry::TASK_TYPE_UME_TELEOP); - entry->set_enable(true); - entry->set_run_mode( - cmvr::config::TaskConfigEntry:: - TASK_RUN_MODE_BLOCKING_SERVICE); - return config; -} - -class TaskManagerLifecycleTest : public ::testing::Test { -protected: - void SetUp() override - { - cmvr::task::TaskManager::destroyInstance(); - cmvr::service::globalStopAllAdmissionGate().clearForTesting(); - task_behavior = {}; - created_task.reset(); - created_ingress_task.reset(); - stop_order.clear(); - cmvr::task::TaskFactory::registerCreator( - cmvr::config::TaskConfigEntry::TASK_TYPE_UME_TELEOP, - [](const cmvr::config::TaskConfigEntry& entry) { - created_task = - std::make_shared(entry.id()); - return created_task; - }); - } - - void TearDown() override - { - if (created_task) { - { - std::lock_guard lock(created_task->start_mutex); - task_behavior.block_start = false; - } - created_task->start_condition.notify_all(); - } - cmvr::task::TaskManager::destroyInstance(); - cmvr::service::globalStopAllAdmissionGate().clearForTesting(); - created_task.reset(); - created_ingress_task.reset(); - stop_order.clear(); - } -}; - -TEST_F(TaskManagerLifecycleTest, - EnabledTaskInitFailureMarksInitializationFailed) -{ - task_behavior.init_result = false; - auto& manager = - cmvr::task::TaskManager::getInstance(enabledTaskConfig()); - - ASSERT_NE(created_task, nullptr); - EXPECT_FALSE(manager.initialized()); - EXPECT_FALSE(manager.startRunTask()); - EXPECT_FALSE(manager.running()); - EXPECT_EQ(created_task->init_calls, 1); - EXPECT_EQ(created_task->start_calls, 0); - EXPECT_EQ(created_task->stop_calls, 1); -} - -TEST_F(TaskManagerLifecycleTest, - TaskStartFailureIsReturnedAndRunningRemainsFalse) -{ - task_behavior.start_result = false; - auto& manager = - cmvr::task::TaskManager::getInstance(enabledTaskConfig()); - - ASSERT_TRUE(manager.initialized()); - ASSERT_NE(created_task, nullptr); - EXPECT_FALSE(manager.startRunTask()); - EXPECT_FALSE(manager.running()); - EXPECT_EQ(created_task->start_calls, 1); - EXPECT_EQ(created_task->stop_calls, 1); -} - -TEST_F(TaskManagerLifecycleTest, - TaskStartExceptionIsReturnedAndRunningRemainsFalse) -{ - task_behavior.throw_on_start = true; - auto& manager = - cmvr::task::TaskManager::getInstance(enabledTaskConfig()); - - ASSERT_TRUE(manager.initialized()); - ASSERT_NE(created_task, nullptr); - EXPECT_FALSE(manager.startRunTask()); - EXPECT_FALSE(manager.running()); - EXPECT_EQ(created_task->start_calls, 1); - EXPECT_EQ(created_task->stop_calls, 1); -} - -TEST_F(TaskManagerLifecycleTest, SuccessfulStartAndStopAreReported) -{ - auto& manager = - cmvr::task::TaskManager::getInstance(enabledTaskConfig()); - - ASSERT_TRUE(manager.initialized()); - ASSERT_NE(created_task, nullptr); - EXPECT_TRUE(manager.startRunTask()); - EXPECT_TRUE(manager.running()); - manager.stopRunTask(); - EXPECT_FALSE(manager.running()); - EXPECT_EQ(created_task->start_calls, 1); - EXPECT_EQ(created_task->stop_calls, 1); -} - -TEST_F(TaskManagerLifecycleTest, - CommandIngressStopsBeforeDependentTaskActivity) -{ - cmvr::task::TaskFactory::registerCreator( - cmvr::config::TaskConfigEntry::TASK_TYPE_GRPC_SERVER, - [](const cmvr::config::TaskConfigEntry& entry) { - created_ingress_task = std::make_shared( - entry.id(), - cmvr::task::TaskShutdownPhase::COMMAND_INGRESS); - return created_ingress_task; - }); - - auto config = enabledTaskConfig(); - auto* ingress = config.add_tasks(); - ingress->set_id("control_ingress"); - ingress->set_type( - cmvr::config::TaskConfigEntry::TASK_TYPE_GRPC_SERVER); - ingress->set_enable(true); - ingress->set_run_mode( - cmvr::config::TaskConfigEntry::TASK_RUN_MODE_BLOCKING_SERVICE); - - auto& manager = cmvr::task::TaskManager::getInstance(config); - ASSERT_TRUE(manager.initialized()); - ASSERT_TRUE(manager.startRunTask()); - manager.stopRunTask(); - - ASSERT_EQ(stop_order.size(), 2U); - EXPECT_EQ(stop_order[0], "control_ingress"); - EXPECT_EQ(stop_order[1], "lifecycle_task"); -} - -TEST_F(TaskManagerLifecycleTest, - DestroyDoesNotHoldSingletonLockWhileStoppingTasks) -{ - task_behavior.query_snapshot_on_stop = true; - auto& manager = - cmvr::task::TaskManager::getInstance(enabledTaskConfig()); - ASSERT_TRUE(manager.initialized()); - ASSERT_TRUE(manager.startRunTask()); - - auto destroy = std::async(std::launch::async, [] { - cmvr::task::TaskManager::destroyInstance(); - }); - ASSERT_EQ( - destroy.wait_for(std::chrono::seconds(1)), - std::future_status::ready); - destroy.get(); - - ASSERT_NE(created_task, nullptr); - EXPECT_EQ(created_task->stop_calls, 1); -} - -TEST_F(TaskManagerLifecycleTest, - StopAllActivitiesDoesNotStopSchedulerOrTaskLifecycle) -{ - auto& manager = - cmvr::task::TaskManager::getInstance(enabledTaskConfig()); - - ASSERT_TRUE(manager.initialized()); - ASSERT_TRUE(manager.startRunTask()); - ASSERT_NE(created_task, nullptr); - EXPECT_TRUE(manager.stopAllActivities()); - EXPECT_TRUE(manager.running()); - EXPECT_EQ(created_task->stop_activity_calls, 1); - EXPECT_EQ(created_task->stop_calls, 0); - - manager.stopRunTask(); - EXPECT_EQ(created_task->stop_calls, 1); -} - -TEST_F(TaskManagerLifecycleTest, - StopAllActivitiesReportsUnconfirmedOperationalStop) -{ - task_behavior.stop_activity_result = false; - auto& manager = - cmvr::task::TaskManager::getInstance(enabledTaskConfig()); - - std::vector failures; - EXPECT_FALSE(manager.stopAllActivities(&failures)); - ASSERT_EQ(failures.size(), 1U); - EXPECT_NE(failures.front().find("lifecycle_task"), std::string::npos); - EXPECT_EQ(created_task->stop_calls, 0); -} - -TEST_F(TaskManagerLifecycleTest, - StopAllActivitiesIsSuccessfulWhenManagerIsNotInitialized) -{ - cmvr::task::TaskManager::destroyInstance(); - std::vector failures; - EXPECT_TRUE( - cmvr::task::TaskManager::stopAllActivitiesIfInitialized(&failures)); - EXPECT_TRUE(failures.empty()); -} - -TEST_F(TaskManagerLifecycleTest, StartIsRejectedWhileStopAllAdmissionIsClosed) -{ - auto& manager = - cmvr::task::TaskManager::getInstance(enabledTaskConfig()); - auto& gate = cmvr::service::globalStopAllAdmissionGate(); - const auto ticket = gate.beginStopAll(); - - EXPECT_FALSE(manager.startRunTask()); - EXPECT_FALSE(manager.running()); - ASSERT_NE(created_task, nullptr); - EXPECT_EQ(created_task->start_calls, 0); - - EXPECT_TRUE(gate.finishStopAll(ticket, true)); - EXPECT_TRUE(manager.startRunTask()); - EXPECT_TRUE(manager.running()); -} - -TEST_F(TaskManagerLifecycleTest, - StartCrossingStopAllGenerationRollsBackStartedTasks) -{ - task_behavior.block_start = true; - auto& manager = - cmvr::task::TaskManager::getInstance(enabledTaskConfig()); - ASSERT_NE(created_task, nullptr); - - std::atomic start_result{true}; - std::thread starter([&] { - start_result.store(manager.startRunTask()); - }); - bool start_entered = false; - { - std::unique_lock lock(created_task->start_mutex); - start_entered = created_task->start_condition.wait_for( - lock, std::chrono::seconds(2), [&] { - return created_task->start_entered; - }); - } - if (!start_entered) { - { - std::lock_guard lock(created_task->start_mutex); - task_behavior.block_start = false; - } - created_task->start_condition.notify_all(); - starter.join(); - FAIL() << "task start did not reach the generation-race barrier"; - } - - auto& gate = cmvr::service::globalStopAllAdmissionGate(); - const auto ticket = gate.beginStopAll(); - { - std::lock_guard lock(created_task->start_mutex); - task_behavior.block_start = false; - } - created_task->start_condition.notify_all(); - starter.join(); - - EXPECT_FALSE(start_result.load()); - EXPECT_FALSE(manager.running()); - EXPECT_EQ(created_task->start_calls, 1); - EXPECT_EQ(created_task->stop_calls, 1); - - EXPECT_TRUE(gate.finishStopAll(ticket, true)); - EXPECT_TRUE(manager.startRunTask()); -} - -TEST_F(TaskManagerLifecycleTest, - FailedStopAllKeepsTaskStartupRejectedUntilSuccessfulRound) -{ - auto& manager = - cmvr::task::TaskManager::getInstance(enabledTaskConfig()); - auto& gate = cmvr::service::globalStopAllAdmissionGate(); - auto ticket = gate.beginStopAll(); - EXPECT_FALSE(gate.finishStopAll(ticket, false)); - - EXPECT_FALSE(manager.startRunTask()); - ASSERT_NE(created_task, nullptr); - EXPECT_EQ(created_task->start_calls, 0); - - ticket = gate.beginStopAll(); - EXPECT_TRUE(gate.finishStopAll(ticket, true)); - EXPECT_TRUE(manager.startRunTask()); -} - -} // namespace diff --git a/cmvr-es/runtime/CMakeLists.txt b/cmvr-es/runtime/CMakeLists.txt index 91c68a2c..b9bb492c 100644 --- a/cmvr-es/runtime/CMakeLists.txt +++ b/cmvr-es/runtime/CMakeLists.txt @@ -19,33 +19,3 @@ target_link_libraries(cmvr_runtime PUBLIC add_library(cmvr_es::runtime ALIAS cmvr_runtime) install(TARGETS cmvr_runtime LIBRARY DESTINATION lib ARCHIVE DESTINATION lib) - -if(BUILD_TESTING) - add_executable(runtime_lifecycle_test - tests/runtime_lifecycle_test.cpp - ) - target_compile_features(runtime_lifecycle_test PRIVATE cxx_std_17) - target_include_directories(runtime_lifecycle_test PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ) - target_link_libraries(runtime_lifecycle_test PRIVATE - cmvr_es::runtime - gtest - gtest_main - pthread - ) - add_test( - NAME runtime_lifecycle_test - COMMAND runtime_lifecycle_test - ) - set(_runtime_lifecycle_test_environment - "LD_LIBRARY_PATH=${CMVR_TEST_EXTERNAL_LIBRARY_PATH}") - if(CMVR_TEST_SYSTEM_LIBSTDCXX) - list(APPEND _runtime_lifecycle_test_environment - "LD_PRELOAD=${CMVR_TEST_SYSTEM_LIBSTDCXX}") - endif() - set_tests_properties(runtime_lifecycle_test PROPERTIES - TIMEOUT 20 - ENVIRONMENT "${_runtime_lifecycle_test_environment}" - ) -endif() diff --git a/cmvr-es/runtime/tests/runtime_lifecycle_test.cpp b/cmvr-es/runtime/tests/runtime_lifecycle_test.cpp deleted file mode 100644 index 60f8d7ca..00000000 --- a/cmvr-es/runtime/tests/runtime_lifecycle_test.cpp +++ /dev/null @@ -1,266 +0,0 @@ -#include "runtime/include/cmvr_runtime.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include "cmvr/config/cmvr_es_config/cmvr_es_config.pb.h" -#include "cmvr/config/device_manager_config/device_manager_config.pb.h" -#include "cmvr/config/grpc_server_config/grpc_server_config.pb.h" -#include "cmvr/config/logger_config/logger_config.pb.h" -#include "cmvr/config/task_manager_config/task_manager_config.pb.h" -#include "common/io/proto_file_io.h" - -namespace { - -class TempConfigTree { -public: - TempConfigTree() - { - std::array pattern{}; - const std::string value = - "/tmp/cmvr-runtime-lifecycle-XXXXXX"; - std::copy(value.begin(), value.end(), pattern.begin()); - char* created = ::mkdtemp(pattern.data()); - if (created) { - root_ = created; - } - } - - ~TempConfigTree() - { - if (root_.empty()) { - return; - } - std::error_code error; - std::filesystem::remove_all(root_, error); - } - - bool valid() const { return !root_.empty(); } - - template - bool write(const std::string& name, const Message& message) const - { - return ProtoMessageIo::setProtoToAsciiFile( - message, (root_ / name).string()); - } - - std::string path(const std::string& name) const - { - return (root_ / name).string(); - } - - bool writeLogger() const - { - cmvr::config::LoggerRootConfig root; - auto* logger = root.mutable_logger(); - logger->set_minimum_level( - cmvr::config::LOG_LEVEL_INFO); - auto* route = logger->add_routes(); - route->set_level(cmvr::config::LOG_LEVEL_INFO); - route->set_terminal(false); - route->set_file(false); - return write("logger.pb.txt", root); - } - - bool writeRoot() const - { - cmvr::config::CMVRESRootConfig root; - auto* config = root.mutable_cmvr_es(); - config->set_logger_config_file("logger.pb.txt"); - config->set_device_manager_config_file( - "device_manager.pb.txt"); - config->set_task_manager_config_file( - "task_manager.pb.txt"); - return write("cmvr_es.pb.txt", root); - } - -private: - std::filesystem::path root_; -}; - -class OccupiedTcpPort { -public: - OccupiedTcpPort() - { - fd_ = ::socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0); - if (fd_ < 0) { - return; - } - - sockaddr_in address{}; - address.sin_family = AF_INET; - address.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - address.sin_port = 0; - if (::bind(fd_, reinterpret_cast(&address), - sizeof(address)) != 0 || - ::listen(fd_, 1) != 0) { - ::close(fd_); - fd_ = -1; - return; - } - - socklen_t length = sizeof(address); - if (::getsockname(fd_, - reinterpret_cast(&address), - &length) != 0) { - ::close(fd_); - fd_ = -1; - return; - } - port_ = ntohs(address.sin_port); - } - - ~OccupiedTcpPort() - { - if (fd_ >= 0) { - ::close(fd_); - } - } - - bool valid() const { return fd_ >= 0 && port_ != 0; } - std::string port() const { return std::to_string(port_); } - -private: - int fd_{-1}; - unsigned short port_{0}; -}; - -TEST(RuntimeLifecycleTest, EnabledDeviceInitFailureFailsRuntimeInit) -{ - TempConfigTree tree; - ASSERT_TRUE(tree.valid()); - ASSERT_TRUE(tree.writeLogger()); - ASSERT_TRUE(tree.writeRoot()); - - cmvr::config::DeviceManagerRootConfig devices; - auto* entry = - devices.mutable_device_manager()->add_devices(); - entry->set_id("unsupported"); - entry->set_type( - cmvr::config::DeviceConfigEntry::DEVICE_TYPE_UNKNOWN); - entry->set_enable(true); - ASSERT_TRUE(tree.write("device_manager.pb.txt", devices)); - - cmvr::config::TaskManagerRootConfig tasks; - ASSERT_TRUE(tree.write("task_manager.pb.txt", tasks)); - - cmvr::Runtime runtime; - EXPECT_FALSE(runtime.init(tree.path("cmvr_es.pb.txt"))); - EXPECT_FALSE(runtime.initialized()); - EXPECT_FALSE(runtime.tasksStarted()); -} - -TEST(RuntimeLifecycleTest, EnabledTaskInitFailureFailsRuntimeInit) -{ - TempConfigTree tree; - ASSERT_TRUE(tree.valid()); - ASSERT_TRUE(tree.writeLogger()); - ASSERT_TRUE(tree.writeRoot()); - - cmvr::config::DeviceManagerRootConfig devices; - ASSERT_TRUE(tree.write("device_manager.pb.txt", devices)); - - cmvr::config::TaskManagerRootConfig tasks; - auto* entry = tasks.mutable_task_manager()->add_tasks(); - entry->set_id("unsupported"); - entry->set_type( - cmvr::config::TaskConfigEntry::TASK_TYPE_UNKNOWN); - entry->set_enable(true); - entry->set_run_mode( - cmvr::config::TaskConfigEntry:: - TASK_RUN_MODE_BLOCKING_SERVICE); - ASSERT_TRUE(tree.write("task_manager.pb.txt", tasks)); - - cmvr::Runtime runtime; - EXPECT_FALSE(runtime.init(tree.path("cmvr_es.pb.txt"))); - EXPECT_FALSE(runtime.initialized()); - EXPECT_FALSE(runtime.tasksStarted()); -} - -TEST(RuntimeLifecycleTest, - TaskConfigLoadFailureRollsBackDeviceManagerSingleton) -{ - TempConfigTree first_tree; - ASSERT_TRUE(first_tree.valid()); - ASSERT_TRUE(first_tree.writeLogger()); - ASSERT_TRUE(first_tree.writeRoot()); - - cmvr::config::DeviceManagerRootConfig first_devices; - first_devices.mutable_device_manager()->set_name("first"); - ASSERT_TRUE(first_tree.write( - "device_manager.pb.txt", first_devices)); - // Deliberately do not create task_manager.pb.txt. - - cmvr::Runtime runtime; - ASSERT_FALSE( - runtime.init(first_tree.path("cmvr_es.pb.txt"))); - ASSERT_FALSE(runtime.initialized()); - - TempConfigTree second_tree; - ASSERT_TRUE(second_tree.valid()); - ASSERT_TRUE(second_tree.writeLogger()); - ASSERT_TRUE(second_tree.writeRoot()); - - cmvr::config::DeviceManagerRootConfig second_devices; - second_devices.mutable_device_manager()->set_name("second"); - ASSERT_TRUE(second_tree.write( - "device_manager.pb.txt", second_devices)); - cmvr::config::TaskManagerRootConfig second_tasks; - ASSERT_TRUE(second_tree.write( - "task_manager.pb.txt", second_tasks)); - - ASSERT_TRUE( - runtime.init(second_tree.path("cmvr_es.pb.txt"))); - EXPECT_EQ(runtime.deviceManager().name(), "second"); -} - -TEST(RuntimeLifecycleTest, GrpcBindFailureDoesNotMarkTasksStarted) -{ - OccupiedTcpPort occupied_port; - ASSERT_TRUE(occupied_port.valid()); - - TempConfigTree tree; - ASSERT_TRUE(tree.valid()); - ASSERT_TRUE(tree.writeLogger()); - ASSERT_TRUE(tree.writeRoot()); - - cmvr::config::DeviceManagerRootConfig devices; - ASSERT_TRUE(tree.write("device_manager.pb.txt", devices)); - - cmvr::config::GRPCServerRootConfig grpc; - auto* grpc_config = grpc.mutable_grpc_server(); - grpc_config->set_id("grpc_server"); - grpc_config->set_host("127.0.0.1"); - grpc_config->set_port(occupied_port.port()); - ASSERT_TRUE(tree.write("grpc.pb.txt", grpc)); - - cmvr::config::TaskManagerRootConfig tasks; - auto* entry = tasks.mutable_task_manager()->add_tasks(); - entry->set_id("grpc_server"); - entry->set_type( - cmvr::config::TaskConfigEntry::TASK_TYPE_GRPC_SERVER); - entry->set_enable(true); - entry->set_run_mode( - cmvr::config::TaskConfigEntry:: - TASK_RUN_MODE_BLOCKING_SERVICE); - entry->set_config_file("grpc.pb.txt"); - ASSERT_TRUE(tree.write("task_manager.pb.txt", tasks)); - - cmvr::Runtime runtime; - ASSERT_TRUE(runtime.init(tree.path("cmvr_es.pb.txt"))); - EXPECT_FALSE(runtime.startTasks()); - EXPECT_FALSE(runtime.tasksStarted()); - EXPECT_FALSE(runtime.taskManager().running()); -} - -} // namespace diff --git a/cmvr-es/service/README.md b/cmvr-es/service/README.md index 39a1ee13..5c7c8c53 100644 --- a/cmvr-es/service/README.md +++ b/cmvr-es/service/README.md @@ -121,7 +121,6 @@ ActionQueue 遵循以下执行语义: - 实现:[`grpc/server/include/grpc_motor_service.h`](grpc/server/include/grpc_motor_service.h) 和 [`grpc/server/src/grpc_motor_service.cpp`](grpc/server/src/grpc_motor_service.cpp) - 注册:[`../task/grpc_server_task/src/grpc_server_task.cpp`](../task/grpc_server_task/src/grpc_server_task.cpp) -- 单元测试:[`grpc/server/tests/grpc_motor_service_test.cpp`](grpc/server/tests/grpc_motor_service_test.cpp) 服务按单电机仲裁。同步 Profile 命令、Cyclic Position/Velocity 双向流、 `setEnabled`、状态读取和软件 `emergencyStop` 共用同一控制权状态: diff --git a/cmvr-es/service/grpc/CMakeLists.txt b/cmvr-es/service/grpc/CMakeLists.txt index cff56bd2..4214e37d 100644 --- a/cmvr-es/service/grpc/CMakeLists.txt +++ b/cmvr-es/service/grpc/CMakeLists.txt @@ -49,136 +49,6 @@ add_library(cmvr_es::service ALIAS service) install(TARGETS service LIBRARY DESTINATION lib) if(BUILD_TESTING) - add_executable(stop_all_admission_gate_test - stop_all/tests/stop_all_admission_gate_test.cpp - stop_all/src/stop_all_admission_gate.cpp - ) - target_include_directories(stop_all_admission_gate_test - PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ) - target_link_libraries(stop_all_admission_gate_test PRIVATE - gtest - gtest_main - pthread - ) - add_test( - NAME stop_all_admission_gate_test - COMMAND stop_all_admission_gate_test - ) - set_tests_properties(stop_all_admission_gate_test PROPERTIES TIMEOUT 10) - - add_executable(stop_operation_dispatcher_test - stop_all/tests/stop_operation_dispatcher_test.cpp - stop_all/src/stop_operation_dispatcher.cpp - ) - target_include_directories(stop_operation_dispatcher_test - PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ) - target_link_libraries(stop_operation_dispatcher_test PRIVATE - gtest - gtest_main - pthread - ) - add_test( - NAME stop_operation_dispatcher_test - COMMAND stop_operation_dispatcher_test - ) - set_tests_properties(stop_operation_dispatcher_test PROPERTIES TIMEOUT 10) - - add_executable(camera_operational_activity_registry_test - server/tests/camera_operational_activity_registry_test.cpp - ) - target_include_directories(camera_operational_activity_registry_test - PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ) - target_link_libraries(camera_operational_activity_registry_test PRIVATE - cmvr_es::proto - cmvr_es::camera_operational_activity_registry - gtest - gtest_main - pthread - ) - add_test( - NAME camera_operational_activity_registry_test - COMMAND camera_operational_activity_registry_test - ) - set_tests_properties(camera_operational_activity_registry_test PROPERTIES - TIMEOUT 10) - - add_executable(camera_ptz_activity_registry_test - server/tests/camera_ptz_activity_registry_test.cpp - server/src/camera_ptz_activity_registry.cpp - stop_all/src/stop_all_admission_gate.cpp - ) - target_include_directories(camera_ptz_activity_registry_test - PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ) - target_link_libraries(camera_ptz_activity_registry_test PRIVATE - cmvr_es::proto - gtest - gtest_main - pthread - ) - add_test( - NAME camera_ptz_activity_registry_test - COMMAND camera_ptz_activity_registry_test - ) - set_tests_properties(camera_ptz_activity_registry_test PROPERTIES TIMEOUT 10) - - add_executable(media_activity_coordinator_test - server/tests/media_activity_coordinator_test.cpp - server/src/media_activity_coordinator.cpp - stop_all/src/stop_all_admission_gate.cpp - ) - target_include_directories(media_activity_coordinator_test - PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ) - target_link_libraries(media_activity_coordinator_test PRIVATE - cmvr_es::logging - pthread - ) - add_test( - NAME media_activity_coordinator_test - COMMAND media_activity_coordinator_test - ) - set(_grpc_media_test_environment - "LD_LIBRARY_PATH=${CMVR_TEST_EXTERNAL_LIBRARY_PATH}" - ) - if(CMVR_TEST_SYSTEM_LIBSTDCXX) - list(APPEND _grpc_media_test_environment - "LD_PRELOAD=${CMVR_TEST_SYSTEM_LIBSTDCXX}") - endif() - set_tests_properties(media_activity_coordinator_test PROPERTIES - TIMEOUT 10 - ENVIRONMENT "${_grpc_media_test_environment}" - ) - - add_executable(motor_activity_coordinator_test - server/tests/motor_activity_coordinator_test.cpp - server/src/motor_activity_coordinator.cpp - ) - target_include_directories(motor_activity_coordinator_test - PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ) - target_link_libraries(motor_activity_coordinator_test PRIVATE - cmvr_es::logging - pthread - ) - add_test( - NAME motor_activity_coordinator_test - COMMAND motor_activity_coordinator_test - ) - set_tests_properties(motor_activity_coordinator_test PROPERTIES - TIMEOUT 10 - ENVIRONMENT "${_grpc_media_test_environment}" - ) - add_executable(grpc_camera_stream_policy_test server/tests/grpc_camera_stream_policy_test.cpp ) @@ -191,306 +61,6 @@ if(BUILD_TESTING) COMMAND grpc_camera_stream_policy_test ) set_tests_properties(grpc_camera_stream_policy_test PROPERTIES TIMEOUT 10) - - add_executable(grpc_system_service_test - server/tests/grpc_system_service_test.cpp - ) - target_include_directories(grpc_system_service_test - PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ${CMAKE_SOURCE_DIR}/cmvr-es/manager/device_manager - ) - target_link_libraries(grpc_system_service_test - PRIVATE - service - cmvr_es::proto - gtest - gtest_main - pthread - ) - add_test( - NAME grpc_system_service_test - COMMAND grpc_system_service_test - ) - set(_grpc_system_test_environment - "LD_LIBRARY_PATH=${CMVR_TEST_EXTERNAL_LIBRARY_PATH}" - ) - if(CMVR_TEST_SYSTEM_LIBSTDCXX) - list(APPEND _grpc_system_test_environment - "LD_PRELOAD=${CMVR_TEST_SYSTEM_LIBSTDCXX}") - endif() - set_tests_properties(grpc_system_service_test PROPERTIES - TIMEOUT 10 - ENVIRONMENT "${_grpc_system_test_environment}" - ) - - add_executable(grpc_error_logging_interceptor_test - server/tests/grpc_error_logging_interceptor_test.cpp - server/src/grpc_error_logging_interceptor.cpp - ) - target_include_directories(grpc_error_logging_interceptor_test - PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ) - target_link_libraries(grpc_error_logging_interceptor_test - PRIVATE - cmvr_es::logging - cmvr_es::proto - gtest - gtest_main - pthread - ) - add_test( - NAME grpc_error_logging_interceptor_test - COMMAND grpc_error_logging_interceptor_test - ) - set_tests_properties(grpc_error_logging_interceptor_test PROPERTIES - TIMEOUT 10 - ENVIRONMENT "${_grpc_system_test_environment}" - ) - - add_executable(grpc_security_test - server/tests/grpc_security_test.cpp - server/src/grpc_security.cpp - ) - target_include_directories(grpc_security_test - PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ) - target_link_libraries(grpc_security_test - PRIVATE - cmvr_es::proto - gtest - gtest_main - pthread - ) - add_test( - NAME grpc_security_test - COMMAND grpc_security_test - ) - set_tests_properties(grpc_security_test PROPERTIES - TIMEOUT 10 - ENVIRONMENT "${_grpc_system_test_environment}" - ) - - add_executable(grpc_command_transaction_test - server/tests/grpc_command_transaction_test.cpp - server/src/grpc_command_transaction.cpp - server/src/grpc_safety_proto.cpp - server/src/grpc_security.cpp - ) - target_include_directories(grpc_command_transaction_test - PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ) - target_link_libraries(grpc_command_transaction_test PRIVATE - cmvr_es::safety_manager - cmvr_es::proto - gtest - gtest_main - pthread - ) - add_test( - NAME grpc_command_transaction_test - COMMAND grpc_command_transaction_test - ) - set_tests_properties(grpc_command_transaction_test PROPERTIES - TIMEOUT 10 - ENVIRONMENT "${_grpc_system_test_environment}" - ) - - add_executable(grpc_arm_service_test - server/tests/grpc_arm_service_test.cpp - ) - target_include_directories(grpc_arm_service_test - PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ${CMAKE_SOURCE_DIR}/cmvr-es/manager/device_manager - ) - target_link_libraries(grpc_arm_service_test - PRIVATE - service - cmvr_es::proto - gtest - gtest_main - pthread - ) - add_test( - NAME grpc_arm_service_test - COMMAND grpc_arm_service_test - ) - set_tests_properties(grpc_arm_service_test PROPERTIES - TIMEOUT 10 - ENVIRONMENT "${_grpc_system_test_environment}" - ) - - add_executable(grpc_arm_teleop_service_test - server/tests/grpc_arm_teleop_service_test.cpp - ) - target_include_directories(grpc_arm_teleop_service_test - PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ) - target_link_libraries(grpc_arm_teleop_service_test - PRIVATE - service - cmvr_es::proto - gtest - gtest_main - pthread - ) - add_test( - NAME grpc_arm_teleop_service_test - COMMAND grpc_arm_teleop_service_test - ) - set(_grpc_arm_teleop_test_environment - "LD_LIBRARY_PATH=${CMVR_TEST_EXTERNAL_LIBRARY_PATH}" - ) - if(CMVR_TEST_SYSTEM_LIBSTDCXX) - list(APPEND _grpc_arm_teleop_test_environment - "LD_PRELOAD=${CMVR_TEST_SYSTEM_LIBSTDCXX}") - endif() - set_tests_properties(grpc_arm_teleop_service_test PROPERTIES - TIMEOUT 20 - ENVIRONMENT "${_grpc_arm_teleop_test_environment}" - ) - - add_executable(grpc_robot_arm_teleop_backend_test - server/tests/grpc_robot_arm_teleop_backend_test.cpp - ) - target_include_directories(grpc_robot_arm_teleop_backend_test - PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ) - target_link_libraries(grpc_robot_arm_teleop_backend_test - PRIVATE - service - cmvr_es::proto - gtest - gtest_main - pthread - ) - add_test( - NAME grpc_robot_arm_teleop_backend_test - COMMAND grpc_robot_arm_teleop_backend_test - ) - set_tests_properties(grpc_robot_arm_teleop_backend_test PROPERTIES - TIMEOUT 10 - ENVIRONMENT "${_grpc_arm_teleop_test_environment}" - ) - - add_executable(grpc_motor_service_test - server/tests/grpc_motor_service_test.cpp - ) - target_include_directories(grpc_motor_service_test - PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ${CMAKE_SOURCE_DIR}/cmvr-es/manager/device_manager - ) - target_link_libraries(grpc_motor_service_test - PRIVATE - service - gtest - gtest_main - pthread - ) - add_test( - NAME grpc_motor_service_test - COMMAND grpc_motor_service_test - ) - set(_grpc_motor_test_environment - "LD_LIBRARY_PATH=${CMVR_TEST_EXTERNAL_LIBRARY_PATH}" - ) - if(CMVR_TEST_SYSTEM_LIBSTDCXX) - list(APPEND _grpc_motor_test_environment - "LD_PRELOAD=${CMVR_TEST_SYSTEM_LIBSTDCXX}") - endif() - set_tests_properties(grpc_motor_service_test PROPERTIES - TIMEOUT 10 - ENVIRONMENT "${_grpc_motor_test_environment}" - ) - - add_executable(grpc_agv_service_test - server/tests/grpc_agv_service_test.cpp - ) - target_include_directories(grpc_agv_service_test - PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ${CMAKE_SOURCE_DIR}/cmvr-es/manager/device_manager - ) - target_link_libraries(grpc_agv_service_test - PRIVATE - service - gtest - gtest_main - pthread - ) - add_test( - NAME grpc_agv_service_test - COMMAND grpc_agv_service_test - ) - set(_grpc_agv_test_environment - "LD_LIBRARY_PATH=${CMVR_TEST_EXTERNAL_LIBRARY_PATH}" - ) - if(CMVR_TEST_SYSTEM_LIBSTDCXX) - list(APPEND _grpc_agv_test_environment - "LD_PRELOAD=${CMVR_TEST_SYSTEM_LIBSTDCXX}") - endif() - set_tests_properties(grpc_agv_service_test PROPERTIES - TIMEOUT 10 - ENVIRONMENT "${_grpc_agv_test_environment}" - ) - - add_executable(grpc_head_service_test - server/tests/grpc_head_service_test.cpp - ) - target_include_directories(grpc_head_service_test - PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ${CMAKE_SOURCE_DIR}/cmvr-es/manager/device_manager - ) - target_link_libraries(grpc_head_service_test - PRIVATE - service - cmvr_es::proto - gtest - gtest_main - pthread - ) - add_test( - NAME grpc_head_service_test - COMMAND grpc_head_service_test - ) - set_tests_properties(grpc_head_service_test PROPERTIES - TIMEOUT 15 - ENVIRONMENT "${_grpc_system_test_environment}" - ) - - add_executable(grpc_dexhand_service_test - server/tests/grpc_dexhand_service_test.cpp - ) - target_include_directories(grpc_dexhand_service_test - PRIVATE - ${CMAKE_SOURCE_DIR}/cmvr-es - ${CMAKE_SOURCE_DIR}/cmvr-es/manager/device_manager - ) - target_link_libraries(grpc_dexhand_service_test - PRIVATE - service - cmvr_es::proto - gtest - gtest_main - pthread - ) - add_test( - NAME grpc_dexhand_service_test - COMMAND grpc_dexhand_service_test - ) - set_tests_properties(grpc_dexhand_service_test PROPERTIES - TIMEOUT 15 - ENVIRONMENT "${_grpc_system_test_environment}" - ) - endif() # -------------------------------------------------------- diff --git a/cmvr-es/service/grpc/client/CMakeLists.txt b/cmvr-es/service/grpc/client/CMakeLists.txt index 8dd1b377..eac4e7e4 100644 --- a/cmvr-es/service/grpc/client/CMakeLists.txt +++ b/cmvr-es/service/grpc/client/CMakeLists.txt @@ -14,25 +14,3 @@ target_link_libraries(arm_teleop_client add_library(cmvr_es::arm_teleop_client ALIAS arm_teleop_client) install(TARGETS arm_teleop_client ARCHIVE DESTINATION lib) - -if(BUILD_TESTING) - add_executable(grpc_arm_teleop_client_test - tests/grpc_arm_teleop_client_test.cpp - ) - target_compile_features(grpc_arm_teleop_client_test PRIVATE cxx_std_17) - target_link_libraries(grpc_arm_teleop_client_test - PRIVATE - cmvr_es::arm_teleop_client - Threads::Threads - ) - add_test(NAME grpc_arm_teleop_client_test COMMAND grpc_arm_teleop_client_test) - set(_arm_teleop_client_test_environment - "LD_LIBRARY_PATH=${CMVR_TEST_EXTERNAL_LIBRARY_PATH}") - if(CMVR_TEST_SYSTEM_LIBSTDCXX) - list(APPEND _arm_teleop_client_test_environment - "LD_PRELOAD=${CMVR_TEST_SYSTEM_LIBSTDCXX}") - endif() - set_tests_properties(grpc_arm_teleop_client_test PROPERTIES - TIMEOUT 10 - ENVIRONMENT "${_arm_teleop_client_test_environment}") -endif() diff --git a/cmvr-es/service/grpc/client/tests/grpc_arm_teleop_client_test.cpp b/cmvr-es/service/grpc/client/tests/grpc_arm_teleop_client_test.cpp deleted file mode 100644 index 3e1caa7c..00000000 --- a/cmvr-es/service/grpc/client/tests/grpc_arm_teleop_client_test.cpp +++ /dev/null @@ -1,220 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "cmvr/api/arm_teleop_v1.grpc.pb.h" -#include "service/grpc/client/include/grpc_arm_teleop_client.h" - -namespace { - -using namespace std::chrono_literals; -namespace api = cmvr::api::armteleop::v1; - -class TestArmTeleopService final : public api::ArmTeleopService::Service { -public: - grpc::Status Teleoperate( - grpc::ServerContext*, - grpc::ServerReaderWriter* stream) override - { - api::ClientFrame frame; - if (!stream->Read(&frame) || !frame.has_open()) { - return grpc::Status( - grpc::StatusCode::INVALID_ARGUMENT, - "OpenSession must be first"); - } - - { - std::lock_guard lock(mutex_); - open_received_ = true; - } - condition_.notify_all(); - - api::ServerFrame opened; - opened.mutable_status()->set_session_id("client-test-session"); - opened.mutable_status()->set_phase(api::SESSION_PHASE_OPENED); - if (!stream->Write(opened)) { - return grpc::Status::OK; - } - - while (stream->Read(&frame)) { - if (frame.has_heartbeat()) { - heartbeat_received_.store(true); - condition_.notify_all(); - } - } - handler_finished_.store(true); - condition_.notify_all(); - return grpc::Status::OK; - } - - bool waitForOpen(const std::chrono::milliseconds timeout) - { - std::unique_lock lock(mutex_); - return condition_.wait_for(lock, timeout, [this] { return open_received_; }); - } - - bool waitForHeartbeat(const std::chrono::milliseconds timeout) - { - std::unique_lock lock(mutex_); - return condition_.wait_for( - lock, timeout, [this] { return heartbeat_received_.load(); }); - } - - bool waitForHandlerFinish(const std::chrono::milliseconds timeout) - { - std::unique_lock lock(mutex_); - return condition_.wait_for( - lock, timeout, [this] { return handler_finished_.load(); }); - } - -private: - std::mutex mutex_; - std::condition_variable condition_; - bool open_received_{false}; - std::atomic heartbeat_received_{false}; - std::atomic handler_finished_{false}; -}; - -int fail(const std::string& detail) -{ - std::cerr << "grpc_arm_teleop_client_test: " << detail << '\n'; - return 1; -} - -} // namespace - -int main() -{ - TestArmTeleopService service; - const std::string socket_path = - "/tmp/cmvr_arm_teleop_client_test_" + - std::to_string(static_cast(::getpid())) + ".sock"; - std::remove(socket_path.c_str()); - const std::string endpoint = "unix:" + socket_path; - - grpc::ServerBuilder builder; - builder.AddListeningPort( - endpoint, - grpc::InsecureServerCredentials()); - builder.RegisterService(&service); - std::unique_ptr server = builder.BuildAndStart(); - if (!server) { - return fail("failed to start in-process gRPC server"); - } - - auto channel = grpc::CreateChannel( - endpoint, - grpc::InsecureChannelCredentials()); - cmvr::teleop::GrpcArmTeleopClient client(channel); - - api::OpenSession open; - open.set_protocol_major(1); - open.set_protocol_minor(0); - open.set_client_instance_id("grpc-client-test"); - open.mutable_expected_robot()->set_robot_id("test-arm"); - open.set_watchdog_timeout_ms(100); - open.set_requested_lease_ms(500); - - std::mutex frame_mutex; - std::condition_variable frame_condition; - bool opened_received = false; - grpc::Status session_status; - std::thread session_thread([&] { - session_status = client.runSession( - open, - [&](const api::ServerFrame& frame) { - if (frame.has_status() && - frame.status().phase() == api::SESSION_PHASE_OPENED) { - { - std::lock_guard lock(frame_mutex); - opened_received = true; - } - frame_condition.notify_all(); - } - }); - }); - - if (!service.waitForOpen(2s)) { - client.tryCancel(); - session_thread.join(); - server->Shutdown(); - return fail("server did not receive OpenSession"); - } - { - std::unique_lock lock(frame_mutex); - if (!frame_condition.wait_for(lock, 2s, [&] { return opened_received; })) { - client.tryCancel(); - session_thread.join(); - server->Shutdown(); - return fail("client did not receive OPENED status"); - } - } - if (!client.isSessionActive()) { - client.tryCancel(); - session_thread.join(); - server->Shutdown(); - return fail("client did not expose an active session"); - } - const std::uint64_t generation = - client.activeSessionGeneration(); - if (generation == 0) { - client.tryCancel(); - session_thread.join(); - server->Shutdown(); - return fail("active stream did not expose a session generation"); - } - - api::ClientHeartbeat heartbeat; - heartbeat.set_sequence(1); - if (client.sendHeartbeat(heartbeat, generation + 1)) { - client.tryCancel(); - session_thread.join(); - server->Shutdown(); - return fail("stale session generation was allowed to write"); - } - if (!client.sendHeartbeat(heartbeat, generation) || - !service.waitForHeartbeat(2s)) { - client.tryCancel(); - session_thread.join(); - server->Shutdown(); - return fail("heartbeat did not traverse the active stream"); - } - - const auto cancel_begin = std::chrono::steady_clock::now(); - client.tryCancel(); - session_thread.join(); - const auto cancel_elapsed = std::chrono::steady_clock::now() - cancel_begin; - - if (cancel_elapsed > 2s) { - server->Shutdown(); - return fail("TryCancel did not unblock and join the session promptly"); - } - if (session_status.error_code() != grpc::StatusCode::CANCELLED) { - server->Shutdown(); - return fail( - "cancelled session returned unexpected status: " + - std::to_string(session_status.error_code())); - } - if (client.isSessionActive()) { - server->Shutdown(); - return fail("client retained an active stream after cancellation"); - } - if (!service.waitForHandlerFinish(2s)) { - server->Shutdown(); - return fail("server handler did not observe client cancellation"); - } - - server->Shutdown(); - std::remove(socket_path.c_str()); - std::cout << "grpc_arm_teleop_client_test: PASS\n"; - return 0; -} diff --git a/cmvr-es/service/grpc/server/tests/camera_operational_activity_registry_test.cpp b/cmvr-es/service/grpc/server/tests/camera_operational_activity_registry_test.cpp deleted file mode 100644 index 973fdd9e..00000000 --- a/cmvr-es/service/grpc/server/tests/camera_operational_activity_registry_test.cpp +++ /dev/null @@ -1,491 +0,0 @@ -#include "service/grpc/server/include/camera_operational_activity_registry.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "service/grpc/stop_all/include/stop_all_admission_gate.h" - -namespace cmvr::service { -namespace { - -class TestCamera final : public device::AbstractCamera { -public: - explicit TestCamera(std::string id) - { - id_ = std::move(id); - state_.is_initialized = true; - } - - std::string typeName() const override { return "TestCamera"; } - - void getState(device::CameraState& state) override - { - std::lock_guard lock(mutex_); - state = state_; - } - - bool start() override - { - ++lifecycle_start_calls_; - return true; - } - - bool stop() override - { - ++lifecycle_stop_calls_; - std::lock_guard lock(mutex_); - operational_active_ = false; - state_.is_opened = false; - return !fail_lifecycle_stop_; - } - - bool startOperationalActivity() override - { - ++operational_start_calls_; - { - std::unique_lock lock(mutex_); - start_entered_ = true; - condition_.notify_all(); - condition_.wait(lock, [this] { return !block_start_; }); - if (fail_operational_start_) { - return false; - } - operational_active_ = true; - state_.is_opened = true; - } - return true; - } - - bool stopOperationalActivity() override - { - ++operational_stop_calls_; - std::unique_lock lock(mutex_); - stop_entered_ = true; - condition_.notify_all(); - condition_.wait(lock, [this] { return !block_stop_; }); - if (fail_operational_stop_) { - return false; - } - operational_active_ = false; - state_.is_opened = false; - return true; - } - - void setFailOperationalStart(const bool fail) - { - fail_operational_start_ = fail; - } - - void setFailOperationalStop(const bool fail) - { - fail_operational_stop_ = fail; - } - - void blockStop() - { - std::lock_guard lock(mutex_); - block_stop_ = true; - stop_entered_ = false; - } - - void waitForStopEntered() - { - std::unique_lock lock(mutex_); - condition_.wait(lock, [this] { return stop_entered_; }); - } - - void releaseStop() - { - { - std::lock_guard lock(mutex_); - block_stop_ = false; - } - condition_.notify_all(); - } - - void blockStart() - { - std::lock_guard lock(mutex_); - block_start_ = true; - start_entered_ = false; - } - - void waitForStartEntered() - { - std::unique_lock lock(mutex_); - condition_.wait(lock, [this] { return start_entered_; }); - } - - void releaseStart() - { - { - std::lock_guard lock(mutex_); - block_start_ = false; - } - condition_.notify_all(); - } - - bool operationalActive() const - { - std::lock_guard lock(mutex_); - return operational_active_; - } - - int lifecycleStartCalls() const { return lifecycle_start_calls_; } - int lifecycleStopCalls() const { return lifecycle_stop_calls_; } - int operationalStartCalls() const { return operational_start_calls_; } - int operationalStopCalls() const { return operational_stop_calls_; } - -private: - mutable std::mutex mutex_; - std::condition_variable condition_; - bool operational_active_{false}; - bool fail_operational_start_{false}; - bool fail_operational_stop_{false}; - bool fail_lifecycle_stop_{false}; - bool block_start_{false}; - bool start_entered_{false}; - bool block_stop_{false}; - bool stop_entered_{false}; - std::atomic lifecycle_start_calls_{0}; - std::atomic lifecycle_stop_calls_{0}; - std::atomic operational_start_calls_{0}; - std::atomic operational_stop_calls_{0}; -}; - -class CameraOperationalActivityRegistryTest : public ::testing::Test { -protected: - void SetUp() override - { - globalStopAllAdmissionGate().clearForTesting(); - } - - void TearDown() override - { - globalStopAllAdmissionGate().clearForTesting(); - } -}; - -TEST_F(CameraOperationalActivityRegistryTest, - StopAllStopsTrackedActivityWithoutLifecycleStopAndCanRestart) -{ - CameraOperationalActivityRegistry registry; - auto camera = std::make_shared("camera"); - - EXPECT_EQ( - registry.start(camera->id(), camera), - CameraOperationalActivityRegistry::DispatchResult::Success); - EXPECT_TRUE(camera->operationalActive()); - EXPECT_EQ(registry.activeCameraCount(), 1U); - - auto ticket = globalStopAllAdmissionGate().beginStopAll(); - ASSERT_TRUE(ticket.valid()); - EXPECT_TRUE(registry.stopAllActivities()); - EXPECT_FALSE(camera->operationalActive()); - EXPECT_EQ(camera->lifecycleStopCalls(), 0); - EXPECT_EQ(camera->operationalStopCalls(), 1); - EXPECT_EQ(registry.activeCameraCount(), 0U); - ASSERT_TRUE(globalStopAllAdmissionGate().finishStopAll(ticket, true)); - - EXPECT_EQ( - registry.start(camera->id(), camera), - CameraOperationalActivityRegistry::DispatchResult::Success); - EXPECT_TRUE(camera->operationalActive()); - EXPECT_EQ(camera->operationalStartCalls(), 2); - EXPECT_EQ(camera->lifecycleStartCalls(), 0); -} - -TEST_F(CameraOperationalActivityRegistryTest, - FailedOperationalStopRemainsTrackedAndKeepsAdmissionClosed) -{ - CameraOperationalActivityRegistry registry; - auto camera = std::make_shared("camera"); - ASSERT_EQ( - registry.start(camera->id(), camera), - CameraOperationalActivityRegistry::DispatchResult::Success); - - camera->setFailOperationalStop(true); - auto ticket = globalStopAllAdmissionGate().beginStopAll(); - std::vector failures; - EXPECT_FALSE(registry.stopAllActivities(&failures)); - EXPECT_EQ(registry.activeCameraCount(), 1U); - ASSERT_EQ(failures.size(), 1U); - EXPECT_EQ( - registry.start(camera->id(), camera), - CameraOperationalActivityRegistry::DispatchResult::RejectedByStopAll); - EXPECT_FALSE(globalStopAllAdmissionGate().finishStopAll(ticket, false)); - - camera->setFailOperationalStop(false); - ticket = globalStopAllAdmissionGate().beginStopAll(); - EXPECT_TRUE(registry.stopAllActivities()); - EXPECT_TRUE(globalStopAllAdmissionGate().finishStopAll(ticket, true)); - EXPECT_EQ(registry.activeCameraCount(), 0U); -} - -TEST_F(CameraOperationalActivityRegistryTest, - StopAllWaitsForRacingStartThenStopsTheStartedActivity) -{ - CameraOperationalActivityRegistry registry; - auto camera = std::make_shared("camera"); - camera->blockStart(); - - CameraOperationalActivityRegistry::DispatchResult start_result = - CameraOperationalActivityRegistry::DispatchResult::DeviceFailure; - std::thread start_thread([&] { - start_result = registry.start(camera->id(), camera); - }); - camera->waitForStartEntered(); - - const auto ticket = globalStopAllAdmissionGate().beginStopAll(); - std::atomic stop_returned{false}; - bool stop_result = false; - std::thread stop_thread([&] { - stop_result = registry.stopAllActivities(); - stop_returned = true; - }); - - std::this_thread::yield(); - EXPECT_FALSE(stop_returned.load()); - camera->releaseStart(); - start_thread.join(); - stop_thread.join(); - - EXPECT_EQ( - start_result, - CameraOperationalActivityRegistry::DispatchResult::Success); - EXPECT_TRUE(stop_result); - EXPECT_FALSE(camera->operationalActive()); - EXPECT_EQ(camera->operationalStopCalls(), 1); - EXPECT_TRUE(globalStopAllAdmissionGate().finishStopAll(ticket, true)); -} - -TEST_F(CameraOperationalActivityRegistryTest, - TrackedIdsExposeAStartThatIsStillInsideDriverIo) -{ - CameraOperationalActivityRegistry registry; - auto camera = std::make_shared("camera.pending"); - camera->blockStart(); - - CameraOperationalActivityRegistry::DispatchResult start_result = - CameraOperationalActivityRegistry::DispatchResult::DeviceFailure; - std::thread start_thread([&] { - start_result = registry.start(camera->id(), camera); - }); - camera->waitForStartEntered(); - - const auto snapshot_started = std::chrono::steady_clock::now(); - EXPECT_EQ( - registry.trackedDeviceIds(), - (std::vector{"camera.pending"})); - EXPECT_LT( - std::chrono::steady_clock::now() - snapshot_started, - std::chrono::milliseconds(100)); - - camera->releaseStart(); - start_thread.join(); - EXPECT_EQ( - start_result, - CameraOperationalActivityRegistry::DispatchResult::Success); -} - -TEST_F(CameraOperationalActivityRegistryTest, - DefaultOperationalStopFailsClosed) -{ - class UnsupportedCamera final : public device::AbstractCamera { - public: - UnsupportedCamera() { id_ = "unsupported"; } - std::string typeName() const override { return "UnsupportedCamera"; } - void getState(device::CameraState& state) override { state = {}; } - }; - - CameraOperationalActivityRegistry registry; - auto camera = std::make_shared(); - ASSERT_EQ( - registry.start(camera->id(), camera), - CameraOperationalActivityRegistry::DispatchResult::Success); - - const auto ticket = globalStopAllAdmissionGate().beginStopAll(); - EXPECT_FALSE(registry.stopAllActivities()); - EXPECT_EQ(registry.activeCameraCount(), 1U); - EXPECT_FALSE(globalStopAllAdmissionGate().finishStopAll(ticket, false)); -} - -TEST_F(CameraOperationalActivityRegistryTest, - StopForDeviceIsSelectiveAndActiveIdsReflectFailures) -{ - CameraOperationalActivityRegistry registry; - auto first = std::make_shared("camera.first"); - auto second = std::make_shared("camera.second"); - ASSERT_EQ( - registry.start(first->id(), first), - CameraOperationalActivityRegistry::DispatchResult::Success); - ASSERT_EQ( - registry.start(second->id(), second), - CameraOperationalActivityRegistry::DispatchResult::Success); - EXPECT_EQ( - registry.activeDeviceIds(), - (std::vector{"camera.first", "camera.second"})); - EXPECT_EQ( - registry.trackedDeviceIds(), - (std::vector{"camera.first", "camera.second"})); - - const auto ticket = globalStopAllAdmissionGate().beginStopAll(); - first->setFailOperationalStop(true); - std::vector failures; - EXPECT_FALSE(registry.stopActivitiesForDevice(first->id(), &failures)); - EXPECT_EQ(failures.size(), 1U); - EXPECT_TRUE(first->operationalActive()); - EXPECT_TRUE(second->operationalActive()); - EXPECT_EQ(second->operationalStopCalls(), 0); - - first->setFailOperationalStop(false); - EXPECT_TRUE(registry.stopActivitiesForDevice(first->id())); - EXPECT_EQ( - registry.activeDeviceIds(), - (std::vector{"camera.second"})); - EXPECT_TRUE(registry.stopActivitiesForDevice("missing")); - EXPECT_TRUE(registry.stopAllActivities()); - EXPECT_TRUE(registry.activeDeviceIds().empty()); - EXPECT_TRUE(globalStopAllAdmissionGate().finishStopAll(ticket, true)); - EXPECT_EQ(first->lifecycleStopCalls(), 0); - EXPECT_EQ(second->lifecycleStopCalls(), 0); -} - -TEST_F(CameraOperationalActivityRegistryTest, - InventoryFallbackStopsOncePerStopAllRoundAndCanStopAgainLater) -{ - CameraOperationalActivityRegistry registry; - auto camera = std::make_shared("inventory-camera"); - ASSERT_TRUE(camera->startOperationalActivity()); - - auto ticket = globalStopAllAdmissionGate().beginStopAll(); - ASSERT_TRUE(ticket.valid()); - EXPECT_TRUE(registry.stopActivitiesForDevice(camera->id(), camera)); - EXPECT_TRUE(registry.stopActivitiesForDevice(camera->id(), camera)); - EXPECT_FALSE(camera->operationalActive()); - EXPECT_EQ(camera->operationalStopCalls(), 1); - EXPECT_EQ(camera->lifecycleStopCalls(), 0); - ASSERT_TRUE(globalStopAllAdmissionGate().finishStopAll(ticket, true)); - - ASSERT_TRUE(camera->startOperationalActivity()); - ticket = globalStopAllAdmissionGate().beginStopAll(); - ASSERT_TRUE(ticket.valid()); - EXPECT_TRUE(registry.stopActivitiesForDevice(camera->id(), camera)); - EXPECT_FALSE(camera->operationalActive()); - EXPECT_EQ(camera->operationalStopCalls(), 2); - EXPECT_EQ(camera->lifecycleStopCalls(), 0); - EXPECT_TRUE(globalStopAllAdmissionGate().finishStopAll(ticket, true)); -} - -TEST_F(CameraOperationalActivityRegistryTest, - TrackedCameraTakesPrecedenceOverInventoryFallback) -{ - CameraOperationalActivityRegistry registry; - auto tracked = std::make_shared("camera"); - auto fallback = std::make_shared("camera"); - ASSERT_EQ( - registry.start(tracked->id(), tracked), - CameraOperationalActivityRegistry::DispatchResult::Success); - ASSERT_TRUE(fallback->startOperationalActivity()); - - const auto ticket = globalStopAllAdmissionGate().beginStopAll(); - ASSERT_TRUE(ticket.valid()); - EXPECT_TRUE(registry.stopActivitiesForDevice( - tracked->id(), fallback)); - EXPECT_FALSE(tracked->operationalActive()); - EXPECT_EQ(tracked->operationalStopCalls(), 1); - EXPECT_TRUE(fallback->operationalActive()); - EXPECT_EQ(fallback->operationalStopCalls(), 0); - EXPECT_EQ(tracked->lifecycleStopCalls(), 0); - EXPECT_EQ(fallback->lifecycleStopCalls(), 0); - EXPECT_TRUE(globalStopAllAdmissionGate().finishStopAll(ticket, true)); -} - -TEST_F(CameraOperationalActivityRegistryTest, - ActiveDeviceIdCannotBeReboundToAnotherCameraInstance) -{ - CameraOperationalActivityRegistry registry; - auto original = std::make_shared("camera"); - auto replacement = std::make_shared("camera"); - ASSERT_EQ( - registry.start(original->id(), original), - CameraOperationalActivityRegistry::DispatchResult::Success); - - CameraOperationalActivityRegistry::ActivityToken replacement_token; - EXPECT_EQ( - registry.start( - replacement->id(), replacement, &replacement_token), - CameraOperationalActivityRegistry::DispatchResult::DeviceFailure); - EXPECT_FALSE(replacement_token.valid()); - EXPECT_TRUE(original->operationalActive()); - EXPECT_FALSE(replacement->operationalActive()); - EXPECT_EQ(replacement->operationalStartCalls(), 0); - - const auto ticket = globalStopAllAdmissionGate().beginStopAll(); - ASSERT_TRUE(ticket.valid()); - EXPECT_TRUE(registry.stopAllActivities()); - EXPECT_FALSE(original->operationalActive()); - EXPECT_EQ(original->operationalStopCalls(), 1); - EXPECT_EQ(replacement->operationalStopCalls(), 0); - EXPECT_TRUE(globalStopAllAdmissionGate().finishStopAll(ticket, true)); -} - -TEST_F(CameraOperationalActivityRegistryTest, - DifferentDevicesStopConcurrentlyAndSameDeviceStopIsSerialized) -{ - CameraOperationalActivityRegistry registry; - auto first = std::make_shared("camera.first"); - auto second = std::make_shared("camera.second"); - ASSERT_EQ( - registry.start(first->id(), first), - CameraOperationalActivityRegistry::DispatchResult::Success); - ASSERT_EQ( - registry.start(second->id(), second), - CameraOperationalActivityRegistry::DispatchResult::Success); - first->blockStop(); - second->blockStop(); - - const auto ticket = globalStopAllAdmissionGate().beginStopAll(); - std::thread first_stop([&] { - EXPECT_TRUE(registry.stopActivitiesForDevice(first->id())); - }); - first->waitForStopEntered(); - const auto snapshot_started = std::chrono::steady_clock::now(); - EXPECT_EQ( - registry.trackedDeviceIds(), - (std::vector{"camera.first", "camera.second"})); - EXPECT_LT( - std::chrono::steady_clock::now() - snapshot_started, - std::chrono::milliseconds(100)); - std::thread second_stop([&] { - EXPECT_TRUE(registry.stopActivitiesForDevice(second->id())); - }); - second->waitForStopEntered(); - - std::atomic matching_stop_returned{false}; - std::thread matching_stop([&] { - EXPECT_TRUE(registry.stopActivitiesForDevice(first->id())); - matching_stop_returned = true; - }); - std::this_thread::yield(); - EXPECT_FALSE(matching_stop_returned.load()); - - second->releaseStop(); - second_stop.join(); - first->releaseStop(); - first_stop.join(); - matching_stop.join(); - EXPECT_TRUE(matching_stop_returned.load()); - EXPECT_TRUE(globalStopAllAdmissionGate().finishStopAll(ticket, true)); -} - -} // namespace -} // namespace cmvr::service diff --git a/cmvr-es/service/grpc/server/tests/camera_ptz_activity_registry_test.cpp b/cmvr-es/service/grpc/server/tests/camera_ptz_activity_registry_test.cpp deleted file mode 100644 index eec9ebe2..00000000 --- a/cmvr-es/service/grpc/server/tests/camera_ptz_activity_registry_test.cpp +++ /dev/null @@ -1,349 +0,0 @@ -#include "service/grpc/server/include/camera_ptz_activity_registry.h" - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "service/grpc/stop_all/include/stop_all_admission_gate.h" - -namespace cmvr::service { -namespace { - -class TestCamera final : public device::AbstractCamera { -public: - struct Call { - device::PtzCommand command; - bool stop; - int speed; - }; - - explicit TestCamera(std::string id) - { - id_ = std::move(id); - } - - std::string typeName() const override { return "TestCamera"; } - void getState(device::CameraState& state) override { state = {}; } - - bool controlPtz( - const device::PtzCommand command, - const bool stop, - const int speed) override - { - std::unique_lock lock(mutex_); - calls_.push_back({command, stop, speed}); - if (stop) { - stop_entered_ = true; - condition_.notify_all(); - condition_.wait(lock, [this] { return !block_stop_; }); - } - return !(stop && fail_stop_); - } - - bool stop() override - { - ++lifecycle_stop_calls_; - return true; - } - - std::vector calls() const - { - std::lock_guard lock(mutex_); - return calls_; - } - - void setFailStop(const bool fail) { fail_stop_ = fail; } - void blockStop() - { - std::lock_guard lock(mutex_); - block_stop_ = true; - stop_entered_ = false; - } - void waitForStopEntered() - { - std::unique_lock lock(mutex_); - condition_.wait(lock, [this] { return stop_entered_; }); - } - void releaseStop() - { - { - std::lock_guard lock(mutex_); - block_stop_ = false; - } - condition_.notify_all(); - } - int lifecycleStopCalls() const { return lifecycle_stop_calls_; } - -private: - mutable std::mutex mutex_; - std::condition_variable condition_; - std::vector calls_; - bool fail_stop_{false}; - bool block_stop_{false}; - bool stop_entered_{false}; - int lifecycle_stop_calls_{0}; -}; - -class CameraPtzActivityRegistryTest : public ::testing::Test { -protected: - void SetUp() override - { - globalStopAllAdmissionGate().clearForTesting(); - } - - void TearDown() override - { - globalStopAllAdmissionGate().clearForTesting(); - } -}; - -TEST_F(CameraPtzActivityRegistryTest, - StopAllMatchesEveryActiveStartAndNeverStopsLifecycle) -{ - CameraPtzActivityRegistry registry; - auto camera = std::make_shared("camera"); - - EXPECT_EQ( - registry.control( - camera->id(), camera, device::PtzCommand::PanLeft, false, 4), - CameraPtzActivityRegistry::DispatchResult::Success); - EXPECT_EQ( - registry.control( - camera->id(), camera, device::PtzCommand::ZoomIn, false, 7), - CameraPtzActivityRegistry::DispatchResult::Success); - - const auto ticket = globalStopAllAdmissionGate().beginStopAll(); - ASSERT_TRUE(ticket.valid()); - EXPECT_TRUE(registry.stopAllActivities()); - EXPECT_EQ(registry.activeCommandCount(), 0U); - EXPECT_EQ(camera->lifecycleStopCalls(), 0); - ASSERT_TRUE(globalStopAllAdmissionGate().finishStopAll(ticket, true)); - - const auto calls = camera->calls(); - ASSERT_EQ(calls.size(), 4U); - EXPECT_FALSE(calls[0].stop); - EXPECT_FALSE(calls[1].stop); - EXPECT_TRUE(calls[2].stop); - EXPECT_TRUE(calls[3].stop); -} - -TEST_F(CameraPtzActivityRegistryTest, - FailedStopRemainsTrackedForRetryAndAdmissionRecovers) -{ - CameraPtzActivityRegistry registry; - auto camera = std::make_shared("camera"); - ASSERT_EQ( - registry.control( - camera->id(), camera, device::PtzCommand::TiltUp, false, 3), - CameraPtzActivityRegistry::DispatchResult::Success); - - auto ticket = globalStopAllAdmissionGate().beginStopAll(); - camera->setFailStop(true); - std::vector failures; - EXPECT_FALSE(registry.stopAllActivities(&failures)); - EXPECT_EQ(registry.activeCommandCount(), 1U); - ASSERT_FALSE(failures.empty()); - EXPECT_TRUE(globalStopAllAdmissionGate().finishStopAll(ticket, false) == false); - - EXPECT_EQ( - registry.control( - camera->id(), camera, device::PtzCommand::ZoomOut, false, 5), - CameraPtzActivityRegistry::DispatchResult::RejectedByStopAll); - - ticket = globalStopAllAdmissionGate().beginStopAll(); - camera->setFailStop(false); - EXPECT_TRUE(registry.stopAllActivities()); - EXPECT_TRUE(globalStopAllAdmissionGate().finishStopAll(ticket, true)); - EXPECT_EQ( - registry.control( - camera->id(), camera, device::PtzCommand::ZoomOut, false, 5), - CameraPtzActivityRegistry::DispatchResult::Success); -} - -TEST_F(CameraPtzActivityRegistryTest, - ExplicitStopRemainsAvailableWhileStartAdmissionIsLatched) -{ - CameraPtzActivityRegistry registry; - auto camera = std::make_shared("camera"); - ASSERT_EQ( - registry.control( - camera->id(), camera, device::PtzCommand::PanLeft, false, 4), - CameraPtzActivityRegistry::DispatchResult::Success); - - const auto ticket = globalStopAllAdmissionGate().beginStopAll(); - ASSERT_TRUE(ticket.valid()); - EXPECT_FALSE(globalStopAllAdmissionGate().finishStopAll(ticket, false)); - EXPECT_EQ( - registry.control( - camera->id(), camera, device::PtzCommand::ZoomIn, false, 4), - CameraPtzActivityRegistry::DispatchResult::RejectedByStopAll); - EXPECT_EQ( - registry.control( - camera->id(), camera, device::PtzCommand::PanLeft, true, 4), - CameraPtzActivityRegistry::DispatchResult::Success); - EXPECT_EQ(registry.activeCommandCount(), 0U); - - const auto calls = camera->calls(); - ASSERT_EQ(calls.size(), 2U); - EXPECT_FALSE(calls.front().stop); - EXPECT_TRUE(calls.back().stop); -} - -TEST_F(CameraPtzActivityRegistryTest, - StopForDeviceIsSelectiveAndActiveIdsReflectFailures) -{ - CameraPtzActivityRegistry registry; - auto first = std::make_shared("camera.first"); - auto second = std::make_shared("camera.second"); - ASSERT_EQ( - registry.control( - first->id(), first, device::PtzCommand::PanLeft, false, 4), - CameraPtzActivityRegistry::DispatchResult::Success); - ASSERT_EQ( - registry.control( - second->id(), second, device::PtzCommand::ZoomIn, false, 7), - CameraPtzActivityRegistry::DispatchResult::Success); - EXPECT_EQ( - registry.activeDeviceIds(), - (std::vector{"camera.first", "camera.second"})); - EXPECT_EQ( - registry.trackedDeviceIds(), - (std::vector{"camera.first", "camera.second"})); - - const auto ticket = globalStopAllAdmissionGate().beginStopAll(); - first->setFailStop(true); - std::vector failures; - EXPECT_FALSE(registry.stopActivitiesForDevice(first->id(), &failures)); - EXPECT_EQ(registry.activeCommandCount(), 2U); - EXPECT_EQ(failures.size(), 1U); - EXPECT_EQ(second->calls().size(), 1U); - - first->setFailStop(false); - EXPECT_TRUE(registry.stopActivitiesForDevice(first->id())); - EXPECT_EQ(registry.activeCommandCount(), 1U); - EXPECT_EQ( - registry.activeDeviceIds(), - (std::vector{"camera.second"})); - EXPECT_TRUE(registry.stopActivitiesForDevice("missing")); - EXPECT_TRUE(registry.stopAllActivities()); - EXPECT_TRUE(registry.activeDeviceIds().empty()); - EXPECT_TRUE(globalStopAllAdmissionGate().finishStopAll(ticket, true)); - EXPECT_EQ(first->lifecycleStopCalls(), 0); - EXPECT_EQ(second->lifecycleStopCalls(), 0); -} - -TEST_F(CameraPtzActivityRegistryTest, - DifferentDevicesStopConcurrentlyButMatchingControlIsSerialized) -{ - CameraPtzActivityRegistry registry; - auto first = std::make_shared("camera.first"); - auto second = std::make_shared("camera.second"); - ASSERT_EQ( - registry.control( - first->id(), first, device::PtzCommand::PanLeft, false, 4), - CameraPtzActivityRegistry::DispatchResult::Success); - ASSERT_EQ( - registry.control( - second->id(), second, device::PtzCommand::ZoomIn, false, 7), - CameraPtzActivityRegistry::DispatchResult::Success); - first->blockStop(); - second->blockStop(); - - const auto ticket = globalStopAllAdmissionGate().beginStopAll(); - std::thread first_stop([&] { - EXPECT_TRUE(registry.stopActivitiesForDevice(first->id())); - }); - first->waitForStopEntered(); - const auto snapshot_started = std::chrono::steady_clock::now(); - EXPECT_EQ( - registry.trackedDeviceIds(), - (std::vector{"camera.first", "camera.second"})); - EXPECT_LT( - std::chrono::steady_clock::now() - snapshot_started, - std::chrono::milliseconds(100)); - std::thread second_stop([&] { - EXPECT_TRUE(registry.stopActivitiesForDevice(second->id())); - }); - second->waitForStopEntered(); - - std::atomic matching_stop_returned{false}; - std::thread matching_stop([&] { - EXPECT_TRUE(registry.stopActivitiesForDevice(first->id())); - matching_stop_returned = true; - }); - std::this_thread::yield(); - EXPECT_FALSE(matching_stop_returned.load()); - - second->releaseStop(); - second_stop.join(); - first->releaseStop(); - first_stop.join(); - matching_stop.join(); - EXPECT_TRUE(matching_stop_returned.load()); - EXPECT_TRUE(globalStopAllAdmissionGate().finishStopAll(ticket, true)); -} - -TEST_F(CameraPtzActivityRegistryTest, - DispatchFenceRunsInsidePerDeviceQueueBeforeHardwareMutation) -{ - CameraPtzActivityRegistry registry; - auto camera = std::make_shared("camera"); - std::mutex mutex; - std::condition_variable condition; - bool first_fence_entered = false; - bool release_first_fence = false; - std::atomic second_fence_entered{false}; - - std::thread first([&] { - EXPECT_EQ( - registry.control( - camera->id(), camera, device::PtzCommand::PanLeft, false, 4, - [&] { - std::unique_lock lock(mutex); - first_fence_entered = true; - condition.notify_all(); - condition.wait(lock, [&] { return release_first_fence; }); - return true; - }), - CameraPtzActivityRegistry::DispatchResult::Success); - }); - { - std::unique_lock lock(mutex); - condition.wait(lock, [&] { return first_fence_entered; }); - } - - std::thread second([&] { - EXPECT_EQ( - registry.control( - camera->id(), camera, device::PtzCommand::ZoomIn, false, 7, - [&] { - second_fence_entered = true; - return false; - }), - CameraPtzActivityRegistry::DispatchResult::RejectedByDispatchFence); - }); - std::this_thread::yield(); - EXPECT_FALSE(second_fence_entered.load()); - - { - std::lock_guard lock(mutex); - release_first_fence = true; - } - condition.notify_all(); - first.join(); - second.join(); - - EXPECT_TRUE(second_fence_entered.load()); - const auto calls = camera->calls(); - ASSERT_EQ(calls.size(), 1U); - EXPECT_EQ(calls.front().command, device::PtzCommand::PanLeft); -} - -} // namespace -} // namespace cmvr::service diff --git a/cmvr-es/service/grpc/server/tests/grpc_agv_service_test.cpp b/cmvr-es/service/grpc/server/tests/grpc_agv_service_test.cpp deleted file mode 100644 index a59e2e13..00000000 --- a/cmvr-es/service/grpc/server/tests/grpc_agv_service_test.cpp +++ /dev/null @@ -1,806 +0,0 @@ -#include "service/grpc/server/include/grpc_agv_service.h" - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "cmvr/config/device_manager_config/device_manager_config.pb.h" -#include "manager/control_authority_manager/include/control_authority_manager.h" -#include "manager/device_manager/include/device_manager.h" -#include "service/grpc/stop_all/include/stop_all_admission_gate.h" - -namespace cmvr::service { -namespace { - -constexpr char kNativeErrorMessage[] = - "SEER Robokit command failed: ret_code=41200, err_msg=speed_illegal"; -constexpr char kNativeNavigationErrorMessage[] = - "SEER Robokit command failed: ret_code=43051, err_msg=planner_rejected_pose"; - -class FakeAgv final : public device::AbstractAGV { -public: - FakeAgv() - { - id_ = "test-agv"; - } - - std::string typeName() const override { return "FakeAgv"; } - - device::AgvResult emergencyStop() override - { - ++emergency_stop_calls_; - emergency_stop_barrier_observed_ = normalLeaseIsBlocked_( - "test-probe:emergencyStop"); - return device::AgvResult::success(); - } - - device::AgvResult navigateToPose( - const math::Pose2d& pose, - const device::AgvMotionOptions& options, - const device::AgvAdapterParams&) override - { - ++navigate_pose_calls_; - pose_cancellation_bound_ = - static_cast(options.cancellation_requested); - pose_cancellation_requested_during_call_ = - pose_cancellation_bound_ && options.cancellation_requested(); - if (pose_cancellation_requested_during_call_) { - return device::AgvResult::failure( - device::AgvErrorCode::TaskCanceled, - "navigation canceled before fake device dispatch"); - } - pose_ = pose; - pose_options_ = options; - pose_options_.cancellation_requested = {}; - return pose_result_; - } - - device::AgvResult navigateToStation( - const std::string& station_id, - const device::AgvMotionOptions& options, - const device::AgvAdapterParams& adapter_params) override - { - station_id_ = station_id; - station_options_ = options; - station_adapter_params_ = adapter_params; - station_cancellation_bound_ = - static_cast(options.cancellation_requested); - station_cancellation_requested_during_call_ = - station_cancellation_bound_ && options.cancellation_requested(); - station_options_.cancellation_requested = {}; - return device::AgvResult::success(); - } - - device::AgvResult followPath( - const std::vector& path, - const device::AgvMotionOptions& options) override - { - path_ = path; - path_options_ = options; - path_cancellation_bound_ = - static_cast(options.cancellation_requested); - path_cancellation_requested_during_call_ = - path_cancellation_bound_ && options.cancellation_requested(); - path_options_.cancellation_requested = {}; - return device::AgvResult::success(); - } - - device::AgvResult setVelocity(const device::AgvVelocity&) override - { - ++set_velocity_calls_; - return device::AgvResult::failure( - device::AgvErrorCode::CommandFailed, - kNativeErrorMessage); - } - - device::AgvResult cancelNavigation() override - { - ++cancel_navigation_calls_; - cancel_navigation_barrier_observed_ = normalLeaseIsBlocked_( - "test-probe:cancelNavigation"); - return device::AgvResult::success(); - } - - device::AgvResult stopVelocityControl() override - { - ++stop_velocity_calls_; - stop_velocity_barrier_observed_ = normalLeaseIsBlocked_( - "test-probe:stopVelocityControl"); - return device::AgvResult::success(); - } - - device::AgvResult confirmMotionStopped() override - { - ++confirm_stopped_calls_; - confirm_stopped_barrier_observed_ = normalLeaseIsBlocked_( - "test-probe:confirmMotionStopped"); - return confirm_stopped_result_; - } - - bool normalLeaseIsBlocked_(const std::string& owner) - { - auto& authority = control::ControlAuthorityManager::instance(); - const auto probe = authority.tryAcquire( - id_, owner, std::chrono::hours(1)); - if (probe.acquired) { - authority.release(probe.token); - } - return !probe.acquired; - } - - math::Pose2d pose_{}; - device::AgvMotionOptions pose_options_; - device::AgvResult pose_result_{device::AgvResult::success()}; - std::string station_id_; - device::AgvMotionOptions station_options_; - device::AgvAdapterParams station_adapter_params_; - std::vector path_; - device::AgvMotionOptions path_options_; - bool pose_cancellation_bound_{false}; - bool pose_cancellation_requested_during_call_{false}; - bool station_cancellation_bound_{false}; - bool station_cancellation_requested_during_call_{false}; - bool path_cancellation_bound_{false}; - bool path_cancellation_requested_during_call_{false}; - int emergency_stop_calls_{0}; - int cancel_navigation_calls_{0}; - int stop_velocity_calls_{0}; - int confirm_stopped_calls_{0}; - int set_velocity_calls_{0}; - int navigate_pose_calls_{0}; - bool emergency_stop_barrier_observed_{false}; - bool cancel_navigation_barrier_observed_{false}; - bool stop_velocity_barrier_observed_{false}; - bool confirm_stopped_barrier_observed_{false}; - device::AgvResult confirm_stopped_result_{ - device::AgvResult::success()}; -}; - -class LegacyFollowPathAgv final : public device::AbstractAGV { -public: - std::string typeName() const override { return "LegacyFollowPathAgv"; } - - device::AgvResult followPath( - const std::vector& path) override - { - path_ = path; - return device::AgvResult::success(); - } - - std::vector path_; -}; - -class GrpcAgvServiceTest : public ::testing::Test { -protected: - void SetUp() override - { - control::ControlAuthorityManager::instance().clear(); - globalStopAllAdmissionGate().clearForTesting(); - config::DeviceManagerConfig config; - auto& manager = device::DeviceManager::getInstance(config); - agv_ = std::make_shared(); - manager.registerDevice(agv_); - service_ = std::make_unique(); - } - - void TearDown() override - { - service_.reset(); - agv_.reset(); - device::DeviceManager::destroyInstance(); - control::ControlAuthorityManager::instance().clear(); - globalStopAllAdmissionGate().clearForTesting(); - } - - std::shared_ptr agv_; - std::unique_ptr service_; -}; - -void setMotionOptions(msgs::AgvMotionOptions* options) -{ - options->set_max_speed(0.4); - options->set_max_angular_speed(0.5); - options->set_max_acceleration(0.6); - options->set_max_angular_acceleration(0.7); - options->set_reach_distance(0.08); - options->set_reach_angle(0.09); - options->set_wait_timeout_ms(1234); - options->set_poll_interval_ms(55); -} - -void expectMotionOptions(const device::AgvMotionOptions& options) -{ - EXPECT_DOUBLE_EQ(options.max_speed, 0.4); - EXPECT_DOUBLE_EQ(options.max_angular_speed, 0.5); - EXPECT_DOUBLE_EQ(options.max_acceleration, 0.6); - EXPECT_DOUBLE_EQ(options.max_angular_acceleration, 0.7); - EXPECT_DOUBLE_EQ(options.reach_distance, 0.08); - EXPECT_DOUBLE_EQ(options.reach_angle, 0.09); - EXPECT_EQ(options.wait_timeout_ms, 1234); - EXPECT_EQ(options.poll_interval_ms, 55); - EXPECT_FALSE(options.asynchronous); -} - -TEST_F(GrpcAgvServiceTest, NavigationRpcsForwardSpeedAndAccelerationOptions) -{ - api::AgvNavigateToPoseCommand_Request pose_request; - pose_request.mutable_header()->set_device_id("test-agv"); - pose_request.mutable_pose()->set_x(1.0); - pose_request.mutable_pose()->set_y(2.0); - pose_request.mutable_pose()->set_theta(0.5); - setMotionOptions(pose_request.mutable_options()); - api::AgvNavigateToPoseCommand_Feedback pose_response; - grpc::ServerContext pose_context; - - const auto pose_status = service_->navigateToPose( - &pose_context, - &pose_request, - &pose_response); - - ASSERT_TRUE(pose_status.ok()) << pose_status.error_message(); - EXPECT_TRUE(pose_response.header().success()); - EXPECT_DOUBLE_EQ(agv_->pose_.x, 1.0); - EXPECT_DOUBLE_EQ(agv_->pose_.y, 2.0); - EXPECT_DOUBLE_EQ(agv_->pose_.theta, 0.5); - expectMotionOptions(agv_->pose_options_); - EXPECT_TRUE(agv_->pose_cancellation_bound_); - EXPECT_FALSE(agv_->pose_cancellation_requested_during_call_); - - api::AgvNavigateToStationCommand_Request station_request; - station_request.mutable_header()->set_device_id("test-agv"); - station_request.set_station_id("station-1"); - setMotionOptions(station_request.mutable_options()); - api::AgvNavigateToStationCommand_Feedback station_response; - grpc::ServerContext station_context; - - const auto station_status = service_->navigateToStation( - &station_context, - &station_request, - &station_response); - - ASSERT_TRUE(station_status.ok()) << station_status.error_message(); - EXPECT_TRUE(station_response.header().success()); - EXPECT_EQ(agv_->station_id_, "station-1"); - expectMotionOptions(agv_->station_options_); - EXPECT_TRUE(agv_->station_cancellation_bound_); - EXPECT_FALSE(agv_->station_cancellation_requested_during_call_); - - api::AgvFollowPathCommand_Request path_request; - path_request.mutable_header()->set_device_id("test-agv"); - auto* segment = path_request.add_path(); - segment->set_source_station("station-1"); - segment->set_target_station("station-2"); - setMotionOptions(path_request.mutable_options()); - api::AgvFollowPathCommand_Feedback path_response; - grpc::ServerContext path_context; - - const auto path_status = service_->followPath( - &path_context, - &path_request, - &path_response); - - ASSERT_TRUE(path_status.ok()) << path_status.error_message(); - EXPECT_TRUE(path_response.header().success()); - ASSERT_EQ(agv_->path_.size(), 1U); - EXPECT_EQ(agv_->path_[0].source_station, "station-1"); - EXPECT_EQ(agv_->path_[0].target_station, "station-2"); - expectMotionOptions(agv_->path_options_); - EXPECT_TRUE(agv_->path_cancellation_bound_); - EXPECT_FALSE(agv_->path_cancellation_requested_during_call_); -} - -TEST_F(GrpcAgvServiceTest, NativeControllerCodeIsReturnedInGrpcMessage) -{ - api::AgvSetVelocityCommand_Request request; - request.mutable_header()->set_device_id("test-agv"); - request.mutable_velocity()->set_vx(0.1); - api::AgvSetVelocityCommand_Feedback response; - grpc::ServerContext context; - - const auto status = service_->setVelocity( - &context, - &request, - &response); - - EXPECT_EQ(status.error_code(), grpc::StatusCode::INTERNAL); - EXPECT_EQ(status.error_message(), kNativeErrorMessage); - EXPECT_FALSE(response.header().success()); - EXPECT_EQ(response.header().error_message(), kNativeErrorMessage); -} - -TEST_F(GrpcAgvServiceTest, NativeNavigationCodeIsReturnedInGrpcMessage) -{ - agv_->pose_result_ = device::AgvResult::failure( - device::AgvErrorCode::CommandFailed, - kNativeNavigationErrorMessage); - api::AgvNavigateToPoseCommand_Request request; - request.mutable_header()->set_device_id("test-agv"); - request.mutable_pose()->set_x(1.0); - request.mutable_pose()->set_y(2.0); - api::AgvNavigateToPoseCommand_Feedback response; - grpc::ServerContext context; - - const auto status = service_->navigateToPose( - &context, - &request, - &response); - - EXPECT_EQ(status.error_code(), grpc::StatusCode::INTERNAL); - EXPECT_EQ(status.error_message(), kNativeNavigationErrorMessage); - EXPECT_FALSE(response.header().success()); - EXPECT_EQ( - response.header().error_message(), - kNativeNavigationErrorMessage); - EXPECT_FALSE(agv_->pose_options_.asynchronous); - EXPECT_EQ(agv_->pose_options_.wait_timeout_ms, 0); - EXPECT_EQ(agv_->pose_options_.poll_interval_ms, 0); - EXPECT_TRUE(agv_->pose_cancellation_bound_); - EXPECT_FALSE(agv_->pose_cancellation_requested_during_call_); -} - -TEST_F(GrpcAgvServiceTest, ExplicitAsynchronousNavigationIsForwarded) -{ - api::AgvNavigateToStationCommand_Request request; - request.mutable_header()->set_device_id("test-agv"); - request.set_station_id("station-async"); - request.mutable_options()->set_asynchronous(true); - api::AgvNavigateToStationCommand_Feedback response; - grpc::ServerContext context; - - const auto status = service_->navigateToStation( - &context, - &request, - &response); - - ASSERT_TRUE(status.ok()) << status.error_message(); - EXPECT_TRUE(agv_->station_options_.asynchronous); - EXPECT_TRUE(agv_->station_cancellation_bound_); - EXPECT_FALSE(agv_->station_cancellation_requested_during_call_); -} - -TEST_F(GrpcAgvServiceTest, ActionLeaseBlocksOrdinaryMutatingRpcs) -{ - auto& authority = control::ControlAuthorityManager::instance(); - const auto action_lease = authority.tryAcquire( - "test-agv", - "action-sequence:test-action", - std::chrono::hours(1)); - ASSERT_TRUE(action_lease.acquired) << action_lease.detail; - - api::AgvNavigateToPoseCommand_Request navigation_request; - navigation_request.mutable_header()->set_device_id("test-agv"); - api::AgvNavigateToPoseCommand_Feedback navigation_response; - grpc::ServerContext navigation_context; - const auto navigation_status = service_->navigateToPose( - &navigation_context, - &navigation_request, - &navigation_response); - EXPECT_EQ( - navigation_status.error_code(), - grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_FALSE(navigation_response.header().success()); - - api::CommandHeader_Request clear_fault_request; - clear_fault_request.set_device_id("test-agv"); - api::CommandHeader_Feedback clear_fault_response; - grpc::ServerContext clear_fault_context; - const auto clear_fault_status = service_->clearFault( - &clear_fault_context, - &clear_fault_request, - &clear_fault_response); - EXPECT_EQ( - clear_fault_status.error_code(), - grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_FALSE(clear_fault_response.success()); - - api::AgvMapCommand_Request switch_map_request; - switch_map_request.mutable_header()->set_device_id("test-agv"); - switch_map_request.set_map_name("map-1"); - api::AgvMapCommand_Feedback switch_map_response; - grpc::ServerContext switch_map_context; - const auto switch_map_status = service_->switchMap( - &switch_map_context, - &switch_map_request, - &switch_map_response); - EXPECT_EQ( - switch_map_status.error_code(), - grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_FALSE(switch_map_response.header().success()); - - authority.release(action_lease.token); -} - -TEST_F(GrpcAgvServiceTest, NavigationCancellationIncludesControlLease) -{ - auto& authority = control::ControlAuthorityManager::instance(); - const auto barrier = authority.preemptAcquire( - "test-agv", "stop-all-test", std::chrono::hours(1)); - ASSERT_TRUE(barrier.acquired) << barrier.detail; - - api::AgvNavigateToPoseCommand_Request request; - request.mutable_header()->set_device_id("test-agv"); - api::AgvNavigateToPoseCommand_Feedback response; - grpc::ServerContext context; - const auto status = service_->navigateToPose( - &context, &request, &response); - - EXPECT_EQ( - status.error_code(), - grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_EQ(agv_->navigate_pose_calls_, 0); - authority.release(barrier.token); -} - -TEST_F(GrpcAgvServiceTest, SetVelocityDispatchRunsUnderControlFence) -{ - api::AgvSetVelocityCommand_Request request; - request.mutable_header()->set_device_id("test-agv"); - request.mutable_velocity()->set_vx(0.1); - api::AgvSetVelocityCommand_Feedback response; - grpc::ServerContext context; - - const auto status = service_->setVelocity( - &context, &request, &response); - - EXPECT_EQ(status.error_code(), grpc::StatusCode::INTERNAL); - EXPECT_EQ(agv_->set_velocity_calls_, 1); -} - -TEST_F(GrpcAgvServiceTest, - StopAllGateRejectsMutatingCommandsButAllowsReadsAndStops) -{ - auto& admission = globalStopAllAdmissionGate(); - const auto ticket = admission.beginStopAll(); - ASSERT_TRUE(ticket.valid()); - - api::AgvNavigateToPoseCommand_Request navigation_request; - navigation_request.mutable_header()->set_device_id("test-agv"); - api::AgvNavigateToPoseCommand_Feedback navigation_response; - grpc::ServerContext navigation_context; - const auto navigation_status = service_->navigateToPose( - &navigation_context, &navigation_request, &navigation_response); - - api::AgvSetVelocityCommand_Request velocity_request; - velocity_request.mutable_header()->set_device_id("test-agv"); - velocity_request.mutable_velocity()->set_vx(0.1); - api::AgvSetVelocityCommand_Feedback velocity_response; - grpc::ServerContext velocity_context; - const auto velocity_status = service_->setVelocity( - &velocity_context, &velocity_request, &velocity_response); - - api::AgvRuntimeStateCommand_Request state_request; - state_request.mutable_header()->set_device_id("test-agv"); - api::AgvRuntimeStateCommand_Feedback state_response; - grpc::ServerContext state_context; - const auto state_status = service_->getRuntimeState( - &state_context, &state_request, &state_response); - - api::CommandHeader_Request stop_request; - stop_request.set_device_id("test-agv"); - api::CommandHeader_Feedback stop_response; - grpc::ServerContext stop_context; - const auto stop_status = service_->cancelNavigation( - &stop_context, &stop_request, &stop_response); - - EXPECT_EQ( - navigation_status.error_code(), - grpc::StatusCode::UNAVAILABLE); - EXPECT_FALSE(navigation_response.header().success()); - EXPECT_EQ(agv_->navigate_pose_calls_, 0); - EXPECT_EQ( - velocity_status.error_code(), - grpc::StatusCode::UNAVAILABLE); - EXPECT_FALSE(velocity_response.header().success()); - EXPECT_EQ(agv_->set_velocity_calls_, 0); - - EXPECT_TRUE(state_status.ok()) << state_status.error_message(); - EXPECT_TRUE(state_response.header().success()); - EXPECT_TRUE(stop_status.ok()) << stop_status.error_message(); - EXPECT_TRUE(stop_response.success()) - << stop_response.error_message(); - EXPECT_EQ(agv_->cancel_navigation_calls_, 2); - - EXPECT_TRUE(admission.finishStopAll(ticket, true)); - const auto resumed_status = service_->navigateToPose( - &navigation_context, &navigation_request, &navigation_response); - EXPECT_TRUE(resumed_status.ok()) << resumed_status.error_message(); - EXPECT_TRUE(navigation_response.header().success()); - EXPECT_EQ(agv_->navigate_pose_calls_, 1); -} - -TEST_F(GrpcAgvServiceTest, QueriesBypassAndSafetyStopsPreemptActionLease) -{ - auto& authority = control::ControlAuthorityManager::instance(); - const auto action_lease = authority.tryAcquire( - "test-agv", - "action-sequence:test-action", - std::chrono::hours(1)); - ASSERT_TRUE(action_lease.acquired) << action_lease.detail; - - api::AgvRuntimeStateCommand_Request state_request; - state_request.mutable_header()->set_device_id("test-agv"); - api::AgvRuntimeStateCommand_Feedback state_response; - grpc::ServerContext state_context; - const auto state_status = service_->getRuntimeState( - &state_context, - &state_request, - &state_response); - EXPECT_TRUE(state_status.ok()) << state_status.error_message(); - EXPECT_TRUE(state_response.header().success()); - EXPECT_TRUE(authority.validate(action_lease.token)); - - api::CommandHeader_Request stop_request; - stop_request.set_device_id("test-agv"); - - api::CommandHeader_Feedback emergency_response; - grpc::ServerContext emergency_context; - auto emergency = std::async( - std::launch::async, - [this, &emergency_context, &stop_request, &emergency_response]() { - return service_->emergencyStop( - &emergency_context, - &stop_request, - &emergency_response); - }); - const auto emergency_deadline = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (authority.validate(action_lease.token) && - std::chrono::steady_clock::now() < emergency_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_FALSE(authority.validate(action_lease.token)); - authority.release(action_lease.token); - const auto emergency_status = emergency.get(); - EXPECT_TRUE(emergency_status.ok()) << emergency_status.error_message(); - EXPECT_TRUE(agv_->emergency_stop_barrier_observed_); - - const auto released_lease_after_emergency = authority.tryAcquire( - "test-agv", - "action-sequence:after-emergency-release", - std::chrono::hours(1)); - ASSERT_TRUE(released_lease_after_emergency.acquired) - << released_lease_after_emergency.detail; - - api::CommandHeader_Feedback cancel_response; - grpc::ServerContext cancel_context; - auto cancel = std::async( - std::launch::async, - [this, &cancel_context, &stop_request, &cancel_response]() { - return service_->cancelNavigation( - &cancel_context, - &stop_request, - &cancel_response); - }); - const auto cancel_deadline = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (authority.validate(released_lease_after_emergency.token) && - std::chrono::steady_clock::now() < cancel_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_FALSE(authority.validate( - released_lease_after_emergency.token)); - authority.release(released_lease_after_emergency.token); - const auto cancel_status = cancel.get(); - EXPECT_TRUE(cancel_status.ok()) << cancel_status.error_message(); - EXPECT_TRUE(agv_->cancel_navigation_barrier_observed_); - - const auto released_lease_after_cancel = authority.tryAcquire( - "test-agv", - "action-sequence:after-cancel-release", - std::chrono::hours(1)); - ASSERT_TRUE(released_lease_after_cancel.acquired) - << released_lease_after_cancel.detail; - - api::CommandHeader_Feedback velocity_response; - grpc::ServerContext velocity_context; - auto velocity = std::async( - std::launch::async, - [this, &velocity_context, &stop_request, &velocity_response]() { - return service_->stopVelocityControl( - &velocity_context, - &stop_request, - &velocity_response); - }); - const auto velocity_deadline = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (authority.validate(released_lease_after_cancel.token) && - std::chrono::steady_clock::now() < velocity_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - EXPECT_FALSE(authority.validate( - released_lease_after_cancel.token)); - authority.release(released_lease_after_cancel.token); - const auto velocity_status = velocity.get(); - EXPECT_TRUE(velocity_status.ok()) << velocity_status.error_message(); - EXPECT_TRUE(agv_->stop_velocity_barrier_observed_); - - const auto lease_after_stops = authority.tryAcquire( - "test-agv", - "action-sequence:after-stops", - std::chrono::hours(1)); - ASSERT_TRUE(lease_after_stops.acquired) - << lease_after_stops.detail; - - EXPECT_EQ(agv_->emergency_stop_calls_, 2); - EXPECT_EQ(agv_->cancel_navigation_calls_, 2); - EXPECT_EQ(agv_->stop_velocity_calls_, 2); - EXPECT_EQ(agv_->confirm_stopped_calls_, 3); - EXPECT_TRUE(agv_->confirm_stopped_barrier_observed_); - - authority.release(lease_after_stops.token); -} - -TEST_F(GrpcAgvServiceTest, - SafetyStopQuarantinesControlWhenStoppedStateIsUnconfirmed) -{ - agv_->confirm_stopped_result_ = device::AgvResult::failure( - device::AgvErrorCode::Timeout, - "two zero-velocity samples were not observed"); - - api::CommandHeader_Request request; - request.set_device_id("test-agv"); - api::CommandHeader_Feedback response; - grpc::ServerContext context; - const auto status = service_->cancelNavigation( - &context, &request, &response); - - EXPECT_EQ(status.error_code(), grpc::StatusCode::DEADLINE_EXCEEDED); - EXPECT_FALSE(response.success()); - EXPECT_NE( - response.error_message().find("confirmed stopped state"), - std::string::npos); - EXPECT_TRUE(agv_->cancel_navigation_barrier_observed_); - EXPECT_TRUE(agv_->confirm_stopped_barrier_observed_); - - const auto lease = - control::ControlAuthorityManager::instance().tryAcquire( - "test-agv", - "normal-control-after-unconfirmed-stop", - std::chrono::hours(1)); - EXPECT_FALSE(lease.acquired); - - auto& authority = control::ControlAuthorityManager::instance(); - const auto recovery = authority.preemptAcquire( - "test-agv", "confirmed-stop-recovery", std::chrono::hours(1)); - ASSERT_TRUE(recovery.acquired) << recovery.detail; - ASSERT_TRUE(authority.waitForPreemptedRelease( - recovery.token, std::chrono::milliseconds::zero())); - ASSERT_TRUE(authority.recoverRetiredSafetyHolders(recovery.token)); - authority.release(recovery.token); - const auto recovered = authority.tryAcquire( - "test-agv", "normal-control-after-recovery", std::chrono::hours(1)); - EXPECT_TRUE(recovered.acquired) << recovered.detail; - authority.release(recovered.token); -} - -TEST_F(GrpcAgvServiceTest, StopMappingFailureReleasesOrdinaryControlLease) -{ - api::CommandHeader_Request request; - request.set_device_id("test-agv"); - api::CommandHeader_Feedback response; - grpc::ServerContext context; - - const auto status = service_->stopMapping( - &context, &request, &response); - - EXPECT_EQ(status.error_code(), grpc::StatusCode::INTERNAL); - EXPECT_FALSE(response.success()); - auto& authority = control::ControlAuthorityManager::instance(); - const auto lease = authority.tryAcquire( - "test-agv", "normal-control-after-mapping-failure", - std::chrono::hours(1)); - EXPECT_TRUE(lease.acquired) << lease.detail; - authority.release(lease.token); -} - -TEST_F(GrpcAgvServiceTest, NavigateToStationForwardsPgvAdapterParams) -{ - api::AgvNavigateToStationCommand_Request request; - request.mutable_header()->set_device_id("test-agv"); - request.set_station_id("AP1"); - auto* values = request.mutable_adapter_params()->mutable_values(); - (*values)["use_pgv"] = "true"; - (*values)["pgv_adjust_dist"] = "0.3"; - (*values)["pgv_adjust_cx"] = "-0.3"; - (*values)["pgv_adjust_cy"] = "0"; - api::AgvNavigateToStationCommand_Feedback response; - grpc::ServerContext context; - - const auto status = service_->navigateToStation( - &context, - &request, - &response); - - ASSERT_TRUE(status.ok()) << status.error_message(); - EXPECT_TRUE(response.header().success()); - EXPECT_EQ(agv_->station_id_, "AP1"); - EXPECT_EQ( - agv_->station_adapter_params_.getString("use_pgv").value_or(""), - "true"); - EXPECT_EQ( - agv_->station_adapter_params_.getString("pgv_adjust_dist").value_or(""), - "0.3"); - EXPECT_EQ( - agv_->station_adapter_params_.getString("pgv_adjust_cx").value_or(""), - "-0.3"); - EXPECT_EQ( - agv_->station_adapter_params_.getString("pgv_adjust_cy").value_or(""), - "0"); -} - -TEST_F(GrpcAgvServiceTest, NavigationErrorsMapToGrpcCodesAndPreserveDetails) -{ - struct ErrorCase { - device::AgvErrorCode device_code; - grpc::StatusCode grpc_code; - }; - const ErrorCase cases[] = { - {device::AgvErrorCode::InvalidArgument, - grpc::StatusCode::INVALID_ARGUMENT}, - {device::AgvErrorCode::TaskCanceled, - grpc::StatusCode::CANCELLED}, - {device::AgvErrorCode::Timeout, - grpc::StatusCode::DEADLINE_EXCEEDED}, - }; - - for (const auto& test_case : cases) { - const std::string detail = - "SEER Robokit navigation detail for code=" - + std::to_string(static_cast(test_case.device_code)); - agv_->pose_result_ = device::AgvResult::failure( - test_case.device_code, - detail); - api::AgvNavigateToPoseCommand_Request request; - request.mutable_header()->set_device_id("test-agv"); - api::AgvNavigateToPoseCommand_Feedback response; - grpc::ServerContext context; - - const auto status = service_->navigateToPose( - &context, - &request, - &response); - - EXPECT_EQ(status.error_code(), test_case.grpc_code); - EXPECT_EQ(status.error_message(), detail); - EXPECT_FALSE(response.header().success()); - EXPECT_EQ(response.header().error_message(), detail); - } -} - -TEST(AbstractAgvCompatibilityTest, FollowPathOptionsDelegateToLegacyOverride) -{ - LegacyFollowPathAgv legacy; - device::AbstractAGV* abstract = &legacy; - const std::vector path = { - {"station-1", "station-2"}, - }; - device::AgvMotionOptions options; - - const auto result = abstract->followPath(path, options); - - ASSERT_TRUE(result.ok()) << result.message; - ASSERT_EQ(legacy.path_.size(), 1U); - EXPECT_EQ(legacy.path_[0].source_station, "station-1"); - EXPECT_EQ(legacy.path_[0].target_station, "station-2"); -} - -TEST(AbstractAgvCompatibilityTest, SynchronousActionSupportDefaultsToFalse) -{ - LegacyFollowPathAgv legacy; - - EXPECT_FALSE(legacy.supportsSynchronousAction( - device::AgvActionKind::NavigateToPose)); - EXPECT_FALSE(legacy.supportsSynchronousAction( - device::AgvActionKind::NavigateToStation)); - EXPECT_FALSE(legacy.supportsSynchronousAction( - device::AgvActionKind::FollowPath)); -} - -} // namespace -} // namespace cmvr::service diff --git a/cmvr-es/service/grpc/server/tests/grpc_arm_service_test.cpp b/cmvr-es/service/grpc/server/tests/grpc_arm_service_test.cpp deleted file mode 100644 index f9720de4..00000000 --- a/cmvr-es/service/grpc/server/tests/grpc_arm_service_test.cpp +++ /dev/null @@ -1,1276 +0,0 @@ -#include "service/grpc/server/include/grpc_arm_service.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "cmvr/config/device_manager_config/device_manager_config.pb.h" -#include "manager/control_authority_manager/include/control_authority_manager.h" -#include "manager/device_manager/include/device_manager.h" -#include "service/grpc/server/include/grpc_error_logging_interceptor.h" -#include "service/grpc/stop_all/include/stop_all_admission_gate.h" - -namespace cmvr::service { -namespace { - -class JsonCommandRobotArm final : public device::RobotArm { -public: - explicit JsonCommandRobotArm(std::string id) - { - id_ = std::move(id); - } - - std::string typeName() const override { return "JsonCommandRobotArm"; } - - bool executeJsonCommand(const std::string& request_json, - std::string& response_json) override - { - ++execute_calls; - last_request_json = request_json; - response_json = next_response_json; - return next_success; - } - - device::RobotModel getRobotModel() const override { return {}; } - std::size_t getDof() const override { return 0U; } - device::ArmState getRobotState() const override - { - device::ArmState state; - state.connected = true; - state.powered_on = powered_on_.load(); - state.robot_mode = state.powered_on - ? device::RobotMode::Running - : device::RobotMode::PowerOff; - return state; - } - device::JointGroupState getJointState() const override { return {}; } - device::CartesianPose getTcpPose( - device::FrameType = device::FrameType::Base) const override - { - return {}; - } - device::RobotMode getRobotMode() const override - { - return device::RobotMode::Unknown; - } - device::SafetyMode getSafetyMode() const override - { - return device::SafetyMode::Unknown; - } - device::ControlMode getControlMode() const override - { - return device::ControlMode::None; - } - - device::Result torqueOn() override { return torqueOn({}); } - device::Result torqueOn( - const std::function& cancellation_requested) override - { - std::unique_lock lock(motion_mutex_); - ++torque_on_calls_; - last_torque_on_had_cancellation_ = - static_cast(cancellation_requested); - if (!block_next_torque_on_) { - return device::Result::success(); - } - - block_next_torque_on_ = false; - blocking_torque_on_started_ = true; - torque_on_started_cv_.notify_all(); - while (!release_blocking_torque_on_) { - lock.unlock(); - const bool cancelled = - cancellation_requested && cancellation_requested(); - lock.lock(); - if (cancelled) { - last_torque_on_cancellation_requested_ = true; - if (fail_next_torque_on_cancellation_) { - fail_next_torque_on_cancellation_ = false; - return device::Result::failure( - device::ArmErrorCode::CommandFailed, - "simulated torqueOn safety termination failure"); - } - return device::Result::failure( - device::ArmErrorCode::CommandRejected, - "simulated torqueOn cancellation"); - } - torque_on_release_cv_.wait_for( - lock, std::chrono::milliseconds(5)); - } - return device::Result::success(); - } - device::Result torqueOff() override - { - std::lock_guard lock(motion_mutex_); - ++torque_off_calls_; - return device::Result::success(); - } - device::Result calibrateZeroQ(const std::string&) override - { - return device::Result::success(); - } - device::Result emergencyStop() override - { - return device::Result::success(); - } - device::Result protectiveStop() override - { - return device::Result::success(); - } - device::Result setSpeedScaling(double) override - { - return device::Result::success(); - } - double getSpeedScaling() const override { return 1.0; } - bool isProtectiveStopped() const override { return false; } - bool isEmergencyStopped() const override { return false; } - bool isFault() const override { return false; } - - device::Result moveJ(const device::JointPositionCommand&, - const device::MotionOptions& options) override - { - return enterMotion("moveJ", move_j_calls_, options); - } - device::Result speedJ(const device::JointVelocityCommand&, - double, - double) override - { - return device::Result::success(); - } - device::Result stopJ(double) override - { - return device::Result::success(); - } - device::Result moveL( - const device::CartesianPose&, - const device::MotionOptions& options, - device::FrameType = device::FrameType::Base) override - { - return enterMotion("moveL", move_l_calls_, options); - } - device::Result speedL( - const device::CartesianVelocity&, - double, - double, - device::FrameType = device::FrameType::Base) override - { - return device::Result::success(); - } - device::Result stopL(std::optional = std::nullopt) override - { - return device::Result::success(); - } - device::Result stopMotion() override - { - std::unique_lock lock(motion_mutex_); - ++stop_motion_calls_; - if (block_next_stop_) { - block_next_stop_ = false; - blocking_stop_started_ = true; - stop_started_cv_.notify_all(); - stop_release_cv_.wait( - lock, - [this]() { return release_blocking_stop_; }); - } - if (throw_next_stop_) { - throw_next_stop_ = false; - throw std::runtime_error("simulated stopMotion exception"); - } - if (fail_next_stop_) { - fail_next_stop_ = false; - return device::Result::failure( - device::ArmErrorCode::CommandFailed, - "simulated stopMotion failure"); - } - return device::Result::success(); - } - - void blockNextMotion() - { - std::lock_guard lock(motion_mutex_); - block_next_motion_ = true; - blocking_motion_started_ = false; - release_blocking_motion_ = false; - blocking_motion_name_.clear(); - } - - void blockNextTorqueOn() - { - std::lock_guard lock(motion_mutex_); - block_next_torque_on_ = true; - blocking_torque_on_started_ = false; - release_blocking_torque_on_ = false; - last_torque_on_cancellation_requested_ = false; - } - - void failNextTorqueOnCancellation() - { - std::lock_guard lock(motion_mutex_); - fail_next_torque_on_cancellation_ = true; - } - - bool waitForBlockingTorqueOn( - const std::chrono::milliseconds timeout) - { - std::unique_lock lock(motion_mutex_); - return torque_on_started_cv_.wait_for( - lock, - timeout, - [this]() { return blocking_torque_on_started_; }); - } - - void releaseBlockingTorqueOn() - { - { - std::lock_guard lock(motion_mutex_); - release_blocking_torque_on_ = true; - } - torque_on_release_cv_.notify_all(); - } - - bool waitForBlockingMotion( - const std::string& operation, - const std::chrono::milliseconds timeout) - { - std::unique_lock lock(motion_mutex_); - return motion_started_cv_.wait_for( - lock, - timeout, - [this, &operation]() { - return blocking_motion_started_ && - blocking_motion_name_ == operation; - }); - } - - void releaseBlockingMotion() - { - { - std::lock_guard lock(motion_mutex_); - release_blocking_motion_ = true; - } - motion_release_cv_.notify_all(); - } - - void blockNextStopMotion() - { - std::lock_guard lock(motion_mutex_); - block_next_stop_ = true; - blocking_stop_started_ = false; - release_blocking_stop_ = false; - } - - void failNextStopMotion() - { - std::lock_guard lock(motion_mutex_); - fail_next_stop_ = true; - } - - void throwNextStopMotion() - { - std::lock_guard lock(motion_mutex_); - throw_next_stop_ = true; - } - - bool waitForBlockingStop(const std::chrono::milliseconds timeout) - { - std::unique_lock lock(motion_mutex_); - return stop_started_cv_.wait_for( - lock, - timeout, - [this]() { return blocking_stop_started_; }); - } - - void releaseBlockingStop() - { - { - std::lock_guard lock(motion_mutex_); - release_blocking_stop_ = true; - } - stop_release_cv_.notify_all(); - } - - int moveJCalls() const - { - std::lock_guard lock(motion_mutex_); - return move_j_calls_; - } - - int moveLCalls() const - { - std::lock_guard lock(motion_mutex_); - return move_l_calls_; - } - - int stopMotionCalls() const - { - std::lock_guard lock(motion_mutex_); - return stop_motion_calls_; - } - - int torqueOffCalls() const - { - std::lock_guard lock(motion_mutex_); - return torque_off_calls_; - } - - int torqueOnCalls() const - { - std::lock_guard lock(motion_mutex_); - return torque_on_calls_; - } - - void setPoweredOn(const bool powered_on) - { - powered_on_.store(powered_on); - } - - bool lastTorqueOnHadCancellation() const - { - std::lock_guard lock(motion_mutex_); - return last_torque_on_had_cancellation_; - } - - bool lastTorqueOnCancellationRequested() const - { - std::lock_guard lock(motion_mutex_); - return last_torque_on_cancellation_requested_; - } - - bool lastMotionHadCancellation() const - { - std::lock_guard lock(motion_mutex_); - return last_motion_had_cancellation_; - } - - bool lastMotionCancellationRequested() const - { - std::lock_guard lock(motion_mutex_); - return last_motion_cancellation_requested_; - } - - device::Result startServoMode(const device::ServoOptions&) override - { - return device::Result::success(); - } - device::Result servoJ(const device::JointPositionCommand&) override - { - return device::Result::success(); - } - device::Result servoL( - const device::CartesianPose&, - device::FrameType = device::FrameType::Base) override - { - return device::Result::success(); - } - device::Result servoSpeedJ(const device::JointVelocityCommand&) override - { - return device::Result::success(); - } - device::Result servoSpeedL( - const device::CartesianVelocity&, - device::FrameType = device::FrameType::Base) override - { - return device::Result::success(); - } - device::Result stopServoMode() override - { - return device::Result::success(); - } - - device::Result connect(const std::string&, int) override - { - return device::Result::success(); - } - device::Result disconnect() override - { - return device::Result::success(); - } - bool isConnected() const override { return true; } - device::Result powerOn() override { return device::Result::success(); } - device::Result powerOff() override { return device::Result::success(); } - device::Result brakeRelease() override - { - return device::Result::success(); - } - device::Result shutdown() override - { - return device::Result::success(); - } - device::Result clearFault() override - { - return device::Result::success(); - } - device::Result unlockProtectiveStop() override - { - return device::Result::success(); - } - device::Result loadProgram(const std::string&) override - { - return device::Result::success(); - } - device::Result playProgram() override - { - return device::Result::success(); - } - device::Result pauseProgram() override - { - return device::Result::success(); - } - device::Result stopProgram() override - { - return device::Result::success(); - } - - std::vector ik(const std::string&, - const std::string&, - const device::CartesianPose&) override - { - return {}; - } - std::shared_ptr kinematicsSolver() const override - { - return nullptr; - } - device::CartesianPose fk(const std::string&, - const std::string&) override - { - return {}; - } - device::CartesianPose fk(bool = true) override { return {}; } - device::CartesianVelocity getSpeedLCommandTwistBase() const override - { - return {}; - } - bool busy() const override { return false; } - - int execute_calls{0}; - bool next_success{true}; - std::string next_response_json; - std::string last_request_json; - -private: - device::Result enterMotion( - const char* operation, - int& call_count, - const device::MotionOptions& options) - { - std::unique_lock lock(motion_mutex_); - ++call_count; - last_motion_had_cancellation_ = - static_cast(options.cancellation_requested); - last_motion_cancellation_requested_ = - last_motion_had_cancellation_ && - options.cancellation_requested(); - if (!block_next_motion_) { - return device::Result::success(); - } - - block_next_motion_ = false; - blocking_motion_started_ = true; - blocking_motion_name_ = operation; - motion_started_cv_.notify_all(); - motion_release_cv_.wait( - lock, - [this]() { return release_blocking_motion_; }); - return device::Result::success(); - } - - mutable std::mutex motion_mutex_; - std::condition_variable motion_started_cv_; - std::condition_variable motion_release_cv_; - std::condition_variable stop_started_cv_; - std::condition_variable stop_release_cv_; - std::condition_variable torque_on_started_cv_; - std::condition_variable torque_on_release_cv_; - bool block_next_motion_{false}; - bool blocking_motion_started_{false}; - bool release_blocking_motion_{false}; - bool block_next_stop_{false}; - bool blocking_stop_started_{false}; - bool release_blocking_stop_{false}; - bool fail_next_stop_{false}; - bool throw_next_stop_{false}; - bool block_next_torque_on_{false}; - bool blocking_torque_on_started_{false}; - bool release_blocking_torque_on_{false}; - bool fail_next_torque_on_cancellation_{false}; - std::string blocking_motion_name_; - int move_j_calls_{0}; - int move_l_calls_{0}; - int stop_motion_calls_{0}; - int torque_off_calls_{0}; - int torque_on_calls_{0}; - bool last_torque_on_had_cancellation_{false}; - bool last_torque_on_cancellation_requested_{false}; - bool last_motion_had_cancellation_{false}; - bool last_motion_cancellation_requested_{false}; - std::atomic powered_on_{false}; -}; - -class JsonCommandNonArmDevice final : public device::AbstractDevice { -public: - explicit JsonCommandNonArmDevice(std::string id) - : AbstractDevice(std::move(id)) - { - } - - std::string typeName() const override { return "JsonCommandNonArmDevice"; } - - bool executeJsonCommand(const std::string&, - std::string& response_json) override - { - ++execute_calls; - response_json = R"({"success":true})"; - return true; - } - - int execute_calls{0}; -}; - -class GrpcArmServiceTest : public ::testing::Test { -protected: - void SetUp() override - { - control::ControlAuthorityManager::instance().clear(); - globalStopAllAdmissionGate().clearForTesting(); - device::DeviceManager::destroyInstance(); - config::DeviceManagerConfig config; - auto& manager = device::DeviceManager::getInstance(config); - - left_arm_ = std::make_shared("left_arm"); - aubo_arm_ = std::make_shared("aubo_arm"); - non_arm_ = std::make_shared("camera"); - manager.registerDevice(left_arm_); - manager.registerDevice(aubo_arm_); - manager.registerDevice(non_arm_); - service_ = std::make_unique(); - } - - void TearDown() override - { - service_.reset(); - non_arm_.reset(); - aubo_arm_.reset(); - left_arm_.reset(); - device::DeviceManager::destroyInstance(); - control::ControlAuthorityManager::instance().clear(); - globalStopAllAdmissionGate().clearForTesting(); - } - - grpc::Status execute(const std::string& device_id, - const std::string& request_json, - api::JsonDeviceCommand_Feedback& response) - { - api::JsonDeviceCommand_Request request; - request.mutable_header()->set_device_id(device_id); - request.set_request_json(request_json); - grpc::ServerContext context; - return service_->ExecuteJsonCommand(&context, &request, &response); - } - - struct MoveOutcome { - grpc::Status status; - bool response_success{false}; - std::string response_error; - }; - - MoveOutcome moveJ(const std::string& device_id) - { - api::MoveJ_Request request; - request.mutable_header()->set_device_id(device_id); - request.mutable_target()->add_position(0.1); - api::MoveJ_Response response; - grpc::ServerContext context; - auto status = service_->moveJ(&context, &request, &response); - return { - std::move(status), - response.header().success(), - response.header().error_message()}; - } - - grpc::Status identifiedMoveJ( - const std::string& command_id, - const double position, - api::MoveJ_Response& response) - { - api::MoveJ_Request request; - auto* header = request.mutable_header(); - header->set_device_id("aubo_arm"); - header->set_command_id(command_id); - header->set_expected_service_instance_id( - device::DeviceManager::getInstance() - .safetyManager() - .serviceInstanceId()); - header->set_valid_for_ms(1000); - request.mutable_target()->add_position(position); - grpc::ServerContext context; - return service_->moveJ(&context, &request, &response); - } - - MoveOutcome moveL(const std::string& device_id) - { - api::MoveL_Request request; - request.mutable_header()->set_device_id(device_id); - request.mutable_target()->set_x(0.1); - api::MoveL_Response response; - grpc::ServerContext context; - auto status = service_->moveL(&context, &request, &response); - return { - std::move(status), - response.header().success(), - response.header().error_message()}; - } - - grpc::Status stopMotion( - const std::string& device_id, - api::CommandHeader_Feedback& response) - { - api::CommandHeader_Request request; - request.set_device_id(device_id); - grpc::ServerContext context; - return service_->stopMotion(&context, &request, &response); - } - - grpc::Status torqueOff( - const std::string& device_id, - api::CommandHeader_Feedback& response) - { - api::CommandHeader_Request request; - request.set_device_id(device_id); - grpc::ServerContext context; - return service_->torqueOff(&context, &request, &response); - } - - grpc::Status torqueOn( - const std::string& device_id, - api::CommandHeader_Feedback& response) - { - api::CommandHeader_Request request; - request.set_device_id(device_id); - grpc::ServerContext context; - return service_->torqueOn(&context, &request, &response); - } - - MoveOutcome torqueOn(const std::string& device_id) - { - api::CommandHeader_Feedback response; - auto status = torqueOn(device_id, response); - return { - std::move(status), - response.success(), - response.error_message()}; - } - - std::shared_ptr left_arm_; - std::shared_ptr aubo_arm_; - std::shared_ptr non_arm_; - std::unique_ptr service_; -}; - -TEST(GrpcArmServiceDescriptorTest, - ExecuteJsonCommandBelongsOnlyToArmService) -{ - const auto* pool = google::protobuf::DescriptorPool::generated_pool(); - const auto* arm_service = - pool->FindServiceByName("cmvr.api.ArmService"); - const auto* system_service = - pool->FindServiceByName("cmvr.api.SystemService"); - - ASSERT_NE(arm_service, nullptr); - ASSERT_NE(system_service, nullptr); - EXPECT_NE(arm_service->FindMethodByName("ExecuteJsonCommand"), nullptr); - EXPECT_EQ(system_service->FindMethodByName("ExecuteJsonCommand"), nullptr); -} - -TEST_F(GrpcArmServiceTest, RoutesByHeaderDeviceIdAndForwardsSuccessfulJson) -{ - const std::string request_json = - R"({"command":"cabinet_io","operation":"get_di","index":0})"; - const std::string response_json = - R"({"success":true,"operation":"get_di","index":0,"value":false})"; - aubo_arm_->next_response_json = response_json; - - api::JsonDeviceCommand_Feedback response; - const auto status = execute("aubo_arm", request_json, response); - - ASSERT_TRUE(status.ok()) << status.error_message(); - EXPECT_TRUE(response.header().success()); - EXPECT_TRUE(response.header().error_message().empty()); - EXPECT_TRUE(response.header().has_timestamp()); - EXPECT_GT(response.header().timestamp().seconds(), 0); - EXPECT_EQ(response.response_json(), response_json); - EXPECT_EQ(aubo_arm_->execute_calls, 1); - EXPECT_EQ(aubo_arm_->last_request_json, request_json); - EXPECT_EQ(left_arm_->execute_calls, 0); -} - -TEST_F(GrpcArmServiceTest, ForwardsDeviceJsonFailureWithLegacyGrpcOkSemantics) -{ - const std::string response_json = - R"({"success":false,"error_code":"not_connected"})"; - aubo_arm_->next_success = false; - aubo_arm_->next_response_json = response_json; - - api::JsonDeviceCommand_Feedback response; - const auto status = execute( - "aubo_arm", - R"({"command":"cabinet_io","operation":"get_do","index":0})", - response); - - ASSERT_TRUE(status.ok()) << status.error_message(); - EXPECT_FALSE(response.header().success()); - EXPECT_EQ(response.header().error_message(), response_json); - EXPECT_TRUE(response.header().has_timestamp()); - EXPECT_GT(response.header().timestamp().seconds(), 0); - EXPECT_EQ(response.response_json(), response_json); - EXPECT_EQ(aubo_arm_->execute_calls, 1); - EXPECT_EQ(left_arm_->execute_calls, 0); -} - -TEST_F(GrpcArmServiceTest, - MissingOrNonArmIdReturnsBusinessFailureWithoutBackendDispatch) -{ - api::JsonDeviceCommand_Feedback non_arm_response; - const auto non_arm_status = execute( - "camera", R"({"command":"cabinet_io"})", non_arm_response); - - ASSERT_TRUE(non_arm_status.ok()) << non_arm_status.error_message(); - EXPECT_FALSE(non_arm_response.header().success()); - EXPECT_EQ(non_arm_response.header().error_message(), - "Device not found: camera"); - EXPECT_TRUE(non_arm_response.header().has_timestamp()); - EXPECT_TRUE(non_arm_response.response_json().empty()); - EXPECT_EQ(non_arm_->execute_calls, 0); - EXPECT_EQ(aubo_arm_->execute_calls, 0); - EXPECT_EQ(left_arm_->execute_calls, 0); - - api::JsonDeviceCommand_Feedback missing_response; - const auto missing_status = execute( - "missing_arm", R"({"command":"cabinet_io"})", missing_response); - - ASSERT_TRUE(missing_status.ok()) << missing_status.error_message(); - EXPECT_FALSE(missing_response.header().success()); - EXPECT_EQ(missing_response.header().error_message(), - "Device not found: missing_arm"); - EXPECT_TRUE(missing_response.header().has_timestamp()); - EXPECT_TRUE(missing_response.response_json().empty()); - EXPECT_EQ(non_arm_->execute_calls, 0); - EXPECT_EQ(aubo_arm_->execute_calls, 0); - EXPECT_EQ(left_arm_->execute_calls, 0); -} - -TEST_F(GrpcArmServiceTest, - TorqueOnAlreadyEnabledArmReturnsOkWithoutDispatchingBackend) -{ - aubo_arm_->setPoweredOn(true); - - api::CommandHeader_Feedback response; - const auto status = torqueOn("aubo_arm", response); - - ASSERT_TRUE(status.ok()) << status.error_message(); - EXPECT_TRUE(response.success()); - EXPECT_EQ(response.error_message(), "RobotArm is already enabled"); - EXPECT_EQ( - response.reason_code(), - api::COMMAND_REASON_CODE_NONE); - EXPECT_EQ(aubo_arm_->torqueOnCalls(), 0); -} - -TEST_F(GrpcArmServiceTest, - StopMotionRevokesBlockedMoveJLeaseBeforeMoveLReturns) -{ - aubo_arm_->blockNextMotion(); - auto blocked_move = std::async( - std::launch::async, - [this]() { return moveJ("aubo_arm"); }); - - const bool move_started = aubo_arm_->waitForBlockingMotion( - "moveJ", std::chrono::seconds(2)); - - MoveOutcome conflict; - MoveOutcome during_stop; - api::CommandHeader_Feedback torque_off_response; - grpc::Status torque_off_status; - api::CommandHeader_Feedback stop_response; - grpc::Status stop_status; - MoveOutcome before_retired_handler_release; - bool stop_started = false; - std::future blocked_stop; - std::future torque_off; - if (move_started) { - conflict = moveL("aubo_arm"); - aubo_arm_->blockNextStopMotion(); - blocked_stop = std::async( - std::launch::async, - [this, &stop_response]() { - return stopMotion("aubo_arm", stop_response); - }); - stop_started = aubo_arm_->waitForBlockingStop( - std::chrono::seconds(2)); - if (stop_started) { - torque_off = std::async( - std::launch::async, - [this, &torque_off_response]() { - return torqueOff("aubo_arm", torque_off_response); - }); - during_stop = moveL("aubo_arm"); - } - aubo_arm_->releaseBlockingStop(); - before_retired_handler_release = moveL("aubo_arm"); - } - - // Keep the original RPC active until after the replacement MoveL has - // attempted to acquire control. This models a driver whose stopped motion - // takes time to unwind and guards the lease hand-off itself. - aubo_arm_->releaseBlockingMotion(); - const auto original_move = blocked_move.get(); - if (blocked_stop.valid()) { - stop_status = blocked_stop.get(); - } - if (torque_off.valid()) { - torque_off_status = torque_off.get(); - } - const auto resumed_move = moveL("aubo_arm"); - - ASSERT_TRUE(move_started); - ASSERT_TRUE(stop_started); - EXPECT_EQ(conflict.status.error_code(), - grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_EQ(conflict.response_error, conflict.status.error_message()); - EXPECT_EQ(during_stop.status.error_code(), - grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_EQ(during_stop.response_error, - during_stop.status.error_message()); - EXPECT_TRUE(torque_off_status.ok()) - << torque_off_status.error_message(); - EXPECT_TRUE(torque_off_response.success()) - << torque_off_response.error_message(); - EXPECT_TRUE(stop_status.ok()) << stop_status.error_message(); - EXPECT_TRUE(stop_response.success()) - << stop_response.error_message(); - EXPECT_EQ( - before_retired_handler_release.status.error_code(), - grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_TRUE(resumed_move.status.ok()) - << resumed_move.status.error_message(); - EXPECT_TRUE(resumed_move.response_success) - << resumed_move.response_error; - EXPECT_TRUE(original_move.status.ok()) - << original_move.status.error_message(); - EXPECT_TRUE(original_move.response_success) - << original_move.response_error; - EXPECT_EQ(aubo_arm_->moveJCalls(), 1); - EXPECT_EQ(aubo_arm_->moveLCalls(), 1); - EXPECT_EQ(aubo_arm_->stopMotionCalls(), 2); - EXPECT_EQ(aubo_arm_->torqueOffCalls(), 2); -} - -TEST_F(GrpcArmServiceTest, MoveBindsLeaseRevocationCancellation) -{ - const auto outcome = moveJ("aubo_arm"); - - ASSERT_TRUE(outcome.status.ok()) - << outcome.status.error_message(); - EXPECT_TRUE(outcome.response_success) << outcome.response_error; - EXPECT_TRUE(aubo_arm_->lastMotionHadCancellation()); - EXPECT_FALSE(aubo_arm_->lastMotionCancellationRequested()); -} - -TEST_F(GrpcArmServiceTest, - IdenticalCommandIdReplaysCachedResultWithoutRedispatch) -{ - api::MoveJ_Response first; - api::MoveJ_Response retry; - - const auto first_status = identifiedMoveJ( - "arm-movej-idempotency-1", 0.1, first); - const auto retry_status = identifiedMoveJ( - "arm-movej-idempotency-1", 0.1, retry); - - ASSERT_TRUE(first_status.ok()) << first_status.error_message(); - ASSERT_TRUE(retry_status.ok()) << retry_status.error_message(); - EXPECT_TRUE(first.header().success()); - EXPECT_TRUE(retry.header().success()); - EXPECT_EQ( - retry.header().execution_state(), - api::COMMAND_EXECUTION_STATE_COMPLETED); - EXPECT_EQ(retry.header().command_id(), "arm-movej-idempotency-1"); - EXPECT_EQ(aubo_arm_->moveJCalls(), 1); -} - -TEST_F(GrpcArmServiceTest, - ReusedCommandIdWithDifferentPayloadIsRejectedWithoutRedispatch) -{ - api::MoveJ_Response first; - api::MoveJ_Response conflict; - - const auto first_status = identifiedMoveJ( - "arm-movej-conflict-1", 0.1, first); - const auto conflict_status = identifiedMoveJ( - "arm-movej-conflict-1", 0.2, conflict); - - ASSERT_TRUE(first_status.ok()) << first_status.error_message(); - EXPECT_EQ( - conflict_status.error_code(), grpc::StatusCode::ALREADY_EXISTS); - EXPECT_FALSE(conflict.header().success()); - EXPECT_EQ( - conflict.header().reason_code(), - api::COMMAND_REASON_CODE_COMMAND_ID_CONFLICT); - EXPECT_EQ(aubo_arm_->moveJCalls(), 1); -} - -TEST_F(GrpcArmServiceTest, - StopAllCancelsInFlightTorqueOnWithoutReportingSuccess) -{ - aubo_arm_->blockNextTorqueOn(); - auto blocked_torque_on = std::async( - std::launch::async, - [this]() { return torqueOn("aubo_arm"); }); - - const bool torque_on_started = aubo_arm_->waitForBlockingTorqueOn( - std::chrono::seconds(2)); - auto& admission = globalStopAllAdmissionGate(); - StopAllAdmissionGate::StopAllTicket stop_all_ticket; - if (torque_on_started) { - stop_all_ticket = admission.beginStopAll(); - } - - const bool cancelled_promptly = - blocked_torque_on.wait_for(std::chrono::seconds(2)) == - std::future_status::ready; - if (!cancelled_promptly) { - aubo_arm_->releaseBlockingTorqueOn(); - } - const auto outcome = blocked_torque_on.get(); - - ASSERT_TRUE(torque_on_started); - ASSERT_TRUE(stop_all_ticket.valid()); - EXPECT_TRUE(cancelled_promptly); - EXPECT_EQ(outcome.status.error_code(), grpc::StatusCode::UNAVAILABLE); - EXPECT_FALSE(outcome.response_success); - EXPECT_EQ(outcome.response_error, outcome.status.error_message()); - EXPECT_NE(outcome.response_error.find("StopAll"), std::string::npos); - EXPECT_EQ(aubo_arm_->torqueOnCalls(), 1); - EXPECT_TRUE(aubo_arm_->lastTorqueOnHadCancellation()); - EXPECT_TRUE(aubo_arm_->lastTorqueOnCancellationRequested()); - - EXPECT_TRUE(admission.finishStopAll(stop_all_ticket, true)); -} - -TEST_F(GrpcArmServiceTest, - StopAllPreservesTorqueOnSafetyTerminationFailure) -{ - aubo_arm_->blockNextTorqueOn(); - aubo_arm_->failNextTorqueOnCancellation(); - auto blocked_torque_on = std::async( - std::launch::async, - [this]() { return torqueOn("aubo_arm"); }); - - const bool torque_on_started = aubo_arm_->waitForBlockingTorqueOn( - std::chrono::seconds(2)); - auto& admission = globalStopAllAdmissionGate(); - StopAllAdmissionGate::StopAllTicket stop_all_ticket; - if (torque_on_started) { - stop_all_ticket = admission.beginStopAll(); - } - - const bool completed_promptly = - blocked_torque_on.wait_for(std::chrono::seconds(2)) == - std::future_status::ready; - if (!completed_promptly) { - aubo_arm_->releaseBlockingTorqueOn(); - } - const auto outcome = blocked_torque_on.get(); - - ASSERT_TRUE(torque_on_started); - ASSERT_TRUE(stop_all_ticket.valid()); - EXPECT_TRUE(completed_promptly); - EXPECT_EQ(outcome.status.error_code(), grpc::StatusCode::INTERNAL); - EXPECT_FALSE(outcome.response_success); - EXPECT_EQ( - outcome.response_error, - "simulated torqueOn safety termination failure"); - EXPECT_EQ(outcome.status.error_message(), outcome.response_error); - EXPECT_TRUE(aubo_arm_->lastTorqueOnCancellationRequested()); - - EXPECT_FALSE(admission.finishStopAll(stop_all_ticket, false)); -} - -TEST_F(GrpcArmServiceTest, - ClientCancellationPreservesTorqueOnSafetyTerminationFailure) -{ - std::mutex records_mutex; - std::condition_variable records_changed; - std::vector records; - - grpc::ServerBuilder builder; - const std::string socket_path = - "/tmp/cmvr_grpc_arm_service_test_" + - std::to_string(static_cast(::getpid())) + ".sock"; - std::remove(socket_path.c_str()); - const std::string address = "unix:" + socket_path; - builder.AddListeningPort( - address, - grpc::InsecureServerCredentials()); - builder.RegisterService(service_.get()); - std::vector> factories; - factories.emplace_back(makeGrpcErrorLoggingInterceptorFactory( - [&records, &records_mutex, &records_changed]( - const GrpcFailureRecord& record) { - { - std::lock_guard lock(records_mutex); - records.push_back(record); - } - records_changed.notify_all(); - })); - builder.experimental().SetInterceptorCreators(std::move(factories)); - auto server = builder.BuildAndStart(); - ASSERT_NE(server, nullptr); - - const auto channel = grpc::CreateChannel( - address, - grpc::InsecureChannelCredentials()); - auto stub = api::ArmService::NewStub(channel); - grpc::ClientContext client_context; - client_context.set_deadline( - std::chrono::system_clock::now() + std::chrono::seconds(3)); - api::CommandHeader_Request request; - request.set_device_id("aubo_arm"); - api::CommandHeader_Feedback response; - grpc::Status client_status; - - aubo_arm_->blockNextTorqueOn(); - aubo_arm_->failNextTorqueOnCancellation(); - std::thread client_call([&]() { - client_status = stub->torqueOn( - &client_context, request, &response); - }); - const bool torque_on_started = aubo_arm_->waitForBlockingTorqueOn( - std::chrono::seconds(2)); - client_context.TryCancel(); - client_call.join(); - - bool failure_recorded = false; - { - std::unique_lock lock(records_mutex); - failure_recorded = records_changed.wait_for( - lock, - std::chrono::seconds(2), - [&records]() { return !records.empty(); }); - } - if (!failure_recorded) { - aubo_arm_->releaseBlockingTorqueOn(); - } - server->Shutdown(); - server->Wait(); - std::remove(socket_path.c_str()); - - ASSERT_TRUE(torque_on_started); - EXPECT_EQ(client_status.error_code(), grpc::StatusCode::CANCELLED); - ASSERT_TRUE(failure_recorded); - ASSERT_EQ(records.size(), 1U); - EXPECT_EQ(records.front().kind, GrpcFailureKind::GRPC_STATUS); - EXPECT_EQ(records.front().status_code, grpc::StatusCode::INTERNAL); - EXPECT_EQ(records.front().severity, GrpcFailureSeverity::ERROR); - EXPECT_EQ( - records.front().detail, - "simulated torqueOn safety termination failure"); - EXPECT_TRUE(aubo_arm_->lastTorqueOnCancellationRequested()); -} - -TEST_F(GrpcArmServiceTest, - StopAllGateRejectsMutatingCommandsButAllowsReadsAndStops) -{ - auto& admission = globalStopAllAdmissionGate(); - const auto ticket = admission.beginStopAll(); - ASSERT_TRUE(ticket.valid()); - - const auto rejected_move = moveJ("aubo_arm"); - - api::JsonDeviceCommand_Feedback json_response; - const auto json_status = execute( - "aubo_arm", R"({"command":"cabinet_io"})", json_response); - - api::JointRequest state_request; - state_request.mutable_header()->set_device_id("aubo_arm"); - api::JointResponse state_response; - grpc::ServerContext state_context; - const auto state_status = service_->getJointState( - &state_context, &state_request, &state_response); - - api::CommandHeader_Feedback stop_response; - const auto stop_status = stopMotion("aubo_arm", stop_response); - - EXPECT_EQ( - rejected_move.status.error_code(), - grpc::StatusCode::UNAVAILABLE); - EXPECT_FALSE(rejected_move.response_success); - EXPECT_EQ(aubo_arm_->moveJCalls(), 0); - EXPECT_EQ(json_status.error_code(), grpc::StatusCode::UNAVAILABLE); - EXPECT_FALSE(json_response.header().success()); - EXPECT_EQ(aubo_arm_->execute_calls, 0); - - EXPECT_TRUE(state_status.ok()) << state_status.error_message(); - EXPECT_TRUE(state_response.header().success()); - EXPECT_TRUE(stop_status.ok()) << stop_status.error_message(); - EXPECT_TRUE(stop_response.success()) - << stop_response.error_message(); - EXPECT_EQ(aubo_arm_->stopMotionCalls(), 2); - - EXPECT_TRUE(admission.finishStopAll(ticket, true)); - const auto resumed_move = moveJ("aubo_arm"); - EXPECT_TRUE(resumed_move.status.ok()) - << resumed_move.status.error_message(); - EXPECT_TRUE(resumed_move.response_success) - << resumed_move.response_error; - EXPECT_EQ(aubo_arm_->moveJCalls(), 1); -} - -TEST_F(GrpcArmServiceTest, - StopMotionRevokesBlockedMoveLLeaseBeforeMoveJReturns) -{ - aubo_arm_->blockNextMotion(); - auto blocked_move = std::async( - std::launch::async, - [this]() { return moveL("aubo_arm"); }); - - const bool move_started = aubo_arm_->waitForBlockingMotion( - "moveL", std::chrono::seconds(2)); - - MoveOutcome conflict; - api::CommandHeader_Feedback stop_response; - grpc::Status stop_status; - MoveOutcome before_retired_handler_release; - if (move_started) { - conflict = moveJ("aubo_arm"); - auto stop = std::async( - std::launch::async, - [this, &stop_response]() { - return stopMotion("aubo_arm", stop_response); - }); - before_retired_handler_release = moveJ("aubo_arm"); - aubo_arm_->releaseBlockingMotion(); - stop_status = stop.get(); - } - - aubo_arm_->releaseBlockingMotion(); - const auto original_move = blocked_move.get(); - const auto resumed_move = moveJ("aubo_arm"); - - ASSERT_TRUE(move_started); - EXPECT_EQ(conflict.status.error_code(), - grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_EQ(conflict.response_error, conflict.status.error_message()); - EXPECT_TRUE(stop_status.ok()) << stop_status.error_message(); - EXPECT_TRUE(stop_response.success()) - << stop_response.error_message(); - EXPECT_EQ( - before_retired_handler_release.status.error_code(), - grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_TRUE(resumed_move.status.ok()) - << resumed_move.status.error_message(); - EXPECT_TRUE(resumed_move.response_success) - << resumed_move.response_error; - EXPECT_TRUE(original_move.status.ok()) - << original_move.status.error_message(); - EXPECT_TRUE(original_move.response_success) - << original_move.response_error; - EXPECT_EQ(aubo_arm_->moveJCalls(), 1); - EXPECT_EQ(aubo_arm_->moveLCalls(), 1); - EXPECT_EQ(aubo_arm_->stopMotionCalls(), 2); -} - -TEST_F(GrpcArmServiceTest, StopMotionFailureRetainsSafetyBarrier) -{ - auto& authority = control::ControlAuthorityManager::instance(); - const auto action_lease = authority.tryAcquire( - "aubo_arm", "action-queue:test", std::chrono::hours(1)); - ASSERT_TRUE(action_lease.acquired) << action_lease.detail; - aubo_arm_->failNextStopMotion(); - - api::CommandHeader_Feedback stop_response; - const auto stop_status = stopMotion("aubo_arm", stop_response); - const auto rejected_move = moveJ("aubo_arm"); - - EXPECT_EQ(stop_status.error_code(), grpc::StatusCode::INTERNAL); - EXPECT_FALSE(stop_response.success()); - EXPECT_EQ( - stop_response.reason_code(), - api::COMMAND_REASON_CODE_STOP_UNCONFIRMED); - EXPECT_FALSE(authority.validate(action_lease.token)); - EXPECT_TRUE(authority.isLeased("aubo_arm")); - EXPECT_EQ( - rejected_move.status.error_code(), - grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_EQ(aubo_arm_->moveJCalls(), 0); - EXPECT_EQ(aubo_arm_->stopMotionCalls(), 1); - - authority.release(action_lease.token); - const auto recovery = authority.preemptAcquire( - "aubo_arm", "confirmed-stop-recovery", std::chrono::hours(1)); - ASSERT_TRUE(recovery.acquired) << recovery.detail; - ASSERT_TRUE(authority.waitForPreemptedRelease( - recovery.token, std::chrono::milliseconds::zero())); - ASSERT_TRUE(authority.recoverRetiredSafetyHolders(recovery.token)); - authority.release(recovery.token); - const auto recovered = authority.tryAcquire( - "aubo_arm", "move-after-recovery", std::chrono::hours(1)); - EXPECT_TRUE(recovered.acquired) << recovered.detail; - authority.release(recovered.token); -} - -TEST_F(GrpcArmServiceTest, StopMotionExceptionRetainsSafetyBarrier) -{ - auto& authority = control::ControlAuthorityManager::instance(); - const auto action_lease = authority.tryAcquire( - "aubo_arm", "action-queue:test", std::chrono::hours(1)); - ASSERT_TRUE(action_lease.acquired) << action_lease.detail; - aubo_arm_->throwNextStopMotion(); - - api::CommandHeader_Feedback stop_response; - const auto stop_status = stopMotion("aubo_arm", stop_response); - const auto rejected_move = moveL("aubo_arm"); - - EXPECT_EQ( - stop_status.error_code(), grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_FALSE(stop_response.success()); - EXPECT_EQ( - stop_response.reason_code(), - api::COMMAND_REASON_CODE_STOP_UNCONFIRMED); - EXPECT_FALSE(authority.validate(action_lease.token)); - EXPECT_TRUE(authority.isLeased("aubo_arm")); - EXPECT_EQ( - rejected_move.status.error_code(), - grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_EQ(aubo_arm_->moveLCalls(), 0); - EXPECT_EQ(aubo_arm_->stopMotionCalls(), 1); - - authority.release(action_lease.token); - const auto recovery = authority.preemptAcquire( - "aubo_arm", "confirmed-exception-recovery", std::chrono::hours(1)); - ASSERT_TRUE(recovery.acquired) << recovery.detail; - ASSERT_TRUE(authority.waitForPreemptedRelease( - recovery.token, std::chrono::milliseconds::zero())); - ASSERT_TRUE(authority.recoverRetiredSafetyHolders(recovery.token)); - authority.release(recovery.token); -} - -} // namespace -} // namespace cmvr::service diff --git a/cmvr-es/service/grpc/server/tests/grpc_arm_teleop_service_test.cpp b/cmvr-es/service/grpc/server/tests/grpc_arm_teleop_service_test.cpp deleted file mode 100644 index 0a6be187..00000000 --- a/cmvr-es/service/grpc/server/tests/grpc_arm_teleop_service_test.cpp +++ /dev/null @@ -1,920 +0,0 @@ -#include "service/grpc/server/include/grpc_arm_teleop_service.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "manager/safety_manager/include/device_safety_endpoint.h" -#include "manager/safety_manager/include/safety_manager.h" -#include "service/grpc/stop_all/include/stop_all_admission_gate.h" - -namespace cmvr::service { -namespace { - -using namespace std::chrono_literals; - -std::atomic g_socket_sequence{0}; - -arm_teleop::RobotManifest makeManifest() -{ - arm_teleop::RobotManifest manifest; - manifest.set_robot_id("fake_humanoid_arm"); - manifest.set_model_sha256(std::string(64, 'a')); - manifest.set_calibration_sha256(std::string(64, 'b')); - manifest.add_joint_names("shoulder_joint"); - manifest.add_joint_names("elbow_joint"); - manifest.set_position_unit("rad"); - manifest.set_velocity_unit("rad/s"); - manifest.set_effort_unit("N*m"); - manifest.set_base_frame("base_link"); - manifest.set_tool_frame("tool_link"); - return manifest; -} - -arm_teleop::ClientFrame makeOpenFrame( - const arm_teleop::RobotManifest& manifest, - const std::uint32_t watchdog_ms = 100, - const std::uint32_t lease_ms = 2000, - const bool request_force_feedback = false) -{ - arm_teleop::ClientFrame frame; - auto* open = frame.mutable_open(); - open->set_protocol_major(1); - open->set_protocol_minor(0); - open->set_client_instance_id("test-client"); - *open->mutable_expected_robot() = manifest; - open->set_requested_command_rate_hz(200); - open->set_requested_state_rate_hz(100); - open->set_watchdog_timeout_ms(watchdog_ms); - open->set_requested_lease_ms(lease_ms); - open->set_request_force_feedback(request_force_feedback); - return frame; -} - -arm_teleop::ClientFrame makeSetpoint( - const std::uint64_t sequence, - const std::uint32_t valid_for_us = 50000) -{ - arm_teleop::ClientFrame frame; - auto* setpoint = frame.mutable_setpoint(); - setpoint->set_sequence(sequence); - setpoint->add_position_rad(0.1 * static_cast(sequence)); - setpoint->add_position_rad(0.2 * static_cast(sequence)); - setpoint->add_velocity_rad_s(0.01); - setpoint->add_velocity_rad_s(0.02); - setpoint->set_valid_for_us(valid_for_us); - return frame; -} - -arm_teleop::ClientFrame makeHeartbeat(const std::uint64_t sequence) -{ - arm_teleop::ClientFrame frame; - frame.mutable_heartbeat()->set_sequence(sequence); - return frame; -} - -arm_teleop::ClientFrame makeStop( - const arm_teleop::StopReason reason = - arm_teleop::STOP_REASON_OPERATOR_REQUEST) -{ - arm_teleop::ClientFrame frame; - frame.mutable_stop()->set_reason(reason); - frame.mutable_stop()->set_detail("test stop"); - return frame; -} - -class FakeArmTeleopBackend final : public ArmTeleopBackend { -public: - explicit FakeArmTeleopBackend( - arm_teleop::RobotManifest manifest = makeManifest()) - : manifest_(std::move(manifest)) - { - } - - bool available() const noexcept override { return true; } - - arm_teleop::RobotManifest manifest() const override - { - recordThread(); - return manifest_; - } - - bool supportsForceFeedback() const noexcept override { return true; } - - ArmTeleopBackendResult open( - const arm_teleop::OpenSession&) override - { - recordThread(); - std::lock_guard lock(mutex_); - ++open_calls_; - return open_result_; - } - - ArmTeleopBackendResult applySetpoint( - const arm_teleop::JointSetpoint& setpoint, - const std::chrono::steady_clock::time_point deadline) override - { - if (std::chrono::steady_clock::now() >= deadline) { - return ArmTeleopBackendResult::failure( - grpc::StatusCode::DEADLINE_EXCEEDED, - "fake backend received an expired setpoint"); - } - recordThread(); - std::unique_lock lock(mutex_); - apply_entered_ = true; - apply_entered_sequence_ = setpoint.sequence(); - cv_.notify_all(); - cv_.wait(lock, [&]() { return !block_apply_; }); - applied_sequences_.push_back(setpoint.sequence()); - return apply_result_; - } - - ArmTeleopBackendResult stop( - const arm_teleop::StopReason reason, - const std::string&) override - { - recordThread(); - std::lock_guard lock(mutex_); - stop_reasons_.push_back(reason); - return stop_result_; - } - - ArmTeleopBackendSnapshot snapshot() const override - { - recordThread(); - std::lock_guard lock(mutex_); - ArmTeleopBackendSnapshot snapshot; - auto* state = &snapshot.joint_state; - state->set_sample_sequence(++sample_sequence_); - state->add_position_rad(0.1); - state->add_position_rad(0.2); - state->add_velocity_rad_s(0.01); - state->add_velocity_rad_s(0.02); - state->add_effort_nm(1.0); - state->add_effort_nm(2.0); - state->set_position_valid(true); - state->set_velocity_valid(true); - state->set_effort_valid(true); - state->set_effort_source( - arm_teleop::EFFORT_SOURCE_JOINT_SENSOR); - snapshot.safety.set_connected(true); - snapshot.safety.set_powered_on(true); - return snapshot; - } - - void blockApply() - { - std::lock_guard lock(mutex_); - block_apply_ = true; - apply_entered_ = false; - apply_entered_sequence_ = 0; - } - - void releaseApply() - { - { - std::lock_guard lock(mutex_); - block_apply_ = false; - } - cv_.notify_all(); - } - - bool waitForApply( - const std::uint64_t sequence, - const std::chrono::milliseconds timeout) - { - std::unique_lock lock(mutex_); - return cv_.wait_for(lock, timeout, [&]() { - return apply_entered_ && - apply_entered_sequence_ == sequence; - }); - } - - int openCalls() const - { - std::lock_guard lock(mutex_); - return open_calls_; - } - - std::vector appliedSequences() const - { - std::lock_guard lock(mutex_); - return applied_sequences_; - } - - std::vector stopReasons() const - { - std::lock_guard lock(mutex_); - return stop_reasons_; - } - - std::size_t backendThreadCount() const - { - std::lock_guard lock(thread_mutex_); - return backend_threads_.size(); - } - -private: - void recordThread() const - { - std::lock_guard lock(thread_mutex_); - backend_threads_.insert(std::this_thread::get_id()); - } - - arm_teleop::RobotManifest manifest_; - mutable std::mutex mutex_; - mutable std::condition_variable cv_; - bool block_apply_{false}; - bool apply_entered_{false}; - std::uint64_t apply_entered_sequence_{0}; - int open_calls_{0}; - std::vector applied_sequences_; - std::vector stop_reasons_; - mutable std::uint64_t sample_sequence_{0}; - ArmTeleopBackendResult open_result_{ - ArmTeleopBackendResult::ok()}; - ArmTeleopBackendResult apply_result_{ - ArmTeleopBackendResult::ok()}; - ArmTeleopBackendResult stop_result_{ - ArmTeleopBackendResult::ok()}; - - mutable std::mutex thread_mutex_; - mutable std::set backend_threads_; -}; - -class FakeTeleopSafetyEndpoint final - : public safety::DeviceSafetyEndpoint { -public: - FakeTeleopSafetyEndpoint() - { - descriptor_.device_id = makeManifest().robot_id(); - descriptor_.kind = device::DeviceKind::Arm; - descriptor_.default_policy = - safety::SafetyPolicyFamily::Control; - descriptor_.maximum_snapshot_age = 1s; - descriptor_.supports_active_refresh = true; - } - - safety::DeviceSafetyDescriptor descriptor() const override - { - return descriptor_; - } - - void bindPublisher( - safety::SafetySnapshotPublisher publisher) override - { - publisher_ = std::move(publisher); - } - - void requestSafetyRefresh() noexcept override - { - if (!publisher_) { - return; - } - safety::DeviceSafetySnapshot snapshot; - snapshot.device_id = descriptor_.device_id; - snapshot.condition = safety::SafetyCondition::Nominal; - snapshot.device_generation = generation_; - snapshot.sample_sequence = ++sequence_; - snapshot.observed_at = safety::SafetyClock::now(); - snapshot.connected = safety::TriState::True; - snapshot.operational_ready = safety::TriState::True; - snapshot.quiescent = safety::TriState::True; - snapshot.motion_active = safety::TriState::False; - snapshot.actuator_enabled = safety::TriState::True; - snapshot.emergency_stop_active = safety::TriState::False; - snapshot.protective_stop_active = safety::TriState::False; - snapshot.fault_active = safety::TriState::False; - (void)publisher_(std::move(snapshot)); - } - - void onDeviceGenerationChanged( - const std::uint64_t generation) noexcept override - { - generation_ = generation; - requestSafetyRefresh(); - } - - safety::HardwareCheckResult validateBeforeDispatch( - const safety::AdmissionPermit&) override - { - ++hardware_checks_; - return {true, safety::SafetyReason::None, {}}; - } - - safety::RecoveryCheckResult reconcileAdmissionState( - const safety::RecoveryContext&) override - { - return {true, safety::SafetyReason::None, {}}; - } - - int hardwareChecks() const noexcept - { - return hardware_checks_.load(); - } - -private: - safety::DeviceSafetyDescriptor descriptor_; - safety::SafetySnapshotPublisher publisher_; - std::uint64_t generation_{1}; - std::uint64_t sequence_{0}; - std::atomic hardware_checks_{0}; -}; - -class TeleopServerHarness final { -public: - explicit TeleopServerHarness( - std::shared_ptr backend, - safety::SafetyManager* safety_manager = nullptr) - : service_( - std::move(backend), nullptr, nullptr, - safety_manager) - { - socket_path_ = - "/tmp/cmvr_arm_teleop_service_test_" + - std::to_string(static_cast(::getpid())) + "_" + - std::to_string( - g_socket_sequence.fetch_add( - 1, std::memory_order_relaxed)) + - ".sock"; - std::remove(socket_path_.c_str()); - const std::string address = "unix:" + socket_path_; - - grpc::ServerBuilder builder; - builder.AddListeningPort( - address, grpc::InsecureServerCredentials()); - builder.RegisterService(&service_); - server_ = builder.BuildAndStart(); - if (!server_) { - throw std::runtime_error( - "failed to start in-process arm teleoperation server"); - } - channel_ = grpc::CreateChannel( - address, grpc::InsecureChannelCredentials()); - if (!channel_->WaitForConnected( - std::chrono::system_clock::now() + 2s)) { - throw std::runtime_error( - "failed to connect arm teleoperation test channel"); - } - stub_ = arm_teleop::ArmTeleopService::NewStub(channel_); - } - - ~TeleopServerHarness() - { - if (server_) { - server_->Shutdown(); - server_->Wait(); - } - if (!socket_path_.empty()) { - std::remove(socket_path_.c_str()); - } - } - - arm_teleop::ArmTeleopService::Stub& stub() { return *stub_; } - -private: - ArmTeleopServiceImpl service_; - std::unique_ptr server_; - std::shared_ptr channel_; - std::unique_ptr stub_; - std::string socket_path_; -}; - -template -void expectOpeningFrames(Stream& stream) -{ - arm_teleop::ServerFrame response; - ASSERT_TRUE(stream.Read(&response)); - EXPECT_EQ( - response.status().phase(), - arm_teleop::SESSION_PHASE_OPENED); - EXPECT_FALSE(response.status().session_id().empty()); - ASSERT_TRUE(stream.Read(&response)); - EXPECT_EQ( - response.status().phase(), - arm_teleop::SESSION_PHASE_READY); - EXPECT_TRUE(response.safety().connected()); -} - -TEST(ArmTeleopServiceTest, ProductionDisabledBackendRejectsOpen) -{ - TeleopServerHarness harness(makeDisabledArmTeleopBackend()); - grpc::ClientContext context; - context.set_deadline(std::chrono::system_clock::now() + 2s); - auto stream = harness.stub().Teleoperate(&context); - - ASSERT_TRUE(stream->Write(makeOpenFrame(makeManifest()))); - ASSERT_TRUE(stream->WritesDone()); - - arm_teleop::ServerFrame response; - ASSERT_TRUE(stream->Read(&response)); - EXPECT_EQ( - response.status().phase(), - arm_teleop::SESSION_PHASE_REJECTED); - EXPECT_TRUE(response.safety().fault()); - const grpc::Status status = stream->Finish(); - EXPECT_EQ( - status.error_code(), - grpc::StatusCode::FAILED_PRECONDITION); -} - -TEST(ArmTeleopServiceTest, RequiresOpenAsFirstFrame) -{ - auto backend = std::make_shared(); - TeleopServerHarness harness(backend); - grpc::ClientContext context; - context.set_deadline(std::chrono::system_clock::now() + 2s); - auto stream = harness.stub().Teleoperate(&context); - - ASSERT_TRUE(stream->Write(makeSetpoint(1))); - ASSERT_TRUE(stream->WritesDone()); - - arm_teleop::ServerFrame response; - ASSERT_TRUE(stream->Read(&response)); - EXPECT_EQ( - response.status().phase(), - arm_teleop::SESSION_PHASE_REJECTED); - const grpc::Status status = stream->Finish(); - EXPECT_EQ( - status.error_code(), - grpc::StatusCode::INVALID_ARGUMENT); - EXPECT_EQ(backend->openCalls(), 0); -} - -TEST(ArmTeleopServiceTest, RejectsManifestMismatchBeforeBackendOpen) -{ - auto backend = std::make_shared(); - TeleopServerHarness harness(backend); - grpc::ClientContext context; - context.set_deadline(std::chrono::system_clock::now() + 2s); - auto stream = harness.stub().Teleoperate(&context); - - auto mismatched = makeManifest(); - mismatched.set_calibration_sha256(std::string(64, 'c')); - ASSERT_TRUE(stream->Write(makeOpenFrame(mismatched))); - ASSERT_TRUE(stream->WritesDone()); - - arm_teleop::ServerFrame response; - ASSERT_TRUE(stream->Read(&response)); - EXPECT_EQ( - response.status().phase(), - arm_teleop::SESSION_PHASE_REJECTED); - const grpc::Status status = stream->Finish(); - EXPECT_EQ( - status.error_code(), - grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_EQ(backend->openCalls(), 0); -} - -TEST(ArmTeleopServiceTest, RejectsNonIncreasingSequenceAndStops) -{ - auto backend = std::make_shared(); - TeleopServerHarness harness(backend); - grpc::ClientContext context; - context.set_deadline(std::chrono::system_clock::now() + 2s); - auto stream = harness.stub().Teleoperate(&context); - - ASSERT_TRUE(stream->Write(makeOpenFrame(makeManifest()))); - expectOpeningFrames(*stream); - ASSERT_TRUE(stream->Write(makeSetpoint(1))); - - arm_teleop::ServerFrame response; - ASSERT_TRUE(stream->Read(&response)); - EXPECT_EQ( - response.status().phase(), - arm_teleop::SESSION_PHASE_ACTIVE); - EXPECT_EQ(response.status().applied_sequence(), 1U); - - ASSERT_TRUE(stream->Write(makeHeartbeat(1))); - ASSERT_TRUE(stream->WritesDone()); - ASSERT_TRUE(stream->Read(&response)); - EXPECT_EQ( - response.status().phase(), - arm_teleop::SESSION_PHASE_REJECTED); - EXPECT_EQ( - response.status().stop_reason(), - arm_teleop::STOP_REASON_PROTOCOL_ERROR); - - const grpc::Status status = stream->Finish(); - EXPECT_EQ( - status.error_code(), - grpc::StatusCode::INVALID_ARGUMENT); - ASSERT_FALSE(backend->stopReasons().empty()); - EXPECT_EQ( - backend->stopReasons().back(), - arm_teleop::STOP_REASON_PROTOCOL_ERROR); - EXPECT_EQ(backend->backendThreadCount(), 1U); -} - -TEST(ArmTeleopServiceTest, ProtocolErrorCancelsReaderWithoutClientHalfClose) -{ - auto backend = std::make_shared(); - TeleopServerHarness harness(backend); - grpc::ClientContext context; - context.set_deadline(std::chrono::system_clock::now() + 2s); - auto stream = harness.stub().Teleoperate(&context); - - ASSERT_TRUE(stream->Write(makeOpenFrame(makeManifest()))); - expectOpeningFrames(*stream); - ASSERT_TRUE(stream->Write(makeHeartbeat(1))); - - arm_teleop::ServerFrame response; - ASSERT_TRUE(stream->Read(&response)); - EXPECT_EQ( - response.status().phase(), - arm_teleop::SESSION_PHASE_READY); - - // Deliberately keep the client write half open after the duplicate - // sequence. The server must cancel its reader and return promptly. - ASSERT_TRUE(stream->Write(makeHeartbeat(1))); - ASSERT_TRUE(stream->Read(&response)); - EXPECT_EQ( - response.status().phase(), - arm_teleop::SESSION_PHASE_REJECTED); - EXPECT_EQ( - response.status().stop_reason(), - arm_teleop::STOP_REASON_PROTOCOL_ERROR); - const auto status = stream->Finish(); - // TryCancel is required to interrupt the server reader's blocking Read - // when the peer deliberately keeps its write half open. Depending on - // gRPC completion ordering, the client may therefore observe CANCELLED - // after it has already received the explicit protocol-error frame. - EXPECT_TRUE( - status.error_code() == grpc::StatusCode::INVALID_ARGUMENT || - status.error_code() == grpc::StatusCode::CANCELLED) - << status.error_message(); -} - -TEST(ArmTeleopServiceTest, WatchdogExpiresWithoutValidClientActivity) -{ - auto backend = std::make_shared(); - TeleopServerHarness harness(backend); - grpc::ClientContext context; - context.set_deadline(std::chrono::system_clock::now() + 2s); - auto stream = harness.stub().Teleoperate(&context); - - ASSERT_TRUE(stream->Write( - makeOpenFrame(makeManifest(), 20, 2000))); - expectOpeningFrames(*stream); - - arm_teleop::ServerFrame response; - ASSERT_TRUE(stream->Read(&response)); - EXPECT_EQ( - response.status().phase(), - arm_teleop::SESSION_PHASE_WATCHDOG_EXPIRED); - EXPECT_EQ( - response.status().stop_reason(), - arm_teleop::STOP_REASON_WATCHDOG); - - const grpc::Status status = stream->Finish(); - EXPECT_TRUE( - status.error_code() == grpc::StatusCode::DEADLINE_EXCEEDED || - status.error_code() == grpc::StatusCode::CANCELLED) - << status.error_message(); - ASSERT_FALSE(backend->stopReasons().empty()); - EXPECT_EQ( - backend->stopReasons().back(), - arm_teleop::STOP_REASON_WATCHDOG); -} - -TEST(ArmTeleopServiceTest, ValidHeartbeatsRenewControlLease) -{ - auto backend = std::make_shared(); - TeleopServerHarness harness(backend); - grpc::ClientContext context; - context.set_deadline(std::chrono::system_clock::now() + 3s); - auto stream = harness.stub().Teleoperate(&context); - - ASSERT_TRUE(stream->Write( - makeOpenFrame(makeManifest(), 100, 200))); - expectOpeningFrames(*stream); - - arm_teleop::ServerFrame response; - for (std::uint64_t sequence = 1; sequence <= 7; ++sequence) { - std::this_thread::sleep_for(40ms); - ASSERT_TRUE(stream->Write(makeHeartbeat(sequence))); - ASSERT_TRUE(stream->Read(&response)); - EXPECT_EQ( - response.status().phase(), - arm_teleop::SESSION_PHASE_READY); - EXPECT_EQ( - response.status().received_sequence(), - sequence); - EXPECT_GT(response.status().lease_remaining_ms(), 0U); - } - - ASSERT_TRUE(stream->Write(makeStop())); - ASSERT_TRUE(stream->WritesDone()); - ASSERT_TRUE(stream->Read(&response)); - EXPECT_EQ( - response.status().phase(), - arm_teleop::SESSION_PHASE_STOPPED); - EXPECT_TRUE(stream->Finish().ok()); -} - -TEST(ArmTeleopServiceTest, RejectsSecondControllerWhileLeaseIsActive) -{ - auto backend = std::make_shared(); - TeleopServerHarness harness(backend); - - grpc::ClientContext first_context; - first_context.set_deadline( - std::chrono::system_clock::now() + 3s); - auto first_stream = - harness.stub().Teleoperate(&first_context); - ASSERT_TRUE(first_stream->Write( - makeOpenFrame(makeManifest(), 500, 2000))); - expectOpeningFrames(*first_stream); - - grpc::ClientContext second_context; - second_context.set_deadline( - std::chrono::system_clock::now() + 2s); - auto second_stream = - harness.stub().Teleoperate(&second_context); - ASSERT_TRUE(second_stream->Write( - makeOpenFrame(makeManifest(), 500, 2000))); - ASSERT_TRUE(second_stream->WritesDone()); - - arm_teleop::ServerFrame response; - ASSERT_TRUE(second_stream->Read(&response)); - EXPECT_EQ( - response.status().phase(), - arm_teleop::SESSION_PHASE_REJECTED); - const grpc::Status second_status = - second_stream->Finish(); - EXPECT_EQ( - second_status.error_code(), - grpc::StatusCode::RESOURCE_EXHAUSTED); - - ASSERT_TRUE(first_stream->Write(makeStop())); - ASSERT_TRUE(first_stream->WritesDone()); - ASSERT_TRUE(first_stream->Read(&response)); - EXPECT_EQ( - response.status().phase(), - arm_teleop::SESSION_PHASE_STOPPED); - EXPECT_TRUE(first_stream->Finish().ok()); -} - -TEST(ArmTeleopServiceTest, LatestOnlySlotDropsIntermediateSetpoints) -{ - auto backend = std::make_shared(); - TeleopServerHarness harness(backend); - grpc::ClientContext context; - context.set_deadline(std::chrono::system_clock::now() + 3s); - auto stream = harness.stub().Teleoperate(&context); - - ASSERT_TRUE(stream->Write( - makeOpenFrame(makeManifest(), 500, 2000))); - expectOpeningFrames(*stream); - - backend->blockApply(); - ASSERT_TRUE(stream->Write(makeSetpoint(1, 400000))); - ASSERT_TRUE(backend->waitForApply(1, 1s)); - ASSERT_TRUE(stream->Write(makeSetpoint(2, 400000))); - ASSERT_TRUE(stream->Write(makeSetpoint(3, 400000))); - ASSERT_TRUE(stream->Write(makeSetpoint(4, 400000))); - std::this_thread::sleep_for(30ms); - backend->releaseApply(); - - arm_teleop::ServerFrame response; - ASSERT_TRUE(stream->Read(&response)); - EXPECT_EQ(response.status().applied_sequence(), 1U); - ASSERT_TRUE(stream->Read(&response)); - EXPECT_EQ(response.status().applied_sequence(), 4U); - EXPECT_GE(response.status().dropped_setpoints(), 2U); - - ASSERT_TRUE(stream->Write(makeStop())); - ASSERT_TRUE(stream->WritesDone()); - ASSERT_TRUE(stream->Read(&response)); - EXPECT_EQ( - response.status().phase(), - arm_teleop::SESSION_PHASE_STOPPED); - EXPECT_TRUE(stream->Finish().ok()); - - const auto applied = backend->appliedSequences(); - ASSERT_EQ(applied.size(), 2U); - EXPECT_EQ(applied[0], 1U); - EXPECT_EQ(applied[1], 4U); - EXPECT_EQ(backend->backendThreadCount(), 1U); -} - -TEST(ArmTeleopServiceTest, ExpiredSetpointIsNeverDispatched) -{ - auto backend = std::make_shared(); - TeleopServerHarness harness(backend); - grpc::ClientContext context; - context.set_deadline(std::chrono::system_clock::now() + 3s); - auto stream = harness.stub().Teleoperate(&context); - - ASSERT_TRUE(stream->Write( - makeOpenFrame(makeManifest(), 500, 2000))); - expectOpeningFrames(*stream); - - backend->blockApply(); - ASSERT_TRUE(stream->Write(makeSetpoint(1, 400000))); - ASSERT_TRUE(backend->waitForApply(1, 1s)); - ASSERT_TRUE(stream->Write(makeSetpoint(2, 1000))); - std::this_thread::sleep_for(30ms); - backend->releaseApply(); - - arm_teleop::ServerFrame response; - ASSERT_TRUE(stream->Read(&response)); - EXPECT_EQ(response.status().applied_sequence(), 1U); - ASSERT_TRUE(stream->Read(&response)); - EXPECT_EQ( - response.status().phase(), - arm_teleop::SESSION_PHASE_HOLDING); - EXPECT_EQ(response.status().received_sequence(), 2U); - EXPECT_EQ(response.status().applied_sequence(), 1U); - EXPECT_EQ(response.status().rejected_setpoints(), 1U); - - ASSERT_TRUE(stream->Write(makeStop())); - ASSERT_TRUE(stream->WritesDone()); - ASSERT_TRUE(stream->Read(&response)); - EXPECT_EQ( - response.status().phase(), - arm_teleop::SESSION_PHASE_STOPPED); - EXPECT_TRUE(stream->Finish().ok()); - - const auto applied = backend->appliedSequences(); - ASSERT_EQ(applied.size(), 1U); - EXPECT_EQ(applied.front(), 1U); -} - -TEST(ArmTeleopServiceTest, - StopAllFencesDispatchRejectsAdmissionAndAllowsReuse) -{ - auto& authority = control::ControlAuthorityManager::instance(); - auto& admission = globalStopAllAdmissionGate(); - authority.clear(); - admission.clearForTesting(); - - auto backend = std::make_shared(); - TeleopServerHarness harness(backend); - grpc::ClientContext active_context; - active_context.set_deadline( - std::chrono::system_clock::now() + 3s); - auto active_stream = harness.stub().Teleoperate(&active_context); - - ASSERT_TRUE(active_stream->Write( - makeOpenFrame(makeManifest(), 500, 2000))); - expectOpeningFrames(*active_stream); - - backend->blockApply(); - ASSERT_TRUE(active_stream->Write(makeSetpoint(1, 400000))); - ASSERT_TRUE(backend->waitForApply(1, 1s)); - - const auto stop_all_ticket = admission.beginStopAll(); - ASSERT_TRUE(stop_all_ticket.valid()); - - grpc::ClientContext blocked_context; - blocked_context.set_deadline( - std::chrono::system_clock::now() + 2s); - auto blocked_stream = harness.stub().Teleoperate(&blocked_context); - ASSERT_TRUE(blocked_stream->Write(makeOpenFrame(makeManifest()))); - ASSERT_TRUE(blocked_stream->WritesDone()); - arm_teleop::ServerFrame response; - ASSERT_TRUE(blocked_stream->Read(&response)); - EXPECT_EQ( - response.status().phase(), - arm_teleop::SESSION_PHASE_REJECTED); - const auto blocked_status = blocked_stream->Finish(); - EXPECT_EQ( - blocked_status.error_code(), grpc::StatusCode::UNAVAILABLE); - EXPECT_EQ(backend->openCalls(), 1); - - const auto safety_lease = authority.preemptAcquire( - makeManifest().robot_id(), "stop-all-test", - std::chrono::hours(1)); - ASSERT_TRUE(safety_lease.acquired) << safety_lease.detail; - const auto safety_token = safety_lease.token; - auto dispatch_fence = std::async( - std::launch::async, - [&authority, safety_token] { - return authority.waitForPreemptedRelease(safety_token, 1s); - }); - - EXPECT_EQ( - dispatch_fence.wait_for(50ms), std::future_status::timeout); - backend->releaseApply(); - ASSERT_EQ( - dispatch_fence.wait_for(1s), std::future_status::ready); - EXPECT_TRUE(dispatch_fence.get()); - - ASSERT_TRUE(active_stream->Read(&response)); - EXPECT_EQ(response.status().applied_sequence(), 1U); - ASSERT_TRUE(active_stream->Read(&response)); - EXPECT_EQ( - response.status().phase(), - arm_teleop::SESSION_PHASE_LEASE_LOST); - EXPECT_EQ( - response.status().stop_reason(), - arm_teleop::STOP_REASON_LEASE_REVOKED); - const auto active_status = active_stream->Finish(); - EXPECT_TRUE( - active_status.error_code() == grpc::StatusCode::ABORTED || - active_status.error_code() == grpc::StatusCode::CANCELLED) - << active_status.error_message(); - - const auto applied = backend->appliedSequences(); - ASSERT_EQ(applied.size(), 1U); - EXPECT_EQ(applied.front(), 1U); - const auto stopped = backend->stopReasons(); - ASSERT_FALSE(stopped.empty()); - EXPECT_EQ( - stopped.back(), arm_teleop::STOP_REASON_LEASE_REVOKED); - - authority.release(safety_token); - ASSERT_TRUE(admission.finishStopAll(stop_all_ticket, true)); - - grpc::ClientContext resumed_context; - resumed_context.set_deadline( - std::chrono::system_clock::now() + 2s); - auto resumed_stream = harness.stub().Teleoperate(&resumed_context); - ASSERT_TRUE(resumed_stream->Write(makeOpenFrame(makeManifest()))); - expectOpeningFrames(*resumed_stream); - ASSERT_TRUE(resumed_stream->Write(makeStop())); - ASSERT_TRUE(resumed_stream->WritesDone()); - ASSERT_TRUE(resumed_stream->Read(&response)); - EXPECT_EQ( - response.status().phase(), - arm_teleop::SESSION_PHASE_STOPPED); - EXPECT_TRUE(resumed_stream->Finish().ok()); - EXPECT_EQ(backend->openCalls(), 2); - - authority.clear(); - admission.clearForTesting(); -} - -TEST(ArmTeleopServiceTest, - CoordinatorInvalidationStopsExistingSessionBeforeAnotherSetpoint) -{ - safety::SafetyManagerConfig config; - config.enforcement_mode = safety::EnforcementMode::EnforceAll; - safety::SafetyManager coordinator(config); - auto endpoint = std::make_shared(); - ASSERT_TRUE(coordinator.registerDevice( - {endpoint->descriptor(), endpoint, {}})); - coordinator.updateDeviceRuntimeState( - makeManifest().robot_id(), - device::ManagedDeviceState::Running, - {device::DeviceHealthState::Healthy, {}}); - coordinator.markStartupComplete(); - - auto backend = std::make_shared(); - TeleopServerHarness harness(backend, &coordinator); - grpc::ClientContext context; - context.set_deadline(std::chrono::system_clock::now() + 2s); - auto stream = harness.stub().Teleoperate(&context); - - ASSERT_TRUE(stream->Write(makeOpenFrame(makeManifest(), 500, 1500))); - expectOpeningFrames(*stream); - EXPECT_EQ(endpoint->hardwareChecks(), 1); - - ASSERT_TRUE(stream->Write(makeSetpoint(1))); - arm_teleop::ServerFrame response; - ASSERT_TRUE(stream->Read(&response)); - EXPECT_EQ(response.status().phase(), arm_teleop::SESSION_PHASE_ACTIVE); - EXPECT_EQ(response.status().applied_sequence(), 1U); - EXPECT_EQ(endpoint->hardwareChecks(), 2); - - coordinator.quarantineDevice( - makeManifest().robot_id(), - safety::SafetyReason::OutcomeUnknown, - "test-quarantine"); - - ASSERT_TRUE(stream->Read(&response)); - EXPECT_EQ( - response.status().phase(), - arm_teleop::SESSION_PHASE_LEASE_LOST); - EXPECT_EQ( - response.status().stop_reason(), - arm_teleop::STOP_REASON_EMERGENCY_STOP); - const auto status = stream->Finish(); - EXPECT_TRUE( - status.error_code() == grpc::StatusCode::FAILED_PRECONDITION || - status.error_code() == grpc::StatusCode::CANCELLED) - << status.error_message(); - EXPECT_EQ(backend->appliedSequences(), - (std::vector{1U})); - ASSERT_FALSE(backend->stopReasons().empty()); - EXPECT_EQ( - backend->stopReasons().back(), - arm_teleop::STOP_REASON_EMERGENCY_STOP); -} - -} // namespace -} // namespace cmvr::service diff --git a/cmvr-es/service/grpc/server/tests/grpc_command_transaction_test.cpp b/cmvr-es/service/grpc/server/tests/grpc_command_transaction_test.cpp deleted file mode 100644 index 3ded4775..00000000 --- a/cmvr-es/service/grpc/server/tests/grpc_command_transaction_test.cpp +++ /dev/null @@ -1,454 +0,0 @@ -#include "service/grpc/server/include/grpc_command_transaction.h" - -#include -#include -#include -#include -#include - -#include - -#include "cmvr/api/arm_command.pb.h" -#include "manager/safety_manager/include/device_safety_endpoint.h" - -namespace cmvr::service { -namespace { - -class FakeEndpoint final : public safety::DeviceSafetyEndpoint { -public: - explicit FakeEndpoint(std::string device_id) - { - descriptor_.device_id = std::move(device_id); - descriptor_.kind = device::DeviceKind::Arm; - descriptor_.default_policy = safety::SafetyPolicyFamily::Control; - descriptor_.maximum_snapshot_age = std::chrono::seconds(1); - descriptor_.supports_active_refresh = true; - } - - safety::DeviceSafetyDescriptor descriptor() const override - { - return descriptor_; - } - - void bindPublisher(safety::SafetySnapshotPublisher publisher) override - { - publisher_ = std::move(publisher); - } - - void requestSafetyRefresh() noexcept override - { - if (!publisher_) { - return; - } - safety::DeviceSafetySnapshot snapshot; - snapshot.device_id = descriptor_.device_id; - snapshot.condition = safety::SafetyCondition::Nominal; - snapshot.device_generation = 1; - snapshot.sample_sequence = ++sequence_; - snapshot.observed_at = safety::SafetyClock::now(); - snapshot.connected = safety::TriState::True; - snapshot.operational_ready = safety::TriState::True; - snapshot.quiescent = safety::TriState::True; - snapshot.motion_active = safety::TriState::False; - snapshot.actuator_enabled = safety::TriState::True; - snapshot.emergency_stop_active = safety::TriState::False; - snapshot.protective_stop_active = safety::TriState::False; - snapshot.fault_active = safety::TriState::False; - (void)publisher_(std::move(snapshot)); - } - - safety::HardwareCheckResult validateBeforeDispatch( - const safety::AdmissionPermit&) override - { - ++hardware_checks; - return final_check; - } - - safety::RecoveryCheckResult reconcileAdmissionState( - const safety::RecoveryContext&) override - { - return {true, safety::SafetyReason::None, {}}; - } - - safety::DeviceSafetyDescriptor descriptor_; - safety::SafetySnapshotPublisher publisher_; - safety::HardwareCheckResult final_check{ - true, safety::SafetyReason::None, {}}; - std::atomic sequence_{0}; - std::atomic hardware_checks{0}; -}; - -api::MoveJ_Request moveRequest( - const safety::SafetyManager& coordinator, - const std::string& command_id, - const double target = 0.25) -{ - api::MoveJ_Request request; - request.mutable_header()->set_device_id("arm"); - request.mutable_header()->set_command_id(command_id); - request.mutable_header()->set_expected_service_instance_id( - coordinator.serviceInstanceId()); - request.mutable_header()->set_valid_for_ms(1000); - request.mutable_target()->add_position(target); - return request; -} - -grpc::Status executeMove( - safety::SafetyManager& coordinator, - const api::MoveJ_Request& request, - api::MoveJ_Response& response, - int& dispatches, - const bool throw_after_dispatch = false) -{ - grpc::ServerContext context; - return executeRegisteredGrpcCommand( - makeDefaultGrpcSecurityGateway(), - &context, - coordinator, - "/cmvr.api.ArmService/moveJ", - &request, - &response, - [&](GrpcCommandTransaction& transaction) { - if (!transaction.beginDispatch()) { - return transaction.dispatchStatus(); - } - ++dispatches; - if (throw_after_dispatch) { - throw std::runtime_error("simulated lost driver acknowledgement"); - } - response.mutable_header()->set_success(true); - return grpc::Status::OK; - }); -} - -TEST(GrpcCommandTransactionTest, - DeterministicHashIgnoresRetryIdentityButIncludesPayload) -{ - safety::SafetyManager coordinator; - auto first = moveRequest(coordinator, "command-1", 0.25); - auto retry = first; - retry.mutable_header()->set_command_id("command-2"); - retry.mutable_header()->set_valid_for_ms(2000); - retry.mutable_header()->mutable_timestamp()->set_seconds(1234); - auto changed = retry; - changed.mutable_target()->set_position(0, 0.5); - - const auto first_hash = deterministicGrpcPayloadHash( - "/cmvr.api.ArmService/moveJ", first); - EXPECT_FALSE(first_hash.empty()); - EXPECT_EQ( - first_hash, - deterministicGrpcPayloadHash( - "/cmvr.api.ArmService/moveJ", retry)); - EXPECT_NE( - first_hash, - deterministicGrpcPayloadHash( - "/cmvr.api.ArmService/moveJ", changed)); - EXPECT_NE( - first_hash, - deterministicGrpcPayloadHash( - "/cmvr.api.ArmService/moveL", first)); -} - -TEST(GrpcCommandTransactionTest, SameIdReturnsCachedResponseWithoutRedispatch) -{ - safety::SafetyManager coordinator; - auto endpoint = std::make_shared("arm"); - ASSERT_TRUE(coordinator.registerDevice( - {endpoint->descriptor(), endpoint, {}})); - coordinator.markStartupComplete(); - - const auto request = moveRequest(coordinator, "command-cache"); - api::MoveJ_Response first_response; - int dispatches = 0; - ASSERT_TRUE(executeMove( - coordinator, request, first_response, dispatches).ok()); - ASSERT_TRUE(first_response.header().success()); - EXPECT_EQ(dispatches, 1); - - auto retry = request; - retry.mutable_header()->set_valid_for_ms(2500); - retry.mutable_header()->mutable_timestamp()->set_seconds(42); - api::MoveJ_Response cached_response; - ASSERT_TRUE(executeMove( - coordinator, retry, cached_response, dispatches).ok()); - EXPECT_EQ(dispatches, 1); - EXPECT_TRUE(cached_response.header().success()); - EXPECT_EQ( - cached_response.header().execution_state(), - api::COMMAND_EXECUTION_STATE_COMPLETED); - EXPECT_EQ(cached_response.header().command_id(), "command-cache"); - - auto conflict = request; - conflict.mutable_target()->set_position(0, 0.75); - api::MoveJ_Response conflict_response; - const auto conflict_status = executeMove( - coordinator, conflict, conflict_response, dispatches); - EXPECT_EQ(conflict_status.error_code(), grpc::StatusCode::ALREADY_EXISTS); - EXPECT_EQ(dispatches, 1); - EXPECT_EQ( - conflict_response.header().reason_code(), - api::COMMAND_REASON_CODE_COMMAND_ID_CONFLICT); -} - -TEST(GrpcCommandTransactionTest, - EnforcedCommandRequiresIdentityAndRunsFinalHardwareCheck) -{ - safety::SafetyManagerConfig config; - config.enforcement_mode = safety::EnforcementMode::EnforceAll; - safety::SafetyManager coordinator(config); - auto endpoint = std::make_shared("arm"); - ASSERT_TRUE(coordinator.registerDevice( - {endpoint->descriptor(), endpoint, {}})); - coordinator.updateDeviceRuntimeState( - "arm", - device::ManagedDeviceState::Running, - {device::DeviceHealthState::Healthy, {}}); - coordinator.markStartupComplete(); - - auto missing_identity = moveRequest(coordinator, ""); - api::MoveJ_Response rejected; - int dispatches = 0; - const auto rejected_status = executeMove( - coordinator, missing_identity, rejected, dispatches); - EXPECT_EQ( - rejected_status.error_code(), grpc::StatusCode::INVALID_ARGUMENT); - EXPECT_EQ(dispatches, 0); - EXPECT_EQ( - rejected.header().reason_code(), - api::COMMAND_REASON_CODE_COMMAND_ID_REQUIRED); - - auto accepted = moveRequest(coordinator, "command-enforced"); - api::MoveJ_Response accepted_response; - ASSERT_TRUE(executeMove( - coordinator, accepted, accepted_response, dispatches).ok()); - EXPECT_EQ(dispatches, 1); - EXPECT_EQ(endpoint->hardware_checks.load(), 1); - EXPECT_EQ( - accepted_response.header().device_generation(), 1U); -} - -TEST(GrpcCommandTransactionTest, - ExceptionAfterDispatchIsQuarantinedAndNeverRedispatched) -{ - safety::SafetyManagerConfig config; - config.enforcement_mode = safety::EnforcementMode::EnforceAll; - safety::SafetyManager coordinator(config); - auto endpoint = std::make_shared("arm"); - ASSERT_TRUE(coordinator.registerDevice( - {endpoint->descriptor(), endpoint, {}})); - coordinator.updateDeviceRuntimeState( - "arm", - device::ManagedDeviceState::Running, - {device::DeviceHealthState::Healthy, {}}); - coordinator.markStartupComplete(); - - const auto request = moveRequest(coordinator, "command-unknown"); - api::MoveJ_Response response; - int dispatches = 0; - ASSERT_TRUE(executeMove( - coordinator, request, response, dispatches, true).ok()); - EXPECT_EQ(dispatches, 1); - EXPECT_EQ( - response.header().reason_code(), - api::COMMAND_REASON_CODE_OUTCOME_UNKNOWN); - ASSERT_EQ(coordinator.snapshot().devices.size(), 1U); - EXPECT_EQ( - coordinator.snapshot().devices.front().admission_state, - safety::DeviceAdmissionState::Quarantined); - - api::MoveJ_Response retry_response; - ASSERT_TRUE(executeMove( - coordinator, request, retry_response, dispatches).ok()); - EXPECT_EQ(dispatches, 1); - EXPECT_EQ( - retry_response.header().execution_state(), - api::COMMAND_EXECUTION_STATE_OUTCOME_UNKNOWN); -} - -TEST(GrpcCommandTransactionTest, - ScopedDispatchChecksHardwareForEverySubmission) -{ - safety::SafetyManagerConfig config; - config.enforcement_mode = safety::EnforcementMode::EnforceAll; - safety::SafetyManager coordinator(config); - auto endpoint = std::make_shared("arm"); - ASSERT_TRUE(coordinator.registerDevice( - {endpoint->descriptor(), endpoint, {}})); - coordinator.updateDeviceRuntimeState( - "arm", - device::ManagedDeviceState::Running, - {device::DeviceHealthState::Healthy, {}}); - coordinator.markStartupComplete(); - - const auto request = moveRequest(coordinator, "command-scoped"); - api::MoveJ_Response response; - grpc::ServerContext context; - int dispatches = 0; - const auto status = executeRegisteredGrpcCommand( - makeDefaultGrpcSecurityGateway(), - &context, - coordinator, - "/cmvr.api.ArmService/moveJ", - &request, - &response, - [&](GrpcCommandTransaction& transaction) { - for (int index = 0; index < 2; ++index) { - auto dispatch = transaction.beginScopedDispatch(); - if (!dispatch.acquired()) { - return transaction.dispatchStatus(); - } - ++dispatches; - } - response.mutable_header()->set_success(true); - return grpc::Status::OK; - }); - - EXPECT_TRUE(status.ok()); - EXPECT_TRUE(response.header().success()); - EXPECT_EQ(dispatches, 2); - EXPECT_EQ(endpoint->hardware_checks.load(), 2); -} - -TEST(GrpcCommandTransactionTest, - RevokedActuationPermitCannotSuppressInternalSafetyStop) -{ - safety::SafetyManagerConfig config; - config.enforcement_mode = safety::EnforcementMode::EnforceAll; - safety::SafetyManager coordinator(config); - auto endpoint = std::make_shared("arm"); - ASSERT_TRUE(coordinator.registerDevice( - {endpoint->descriptor(), endpoint, {}})); - coordinator.updateDeviceRuntimeState( - "arm", - device::ManagedDeviceState::Running, - {device::DeviceHealthState::Healthy, {}}); - coordinator.markStartupComplete(); - - const auto request = moveRequest(coordinator, "command-revoked"); - api::MoveJ_Response response; - grpc::ServerContext context; - int actuations = 0; - int safety_stops = 0; - const auto status = executeRegisteredGrpcCommand( - makeDefaultGrpcSecurityGateway(), - &context, - coordinator, - "/cmvr.api.ArmService/moveJ", - &request, - &response, - [&](GrpcCommandTransaction& transaction) { - { - auto dispatch = transaction.beginScopedDispatch(); - if (!dispatch.acquired()) { - return transaction.dispatchStatus(); - } - ++actuations; - } - - const auto stop_all = coordinator.stopAll("revoke-scoped-permit"); - EXPECT_TRUE(stop_all.success); - EXPECT_FALSE(transaction.revalidate()); - const auto revoked_status = transaction.dispatchStatus(); - EXPECT_FALSE(transaction.beginScopedDispatch().acquired()); - - auto stop_dispatch = transaction.beginSafetyStopDispatch(); - if (stop_dispatch.acquired()) { - ++safety_stops; - } - response.mutable_header()->set_success(false); - return revoked_status; - }); - - // Ledger-backed commands report their terminal outcome in Feedback. - EXPECT_TRUE(status.ok()); - EXPECT_FALSE(response.header().success()); - EXPECT_EQ( - response.header().reason_code(), - api::COMMAND_REASON_CODE_SAFETY_LATCHED); - EXPECT_EQ(actuations, 1); - EXPECT_EQ(safety_stops, 1); - EXPECT_EQ(endpoint->hardware_checks.load(), 2); -} - -TEST(GrpcCommandTransactionTest, - ServerDerivedStopRemainsDispatchableWhenActuationIsQuarantined) -{ - safety::SafetyManagerConfig config; - config.enforcement_mode = safety::EnforcementMode::EnforceAll; - safety::SafetyManager coordinator(config); - auto endpoint = std::make_shared("arm"); - ASSERT_TRUE(coordinator.registerDevice( - {endpoint->descriptor(), endpoint, {}})); - coordinator.updateDeviceRuntimeState( - "arm", - device::ManagedDeviceState::Running, - {device::DeviceHealthState::Healthy, {}}); - coordinator.markStartupComplete(); - coordinator.quarantineDevice( - "arm", safety::SafetyReason::OutcomeUnknown, - "uncertain-ptz-start"); - - const auto registered = defaultGrpcMethodPolicyRegistry().find( - "/cmvr.api.CameraService/ControlPtz"); - ASSERT_TRUE(registered.has_value()); - - auto start_request = moveRequest(coordinator, "ptz-start"); - api::MoveJ_Response start_response; - grpc::ServerContext start_context; - int start_dispatches = 0; - const auto start_status = executeServerDerivedGrpcCommand( - makeDefaultGrpcSecurityGateway(), - &start_context, - coordinator, - "/cmvr.api.CameraService/ControlPtz", - *registered, - &start_request, - &start_response, - [&](GrpcCommandTransaction& transaction) { - if (!transaction.beginDispatch()) { - return transaction.dispatchStatus(); - } - ++start_dispatches; - start_response.mutable_header()->set_success(true); - return grpc::Status::OK; - }); - EXPECT_TRUE(start_status.ok()); - EXPECT_EQ(start_dispatches, 0); - EXPECT_FALSE(start_response.header().success()); - EXPECT_EQ( - start_response.header().reason_code(), - api::COMMAND_REASON_CODE_SAFETY_LATCHED); - - auto stop_request = moveRequest(coordinator, "ptz-stop"); - api::MoveJ_Response stop_response; - grpc::ServerContext stop_context; - auto stop_policy = *registered; - stop_policy.access = GrpcAccessClass::Stop; - stop_policy.command_intent = safety::CommandIntent::Stop; - stop_policy.safety_lane = true; - int stop_dispatches = 0; - const auto stop_status = executeServerDerivedGrpcCommand( - makeDefaultGrpcSecurityGateway(), - &stop_context, - coordinator, - "/cmvr.api.CameraService/ControlPtz", - std::move(stop_policy), - &stop_request, - &stop_response, - [&](GrpcCommandTransaction& transaction) { - if (!transaction.beginDispatch()) { - return transaction.dispatchStatus(); - } - ++stop_dispatches; - stop_response.mutable_header()->set_success(true); - return grpc::Status::OK; - }); - EXPECT_TRUE(stop_status.ok()); - EXPECT_TRUE(stop_response.header().success()); - EXPECT_EQ(stop_dispatches, 1); - EXPECT_EQ(endpoint->hardware_checks.load(), 1); -} - -} // namespace -} // namespace cmvr::service diff --git a/cmvr-es/service/grpc/server/tests/grpc_dexhand_service_test.cpp b/cmvr-es/service/grpc/server/tests/grpc_dexhand_service_test.cpp deleted file mode 100644 index 6638b27e..00000000 --- a/cmvr-es/service/grpc/server/tests/grpc_dexhand_service_test.cpp +++ /dev/null @@ -1,351 +0,0 @@ -#include "service/grpc/server/include/grpc_dexhand_service.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "cmvr/config/device_manager_config/device_manager_config.pb.h" -#include "manager/control_authority_manager/include/control_authority_manager.h" -#include "manager/device_manager/include/device_manager.h" -#include "service/grpc/server/include/media_activity_coordinator.h" -#include "service/grpc/stop_all/include/stop_all_admission_gate.h" - -namespace cmvr::service { -namespace { - -using namespace std::chrono_literals; - -class FakeDexHand final : public device::AbstractDexHand { -public: - FakeDexHand() { - id_ = "test-dexhand"; - sensor_points_[0] = TactilePoint::fromFz(42); - } - - std::string typeName() const override { return "FakeDexHand"; } - Status state() const override { return Status::STREAMING; } - std::string lastError() const override { return {}; } - - bool stopOperationalActivity() override { - ++stop_operational_calls; - return true; - } - - bool resumeOperationalActivity() override { - ++resume_operational_calls; - return true; - } - - void setAngles(const std::vector&) override { - ++set_angle_calls; - std::unique_lock lock(command_mutex_); - command_entered_ = true; - command_cv_.notify_all(); - command_cv_.wait(lock, [this] { return !block_angle_command_; }); - } - - void setPositions(const std::vector&) override { - ++set_position_calls; - } - - void setVelocities(const std::vector&) override { - ++set_speed_calls; - } - - void setForce(const std::vector&) override { - ++set_force_calls; - } - - void setPresetAct(int) override { - ++set_preset_calls; - } - - void setTactilePollingRegions( - const std::vector&) override { - ++configure_sensor_calls; - } - - std::vector getSensorData() override { - ++sensor_read_calls; - return {sensorRegion()}; - } - - TactileRegionData getSensorData( - FingerType finger, TactileRegion region) override { - return finger == FingerType::INDEX && region == TactileRegion::TIP - ? sensorRegion() - : TactileRegionData{}; - } - - ResultantForce getResultantForce( - FingerType finger, TactileRegion region) override { - return finger == FingerType::INDEX && region == TactileRegion::TIP - ? sensor_points_[0] - : ResultantForce{}; - } - - void blockAngleCommand() { - std::lock_guard lock(command_mutex_); - block_angle_command_ = true; - command_entered_ = false; - } - - bool waitForAngleCommand(const std::chrono::milliseconds timeout) { - std::unique_lock lock(command_mutex_); - return command_cv_.wait_for( - lock, timeout, [this] { return command_entered_; }); - } - - void releaseAngleCommand() { - { - std::lock_guard lock(command_mutex_); - block_angle_command_ = false; - } - command_cv_.notify_all(); - } - - std::atomic set_position_calls{0}; - std::atomic set_angle_calls{0}; - std::atomic set_force_calls{0}; - std::atomic set_speed_calls{0}; - std::atomic set_preset_calls{0}; - std::atomic configure_sensor_calls{0}; - std::atomic sensor_read_calls{0}; - std::atomic stop_operational_calls{0}; - std::atomic resume_operational_calls{0}; - -private: - TactileRegionData sensorRegion() { - return TactileRegionData( - FingerType::INDEX, - TactileRegion::TIP, - TactileMatrixView{sensor_points_.data(), 1, 1}, - "fake-tactile"); - } - - std::array sensor_points_{}; - std::mutex command_mutex_; - std::condition_variable command_cv_; - bool block_angle_command_{false}; - bool command_entered_{false}; -}; - -class GrpcDexHandServiceTest : public ::testing::Test { -protected: - void SetUp() override { - device::DeviceManager::destroyInstance(); - control::ControlAuthorityManager::instance().clear(); - globalStopAllAdmissionGate().clearForTesting(); - config::DeviceManagerConfig config; - auto& manager = device::DeviceManager::getInstance(config); - hand_ = std::make_shared(); - manager.registerDevice(hand_); - service_ = std::make_unique(); - } - - void TearDown() override { - hand_->releaseAngleCommand(); - if (server_) { - server_->Shutdown(); - server_->Wait(); - } - stub_.reset(); - service_.reset(); - hand_.reset(); - if (!socket_path_.empty()) { - std::remove(socket_path_.c_str()); - } - device::DeviceManager::destroyInstance(); - control::ControlAuthorityManager::instance().clear(); - globalStopAllAdmissionGate().clearForTesting(); - } - - bool startGrpcServer() { - socket_path_ = - "/tmp/cmvr_dexhand_service_test_" + - std::to_string(static_cast(::getpid())) + ".sock"; - std::remove(socket_path_.c_str()); - const std::string address = "unix:" + socket_path_; - grpc::ServerBuilder builder; - builder.AddListeningPort( - address, - grpc::InsecureServerCredentials()); - builder.RegisterService(service_.get()); - server_ = builder.BuildAndStart(); - if (!server_) { - return false; - } - stub_ = api::DexHandService::NewStub(grpc::CreateChannel( - address, - grpc::InsecureChannelCredentials())); - return stub_ != nullptr; - } - - static api::GetSensorDataStreamCommand_Request sensorStreamRequest() { - api::GetSensorDataStreamCommand_Request request; - request.mutable_header()->set_device_id("test-dexhand"); - return request; - } - - std::shared_ptr hand_; - std::unique_ptr service_; - std::unique_ptr server_; - std::unique_ptr stub_; - std::string socket_path_; -}; - -TEST_F(GrpcDexHandServiceTest, StopAllGateRejectsEveryControlCommand) { - const auto ticket = globalStopAllAdmissionGate().beginStopAll(); - ASSERT_TRUE(ticket.valid()); - - grpc::ServerContext position_context; - api::SetDexHandPositionsCommand_Request position_request; - api::SetDexHandPositionsCommand_Feedback position_response; - position_request.mutable_header()->set_device_id("test-dexhand"); - EXPECT_TRUE(service_->SetDexHandPos( - &position_context, &position_request, &position_response).ok()); - EXPECT_FALSE(position_response.header().success()); - - grpc::ServerContext angle_context; - api::SetDexHandAnglesCommand_Request angle_request; - api::SetDexHandAnglesCommand_Feedback angle_response; - angle_request.mutable_header()->set_device_id("test-dexhand"); - EXPECT_TRUE(service_->SetDexHandAngle( - &angle_context, &angle_request, &angle_response).ok()); - EXPECT_FALSE(angle_response.header().success()); - - grpc::ServerContext force_context; - api::SetDexHandForceCommand_Request force_request; - api::SetDexHandForceCommand_Feedback force_response; - force_request.mutable_header()->set_device_id("test-dexhand"); - EXPECT_TRUE(service_->SetDexHandForce( - &force_context, &force_request, &force_response).ok()); - EXPECT_FALSE(force_response.header().success()); - - grpc::ServerContext speed_context; - api::SetDexHandSpeedCommand_Request speed_request; - api::SetDexHandSpeedCommand_Feedback speed_response; - speed_request.mutable_header()->set_device_id("test-dexhand"); - EXPECT_TRUE(service_->SetDexHandSpeed( - &speed_context, &speed_request, &speed_response).ok()); - EXPECT_FALSE(speed_response.header().success()); - - grpc::ServerContext preset_context; - api::SetDexHandPresetActCommand_Request preset_request; - api::SetDexHandPresetActCommand_Feedback preset_response; - preset_request.mutable_header()->set_device_id("test-dexhand"); - EXPECT_TRUE(service_->SetDexHandPresetAct( - &preset_context, &preset_request, &preset_response).ok()); - EXPECT_FALSE(preset_response.header().success()); - - EXPECT_EQ(hand_->set_position_calls.load(), 0); - EXPECT_EQ(hand_->set_angle_calls.load(), 0); - EXPECT_EQ(hand_->set_force_calls.load(), 0); - EXPECT_EQ(hand_->set_speed_calls.load(), 0); - EXPECT_EQ(hand_->set_preset_calls.load(), 0); - EXPECT_EQ(hand_->resume_operational_calls.load(), 0); - EXPECT_TRUE(globalStopAllAdmissionGate().finishStopAll(ticket, true)); -} - -TEST_F(GrpcDexHandServiceTest, - SafetyPreemptionCannotPassAnExecutingDeviceDispatch) { - hand_->blockAngleCommand(); - grpc::ServerContext context; - api::SetDexHandAnglesCommand_Request request; - api::SetDexHandAnglesCommand_Feedback response; - request.mutable_header()->set_device_id("test-dexhand"); - request.add_values()->set_value(0.5F); - - auto rpc = std::async(std::launch::async, [&] { - return service_->SetDexHandAngle(&context, &request, &response); - }); - ASSERT_TRUE(hand_->waitForAngleCommand(1s)); - - auto& authority = control::ControlAuthorityManager::instance(); - auto safety_result = authority.preemptAcquire( - "test-dexhand", - "test-stop-all", - std::chrono::duration_cast< - control::ControlAuthorityManager::Duration>(1h)); - ASSERT_TRUE(safety_result.acquired); - const auto safety_token = safety_result.token; - auto dispatch_fence = std::async(std::launch::async, - [&authority, safety_token] { - return authority.waitForPreemptedRelease(safety_token, 1s); - }); - EXPECT_EQ( - dispatch_fence.wait_for(50ms), std::future_status::timeout); - - hand_->releaseAngleCommand(); - ASSERT_EQ(rpc.wait_for(1s), std::future_status::ready); - EXPECT_TRUE(rpc.get().ok()); - EXPECT_TRUE(response.header().success()); - ASSERT_EQ(dispatch_fence.wait_for(1s), std::future_status::ready); - EXPECT_TRUE(dispatch_fence.get()); - authority.release(safety_token); -} - -TEST_F(GrpcDexHandServiceTest, - StopAllCancelsOldSensorStreamAndARecoveredStreamResumesActivity) { - ASSERT_TRUE(startGrpcServer()); - grpc::ClientContext context; - context.set_deadline(std::chrono::system_clock::now() + 3s); - auto stream = stub_->GetSensorDataStream(&context); - ASSERT_TRUE(stream->Write(sensorStreamRequest())); - - api::GetSensorDataStreamCommand_Feedback feedback; - ASSERT_TRUE(stream->Read(&feedback)); - ASSERT_TRUE(feedback.header().success()); - ASSERT_GE(hand_->sensor_read_calls.load(), 1); - - const auto admission_ticket = globalStopAllAdmissionGate().beginStopAll(); - const auto media_ticket = globalMediaActivityCoordinator().beginStopAll(); - ASSERT_TRUE(admission_ticket.valid()); - ASSERT_TRUE(media_ticket.valid()); - - stream->WritesDone(); - while (stream->Read(&feedback)) { - } - const auto status = stream->Finish(); - EXPECT_TRUE( - status.ok() || status.error_code() == grpc::StatusCode::CANCELLED); - EXPECT_TRUE(globalMediaActivityCoordinator().waitForStopped( - media_ticket, 1s)); - const int stopped_stream_reads = hand_->sensor_read_calls.load(); - std::this_thread::sleep_for(50ms); - EXPECT_EQ(hand_->sensor_read_calls.load(), stopped_stream_reads); - EXPECT_TRUE(globalMediaActivityCoordinator().finishStopAll( - media_ticket, true)); - EXPECT_TRUE(globalStopAllAdmissionGate().finishStopAll( - admission_ticket, true)); - - grpc::ClientContext resumed_context; - resumed_context.set_deadline(std::chrono::system_clock::now() + 3s); - auto resumed = stub_->GetSensorDataStream(&resumed_context); - ASSERT_TRUE(resumed->Write(sensorStreamRequest())); - ASSERT_TRUE(resumed->Read(&feedback)); - EXPECT_TRUE(feedback.header().success()); - EXPECT_GT(hand_->sensor_read_calls.load(), stopped_stream_reads); - EXPECT_GE(hand_->resume_operational_calls.load(), 2); - resumed_context.TryCancel(); - resumed->WritesDone(); - while (resumed->Read(&feedback)) { - } - (void)resumed->Finish(); -} - -} // namespace -} // namespace cmvr::service diff --git a/cmvr-es/service/grpc/server/tests/grpc_error_logging_interceptor_test.cpp b/cmvr-es/service/grpc/server/tests/grpc_error_logging_interceptor_test.cpp deleted file mode 100644 index 2287e2d2..00000000 --- a/cmvr-es/service/grpc/server/tests/grpc_error_logging_interceptor_test.cpp +++ /dev/null @@ -1,864 +0,0 @@ -#include "service/grpc/server/include/grpc_error_logging_interceptor.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "cmvr/api/agv_service.grpc.pb.h" -#include "cmvr/api/camera_service.grpc.pb.h" -#include "cmvr/api/test_service.grpc.pb.h" -#include "common/base/logging/logger.h" - -namespace cmvr::service { -namespace { - -std::atomic g_socket_sequence{0}; - -void setRpcDeadline(grpc::ClientContext& context) -{ - context.set_deadline( - std::chrono::system_clock::now() + std::chrono::seconds(3)); -} - -grpc::ByteBuffer byteBuffer(const std::string& payload) -{ - const grpc::Slice slice(payload); - return grpc::ByteBuffer(&slice, 1); -} - -std::string byteBufferString(const grpc::ByteBuffer& buffer) -{ - std::vector slices; - EXPECT_TRUE(buffer.Dump(&slices).ok()); - std::string payload; - for (const auto& slice : slices) { - payload.append( - reinterpret_cast(slice.begin()), slice.size()); - } - return payload; -} - -grpc::Status rawUnaryCall(const std::shared_ptr& channel, - const std::string& method, - const std::string& request_payload, - grpc::ByteBuffer& response) -{ - grpc::ClientContext context; - setRpcDeadline(context); - const auto request = byteBuffer(request_payload); - const grpc::internal::RpcMethod rpc_method( - method.c_str(), grpc::internal::RpcMethod::NORMAL_RPC); - return grpc::internal::BlockingUnaryCall( - channel.get(), rpc_method, &context, request, &response); -} - -class ErrorLoggingTestService final : public api::TestService::Service { -public: - grpc::Status Call(grpc::ServerContext* context, - const api::TestReqeust* request, - api::TestResponse* response) override - { - if (request->data() == "grpc-error") { - return grpc::Status( - grpc::StatusCode::INTERNAL, "transport sentinel"); - } - if (request->data() == "cancelled") { - return grpc::Status( - grpc::StatusCode::CANCELLED, "client closed stream"); - } - if (request->data() == "server-cancel") { - context->TryCancel(); - return grpc::Status::OK; - } - if (request->data() == "client-cancel") { - { - std::lock_guard lock(cancel_mutex_); - cancel_started_ = true; - } - cancel_started_condition_.notify_all(); - const auto timeout = - std::chrono::steady_clock::now() + std::chrono::seconds(3); - while (!context->IsCancelled() && - std::chrono::steady_clock::now() < timeout) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - return grpc::Status::OK; - } - response->set_data("ok"); - return grpc::Status::OK; - } - - bool waitForCancelableCall() - { - std::unique_lock lock(cancel_mutex_); - return cancel_started_condition_.wait_for( - lock, std::chrono::seconds(3), - [this] { return cancel_started_; }); - } - -private: - std::mutex cancel_mutex_; - std::condition_variable cancel_started_condition_; - bool cancel_started_{false}; -}; - -class ErrorLoggingAgvService final : public api::AgvService::Service { -public: - grpc::Status emergencyStop( - grpc::ServerContext*, - const api::CommandHeader_Request* request, - api::CommandHeader_Feedback* response) override - { - if (request->device_id() == "missing") { - response->set_success(false); - response->set_error_message("missing sentinel"); - return grpc::Status( - grpc::StatusCode::NOT_FOUND, "missing sentinel"); - } - response->set_success(false); - response->set_error_message("direct sentinel"); - return grpc::Status::OK; - } - - grpc::Status streamMap( - grpc::ServerContext*, - const api::AgvMapStreamCommand_Request* request, - grpc::ServerWriter* writer) override - { - const auto write_failure = [writer](const std::string& detail) { - api::AgvMapStreamCommand_Feedback response; - response.mutable_header()->set_success(false); - response.mutable_header()->set_error_message(detail); - return writer->Write(response); - }; - - if (request->resume_token() == "multiple") { - write_failure("first stream sentinel"); - write_failure("second stream sentinel"); - return grpc::Status::OK; - } - if (request->resume_token() == "hold") { - write_failure("immediate stream sentinel"); - std::unique_lock lock(stream_mutex_); - stream_released_.wait_for( - lock, std::chrono::seconds(3), - [this] { return release_stream_; }); - return grpc::Status::OK; - } - if (request->resume_token() == "different") { - write_failure("application stream sentinel"); - return grpc::Status( - grpc::StatusCode::INTERNAL, "status stream sentinel"); - } - if (request->resume_token() == "long-different") { - const std::string common_prefix(1100, 'x'); - write_failure(common_prefix + " application"); - return grpc::Status( - grpc::StatusCode::INTERNAL, - common_prefix + " status"); - } - - write_failure("stream sentinel"); - return grpc::Status( - grpc::StatusCode::INTERNAL, "stream sentinel"); - } - - void releaseHeldStream() - { - { - std::lock_guard lock(stream_mutex_); - release_stream_ = true; - } - stream_released_.notify_all(); - } - -private: - std::mutex stream_mutex_; - std::condition_variable stream_released_; - bool release_stream_{false}; -}; - -class ErrorLoggingCameraService final : public api::CameraService::Service { -public: - grpc::Status StartCamera( - grpc::ServerContext*, - const api::StartCameraCommand_Request*, - api::StartCameraCommand_Feedback* response) override - { - response->mutable_header()->set_success(false); - response->mutable_header()->set_error_message("nested sentinel"); - return grpc::Status::OK; - } - - grpc::Status GetRGBImage( - grpc::ServerContext*, - const api::GetRGBImageCommand_Request*, - api::GetRGBImageCommand_Feedback* response) override - { - response->mutable_header()->set_success(true); - response->mutable_color_frame()->set_data( - std::string(2 * 1024 * 1024, 'x')); - return grpc::Status::OK; - } -}; - -class RawCameraService final - : public api::CameraService::WithRawCallbackMethod_StartCamera< - api::CameraService::Service> { -public: - explicit RawCameraService(std::string response) - : response_(std::move(response)) - { - } - - grpc::ServerUnaryReactor* StartCamera( - grpc::CallbackServerContext* context, - const grpc::ByteBuffer*, - grpc::ByteBuffer* response) override - { - *response = byteBuffer(response_); - auto* reactor = context->DefaultReactor(); - reactor->Finish(grpc::Status::OK); - return reactor; - } - -private: - std::string response_; -}; - -struct RawCallResult { - grpc::Status status; - std::vector records; - std::string response; -}; - -class ScopedServer final { -public: - ScopedServer(std::unique_ptr server, - std::string socket_path = {}) - : server_(std::move(server)), socket_path_(std::move(socket_path)) - { - } - - ~ScopedServer() - { - if (server_) { - server_->Shutdown(); - server_->Wait(); - } - if (!socket_path_.empty()) { - std::remove(socket_path_.c_str()); - } - } - - grpc::Server* get() const { return server_.get(); } - -private: - std::unique_ptr server_; - std::string socket_path_; -}; - -class ScopedSocket final { -public: - explicit ScopedSocket(std::string path) : path_(std::move(path)) - { - std::remove(path_.c_str()); - } - - ~ScopedSocket() { std::remove(path_.c_str()); } - -private: - std::string path_; -}; - -RawCallResult callRawStartCamera(const std::string& response_payload) -{ - std::mutex records_mutex; - std::vector records; - RawCameraService service(response_payload); - grpc::ServerBuilder builder; - const std::string address = - "unix:/tmp/cmvr_grpc_error_logging_raw_" + - std::to_string(static_cast(::getpid())) + "_" + - std::to_string(g_socket_sequence.fetch_add(1U)) + ".sock"; - const std::string socket_path = address.substr(5); - ScopedSocket socket(socket_path); - builder.AddListeningPort(address, grpc::InsecureServerCredentials()); - builder.RegisterService(&service); - std::vector> factories; - factories.emplace_back(makeGrpcErrorLoggingInterceptorFactory( - [&records, &records_mutex](const GrpcFailureRecord& record) { - std::lock_guard lock(records_mutex); - records.push_back(record); - })); - builder.experimental().SetInterceptorCreators(std::move(factories)); - ScopedServer server(builder.BuildAndStart()); - EXPECT_NE(server.get(), nullptr); - if (server.get() == nullptr) { - return {}; - } - - const auto channel = grpc::CreateChannel( - address, grpc::InsecureChannelCredentials()); - api::StartCameraCommand_Request request; - grpc::ByteBuffer response; - const auto status = rawUnaryCall( - channel, "/cmvr.api.CameraService/StartCamera", - request.SerializeAsString(), response); - std::lock_guard lock(records_mutex); - return {status, records, byteBufferString(response)}; -} - -class GrpcErrorLoggingInterceptorTest : public testing::Test { -protected: - void SetUp() override - { - grpc::ServerBuilder builder; - socket_path_ = - "/tmp/cmvr_grpc_error_logging_interceptor_test_" + - std::to_string(static_cast(::getpid())) + "_" + - std::to_string(g_socket_sequence.fetch_add(1U)) + ".sock"; - std::remove(socket_path_.c_str()); - const std::string address = "unix:" + socket_path_; - builder.AddListeningPort( - address, grpc::InsecureServerCredentials()); - builder.RegisterService(&test_service_); - builder.RegisterService(&agv_service_); - builder.RegisterService(&camera_service_); - - std::vector> factories; - factories.emplace_back(makeGrpcErrorLoggingInterceptorFactory( - [this](const GrpcFailureRecord& record) { - { - std::lock_guard lock(records_mutex_); - records_.push_back(record); - } - records_changed_.notify_all(); - })); - builder.experimental().SetInterceptorCreators(std::move(factories)); - server_ = builder.BuildAndStart(); - ASSERT_NE(server_, nullptr); - - const auto channel = grpc::CreateChannel( - address, - grpc::InsecureChannelCredentials()); - test_stub_ = api::TestService::NewStub(channel); - agv_stub_ = api::AgvService::NewStub(channel); - camera_stub_ = api::CameraService::NewStub(channel); - } - - void TearDown() override - { - if (server_) { - server_->Shutdown(); - server_->Wait(); - } - test_stub_.reset(); - agv_stub_.reset(); - camera_stub_.reset(); - if (!socket_path_.empty()) { - std::remove(socket_path_.c_str()); - } - } - - std::vector records() - { - std::lock_guard lock(records_mutex_); - return records_; - } - - std::vector waitForRecords( - const std::size_t count, - const std::chrono::milliseconds timeout = std::chrono::seconds(3)) - { - std::unique_lock lock(records_mutex_); - records_changed_.wait_for( - lock, timeout, [this, count] { return records_.size() >= count; }); - return records_; - } - - ErrorLoggingTestService test_service_; - ErrorLoggingAgvService agv_service_; - ErrorLoggingCameraService camera_service_; - std::unique_ptr server_; - std::unique_ptr test_stub_; - std::unique_ptr agv_stub_; - std::unique_ptr camera_stub_; - std::string socket_path_; - std::mutex records_mutex_; - std::condition_variable records_changed_; - std::vector records_; -}; - -TEST_F(GrpcErrorLoggingInterceptorTest, RecordsNonOkGrpcStatus) -{ - grpc::ClientContext context; - setRpcDeadline(context); - api::TestReqeust request; - api::TestResponse response; - request.set_data("grpc-error"); - - const grpc::Status status = test_stub_->Call(&context, request, &response); - ASSERT_EQ(status.error_code(), grpc::StatusCode::INTERNAL); - - const auto captured = waitForRecords(1U); - ASSERT_EQ(captured.size(), 1U); - EXPECT_EQ(captured.front().kind, GrpcFailureKind::GRPC_STATUS); - EXPECT_EQ(captured.front().method, "/cmvr.api.TestService/Call"); - EXPECT_EQ(captured.front().status_code, grpc::StatusCode::INTERNAL); - EXPECT_EQ(captured.front().severity, GrpcFailureSeverity::ERROR); - EXPECT_EQ(captured.front().detail, "transport sentinel"); -} - -TEST_F(GrpcErrorLoggingInterceptorTest, RecordsDirectFeedbackFailure) -{ - grpc::ClientContext context; - setRpcDeadline(context); - api::CommandHeader_Request request; - api::CommandHeader_Feedback response; - - ASSERT_TRUE(agv_stub_->emergencyStop(&context, request, &response).ok()); - ASSERT_FALSE(response.success()); - - const auto captured = waitForRecords(1U); - ASSERT_EQ(captured.size(), 1U); - EXPECT_EQ(captured.front().kind, GrpcFailureKind::APPLICATION); - EXPECT_EQ(captured.front().method, "/cmvr.api.AgvService/emergencyStop"); - EXPECT_EQ(captured.front().status_code, grpc::StatusCode::OK); - EXPECT_EQ(captured.front().severity, GrpcFailureSeverity::ERROR); - EXPECT_EQ(captured.front().detail, "direct sentinel"); -} - -TEST_F(GrpcErrorLoggingInterceptorTest, RecordsCancellationAsWarning) -{ - grpc::ClientContext context; - setRpcDeadline(context); - api::TestReqeust request; - api::TestResponse response; - request.set_data("cancelled"); - - const grpc::Status status = test_stub_->Call(&context, request, &response); - ASSERT_EQ(status.error_code(), grpc::StatusCode::CANCELLED); - - const auto captured = waitForRecords(1U); - ASSERT_EQ(captured.size(), 1U); - EXPECT_EQ(captured.front().kind, GrpcFailureKind::GRPC_STATUS); - EXPECT_EQ(captured.front().severity, GrpcFailureSeverity::WARNING); - EXPECT_EQ(captured.front().detail, "client closed stream"); -} - -TEST(GrpcErrorLoggingInterceptorFileTest, WarningStatusIsFlushedToFile) -{ - std::array directory_pattern{}; - const std::string pattern = "/tmp/cmvr-grpc-log-test-XXXXXX"; - std::copy(pattern.begin(), pattern.end(), directory_pattern.begin()); - const char* created = ::mkdtemp(directory_pattern.data()); - ASSERT_NE(created, nullptr); - const std::filesystem::path directory(created); - - struct Cleanup { - ~Cleanup() - { - logging::shutdownLogging(); - if (!socket_path.empty()) { - std::remove(socket_path.c_str()); - } - std::error_code error; - std::filesystem::remove_all(directory, error); - } - - std::filesystem::path directory; - std::string socket_path; - } cleanup{directory, {}}; - - config::LoggerConfig config; - config.set_minimum_level(config::LOG_LEVEL_WARNING); - config.set_directory(directory.string()); - config.set_flush_interval_seconds(3600); - auto* warning_route = config.add_routes(); - warning_route->set_level(config::LOG_LEVEL_WARNING); - warning_route->set_file(true); - ASSERT_TRUE(logging::initLogging(config, "grpc_log_test", directory)); - - ErrorLoggingTestService service; - grpc::ServerBuilder builder; - const std::string socket_path = - "/tmp/cmvr_grpc_error_logging_file_test_" + - std::to_string(static_cast(::getpid())) + "_" + - std::to_string(g_socket_sequence.fetch_add(1U)) + ".sock"; - cleanup.socket_path = socket_path; - ScopedSocket socket(socket_path); - const std::string address = "unix:" + socket_path; - builder.AddListeningPort(address, grpc::InsecureServerCredentials()); - builder.RegisterService(&service); - std::vector> factories; - factories.emplace_back(makeGrpcErrorLoggingInterceptorFactory()); - builder.experimental().SetInterceptorCreators(std::move(factories)); - ScopedServer server(builder.BuildAndStart()); - ASSERT_NE(server.get(), nullptr); - - const auto channel = grpc::CreateChannel( - address, grpc::InsecureChannelCredentials()); - auto stub = api::TestService::NewStub(channel); - grpc::ClientContext context; - setRpcDeadline(context); - api::TestReqeust request; - api::TestResponse response; - request.set_data("cancelled"); - const grpc::Status status = stub->Call(&context, request, &response); - ASSERT_EQ(status.error_code(), grpc::StatusCode::CANCELLED); - - std::ifstream input(directory / "grpc_log_test.log"); - const std::string contents{ - std::istreambuf_iterator(input), - std::istreambuf_iterator()}; - EXPECT_NE(contents.find("/cmvr.api.TestService/Call"), std::string::npos); - EXPECT_NE(contents.find("code=1(CANCELLED)"), std::string::npos); - EXPECT_NE(contents.find("client closed stream"), std::string::npos); - -} - -TEST_F(GrpcErrorLoggingInterceptorTest, RecordsServerCancellationReturnedAsOk) -{ - grpc::ClientContext context; - setRpcDeadline(context); - api::TestReqeust request; - api::TestResponse response; - request.set_data("server-cancel"); - - const grpc::Status status = test_stub_->Call(&context, request, &response); - ASSERT_EQ(status.error_code(), grpc::StatusCode::CANCELLED); - - // TryCancel is best effort: the final status may be intercepted before - // the cancellation hook. Either way, the interceptor must not recurse or - // emit duplicate records. - const auto captured = waitForRecords(1U, std::chrono::milliseconds(50)); - ASSERT_LE(captured.size(), 1U); - if (!captured.empty()) { - EXPECT_EQ(captured.front().kind, GrpcFailureKind::GRPC_STATUS); - EXPECT_EQ(captured.front().status_code, grpc::StatusCode::CANCELLED); - EXPECT_EQ(captured.front().severity, GrpcFailureSeverity::WARNING); - EXPECT_EQ( - captured.front().detail, - "RPC cancellation was requested by the edge server before completion"); - } -} - -TEST_F(GrpcErrorLoggingInterceptorTest, RecordsClientCancellation) -{ - grpc::ClientContext context; - setRpcDeadline(context); - api::TestReqeust request; - api::TestResponse response; - request.set_data("client-cancel"); - - grpc::Status status; - std::thread call([&] { - status = test_stub_->Call(&context, request, &response); - }); - const bool call_started = test_service_.waitForCancelableCall(); - context.TryCancel(); - call.join(); - - ASSERT_TRUE(call_started); - ASSERT_EQ(status.error_code(), grpc::StatusCode::CANCELLED); - const auto captured = waitForRecords(1U); - ASSERT_EQ(captured.size(), 1U); - EXPECT_EQ(captured.front().kind, GrpcFailureKind::GRPC_STATUS); - EXPECT_EQ(captured.front().status_code, grpc::StatusCode::CANCELLED); - EXPECT_EQ(captured.front().severity, GrpcFailureSeverity::WARNING); - EXPECT_EQ( - captured.front().detail, - "RPC was cancelled by the client or transport before completion"); -} - -TEST_F(GrpcErrorLoggingInterceptorTest, - RecordsStatusWhenNonOkSuppressesUnaryResponse) -{ - grpc::ClientContext context; - setRpcDeadline(context); - api::CommandHeader_Request request; - api::CommandHeader_Feedback response; - request.set_device_id("missing"); - - const grpc::Status status = - agv_stub_->emergencyStop(&context, request, &response); - ASSERT_EQ(status.error_code(), grpc::StatusCode::NOT_FOUND); - - const auto captured = waitForRecords(1U); - ASSERT_EQ(captured.size(), 1U); - EXPECT_EQ(captured.front().kind, GrpcFailureKind::GRPC_STATUS); - EXPECT_EQ(captured.front().status_code, grpc::StatusCode::NOT_FOUND); - EXPECT_EQ(captured.front().severity, GrpcFailureSeverity::WARNING); - EXPECT_EQ(captured.front().detail, "missing sentinel"); -} - -TEST_F(GrpcErrorLoggingInterceptorTest, RecordsNestedFeedbackFailure) -{ - grpc::ClientContext context; - setRpcDeadline(context); - api::StartCameraCommand_Request request; - api::StartCameraCommand_Feedback response; - - ASSERT_TRUE(camera_stub_->StartCamera(&context, request, &response).ok()); - ASSERT_FALSE(response.header().success()); - - const auto captured = waitForRecords(1U); - ASSERT_EQ(captured.size(), 1U); - EXPECT_EQ(captured.front().kind, GrpcFailureKind::APPLICATION); - EXPECT_EQ(captured.front().method, "/cmvr.api.CameraService/StartCamera"); - EXPECT_EQ(captured.front().detail, "nested sentinel"); -} - -TEST_F(GrpcErrorLoggingInterceptorTest, - RecordsStreamingResponseAndFinalNonOkStatus) -{ - grpc::ClientContext context; - setRpcDeadline(context); - api::AgvMapStreamCommand_Request request; - auto reader = agv_stub_->streamMap(&context, request); - api::AgvMapStreamCommand_Feedback response; - - ASSERT_TRUE(reader->Read(&response)); - ASSERT_FALSE(response.header().success()); - const grpc::Status status = reader->Finish(); - ASSERT_EQ(status.error_code(), grpc::StatusCode::INTERNAL); - - const auto captured = waitForRecords(2U); - ASSERT_EQ(captured.size(), 2U); - EXPECT_EQ(captured[0].kind, GrpcFailureKind::APPLICATION); - EXPECT_EQ(captured[0].method, "/cmvr.api.AgvService/streamMap"); - EXPECT_EQ(captured[0].status_code, grpc::StatusCode::OK); - EXPECT_EQ(captured[0].severity, GrpcFailureSeverity::ERROR); - EXPECT_EQ(captured[0].detail, "stream sentinel"); - EXPECT_EQ(captured[1].kind, GrpcFailureKind::GRPC_STATUS); - EXPECT_EQ(captured[1].status_code, grpc::StatusCode::INTERNAL); - EXPECT_EQ(captured[1].severity, GrpcFailureSeverity::ERROR); - EXPECT_EQ(captured[1].detail, "stream sentinel"); -} - -TEST_F(GrpcErrorLoggingInterceptorTest, - RecordsStreamingFailureBeforeTheStreamFinishes) -{ - grpc::ClientContext context; - setRpcDeadline(context); - api::AgvMapStreamCommand_Request request; - request.set_resume_token("hold"); - auto reader = agv_stub_->streamMap(&context, request); - api::AgvMapStreamCommand_Feedback response; - - const bool read = reader->Read(&response); - const auto captured_before_finish = waitForRecords(1U); - agv_service_.releaseHeldStream(); - const grpc::Status status = reader->Finish(); - - ASSERT_TRUE(read); - ASSERT_TRUE(status.ok()); - ASSERT_EQ(captured_before_finish.size(), 1U); - EXPECT_EQ( - captured_before_finish.front().detail, - "immediate stream sentinel"); -} - -TEST_F(GrpcErrorLoggingInterceptorTest, - RecordsEveryStreamingFailureResponse) -{ - grpc::ClientContext context; - setRpcDeadline(context); - api::AgvMapStreamCommand_Request request; - request.set_resume_token("multiple"); - auto reader = agv_stub_->streamMap(&context, request); - api::AgvMapStreamCommand_Feedback response; - - ASSERT_TRUE(reader->Read(&response)); - ASSERT_TRUE(reader->Read(&response)); - ASSERT_TRUE(reader->Finish().ok()); - - const auto captured = waitForRecords(2U); - ASSERT_EQ(captured.size(), 2U); - EXPECT_EQ(captured[0].detail, "first stream sentinel"); - EXPECT_EQ(captured[1].detail, "second stream sentinel"); -} - -TEST_F(GrpcErrorLoggingInterceptorTest, - PreservesDifferentResponseAndStatusErrors) -{ - grpc::ClientContext context; - setRpcDeadline(context); - api::AgvMapStreamCommand_Request request; - request.set_resume_token("different"); - auto reader = agv_stub_->streamMap(&context, request); - api::AgvMapStreamCommand_Feedback response; - - ASSERT_TRUE(reader->Read(&response)); - const grpc::Status status = reader->Finish(); - ASSERT_EQ(status.error_code(), grpc::StatusCode::INTERNAL); - - const auto captured = waitForRecords(2U); - ASSERT_EQ(captured.size(), 2U); - EXPECT_EQ(captured[0].kind, GrpcFailureKind::APPLICATION); - EXPECT_EQ(captured[0].detail, "application stream sentinel"); - EXPECT_EQ(captured[1].kind, GrpcFailureKind::GRPC_STATUS); - EXPECT_EQ(captured[1].status_code, grpc::StatusCode::INTERNAL); - EXPECT_EQ(captured[1].detail, "status stream sentinel"); -} - -TEST_F(GrpcErrorLoggingInterceptorTest, - DoesNotDeduplicateLongErrorsByTruncatedPrefix) -{ - grpc::ClientContext context; - setRpcDeadline(context); - api::AgvMapStreamCommand_Request request; - request.set_resume_token("long-different"); - auto reader = agv_stub_->streamMap(&context, request); - api::AgvMapStreamCommand_Feedback response; - - ASSERT_TRUE(reader->Read(&response)); - const grpc::Status status = reader->Finish(); - ASSERT_EQ(status.error_code(), grpc::StatusCode::INTERNAL); - - const auto captured = waitForRecords(2U); - ASSERT_EQ(captured.size(), 2U); - EXPECT_EQ(captured[0].kind, GrpcFailureKind::APPLICATION); - EXPECT_EQ(captured[1].kind, GrpcFailureKind::GRPC_STATUS); -} - -TEST(GrpcErrorLoggingInterceptorWireTest, RequiresHeaderAsFirstField) -{ - api::CommandHeader_Feedback header; - header.set_success(false); - header.set_error_message("out-of-order sentinel"); - std::string payload; - payload.push_back(static_cast(0x12)); - payload.push_back(static_cast(0x01)); - payload.push_back('x'); - payload.push_back(static_cast(0x0a)); - payload.push_back(static_cast(header.ByteSizeLong())); - payload.append(header.SerializeAsString()); - - const auto result = callRawStartCamera(payload); - - ASSERT_TRUE(result.status.ok()); - ASSERT_EQ(result.response, payload); - ASSERT_EQ(result.records.size(), 1U); - EXPECT_EQ( - result.records.front().kind, - GrpcFailureKind::MALFORMED_RESPONSE); -} - -TEST(GrpcErrorLoggingInterceptorWireTest, DoesNotScanPayloadAfterHeader) -{ - api::CommandHeader_Feedback header; - header.set_success(false); - header.set_error_message("leading header sentinel"); - std::string payload; - payload.push_back(static_cast(0x0a)); - payload.push_back(static_cast(header.ByteSizeLong())); - payload.append(header.SerializeAsString()); - payload.push_back(static_cast(0x12)); - payload.push_back(static_cast(0xff)); - payload.append(2U * 1024U * 1024U, 'x'); - - const auto result = callRawStartCamera(payload); - - ASSERT_TRUE(result.status.ok()); - ASSERT_EQ(result.records.size(), 1U); - EXPECT_EQ(result.records.front().kind, GrpcFailureKind::APPLICATION); - EXPECT_EQ(result.records.front().detail, "leading header sentinel"); -} - -TEST(GrpcErrorLoggingInterceptorWireTest, TreatsExplicitEmptyHeaderAsFailure) -{ - const std::string payload{ - static_cast(0x0a), static_cast(0x00)}; - - const auto result = callRawStartCamera(payload); - - ASSERT_TRUE(result.status.ok()); - ASSERT_EQ(result.records.size(), 1U); - EXPECT_EQ(result.records.front().kind, GrpcFailureKind::APPLICATION); - EXPECT_EQ( - result.records.front().detail, - "operation failed without an error message"); -} - -TEST(GrpcErrorLoggingInterceptorWireTest, RejectsInvalidHeaderWireType) -{ - const std::string payload{ - static_cast(0x08), static_cast(0x01)}; - - const auto result = callRawStartCamera(payload); - - ASSERT_TRUE(result.status.ok()); - ASSERT_EQ(result.records.size(), 1U); - EXPECT_EQ( - result.records.front().kind, - GrpcFailureKind::MALFORMED_RESPONSE); -} - -TEST(GrpcErrorLoggingInterceptorWireTest, RejectsInvalidUtf8ErrorMessage) -{ - const std::string payload{ - static_cast(0x0a), static_cast(0x04), - static_cast(0x12), static_cast(0x02), - static_cast(0xc3), static_cast(0x28)}; - - const auto result = callRawStartCamera(payload); - - ASSERT_TRUE(result.status.ok()); - ASSERT_EQ(result.records.size(), 1U); - EXPECT_EQ( - result.records.front().kind, - GrpcFailureKind::MALFORMED_RESPONSE); -} - -TEST_F(GrpcErrorLoggingInterceptorTest, DoesNotRecordSuccessfulLargeResponse) -{ - grpc::ClientContext context; - setRpcDeadline(context); - api::GetRGBImageCommand_Request request; - api::GetRGBImageCommand_Feedback response; - - ASSERT_TRUE(camera_stub_->GetRGBImage(&context, request, &response).ok()); - ASSERT_TRUE(response.header().success()); - ASSERT_EQ(response.color_frame().data().size(), 2U * 1024U * 1024U); - EXPECT_TRUE(records().empty()); -} - -TEST_F(GrpcErrorLoggingInterceptorTest, IgnoresSuccessfulResponseWithoutHeader) -{ - grpc::ClientContext context; - setRpcDeadline(context); - api::TestReqeust request; - api::TestResponse response; - request.set_data("ok"); - - ASSERT_TRUE(test_stub_->Call(&context, request, &response).ok()); - EXPECT_EQ(response.data(), "ok"); - EXPECT_TRUE(records().empty()); -} - -} // namespace -} // namespace cmvr::service diff --git a/cmvr-es/service/grpc/server/tests/grpc_head_service_test.cpp b/cmvr-es/service/grpc/server/tests/grpc_head_service_test.cpp deleted file mode 100644 index 0bef7581..00000000 --- a/cmvr-es/service/grpc/server/tests/grpc_head_service_test.cpp +++ /dev/null @@ -1,391 +0,0 @@ -#include "service/grpc/server/include/grpc_head_service.h" - -#include -#include -#include -#include -#include - -#include -#include - -#include "cmvr/config/device_manager_config/device_manager_config.pb.h" -#include "manager/device_manager/include/device_manager.h" -#include "service/grpc/server/include/media_activity_coordinator.h" -#include "service/grpc/stop_all/include/stop_all_admission_gate.h" - -namespace cmvr::service { -namespace { - -using namespace std::chrono_literals; - -class FakeBiohead final : public device::AbstractBiohead { -public: - FakeBiohead() { id_ = "test-head"; } - - std::string typeName() const override { return "FakeBiohead"; } - bool stop() override - { - ++lifecycle_stop_calls; - return true; - } - - bool setExpressionPoseIfCurrent( - const OperationalToken token, - device::FacialExpressionState&, - double, - double) override - { - return recordIfCurrent(token, set_expression_calls); - } - - bool streamFacialPoseIfCurrent( - const OperationalToken token, - device::FacialExpressionState&, - double, - double) override - { - return recordIfCurrent(token, stream_expression_calls); - } - - bool speakStartIfCurrent(const OperationalToken token) override - { - return recordIfCurrent(token, speak_start_calls); - } - - bool expressionHappyIfCurrent(const OperationalToken token) override - { - return recordIfCurrent(token, happy_calls); - } - - bool expressionSurprisedIfCurrent(const OperationalToken token) override - { - return recordIfCurrent(token, surprise_calls); - } - - bool expressionTiredIfCurrent(const OperationalToken token) override - { - return recordIfCurrent(token, tired_calls); - } - - bool expressionAngryIfCurrent(const OperationalToken token) override - { - return recordIfCurrent(token, angry_calls); - } - - bool expressionSadnessIfCurrent(const OperationalToken token) override - { - return recordIfCurrent(token, sadness_calls); - } - - bool expressionYawnIfCurrent(const OperationalToken token) override - { - return recordIfCurrent(token, yawn_calls); - } - - void speakstop() override { ++speak_stop_calls; } - - bool stopOperationalActivity() override - { - invalidateOperationalActivities_(); - ++operational_stop_calls; - ++speak_stop_calls; - return stop_confirmed.load(std::memory_order_acquire); - } - - bool recordIfCurrent( - const OperationalToken token, - std::atomic& calls) - { - return runIfOperationalActivityCurrent_(token, [&] { ++calls; }); - } - - std::atomic set_expression_calls{0}; - std::atomic stream_expression_calls{0}; - std::atomic speak_start_calls{0}; - std::atomic speak_stop_calls{0}; - std::atomic happy_calls{0}; - std::atomic surprise_calls{0}; - std::atomic tired_calls{0}; - std::atomic angry_calls{0}; - std::atomic sadness_calls{0}; - std::atomic yawn_calls{0}; - std::atomic operational_stop_calls{0}; - std::atomic lifecycle_stop_calls{0}; - std::atomic stop_confirmed{true}; -}; - -class GrpcHeadServiceTest : public ::testing::Test { -protected: - void SetUp() override - { - device::DeviceManager::destroyInstance(); - globalStopAllAdmissionGate().clearForTesting(); - config::DeviceManagerConfig config; - auto& manager = device::DeviceManager::getInstance(config); - head_ = std::make_shared(); - manager.registerDevice(head_); - service_ = std::make_unique(); - } - - void TearDown() override - { - if (server_) { - server_->Shutdown(); - server_->Wait(); - } - stub_.reset(); - service_.reset(); - head_.reset(); - device::DeviceManager::destroyInstance(); - globalStopAllAdmissionGate().clearForTesting(); - } - - bool startGrpcServer() - { - int selected_port = 0; - grpc::ServerBuilder builder; - builder.AddListeningPort( - "127.0.0.1:0", - grpc::InsecureServerCredentials(), - &selected_port); - builder.RegisterService(service_.get()); - server_ = builder.BuildAndStart(); - if (!server_ || selected_port <= 0) { - return false; - } - const std::string address = - "127.0.0.1:" + std::to_string(selected_port); - stub_ = api::BioHeadService::NewStub(grpc::CreateChannel( - address, grpc::InsecureChannelCredentials())); - return stub_ != nullptr; - } - - static api::StreamFacialExpression_Request streamRequest() - { - api::StreamFacialExpression_Request request; - request.mutable_header()->set_device_id("test-head"); - request.mutable_expr()->mutable_jaw()->set_x(0.5F); - return request; - } - - std::shared_ptr head_; - std::unique_ptr service_; - std::unique_ptr server_; - std::unique_ptr stub_; -}; - -TEST_F(GrpcHeadServiceTest, - OperationalStopInvalidatesOldTokenWithoutStoppingLifecycle) -{ - const auto old_token = head_->beginOperationalActivity(); - ASSERT_TRUE(head_->recordIfCurrent(old_token, head_->happy_calls)); - - EXPECT_TRUE(head_->stopOperationalActivity()); - EXPECT_FALSE(head_->recordIfCurrent(old_token, head_->happy_calls)); - EXPECT_EQ(head_->happy_calls.load(), 1); - EXPECT_EQ(head_->operational_stop_calls.load(), 1); - EXPECT_EQ(head_->lifecycle_stop_calls.load(), 0); - - const auto current_token = head_->beginOperationalActivity(); - EXPECT_NE(current_token, old_token); - EXPECT_TRUE(head_->recordIfCurrent(current_token, head_->happy_calls)); - EXPECT_EQ(head_->happy_calls.load(), 2); -} - -TEST_F(GrpcHeadServiceTest, - StopAllGateRejectsMotionButAllowsOperationalStopRpcs) -{ - const auto ticket = globalStopAllAdmissionGate().beginStopAll(); - ASSERT_TRUE(ticket.valid()); - - api::Happy_Request happy_request; - happy_request.mutable_header()->set_device_id("test-head"); - api::Happy_Feedback happy_response; - grpc::ServerContext happy_context; - EXPECT_TRUE(service_->Happy( - &happy_context, &happy_request, &happy_response).ok()); - EXPECT_FALSE(happy_response.header().success()); - EXPECT_EQ(head_->happy_calls.load(), 0); - - api::Surprise_Request surprise_request; - surprise_request.mutable_header()->set_device_id("test-head"); - api::Surprise_Feedback surprise_response; - grpc::ServerContext surprise_context; - EXPECT_TRUE(service_->Surprise( - &surprise_context, &surprise_request, &surprise_response).ok()); - EXPECT_FALSE(surprise_response.header().success()); - EXPECT_EQ(head_->surprise_calls.load(), 0); - - api::ExpressionTired_Request tired_request; - tired_request.mutable_header()->set_device_id("test-head"); - api::ExpressionTired_Feedback tired_response; - grpc::ServerContext tired_context; - EXPECT_TRUE(service_->ExpressionTired( - &tired_context, &tired_request, &tired_response).ok()); - EXPECT_FALSE(tired_response.header().success()); - EXPECT_EQ(head_->tired_calls.load(), 0); - - api::ExpressionAngry_Request angry_request; - angry_request.mutable_header()->set_device_id("test-head"); - api::ExpressionAngry_Feedback angry_response; - grpc::ServerContext angry_context; - EXPECT_TRUE(service_->ExpressionAngry( - &angry_context, &angry_request, &angry_response).ok()); - EXPECT_FALSE(angry_response.header().success()); - EXPECT_EQ(head_->angry_calls.load(), 0); - - api::ExpressionSadness_Request sadness_request; - sadness_request.mutable_header()->set_device_id("test-head"); - api::ExpressionSadness_Feedback sadness_response; - grpc::ServerContext sadness_context; - EXPECT_TRUE(service_->ExpressionSadness( - &sadness_context, &sadness_request, &sadness_response).ok()); - EXPECT_FALSE(sadness_response.header().success()); - EXPECT_EQ(head_->sadness_calls.load(), 0); - - api::ExpressionYawn_Request yawn_request; - yawn_request.mutable_header()->set_device_id("test-head"); - api::ExpressionYawn_Feedback yawn_response; - grpc::ServerContext yawn_context; - EXPECT_TRUE(service_->ExpressionYawn( - &yawn_context, &yawn_request, &yawn_response).ok()); - EXPECT_FALSE(yawn_response.header().success()); - EXPECT_EQ(head_->yawn_calls.load(), 0); - - api::SetFacialExpression_Request expression_request; - expression_request.mutable_header()->set_device_id("test-head"); - api::SetFacialExpression_Feedback expression_response; - grpc::ServerContext expression_context; - EXPECT_TRUE(service_->SetExpression( - &expression_context, - &expression_request, - &expression_response).ok()); - EXPECT_FALSE(expression_response.header().success()); - EXPECT_EQ(head_->set_expression_calls.load(), 0); - - api::SpeakStart_Request speak_request; - speak_request.mutable_header()->set_device_id("test-head"); - api::SpeakStart_Feedback speak_response; - grpc::ServerContext speak_context; - EXPECT_TRUE(service_->SpeakStart( - &speak_context, &speak_request, &speak_response).ok()); - EXPECT_FALSE(speak_response.header().success()); - EXPECT_EQ(head_->speak_start_calls.load(), 0); - - api::SpeakStop_Request speak_stop_request; - speak_stop_request.mutable_header()->set_device_id("test-head"); - api::SpeakStop_Feedback speak_stop_response; - grpc::ServerContext speak_stop_context; - EXPECT_TRUE(service_->SpeakStop( - &speak_stop_context, - &speak_stop_request, - &speak_stop_response).ok()); - EXPECT_TRUE(speak_stop_response.header().success()); - - api::EmergencyStop_Request stop_request; - stop_request.mutable_header()->set_device_id("test-head"); - api::EmergencyStop_Feedback stop_response; - grpc::ServerContext stop_context; - EXPECT_TRUE(service_->EmergencyStop( - &stop_context, &stop_request, &stop_response).ok()); - EXPECT_TRUE(stop_response.header().success()); - EXPECT_EQ(head_->operational_stop_calls.load(), 1); - EXPECT_EQ(head_->lifecycle_stop_calls.load(), 0); - - EXPECT_TRUE(globalStopAllAdmissionGate().finishStopAll(ticket, true)); -} - -TEST_F(GrpcHeadServiceTest, - StreamIsCancelledByStopAllAndNewStreamWorksAfterRecovery) -{ - ASSERT_TRUE(startGrpcServer()); - grpc::ClientContext context; - context.set_deadline(std::chrono::system_clock::now() + 2s); - auto stream = stub_->StreamExpression(&context); - - ASSERT_TRUE(stream->Write(streamRequest())); - api::StreamFacialExpression_Feedback feedback; - ASSERT_TRUE(stream->Read(&feedback)); - ASSERT_TRUE(feedback.header().success()); - ASSERT_EQ(head_->stream_expression_calls.load(), 1); - - const auto admission_ticket = globalStopAllAdmissionGate().beginStopAll(); - const auto media_ticket = globalMediaActivityCoordinator().beginStopAll(); - ASSERT_TRUE(admission_ticket.valid()); - ASSERT_TRUE(media_ticket.valid()); - - (void)stream->Write(streamRequest()); - stream->WritesDone(); - while (stream->Read(&feedback)) { - } - const auto status = stream->Finish(); - EXPECT_TRUE( - status.ok() || status.error_code() == grpc::StatusCode::CANCELLED); - EXPECT_TRUE(globalMediaActivityCoordinator().waitForStopped( - media_ticket, 1s)); - EXPECT_EQ(head_->stream_expression_calls.load(), 1); - EXPECT_TRUE(globalMediaActivityCoordinator().finishStopAll( - media_ticket, true)); - EXPECT_TRUE(globalStopAllAdmissionGate().finishStopAll( - admission_ticket, true)); - - grpc::ClientContext resumed_context; - resumed_context.set_deadline(std::chrono::system_clock::now() + 2s); - auto resumed = stub_->StreamExpression(&resumed_context); - ASSERT_TRUE(resumed->Write(streamRequest())); - ASSERT_TRUE(resumed->Read(&feedback)); - EXPECT_TRUE(feedback.header().success()); - EXPECT_EQ(head_->stream_expression_calls.load(), 2); - resumed_context.TryCancel(); - resumed->WritesDone(); - while (resumed->Read(&feedback)) { - } - (void)resumed->Finish(); -} - -TEST_F(GrpcHeadServiceTest, - StopAllCancelsStreamBeforeItsFirstFrameCanClearStopState) -{ - ASSERT_TRUE(startGrpcServer()); - grpc::ClientContext context; - context.set_deadline(std::chrono::system_clock::now() + 2s); - auto stream = stub_->StreamExpression(&context); - - std::this_thread::sleep_for(20ms); - const auto admission_ticket = globalStopAllAdmissionGate().beginStopAll(); - const auto media_ticket = globalMediaActivityCoordinator().beginStopAll(); - ASSERT_TRUE(admission_ticket.valid()); - ASSERT_TRUE(media_ticket.valid()); - - (void)stream->Write(streamRequest()); - stream->WritesDone(); - api::StreamFacialExpression_Feedback feedback; - while (stream->Read(&feedback)) { - } - (void)stream->Finish(); - EXPECT_TRUE(globalMediaActivityCoordinator().waitForStopped( - media_ticket, 1s)); - EXPECT_EQ(head_->stream_expression_calls.load(), 0); - EXPECT_TRUE(globalMediaActivityCoordinator().finishStopAll( - media_ticket, true)); - EXPECT_TRUE(globalStopAllAdmissionGate().finishStopAll( - admission_ticket, true)); -} - -TEST_F(GrpcHeadServiceTest, UnconfirmedOperationalStopIsReported) -{ - head_->stop_confirmed = false; - api::EmergencyStop_Request request; - request.mutable_header()->set_device_id("test-head"); - api::EmergencyStop_Feedback response; - grpc::ServerContext context; - - EXPECT_TRUE(service_->EmergencyStop(&context, &request, &response).ok()); - EXPECT_FALSE(response.header().success()); - EXPECT_EQ(head_->operational_stop_calls.load(), 1); - EXPECT_EQ(head_->lifecycle_stop_calls.load(), 0); -} - -} // namespace -} // namespace cmvr::service diff --git a/cmvr-es/service/grpc/server/tests/grpc_motor_service_test.cpp b/cmvr-es/service/grpc/server/tests/grpc_motor_service_test.cpp deleted file mode 100644 index ea369cb8..00000000 --- a/cmvr-es/service/grpc/server/tests/grpc_motor_service_test.cpp +++ /dev/null @@ -1,1856 +0,0 @@ -#include "service/grpc/server/include/grpc_motor_service.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "cmvr/config/device_manager_config/device_manager_config.pb.h" -#include "cmvr/config/motor_config/motor_config.pb.h" -#include "devices/motor/manager/include/motor_manager.h" -#include "devices/motor/motor_protocol_interface.h" -#include "manager/device_manager/include/device_manager.h" -#include "service/grpc/server/include/motor_activity_coordinator.h" -#include "service/grpc/stop_all/include/stop_all_admission_gate.h" - -namespace cmvr::service { - -class gRPCMotorServiceImplTestAccess { -public: - static void bestEffortQuickStop(gRPCMotorServiceImpl& service, - const api::MotorTarget& target, - const std::string& error) - { - service.bestEffortQuickStop(target, error); - } - - static std::unique_lock holdExceptionCleanupMutex( - gRPCMotorServiceImpl& service, - const api::MotorTarget& target) - { - gRPCMotorServiceImpl::ResolvedMotor resolved; - const auto status = service.resolveMotor(target, resolved); - if (!status.ok()) { - throw std::runtime_error(status.error_message()); - } - return std::unique_lock( - resolved.control->exception_cleanup_mutex); - } -}; - -namespace { - -class FakeMotorProtocol final : public device::MotorProtocolInterface { -public: - bool initNode(std::uint8_t) override { return true; } - void setMode(std::uint8_t, msgs::RunMode mode) override - { - if (throw_set_mode_.load()) { - throw std::runtime_error("injected setMode exception"); - } - mode_ = mode; - } - msgs::RunMode getMode(std::uint8_t) override { return mode_.load(); } - void setLimitQdd(std::uint8_t, double, double) override {} - void setLimitQd(std::uint8_t, double) override {} - void setLimitQ(std::uint8_t, double, double) override {} - bool calibrateZeroQ(std::uint8_t) override - { - calibrate_started_ = true; - if (calibrate_delay_ms_.load() > 0) { - std::this_thread::sleep_for( - std::chrono::milliseconds(calibrate_delay_ms_.load())); - } - position_ = 0.0; - calibrate_finished_ = true; - return calibrate_success_.load(); - } - bool reachedTargetQ(std::uint8_t) override { return reached_.load(); } - bool commandProfilePosition(std::uint8_t, double target_q, - double, double) override - { - command_started_ = true; - if (throw_profile_position_.load()) { - throw std::runtime_error("injected profile position exception"); - } - profile_command_order_ = ++operation_counter_; - if (profile_delay_ms_.load() > 0) { - std::this_thread::sleep_for( - std::chrono::milliseconds(profile_delay_ms_.load())); - } - if (!hold_position_.load()) { - position_ = target_q; - velocity_ = 0.0; - reached_ = true; - } - return profile_position_success_.load(); - } - bool commandProfileVelocity(std::uint8_t, double target_qd, - double) override - { - profile_velocity_started_ = true; - if (profile_velocity_delay_ms_.load() > 0) { - std::this_thread::sleep_for( - std::chrono::milliseconds(profile_velocity_delay_ms_.load())); - } - velocity_ = target_qd; - return profile_velocity_success_.load(); - } - bool commandCyclicPosition(std::uint8_t, double target_q, - double target_qd) override - { - cyclic_position_started_ = true; - if (cyclic_position_delay_ms_.load() > 0) { - std::this_thread::sleep_for( - std::chrono::milliseconds(cyclic_position_delay_ms_.load())); - } - if (throw_cyclic_position_.load()) { - throw std::runtime_error("injected cyclic position exception"); - } - position_ = target_q; - velocity_ = target_qd; - return true; - } - bool commandCyclicVelocity(std::uint8_t, double target_qd) override - { - velocity_ = target_qd; - return true; - } - bool commandCyclicTorque(std::uint8_t, double) override { return false; } - void setMotorConversion(std::uint8_t, double, double) override {} - bool torqueOn(std::uint8_t) override - { - torque_on_started_ = true; - torque_on_order_ = ++operation_counter_; - if (torque_on_delay_ms_.load() > 0) { - std::this_thread::sleep_for( - std::chrono::milliseconds(torque_on_delay_ms_.load())); - } - return torque_on_success_.load(); - } - bool torqueOff(std::uint8_t) override - { - ++torque_off_count_; - return torque_off_success_.load(); - } - bool brakeRelease(std::uint8_t) override { return true; } - bool quickStop(std::uint8_t) override - { - last_quick_stop_order_ = ++operation_counter_; - ++quick_stop_count_; - if (quick_stop_delay_ms_.load() > 0) { - std::this_thread::sleep_for( - std::chrono::milliseconds(quick_stop_delay_ms_.load())); - } - if (quick_stop_success_.load()) { - velocity_ = 0.0; - return true; - } - return false; - } - double getQ(std::uint8_t) override - { - get_q_started_ = true; - if (get_q_delay_ms_.load() > 0) { - std::this_thread::sleep_for( - std::chrono::milliseconds(get_q_delay_ms_.load())); - } - if (throw_get_q_.load()) { - throw std::runtime_error("injected getQ exception"); - } - if (nonfinite_get_q_.load()) { - return std::numeric_limits::quiet_NaN(); - } - return position_.load(); - } - double getQd(std::uint8_t) override - { - get_qd_started_ = true; - if (nonfinite_get_qd_.load()) { - return std::numeric_limits::quiet_NaN(); - } - return velocity_.load(); - } - - std::atomic hold_position_{false}; - std::atomic calibrate_started_{false}; - std::atomic calibrate_finished_{false}; - std::atomic calibrate_delay_ms_{0}; - std::atomic calibrate_success_{true}; - std::atomic command_started_{false}; - std::atomic quick_stop_count_{0}; - std::atomic quick_stop_success_{true}; - std::atomic quick_stop_delay_ms_{0}; - std::atomic throw_set_mode_{false}; - std::atomic throw_profile_position_{false}; - std::atomic throw_cyclic_position_{false}; - std::atomic throw_get_q_{false}; - std::atomic nonfinite_get_q_{false}; - std::atomic nonfinite_get_qd_{false}; - std::atomic get_qd_started_{false}; - std::atomic profile_position_success_{true}; - std::atomic profile_velocity_success_{true}; - std::atomic torque_on_success_{true}; - std::atomic torque_off_success_{true}; - std::atomic torque_off_count_{0}; - std::atomic profile_delay_ms_{0}; - std::atomic profile_velocity_delay_ms_{0}; - std::atomic profile_velocity_started_{false}; - std::atomic cyclic_position_delay_ms_{0}; - std::atomic cyclic_position_started_{false}; - std::atomic get_q_delay_ms_{0}; - std::atomic get_q_started_{false}; - std::atomic torque_on_delay_ms_{0}; - std::atomic torque_on_started_{false}; - std::atomic operation_counter_{0}; - std::atomic profile_command_order_{0}; - std::atomic torque_on_order_{0}; - std::atomic last_quick_stop_order_{0}; - -private: - std::atomic mode_{msgs::RUN_MODE_UNSPECIFIED}; - std::atomic position_{0.0}; - std::atomic velocity_{0.0}; - std::atomic reached_{false}; -}; - -class FakeMotor final : public device::AbstractMotor { -public: - explicit FakeMotor( - const std::uint8_t node_id, - std::string joint_name = "test_joint") - : AbstractMotor(node_id) - { - info_.id = node_id; - info_.joint_name = std::move(joint_name); - } - - std::string typeName() const override { return "FakeMotor"; } -}; - -class MotorServiceTest : public ::testing::Test { -protected: - void SetUp() override - { - globalStopAllAdmissionGate().clearForTesting(); - globalMotorActivityCoordinator().clearForTesting(); - config::DeviceManagerConfig device_config; - auto& device_manager = device::DeviceManager::getInstance(device_config); - - config::MotorConfig motor_config; - manager_ = std::make_shared( - "test-motor-manager", motor_config); - protocol_ = std::make_shared(); - motor_ = std::make_shared(1); - motor_->setProtocol(protocol_); - ASSERT_TRUE(manager_->addMotor(motor_)); - device_manager.registerDevice("test-motor-manager", manager_); - service_ = std::make_unique(); - } - - void TearDown() override - { - if (grpc_server_) { - grpc_server_->Shutdown(); - grpc_server_->Wait(); - grpc_server_.reset(); - } - stub_.reset(); - if (!grpc_socket_path_.empty()) { - std::remove(grpc_socket_path_.c_str()); - grpc_socket_path_.clear(); - } - service_.reset(); - manager_.reset(); - motor_.reset(); - protocol_.reset(); - device::DeviceManager::destroyInstance(); - globalMotorActivityCoordinator().clearForTesting(); - globalStopAllAdmissionGate().clearForTesting(); - } - - static api::MotorTarget makeTarget() - { - api::MotorTarget target; - target.mutable_header()->set_device_id("test-motor-manager"); - target.set_motor_id(1); - return target; - } - - bool startGrpcServer() - { - grpc_socket_path_ = - "/tmp/cmvr_motor_service_test_" + - std::to_string(static_cast(::getpid())) + ".sock"; - std::remove(grpc_socket_path_.c_str()); - const std::string server_address = "unix:" + grpc_socket_path_; - - grpc::ServerBuilder builder; - builder.AddListeningPort( - server_address, grpc::InsecureServerCredentials()); - builder.RegisterService(service_.get()); - grpc_server_ = builder.BuildAndStart(); - if (!grpc_server_) { - return false; - } - stub_ = api::MotorService::NewStub( - grpc::CreateChannel( - server_address, - grpc::InsecureChannelCredentials())); - return stub_ != nullptr; - } - - std::shared_ptr protocol_; - std::shared_ptr motor_; - std::shared_ptr manager_; - std::unique_ptr service_; - std::unique_ptr grpc_server_; - std::unique_ptr stub_; - std::string grpc_socket_path_; -}; - -TEST_F(MotorServiceTest, SetZeroBackendFailureReportsUnknownOutcome) -{ - protocol_->calibrate_success_ = false; - - api::SetMotorZeroRequest request; - *request.mutable_target() = makeTarget(); - grpc::ServerContext context; - api::MotorCommandResponse response; - const auto status = service_->setZero(&context, &request, &response); - - EXPECT_EQ(status.error_code(), grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_FALSE(response.header().success()); - EXPECT_NE(response.header().error_message().find("outcome unknown"), - std::string::npos); - EXPECT_NE(response.header().error_message().find("device state"), - std::string::npos); - EXPECT_EQ(protocol_->quick_stop_count_.load(), 0); -} - -TEST_F(MotorServiceTest, RejectedSetZeroPreemptedInFlightReturnsAborted) -{ - protocol_->calibrate_success_ = false; - protocol_->calibrate_delay_ms_ = 100; - - api::SetMotorZeroRequest request; - *request.mutable_target() = makeTarget(); - grpc::ServerContext zero_context; - api::MotorCommandResponse zero_response; - grpc::Status zero_status; - std::thread zeroing([&]() { - zero_status = service_->setZero( - &zero_context, &request, &zero_response); - }); - const auto dispatch_deadline = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (!protocol_->calibrate_started_.load() && - std::chrono::steady_clock::now() < dispatch_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - ASSERT_TRUE(protocol_->calibrate_started_.load()); - - api::EmergencyStopRequest stop_request; - *stop_request.mutable_target() = makeTarget(); - grpc::ServerContext stop_context; - api::MotorCommandResponse stop_response; - const auto stop_status = service_->emergencyStop( - &stop_context, &stop_request, &stop_response); - - zeroing.join(); - ASSERT_TRUE(stop_status.ok()) << stop_status.error_message(); - EXPECT_EQ(zero_status.error_code(), grpc::StatusCode::ABORTED); -} - -TEST_F(MotorServiceTest, SetZeroDeadlineDuringDispatchReportsDeadline) -{ - ASSERT_TRUE(startGrpcServer()); - protocol_->calibrate_success_ = false; - protocol_->calibrate_delay_ms_ = 100; - - api::SetMotorZeroRequest request; - *request.mutable_target() = makeTarget(); - grpc::ClientContext context; - context.set_deadline( - std::chrono::system_clock::now() + std::chrono::milliseconds(50)); - api::MotorCommandResponse response; - const auto status = stub_->setZero(&context, request, &response); - EXPECT_EQ(status.error_code(), grpc::StatusCode::DEADLINE_EXCEEDED); - - const auto completion_deadline = - std::chrono::steady_clock::now() + std::chrono::milliseconds(300); - while (!protocol_->calibrate_finished_.load() && - std::chrono::steady_clock::now() < completion_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(2)); - } - EXPECT_TRUE(protocol_->calibrate_finished_.load()); - EXPECT_EQ(protocol_->quick_stop_count_.load(), 0); -} - -TEST_F(MotorServiceTest, ProfilePositionReturnsOnlyAfterTargetIsReached) -{ - api::ProfilePositionRequest request; - *request.mutable_target() = makeTarget(); - request.set_target_position_rad(1.25); - request.set_max_velocity_rad_s(1.0); - request.set_acceleration_rad_s2(2.0); - request.mutable_wait()->set_settle_sample_count(1); - request.mutable_wait()->set_poll_period_ms(1); - - grpc::ServerContext context; - api::MotorCommandResponse response; - const auto status = service_->profilePosition(&context, &request, &response); - - ASSERT_TRUE(status.ok()) << status.error_message(); - EXPECT_TRUE(response.header().success()); - EXPECT_DOUBLE_EQ(response.status().position_rad(), 1.25); - EXPECT_FALSE(response.status().service_busy()); - EXPECT_EQ(response.status().active_control(), api::MOTOR_CONTROL_NONE); -} - -TEST_F(MotorServiceTest, DirectControlRejectsMotorClaimedByRobotArm) -{ - std::uint64_t claim_id = 0; - std::string claim_error; - ASSERT_TRUE(manager_->claimArmJoints( - "test_arm", {"test_joint"}, claim_id, &claim_error)) - << claim_error; - - api::ProfilePositionRequest request; - *request.mutable_target() = makeTarget(); - request.set_target_position_rad(1.25); - request.set_max_velocity_rad_s(1.0); - request.set_acceleration_rad_s2(2.0); - grpc::ServerContext context; - api::MotorCommandResponse response; - - const auto status = service_->profilePosition( - &context, &request, &response); - - EXPECT_EQ(status.error_code(), grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_FALSE(response.header().success()); - EXPECT_NE(status.error_message().find("test_arm"), std::string::npos); - EXPECT_NE(status.error_message().find("ArmService"), std::string::npos); - EXPECT_FALSE(protocol_->command_started_.load()); - EXPECT_EQ(protocol_->quick_stop_count_.load(), 0); -} - -TEST_F(MotorServiceTest, ClaimedArmMotorRemainsObservableWithoutStopRegistration) -{ - std::uint64_t claim_id = 0; - ASSERT_TRUE(manager_->claimArmJoints( - "test_arm", {"test_joint"}, claim_id)); - - api::GetMotorStatusRequest request; - *request.mutable_target() = makeTarget(); - grpc::ServerContext context; - api::GetMotorStatusResponse response; - const auto status = service_->getStatus(&context, &request, &response); - - ASSERT_TRUE(status.ok()) << status.error_message(); - EXPECT_TRUE(response.header().success()); - EXPECT_EQ(response.status().joint_name(), "test_joint"); - - auto& coordinator = globalMotorActivityCoordinator(); - const auto ticket = coordinator.beginStopAll(); - ASSERT_TRUE(ticket.valid()); - std::string stop_error; - EXPECT_TRUE(coordinator.requestStop(ticket, &stop_error)) << stop_error; - EXPECT_EQ(protocol_->quick_stop_count_.load(), 0); - EXPECT_TRUE(coordinator.waitForStopped( - ticket, std::chrono::milliseconds(50), &stop_error)) << stop_error; - EXPECT_TRUE(coordinator.finishStopAll(ticket, true)); -} - -TEST_F(MotorServiceTest, ReleasingArmClaimRestoresDirectMotorControl) -{ - std::uint64_t claim_id = 0; - ASSERT_TRUE(manager_->claimArmJoints( - "test_arm", {"test_joint"}, claim_id)); - manager_->releaseArmJoints(claim_id); - - api::ProfilePositionRequest request; - *request.mutable_target() = makeTarget(); - request.set_target_position_rad(0.75); - request.set_max_velocity_rad_s(1.0); - request.set_acceleration_rad_s2(2.0); - request.mutable_wait()->set_settle_sample_count(1); - request.mutable_wait()->set_poll_period_ms(1); - grpc::ServerContext context; - api::MotorCommandResponse response; - - const auto status = service_->profilePosition( - &context, &request, &response); - - ASSERT_TRUE(status.ok()) << status.error_message(); - EXPECT_TRUE(response.header().success()); - EXPECT_DOUBLE_EQ(response.status().position_rad(), 0.75); -} - -TEST_F(MotorServiceTest, ArmClaimCannotBeDisplacedOrReleasedByAnotherToken) -{ - std::uint64_t first_claim = 0; - ASSERT_TRUE(manager_->claimArmJoints( - "first_arm", {"test_joint"}, first_claim)); - - std::uint64_t conflicting_claim = 0; - std::string claim_error; - EXPECT_FALSE(manager_->claimArmJoints( - "second_arm", {"test_joint"}, conflicting_claim, &claim_error)); - EXPECT_EQ(conflicting_claim, 0U); - EXPECT_NE(claim_error.find("first_arm"), std::string::npos); - - manager_->releaseArmJoints(first_claim + 1U); - EXPECT_EQ(manager_->armOwnerForJoint("test_joint"), "first_arm"); - - manager_->releaseArmJoints(first_claim); - EXPECT_TRUE(manager_->armOwnerForJoint("test_joint").empty()); -} - -TEST_F(MotorServiceTest, ArmClaimDoesNotRejectUnclaimedMotor) -{ - auto other_protocol = std::make_shared(); - auto other_motor = std::make_shared(2, "other_joint"); - other_motor->setProtocol(other_protocol); - ASSERT_TRUE(manager_->addMotor(other_motor)); - - std::uint64_t claim_id = 0; - ASSERT_TRUE(manager_->claimArmJoints( - "test_arm", {"test_joint"}, claim_id)); - - api::ProfilePositionRequest request; - *request.mutable_target() = makeTarget(); - request.mutable_target()->set_motor_id(2); - request.set_target_position_rad(0.5); - request.set_max_velocity_rad_s(1.0); - request.set_acceleration_rad_s2(2.0); - request.mutable_wait()->set_settle_sample_count(1); - request.mutable_wait()->set_poll_period_ms(1); - grpc::ServerContext context; - api::MotorCommandResponse response; - - const auto status = service_->profilePosition( - &context, &request, &response); - - ASSERT_TRUE(status.ok()) << status.error_message(); - EXPECT_TRUE(response.header().success()); - EXPECT_DOUBLE_EQ(response.status().position_rad(), 0.5); -} - -TEST_F(MotorServiceTest, ProfileVelocityReturnsAfterTargetSettles) -{ - api::ProfileVelocityRequest request; - *request.mutable_target() = makeTarget(); - request.set_target_velocity_rad_s(1.5); - request.set_acceleration_rad_s2(2.0); - request.mutable_wait()->set_settle_sample_count(2); - request.mutable_wait()->set_poll_period_ms(1); - request.mutable_wait()->set_velocity_tolerance_rad_s(1e-4); - - grpc::ServerContext context; - api::MotorCommandResponse response; - const auto status = service_->profileVelocity(&context, &request, &response); - - ASSERT_TRUE(status.ok()) << status.error_message(); - EXPECT_TRUE(response.header().success()); - EXPECT_DOUBLE_EQ(response.status().velocity_rad_s(), 1.5); - EXPECT_FALSE(response.status().service_busy()); - EXPECT_EQ(response.status().active_control(), api::MOTOR_CONTROL_NONE); -} - -TEST_F(MotorServiceTest, ProfilePositionStopsImmediatelyOnNonFiniteFeedback) -{ - protocol_->hold_position_ = true; - - api::ProfilePositionRequest request; - *request.mutable_target() = makeTarget(); - request.set_target_position_rad(1.0); - request.set_max_velocity_rad_s(1.0); - request.set_acceleration_rad_s2(1.0); - request.mutable_wait()->set_timeout_ms(5000); - request.mutable_wait()->set_poll_period_ms(2); - - grpc::ServerContext context; - api::MotorCommandResponse response; - grpc::Status status; - const auto started = std::chrono::steady_clock::now(); - std::thread motion([&]() { - status = service_->profilePosition(&context, &request, &response); - }); - - const auto sample_deadline = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (!protocol_->get_q_started_.load() && - std::chrono::steady_clock::now() < sample_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - if (!protocol_->get_q_started_.load()) { - context.TryCancel(); - motion.join(); - FAIL() << "profile position feedback sampling did not start"; - return; - } - - protocol_->nonfinite_get_q_ = true; - motion.join(); - - EXPECT_EQ(status.error_code(), grpc::StatusCode::UNAVAILABLE); - EXPECT_FALSE(response.header().success()); - EXPECT_FALSE(response.status().emergency_stopped()); - EXPECT_GE(protocol_->quick_stop_count_.load(), 1); - EXPECT_LT(std::chrono::steady_clock::now() - started, - std::chrono::seconds(1)); -} - -TEST_F(MotorServiceTest, - ProfileVelocityFailedStopOnNonFiniteFeedbackLatchesEmergency) -{ - protocol_->quick_stop_success_ = false; - - api::ProfileVelocityRequest request; - *request.mutable_target() = makeTarget(); - request.set_target_velocity_rad_s(1.5); - request.set_acceleration_rad_s2(2.0); - request.mutable_wait()->set_timeout_ms(5000); - request.mutable_wait()->set_poll_period_ms(2); - request.mutable_wait()->set_settle_sample_count(1000); - - grpc::ServerContext context; - api::MotorCommandResponse response; - grpc::Status status; - const auto started = std::chrono::steady_clock::now(); - std::thread motion([&]() { - status = service_->profileVelocity(&context, &request, &response); - }); - - const auto sample_deadline = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (!protocol_->get_qd_started_.load() && - std::chrono::steady_clock::now() < sample_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - if (!protocol_->get_qd_started_.load()) { - context.TryCancel(); - motion.join(); - FAIL() << "profile velocity feedback sampling did not start"; - return; - } - - protocol_->nonfinite_get_qd_ = true; - motion.join(); - - EXPECT_EQ(status.error_code(), grpc::StatusCode::INTERNAL); - EXPECT_FALSE(response.header().success()); - EXPECT_TRUE(response.status().emergency_stopped()); - EXPECT_GE(protocol_->quick_stop_count_.load(), 1); - EXPECT_LT(std::chrono::steady_clock::now() - started, - std::chrono::seconds(1)); - - api::ProfilePositionRequest blocked_request; - *blocked_request.mutable_target() = makeTarget(); - blocked_request.set_target_position_rad(1.0); - blocked_request.set_max_velocity_rad_s(1.0); - blocked_request.set_acceleration_rad_s2(1.0); - grpc::ServerContext blocked_context; - api::MotorCommandResponse blocked_response; - const auto blocked_status = service_->profilePosition( - &blocked_context, &blocked_request, &blocked_response); - EXPECT_EQ(blocked_status.error_code(), - grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_TRUE(blocked_response.status().emergency_stopped()); -} - -TEST_F(MotorServiceTest, - ProfileBackendExceptionReportsUnknownOutcomeAndQuickStops) -{ - protocol_->throw_profile_position_ = true; - - api::ProfilePositionRequest request; - *request.mutable_target() = makeTarget(); - request.set_target_position_rad(1.0); - request.set_max_velocity_rad_s(1.0); - request.set_acceleration_rad_s2(1.0); - - grpc::ServerContext context; - api::MotorCommandResponse response; - const auto status = service_->profilePosition(&context, &request, &response); - - EXPECT_EQ(status.error_code(), grpc::StatusCode::ABORTED); - EXPECT_FALSE(response.header().success()); - EXPECT_EQ( - response.header().reason_code(), - api::COMMAND_REASON_CODE_OUTCOME_UNKNOWN); - EXPECT_NE(response.header().error_message().find( - "injected profile position exception"), - std::string::npos); - EXPECT_GE(protocol_->quick_stop_count_.load(), 1); - const auto safety = device::DeviceManager::getInstance() - .safetyManager() - .snapshot(); - ASSERT_EQ(safety.devices.size(), 1U); - EXPECT_EQ( - safety.devices.front().admission_state, - safety::DeviceAdmissionState::Quarantined); -} - -TEST_F(MotorServiceTest, ExceptionCleanupKeepsMotorReservedUntilQuickStopFinishes) -{ - protocol_->throw_profile_position_ = true; - protocol_->quick_stop_delay_ms_ = 100; - - api::ProfilePositionRequest failing_request; - *failing_request.mutable_target() = makeTarget(); - failing_request.set_target_position_rad(1.0); - failing_request.set_max_velocity_rad_s(1.0); - failing_request.set_acceleration_rad_s2(1.0); - grpc::ServerContext failing_context; - api::MotorCommandResponse failing_response; - grpc::Status failing_status; - std::thread failing([&]() { - failing_status = service_->profilePosition( - &failing_context, &failing_request, &failing_response); - }); - - const auto cleanup_deadline = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (protocol_->quick_stop_count_.load() == 0 && - std::chrono::steady_clock::now() < cleanup_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - if (protocol_->quick_stop_count_.load() == 0) { - failing.join(); - FAIL() << "exception cleanup did not start"; - return; - } - protocol_->throw_profile_position_ = false; - - api::ProfilePositionRequest competing_request; - *competing_request.mutable_target() = makeTarget(); - competing_request.set_target_position_rad(2.0); - competing_request.set_max_velocity_rad_s(1.0); - competing_request.set_acceleration_rad_s2(1.0); - grpc::ServerContext competing_context; - api::MotorCommandResponse competing_response; - const auto competing_status = service_->profilePosition( - &competing_context, &competing_request, &competing_response); - - failing.join(); - EXPECT_EQ(failing_status.error_code(), grpc::StatusCode::ABORTED); - EXPECT_EQ( - failing_response.header().reason_code(), - api::COMMAND_REASON_CODE_OUTCOME_UNKNOWN); - EXPECT_EQ(competing_status.error_code(), - grpc::StatusCode::RESOURCE_EXHAUSTED); -} - -TEST_F(MotorServiceTest, WaitingStaleCleanupCannotStopOrReleaseNewOwner) -{ - const auto target = makeTarget(); - gRPCMotorServiceImplTestAccess::bestEffortQuickStop( - *service_, target, "first completed exception cleanup"); - ASSERT_EQ(protocol_->quick_stop_count_.load(), 1); - - auto cleanup_gate = - gRPCMotorServiceImplTestAccess::holdExceptionCleanupMutex( - *service_, target); - std::atomic stale_cleanup_entered{false}; - std::thread stale_cleanup([&]() { - stale_cleanup_entered = true; - gRPCMotorServiceImplTestAccess::bestEffortQuickStop( - *service_, target, "second stale exception cleanup"); - }); - const auto stale_deadline = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (!stale_cleanup_entered.load() && - std::chrono::steady_clock::now() < stale_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - if (!stale_cleanup_entered.load()) { - cleanup_gate.unlock(); - stale_cleanup.join(); - FAIL() << "second cleanup did not start waiting"; - return; - } - - protocol_->profile_delay_ms_ = 100; - protocol_->command_started_ = false; - api::ProfilePositionRequest request; - *request.mutable_target() = target; - request.set_target_position_rad(1.0); - request.set_max_velocity_rad_s(1.0); - request.set_acceleration_rad_s2(1.0); - request.mutable_wait()->set_settle_sample_count(1); - grpc::ServerContext motion_context; - api::MotorCommandResponse motion_response; - grpc::Status motion_status; - std::thread motion([&]() { - motion_status = service_->profilePosition( - &motion_context, &request, &motion_response); - }); - const auto motion_deadline = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (!protocol_->command_started_.load() && - std::chrono::steady_clock::now() < motion_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - if (!protocol_->command_started_.load()) { - cleanup_gate.unlock(); - stale_cleanup.join(); - motion_context.TryCancel(); - motion.join(); - FAIL() << "new owner did not dispatch while stale cleanup waited"; - return; - } - - cleanup_gate.unlock(); - stale_cleanup.join(); - EXPECT_EQ(protocol_->quick_stop_count_.load(), 1); - - motion.join(); - ASSERT_TRUE(motion_status.ok()) << motion_status.error_message(); - EXPECT_TRUE(motion_response.header().success()); - EXPECT_EQ(protocol_->quick_stop_count_.load(), 1); -} - -TEST_F(MotorServiceTest, GetStatusBackendExceptionReturnsInternal) -{ - protocol_->throw_get_q_ = true; - - api::GetMotorStatusRequest request; - *request.mutable_target() = makeTarget(); - - grpc::ServerContext context; - api::GetMotorStatusResponse response; - const auto status = service_->getStatus(&context, &request, &response); - - EXPECT_EQ(status.error_code(), grpc::StatusCode::INTERNAL); - EXPECT_FALSE(response.header().success()); - EXPECT_NE(response.header().error_message().find( - "injected getQ exception"), - std::string::npos); - EXPECT_EQ(protocol_->quick_stop_count_.load(), 0); -} - -TEST_F(MotorServiceTest, GetStatusRejectsNonFiniteFeedback) -{ - protocol_->nonfinite_get_q_ = true; - - api::GetMotorStatusRequest request; - *request.mutable_target() = makeTarget(); - - grpc::ServerContext context; - api::GetMotorStatusResponse response; - const auto status = service_->getStatus(&context, &request, &response); - - EXPECT_EQ(status.error_code(), grpc::StatusCode::UNAVAILABLE); - EXPECT_FALSE(response.header().success()); -} - -TEST_F(MotorServiceTest, ProfileRejectsInfiniteWaitTolerance) -{ - api::ProfilePositionRequest request; - *request.mutable_target() = makeTarget(); - request.set_target_position_rad(1.0); - request.set_max_velocity_rad_s(1.0); - request.set_acceleration_rad_s2(1.0); - request.mutable_wait()->set_position_tolerance_rad( - std::numeric_limits::infinity()); - - grpc::ServerContext context; - api::MotorCommandResponse response; - const auto status = service_->profilePosition(&context, &request, &response); - - EXPECT_EQ(status.error_code(), grpc::StatusCode::INVALID_ARGUMENT); - EXPECT_FALSE(response.header().success()); - EXPECT_FALSE(protocol_->command_started_.load()); -} - -TEST_F(MotorServiceTest, ProfileRejectAckLossQuickStopsBeforeReturning) -{ - protocol_->profile_position_success_ = false; - - api::ProfilePositionRequest request; - *request.mutable_target() = makeTarget(); - request.set_target_position_rad(1.0); - request.set_max_velocity_rad_s(1.0); - request.set_acceleration_rad_s2(1.0); - - grpc::ServerContext context; - api::MotorCommandResponse response; - const auto status = service_->profilePosition(&context, &request, &response); - - EXPECT_EQ(status.error_code(), grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_FALSE(response.header().success()); - EXPECT_FALSE(response.status().emergency_stopped()); - EXPECT_GE(protocol_->quick_stop_count_.load(), 1); -} - -TEST_F(MotorServiceTest, ProfileRejectAckLossWithFailedStopReturnsInternal) -{ - protocol_->profile_position_success_ = false; - protocol_->quick_stop_success_ = false; - - api::ProfilePositionRequest request; - *request.mutable_target() = makeTarget(); - request.set_target_position_rad(1.0); - request.set_max_velocity_rad_s(1.0); - request.set_acceleration_rad_s2(1.0); - - grpc::ServerContext context; - api::MotorCommandResponse response; - const auto status = service_->profilePosition(&context, &request, &response); - - EXPECT_EQ(status.error_code(), grpc::StatusCode::INTERNAL); - EXPECT_FALSE(response.header().success()); - EXPECT_TRUE(response.status().emergency_stopped()); - EXPECT_GE(protocol_->quick_stop_count_.load(), 1); - - grpc::ServerContext blocked_context; - api::MotorCommandResponse blocked_response; - const auto blocked_status = service_->profilePosition( - &blocked_context, &request, &blocked_response); - EXPECT_EQ(blocked_status.error_code(), - grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_TRUE(blocked_response.status().emergency_stopped()); - - protocol_->quick_stop_success_ = true; - protocol_->profile_position_success_ = true; - api::SetMotorEnabledRequest enable_request; - *enable_request.mutable_target() = makeTarget(); - enable_request.set_enabled(true); - grpc::ServerContext enable_context; - api::MotorCommandResponse enable_response; - const auto enable_status = service_->setEnabled( - &enable_context, &enable_request, &enable_response); - ASSERT_TRUE(enable_status.ok()) << enable_status.error_message(); - EXPECT_FALSE(enable_response.status().emergency_stopped()); - - grpc::ServerContext recovered_context; - api::MotorCommandResponse recovered_response; - const auto recovered_status = service_->profilePosition( - &recovered_context, &request, &recovered_response); - EXPECT_TRUE(recovered_status.ok()) << recovered_status.error_message(); -} - -TEST_F(MotorServiceTest, ProfileAckLossAfterDeadlineStillQuickStops) -{ - ASSERT_TRUE(startGrpcServer()); - protocol_->profile_position_success_ = false; - protocol_->profile_delay_ms_ = 100; - - api::ProfilePositionRequest request; - *request.mutable_target() = makeTarget(); - request.set_target_position_rad(1.0); - request.set_max_velocity_rad_s(1.0); - request.set_acceleration_rad_s2(1.0); - grpc::ClientContext context; - context.set_deadline( - std::chrono::system_clock::now() + std::chrono::milliseconds(50)); - api::MotorCommandResponse response; - const auto status = stub_->profilePosition(&context, request, &response); - EXPECT_EQ(status.error_code(), grpc::StatusCode::DEADLINE_EXCEEDED); - - const auto cleanup_deadline = - std::chrono::steady_clock::now() + std::chrono::milliseconds(300); - while (protocol_->quick_stop_count_.load() == 0 && - std::chrono::steady_clock::now() < cleanup_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(2)); - } - EXPECT_GE(protocol_->quick_stop_count_.load(), 1); -} - -TEST_F(MotorServiceTest, RejectedProfilePositionPreemptedInFlightReturnsAborted) -{ - protocol_->profile_position_success_ = false; - protocol_->profile_delay_ms_ = 100; - - api::ProfilePositionRequest request; - *request.mutable_target() = makeTarget(); - request.set_target_position_rad(1.0); - request.set_max_velocity_rad_s(1.0); - request.set_acceleration_rad_s2(1.0); - - grpc::ServerContext motion_context; - api::MotorCommandResponse motion_response; - grpc::Status motion_status; - std::thread motion([&]() { - motion_status = service_->profilePosition( - &motion_context, &request, &motion_response); - }); - const auto dispatch_deadline = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (!protocol_->command_started_.load() && - std::chrono::steady_clock::now() < dispatch_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - ASSERT_TRUE(protocol_->command_started_.load()); - - api::EmergencyStopRequest stop_request; - *stop_request.mutable_target() = makeTarget(); - grpc::ServerContext stop_context; - api::MotorCommandResponse stop_response; - const auto stop_status = service_->emergencyStop( - &stop_context, &stop_request, &stop_response); - - motion.join(); - ASSERT_TRUE(stop_status.ok()) << stop_status.error_message(); - EXPECT_EQ(motion_status.error_code(), grpc::StatusCode::ABORTED); -} - -TEST_F(MotorServiceTest, RejectedProfileVelocityPreemptedInFlightReturnsAborted) -{ - protocol_->profile_velocity_success_ = false; - protocol_->profile_velocity_delay_ms_ = 100; - - api::ProfileVelocityRequest request; - *request.mutable_target() = makeTarget(); - request.set_target_velocity_rad_s(1.0); - request.set_acceleration_rad_s2(1.0); - - grpc::ServerContext motion_context; - api::MotorCommandResponse motion_response; - grpc::Status motion_status; - std::thread motion([&]() { - motion_status = service_->profileVelocity( - &motion_context, &request, &motion_response); - }); - const auto dispatch_deadline = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (!protocol_->profile_velocity_started_.load() && - std::chrono::steady_clock::now() < dispatch_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - ASSERT_TRUE(protocol_->profile_velocity_started_.load()); - - api::EmergencyStopRequest stop_request; - *stop_request.mutable_target() = makeTarget(); - grpc::ServerContext stop_context; - api::MotorCommandResponse stop_response; - const auto stop_status = service_->emergencyStop( - &stop_context, &stop_request, &stop_response); - - motion.join(); - ASSERT_TRUE(stop_status.ok()) << stop_status.error_message(); - EXPECT_EQ(motion_status.error_code(), grpc::StatusCode::ABORTED); -} - -TEST_F(MotorServiceTest, EmergencyStopDuringProfileStatusSampleCannotReturnOk) -{ - protocol_->get_q_delay_ms_ = 100; - - api::ProfilePositionRequest motion_request; - *motion_request.mutable_target() = makeTarget(); - motion_request.set_target_position_rad(1.0); - motion_request.set_max_velocity_rad_s(1.0); - motion_request.set_acceleration_rad_s2(1.0); - motion_request.mutable_wait()->set_settle_sample_count(1); - - grpc::ServerContext motion_context; - api::MotorCommandResponse motion_response; - grpc::Status motion_status; - std::thread motion([&]() { - motion_status = service_->profilePosition( - &motion_context, &motion_request, &motion_response); - }); - - const auto sample_deadline = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (!protocol_->get_q_started_.load() && - std::chrono::steady_clock::now() < sample_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - if (!protocol_->get_q_started_.load()) { - motion_context.TryCancel(); - motion.join(); - FAIL() << "profile status sampling did not start"; - return; - } - - api::EmergencyStopRequest stop_request; - *stop_request.mutable_target() = makeTarget(); - grpc::ServerContext stop_context; - api::MotorCommandResponse stop_response; - const auto stop_status = service_->emergencyStop( - &stop_context, &stop_request, &stop_response); - - motion.join(); - ASSERT_TRUE(stop_status.ok()) << stop_status.error_message(); - EXPECT_EQ(motion_status.error_code(), grpc::StatusCode::ABORTED); - EXPECT_FALSE(motion_response.header().success()); -} - -TEST_F(MotorServiceTest, EmergencyStopPreemptsBlockingProfilePosition) -{ - protocol_->hold_position_ = true; - protocol_->profile_delay_ms_ = 50; - - api::ProfilePositionRequest motion_request; - *motion_request.mutable_target() = makeTarget(); - motion_request.set_target_position_rad(2.0); - motion_request.set_max_velocity_rad_s(1.0); - motion_request.set_acceleration_rad_s2(1.0); - motion_request.mutable_wait()->set_timeout_ms(5000); - motion_request.mutable_wait()->set_poll_period_ms(1); - - grpc::ServerContext motion_context; - api::MotorCommandResponse motion_response; - grpc::Status motion_status; - std::thread motion([&]() { - motion_status = service_->profilePosition( - &motion_context, &motion_request, &motion_response); - }); - - const auto wait_until = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (!protocol_->command_started_.load() && - std::chrono::steady_clock::now() < wait_until) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - ASSERT_TRUE(protocol_->command_started_.load()); - - api::EmergencyStopRequest stop_request; - *stop_request.mutable_target() = makeTarget(); - grpc::ServerContext stop_context; - api::MotorCommandResponse stop_response; - const auto stop_status = service_->emergencyStop( - &stop_context, &stop_request, &stop_response); - - motion.join(); - ASSERT_TRUE(stop_status.ok()) << stop_status.error_message(); - EXPECT_EQ(motion_status.error_code(), grpc::StatusCode::ABORTED); - EXPECT_GE(protocol_->quick_stop_count_.load(), 1); - EXPECT_GT(protocol_->last_quick_stop_order_.load(), - protocol_->profile_command_order_.load()); - EXPECT_TRUE(stop_response.status().emergency_stopped()); -} - -TEST_F(MotorServiceTest, EnableClearsEmergencyStopLatch) -{ - api::EmergencyStopRequest stop_request; - *stop_request.mutable_target() = makeTarget(); - grpc::ServerContext stop_context; - api::MotorCommandResponse stop_response; - ASSERT_TRUE(service_->emergencyStop( - &stop_context, &stop_request, &stop_response).ok()); - - api::SetMotorEnabledRequest enable_request; - *enable_request.mutable_target() = makeTarget(); - enable_request.set_enabled(true); - grpc::ServerContext enable_context; - api::MotorCommandResponse enable_response; - const auto enable_status = service_->setEnabled( - &enable_context, &enable_request, &enable_response); - - ASSERT_TRUE(enable_status.ok()) << enable_status.error_message(); - EXPECT_FALSE(enable_response.status().emergency_stopped()); -} - -TEST_F(MotorServiceTest, RejectedEnableQuickStopsAndDisables) -{ - protocol_->torque_on_success_ = false; - - api::SetMotorEnabledRequest request; - *request.mutable_target() = makeTarget(); - request.set_enabled(true); - grpc::ServerContext context; - api::MotorCommandResponse response; - const auto status = service_->setEnabled(&context, &request, &response); - - EXPECT_EQ(status.error_code(), grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_FALSE(response.status().emergency_stopped()); - EXPECT_GE(protocol_->quick_stop_count_.load(), 1); - EXPECT_GE(protocol_->torque_off_count_.load(), 1); -} - -TEST_F(MotorServiceTest, RejectedEnableCleanupFailureReturnsInternal) -{ - protocol_->torque_on_success_ = false; - protocol_->torque_off_success_ = false; - - api::SetMotorEnabledRequest request; - *request.mutable_target() = makeTarget(); - request.set_enabled(true); - grpc::ServerContext context; - api::MotorCommandResponse response; - const auto status = service_->setEnabled(&context, &request, &response); - - EXPECT_EQ(status.error_code(), grpc::StatusCode::INTERNAL); - EXPECT_TRUE(response.status().emergency_stopped()); - EXPECT_GE(protocol_->quick_stop_count_.load(), 1); - EXPECT_GE(protocol_->torque_off_count_.load(), 1); -} - -TEST_F(MotorServiceTest, RejectedEnablePreemptedInFlightReturnsAborted) -{ - protocol_->torque_on_success_ = false; - protocol_->torque_on_delay_ms_ = 100; - - api::SetMotorEnabledRequest enable_request; - *enable_request.mutable_target() = makeTarget(); - enable_request.set_enabled(true); - grpc::ServerContext enable_context; - api::MotorCommandResponse enable_response; - grpc::Status enable_status; - std::thread enabling([&]() { - enable_status = service_->setEnabled( - &enable_context, &enable_request, &enable_response); - }); - const auto dispatch_deadline = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (!protocol_->torque_on_started_.load() && - std::chrono::steady_clock::now() < dispatch_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - ASSERT_TRUE(protocol_->torque_on_started_.load()); - - api::EmergencyStopRequest stop_request; - *stop_request.mutable_target() = makeTarget(); - grpc::ServerContext stop_context; - api::MotorCommandResponse stop_response; - const auto stop_status = service_->emergencyStop( - &stop_context, &stop_request, &stop_response); - - enabling.join(); - ASSERT_TRUE(stop_status.ok()) << stop_status.error_message(); - EXPECT_EQ(enable_status.error_code(), grpc::StatusCode::ABORTED); -} - -TEST_F(MotorServiceTest, SuccessfulEnableCancelledInFlightRollsBack) -{ - ASSERT_TRUE(startGrpcServer()); - protocol_->torque_on_delay_ms_ = 100; - - api::SetMotorEnabledRequest request; - *request.mutable_target() = makeTarget(); - request.set_enabled(true); - grpc::ClientContext context; - context.set_deadline( - std::chrono::system_clock::now() + std::chrono::milliseconds(50)); - api::MotorCommandResponse response; - const auto status = stub_->setEnabled(&context, request, &response); - EXPECT_EQ(status.error_code(), grpc::StatusCode::DEADLINE_EXCEEDED); - - const auto cleanup_deadline = - std::chrono::steady_clock::now() + std::chrono::milliseconds(400); - while ((protocol_->quick_stop_count_.load() == 0 || - protocol_->torque_off_count_.load() == 0) && - std::chrono::steady_clock::now() < cleanup_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(2)); - } - EXPECT_GE(protocol_->quick_stop_count_.load(), 1); - EXPECT_GE(protocol_->torque_off_count_.load(), 1); -} - -TEST_F(MotorServiceTest, EmergencyStopPreemptsEnableDuringDispatch) -{ - api::EmergencyStopRequest initial_stop; - *initial_stop.mutable_target() = makeTarget(); - grpc::ServerContext initial_stop_context; - api::MotorCommandResponse initial_stop_response; - ASSERT_TRUE(service_->emergencyStop( - &initial_stop_context, &initial_stop, &initial_stop_response).ok()); - - protocol_->operation_counter_ = 0; - protocol_->last_quick_stop_order_ = 0; - protocol_->torque_on_started_ = false; - protocol_->torque_on_delay_ms_ = 50; - - api::SetMotorEnabledRequest enable_request; - *enable_request.mutable_target() = makeTarget(); - enable_request.set_enabled(true); - grpc::ServerContext enable_context; - api::MotorCommandResponse enable_response; - grpc::Status enable_status; - std::thread enabling([&]() { - enable_status = service_->setEnabled( - &enable_context, &enable_request, &enable_response); - }); - - const auto wait_until = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (!protocol_->torque_on_started_.load() && - std::chrono::steady_clock::now() < wait_until) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - ASSERT_TRUE(protocol_->torque_on_started_.load()); - - api::EmergencyStopRequest stop_request; - *stop_request.mutable_target() = makeTarget(); - grpc::ServerContext stop_context; - api::MotorCommandResponse stop_response; - const auto stop_status = service_->emergencyStop( - &stop_context, &stop_request, &stop_response); - - enabling.join(); - ASSERT_TRUE(stop_status.ok()) << stop_status.error_message(); - EXPECT_EQ(enable_status.error_code(), grpc::StatusCode::ABORTED); - EXPECT_TRUE(stop_response.status().emergency_stopped()); - EXPECT_GT(protocol_->last_quick_stop_order_.load(), - protocol_->torque_on_order_.load()); - EXPECT_GE(protocol_->torque_off_count_.load(), 1); -} - -TEST_F(MotorServiceTest, SuccessfulEnablePreemptCleanupFailureReturnsInternal) -{ - protocol_->torque_on_delay_ms_ = 100; - protocol_->torque_off_success_ = false; - - api::SetMotorEnabledRequest enable_request; - *enable_request.mutable_target() = makeTarget(); - enable_request.set_enabled(true); - grpc::ServerContext enable_context; - api::MotorCommandResponse enable_response; - grpc::Status enable_status; - std::thread enabling([&]() { - enable_status = service_->setEnabled( - &enable_context, &enable_request, &enable_response); - }); - const auto dispatch_deadline = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (!protocol_->torque_on_started_.load() && - std::chrono::steady_clock::now() < dispatch_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - ASSERT_TRUE(protocol_->torque_on_started_.load()); - - api::EmergencyStopRequest stop_request; - *stop_request.mutable_target() = makeTarget(); - grpc::ServerContext stop_context; - api::MotorCommandResponse stop_response; - const auto stop_status = service_->emergencyStop( - &stop_context, &stop_request, &stop_response); - - enabling.join(); - ASSERT_TRUE(stop_status.ok()) << stop_status.error_message(); - EXPECT_EQ(enable_status.error_code(), grpc::StatusCode::INTERNAL); - EXPECT_GE(protocol_->torque_off_count_.load(), 1); -} - -TEST_F(MotorServiceTest, ConcurrentEmergencyStopsCannotBeClearedByEnable) -{ - protocol_->quick_stop_delay_ms_ = 60; - - api::EmergencyStopRequest first_request; - *first_request.mutable_target() = makeTarget(); - api::EmergencyStopRequest second_request; - *second_request.mutable_target() = makeTarget(); - grpc::ServerContext first_context; - grpc::ServerContext second_context; - api::MotorCommandResponse first_response; - api::MotorCommandResponse second_response; - grpc::Status first_status; - grpc::Status second_status; - - std::thread first([&]() { - first_status = service_->emergencyStop( - &first_context, &first_request, &first_response); - }); - const auto first_stop_deadline = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (protocol_->quick_stop_count_.load() < 1 && - std::chrono::steady_clock::now() < first_stop_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - if (protocol_->quick_stop_count_.load() < 1) { - first.join(); - FAIL() << "first emergency stop did not dispatch"; - return; - } - - std::thread second([&]() { - second_status = service_->emergencyStop( - &second_context, &second_request, &second_response); - }); - first.join(); - - const auto second_stop_deadline = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (protocol_->quick_stop_count_.load() < 3 && - std::chrono::steady_clock::now() < second_stop_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - if (protocol_->quick_stop_count_.load() < 3) { - second.join(); - FAIL() << "second emergency stop did not dispatch"; - return; - } - - api::SetMotorEnabledRequest enable_request; - *enable_request.mutable_target() = makeTarget(); - enable_request.set_enabled(true); - grpc::ServerContext enable_context; - api::MotorCommandResponse enable_response; - const auto enable_status = service_->setEnabled( - &enable_context, &enable_request, &enable_response); - - second.join(); - ASSERT_TRUE(first_status.ok()) << first_status.error_message(); - ASSERT_TRUE(second_status.ok()) << second_status.error_message(); - EXPECT_EQ(enable_status.error_code(), grpc::StatusCode::ABORTED); - - api::ProfilePositionRequest motion_request; - *motion_request.mutable_target() = makeTarget(); - motion_request.set_target_position_rad(1.0); - motion_request.set_max_velocity_rad_s(1.0); - motion_request.set_acceleration_rad_s2(1.0); - grpc::ServerContext motion_context; - api::MotorCommandResponse motion_response; - const auto motion_status = service_->profilePosition( - &motion_context, &motion_request, &motion_response); - EXPECT_EQ(motion_status.error_code(), - grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_TRUE(motion_response.status().emergency_stopped()); -} - -TEST_F(MotorServiceTest, ProfileCancellationInterruptsLongPollAndQuickStops) -{ - ASSERT_TRUE(startGrpcServer()); - protocol_->hold_position_ = true; - - api::ProfilePositionRequest request; - *request.mutable_target() = makeTarget(); - request.set_target_position_rad(1.0); - request.set_max_velocity_rad_s(1.0); - request.set_acceleration_rad_s2(1.0); - request.mutable_wait()->set_timeout_ms(5000); - request.mutable_wait()->set_poll_period_ms(1000); - - grpc::ClientContext context; - context.set_deadline( - std::chrono::system_clock::now() + std::chrono::milliseconds(75)); - api::MotorCommandResponse response; - const auto started = std::chrono::steady_clock::now(); - const auto status = stub_->profilePosition(&context, request, &response); - EXPECT_EQ(status.error_code(), grpc::StatusCode::DEADLINE_EXCEEDED); - - const auto stop_deadline = - std::chrono::steady_clock::now() + std::chrono::milliseconds(250); - while (protocol_->quick_stop_count_.load() == 0 && - std::chrono::steady_clock::now() < stop_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(2)); - } - EXPECT_GE(protocol_->quick_stop_count_.load(), 1); - EXPECT_LT(std::chrono::steady_clock::now() - started, - std::chrono::milliseconds(350)); -} - -TEST_F(MotorServiceTest, CyclicPositionStreamAppliesSetpointAndStopsOnWritesDone) -{ - ASSERT_TRUE(startGrpcServer()); - - grpc::ClientContext context; - context.set_deadline( - std::chrono::system_clock::now() + std::chrono::seconds(2)); - auto stream = stub_->streamCyclicPosition(&context); - ASSERT_NE(stream, nullptr); - - api::CyclicPositionRequest open_request; - *open_request.mutable_open()->mutable_target() = makeTarget(); - open_request.mutable_open()->set_watchdog_timeout_ms(500); - ASSERT_TRUE(stream->Write(open_request)); - - api::CyclicControlResponse response; - ASSERT_TRUE(stream->Read(&response)); - ASSERT_TRUE(response.header().success()) - << response.header().error_message(); - EXPECT_EQ(response.phase(), api::CYCLIC_STREAM_OPENED); - - api::CyclicPositionRequest setpoint_request; - auto* setpoint = setpoint_request.mutable_setpoint(); - setpoint->set_sequence(1); - setpoint->set_target_position_rad(0.75); - setpoint->set_target_velocity_rad_s(0.2); - ASSERT_TRUE(stream->Write(setpoint_request)); - - response.Clear(); - ASSERT_TRUE(stream->Read(&response)); - ASSERT_TRUE(response.header().success()) - << response.header().error_message(); - EXPECT_EQ(response.phase(), api::CYCLIC_STREAM_APPLIED); - EXPECT_EQ(response.sequence(), 1); - EXPECT_FALSE(response.has_status()); - - ASSERT_TRUE(stream->WritesDone()); - response.Clear(); - ASSERT_TRUE(stream->Read(&response)); - EXPECT_TRUE(response.header().success()); - EXPECT_EQ(response.phase(), api::CYCLIC_STREAM_STOPPED); - EXPECT_EQ(response.sequence(), 1); - EXPECT_FALSE(stream->Read(&response)); - - const auto finish = stream->Finish(); - EXPECT_TRUE(finish.ok()) << finish.error_message(); - EXPECT_GE(protocol_->quick_stop_count_.load(), 1); -} - -TEST_F(MotorServiceTest, CyclicVelocityStreamAppliesAndStopsOnWritesDone) -{ - ASSERT_TRUE(startGrpcServer()); - - grpc::ClientContext context; - context.set_deadline( - std::chrono::system_clock::now() + std::chrono::seconds(2)); - auto stream = stub_->streamCyclicVelocity(&context); - ASSERT_NE(stream, nullptr); - - api::CyclicVelocityRequest open_request; - *open_request.mutable_open()->mutable_target() = makeTarget(); - open_request.mutable_open()->set_watchdog_timeout_ms(500); - ASSERT_TRUE(stream->Write(open_request)); - - api::CyclicControlResponse response; - ASSERT_TRUE(stream->Read(&response)); - ASSERT_TRUE(response.header().success()) - << response.header().error_message(); - EXPECT_EQ(response.phase(), api::CYCLIC_STREAM_OPENED); - EXPECT_TRUE(response.has_status()); - - api::CyclicVelocityRequest setpoint_request; - auto* setpoint = setpoint_request.mutable_setpoint(); - setpoint->set_sequence(1); - setpoint->set_target_velocity_rad_s(0.6); - ASSERT_TRUE(stream->Write(setpoint_request)); - - response.Clear(); - ASSERT_TRUE(stream->Read(&response)); - ASSERT_TRUE(response.header().success()) - << response.header().error_message(); - EXPECT_EQ(response.phase(), api::CYCLIC_STREAM_APPLIED); - EXPECT_EQ(response.sequence(), 1); - EXPECT_FALSE(response.has_status()); - - ASSERT_TRUE(stream->WritesDone()); - response.Clear(); - ASSERT_TRUE(stream->Read(&response)); - EXPECT_TRUE(response.header().success()); - EXPECT_EQ(response.phase(), api::CYCLIC_STREAM_STOPPED); - EXPECT_EQ(response.sequence(), 1); - EXPECT_TRUE(response.has_status()); - EXPECT_FALSE(stream->Read(&response)); - - const auto finish = stream->Finish(); - EXPECT_TRUE(finish.ok()) << finish.error_message(); - EXPECT_GE(protocol_->quick_stop_count_.load(), 1); -} - -TEST_F(MotorServiceTest, EmergencyStopDuringCyclicDispatchCannotPublishApplied) -{ - ASSERT_TRUE(startGrpcServer()); - protocol_->cyclic_position_delay_ms_ = 100; - - grpc::ClientContext context; - context.set_deadline( - std::chrono::system_clock::now() + std::chrono::seconds(3)); - auto stream = stub_->streamCyclicPosition(&context); - ASSERT_NE(stream, nullptr); - - api::CyclicPositionRequest open_request; - *open_request.mutable_open()->mutable_target() = makeTarget(); - ASSERT_TRUE(stream->Write(open_request)); - - api::CyclicControlResponse response; - ASSERT_TRUE(stream->Read(&response)); - ASSERT_EQ(response.phase(), api::CYCLIC_STREAM_OPENED); - - api::CyclicPositionRequest setpoint_request; - setpoint_request.mutable_setpoint()->set_sequence(1); - setpoint_request.mutable_setpoint()->set_target_position_rad(0.5); - ASSERT_TRUE(stream->Write(setpoint_request)); - - const auto dispatch_deadline = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (!protocol_->cyclic_position_started_.load() && - std::chrono::steady_clock::now() < dispatch_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - ASSERT_TRUE(protocol_->cyclic_position_started_.load()); - - api::EmergencyStopRequest stop_request; - *stop_request.mutable_target() = makeTarget(); - grpc::ServerContext stop_context; - api::MotorCommandResponse stop_response; - grpc::Status stop_status; - std::thread stopping([&]() { - stop_status = service_->emergencyStop( - &stop_context, &stop_request, &stop_response); - }); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - stream->WritesDone(); - stopping.join(); - ASSERT_TRUE(stop_status.ok()) << stop_status.error_message(); - - response.Clear(); - ASSERT_TRUE(stream->Read(&response)); - EXPECT_NE(response.phase(), api::CYCLIC_STREAM_APPLIED); - EXPECT_EQ(response.phase(), api::CYCLIC_STREAM_FAILED); - EXPECT_FALSE(response.header().success()); - EXPECT_FALSE(stream->Read(&response)); - const auto finish = stream->Finish(); - EXPECT_EQ(finish.error_code(), grpc::StatusCode::ABORTED); -} - -TEST_F(MotorServiceTest, CyclicOpenSetModeExceptionReturnsInternalAndQuickStops) -{ - ASSERT_TRUE(startGrpcServer()); - protocol_->throw_set_mode_ = true; - - grpc::ClientContext context; - context.set_deadline( - std::chrono::system_clock::now() + std::chrono::seconds(2)); - auto stream = stub_->streamCyclicPosition(&context); - ASSERT_NE(stream, nullptr); - - api::CyclicPositionRequest open_request; - *open_request.mutable_open()->mutable_target() = makeTarget(); - ASSERT_TRUE(stream->Write(open_request)); - stream->WritesDone(); - - api::CyclicControlResponse response; - EXPECT_FALSE(stream->Read(&response)); - const auto finish = stream->Finish(); - EXPECT_EQ(finish.error_code(), grpc::StatusCode::INTERNAL); - EXPECT_NE(finish.error_message().find("injected setMode exception"), - std::string::npos); - EXPECT_GE(protocol_->quick_stop_count_.load(), 1); -} - -TEST_F(MotorServiceTest, CyclicStreamReportsFailureWhenQuickStopFails) -{ - ASSERT_TRUE(startGrpcServer()); - protocol_->quick_stop_success_ = false; - - grpc::ClientContext context; - context.set_deadline( - std::chrono::system_clock::now() + std::chrono::seconds(2)); - auto stream = stub_->streamCyclicPosition(&context); - ASSERT_NE(stream, nullptr); - - api::CyclicPositionRequest open_request; - *open_request.mutable_open()->mutable_target() = makeTarget(); - open_request.mutable_open()->set_watchdog_timeout_ms(500); - ASSERT_TRUE(stream->Write(open_request)); - - api::CyclicControlResponse response; - ASSERT_TRUE(stream->Read(&response)); - ASSERT_EQ(response.phase(), api::CYCLIC_STREAM_OPENED); - ASSERT_TRUE(stream->WritesDone()); - - response.Clear(); - ASSERT_TRUE(stream->Read(&response)); - EXPECT_FALSE(response.header().success()); - EXPECT_EQ(response.phase(), api::CYCLIC_STREAM_FAILED); - EXPECT_FALSE(stream->Read(&response)); - const auto finish = stream->Finish(); - EXPECT_EQ(finish.error_code(), grpc::StatusCode::INTERNAL); - - api::ProfilePositionRequest profile_request; - *profile_request.mutable_target() = makeTarget(); - profile_request.set_target_position_rad(1.0); - profile_request.set_max_velocity_rad_s(1.0); - profile_request.set_acceleration_rad_s2(1.0); - grpc::ServerContext profile_context; - api::MotorCommandResponse profile_response; - const auto profile_status = service_->profilePosition( - &profile_context, &profile_request, &profile_response); - EXPECT_EQ(profile_status.error_code(), - grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_TRUE(profile_response.status().emergency_stopped()); -} - -TEST_F(MotorServiceTest, CyclicDriverExceptionReturnsInternalWithoutTerminating) -{ - ASSERT_TRUE(startGrpcServer()); - protocol_->throw_cyclic_position_ = true; - - grpc::ClientContext context; - context.set_deadline( - std::chrono::system_clock::now() + std::chrono::seconds(2)); - auto stream = stub_->streamCyclicPosition(&context); - ASSERT_NE(stream, nullptr); - - api::CyclicPositionRequest open_request; - *open_request.mutable_open()->mutable_target() = makeTarget(); - ASSERT_TRUE(stream->Write(open_request)); - - api::CyclicControlResponse response; - ASSERT_TRUE(stream->Read(&response)); - ASSERT_EQ(response.phase(), api::CYCLIC_STREAM_OPENED); - - api::CyclicPositionRequest setpoint_request; - setpoint_request.mutable_setpoint()->set_sequence(1); - setpoint_request.mutable_setpoint()->set_target_position_rad(0.5); - ASSERT_TRUE(stream->Write(setpoint_request)); - - response.Clear(); - ASSERT_TRUE(stream->Read(&response)); - EXPECT_FALSE(response.header().success()); - EXPECT_EQ(response.phase(), api::CYCLIC_STREAM_FAILED); - EXPECT_TRUE(stream->WritesDone()); - EXPECT_FALSE(stream->Read(&response)); - const auto finish = stream->Finish(); - EXPECT_EQ(finish.error_code(), grpc::StatusCode::INTERNAL); - EXPECT_GE(protocol_->quick_stop_count_.load(), 1); -} - -TEST_F(MotorServiceTest, CyclicPositionStreamWatchdogStopsSilentClient) -{ - ASSERT_TRUE(startGrpcServer()); - - grpc::ClientContext context; - context.set_deadline( - std::chrono::system_clock::now() + std::chrono::seconds(2)); - auto stream = stub_->streamCyclicPosition(&context); - ASSERT_NE(stream, nullptr); - - api::CyclicPositionRequest open_request; - *open_request.mutable_open()->mutable_target() = makeTarget(); - open_request.mutable_open()->set_watchdog_timeout_ms(25); - ASSERT_TRUE(stream->Write(open_request)); - - api::CyclicControlResponse response; - ASSERT_TRUE(stream->Read(&response)); - EXPECT_EQ(response.phase(), api::CYCLIC_STREAM_OPENED); - - response.Clear(); - ASSERT_TRUE(stream->Read(&response)); - EXPECT_FALSE(response.header().success()); - EXPECT_EQ(response.phase(), api::CYCLIC_STREAM_WATCHDOG_EXPIRED); - EXPECT_FALSE(stream->Read(&response)); - - const auto finish = stream->Finish(); - EXPECT_TRUE( - finish.error_code() == grpc::StatusCode::DEADLINE_EXCEEDED || - finish.error_code() == grpc::StatusCode::CANCELLED) - << finish.error_message(); - EXPECT_GE(protocol_->quick_stop_count_.load(), 1); -} - -TEST_F(MotorServiceTest, SystemStopAllPreemptsProfileAndResumesControl) -{ - protocol_->hold_position_ = true; - - api::ProfilePositionRequest motion_request; - *motion_request.mutable_target() = makeTarget(); - motion_request.set_target_position_rad(2.0); - motion_request.set_max_velocity_rad_s(1.0); - motion_request.set_acceleration_rad_s2(1.0); - motion_request.mutable_wait()->set_timeout_ms(5000); - motion_request.mutable_wait()->set_poll_period_ms(1); - - grpc::ServerContext motion_context; - api::MotorCommandResponse motion_response; - grpc::Status motion_status; - std::thread motion([&]() { - motion_status = service_->profilePosition( - &motion_context, &motion_request, &motion_response); - }); - - const auto command_deadline = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (!protocol_->command_started_.load() && - std::chrono::steady_clock::now() < command_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - if (!protocol_->command_started_.load()) { - motion_context.TryCancel(); - motion.join(); - FAIL() << "profile command did not start"; - return; - } - - auto& coordinator = globalMotorActivityCoordinator(); - const auto ticket = coordinator.beginStopAll(); - ASSERT_TRUE(ticket.valid()); - std::string stop_error; - EXPECT_TRUE(coordinator.stopAndWait( - ticket, std::chrono::seconds(1), &stop_error)) - << stop_error; - EXPECT_TRUE(coordinator.finishStopAll(ticket, true)); - - motion.join(); - EXPECT_EQ(motion_status.error_code(), grpc::StatusCode::ABORTED); - EXPECT_FALSE(motion_response.header().success()); - EXPECT_FALSE(motion_response.status().emergency_stopped()); - EXPECT_GE(protocol_->quick_stop_count_.load(), 1); - EXPECT_GT(protocol_->last_quick_stop_order_.load(), - protocol_->profile_command_order_.load()); - - protocol_->hold_position_ = false; - api::ProfilePositionRequest resumed_request; - *resumed_request.mutable_target() = makeTarget(); - resumed_request.set_target_position_rad(0.5); - resumed_request.set_max_velocity_rad_s(1.0); - resumed_request.set_acceleration_rad_s2(1.0); - resumed_request.mutable_wait()->set_settle_sample_count(1); - grpc::ServerContext resumed_context; - api::MotorCommandResponse resumed_response; - const auto resumed_status = service_->profilePosition( - &resumed_context, &resumed_request, &resumed_response); - ASSERT_TRUE(resumed_status.ok()) << resumed_status.error_message(); - EXPECT_TRUE(resumed_response.header().success()); - EXPECT_FALSE(resumed_response.status().emergency_stopped()); -} - -TEST_F(MotorServiceTest, FailedSystemStopAllRemainsFailClosedUntilRecovery) -{ - // Resolve the motor once so its control state is registered even though no - // motion RPC is active when StopAll starts. - api::GetMotorStatusRequest status_request; - *status_request.mutable_target() = makeTarget(); - grpc::ServerContext status_context; - api::GetMotorStatusResponse status_response; - ASSERT_TRUE(service_->getStatus( - &status_context, &status_request, &status_response).ok()); - - auto& coordinator = globalMotorActivityCoordinator(); - protocol_->quick_stop_success_ = false; - const auto failed_ticket = coordinator.beginStopAll(); - ASSERT_TRUE(failed_ticket.valid()); - std::string stop_error; - EXPECT_FALSE(coordinator.stopAndWait( - failed_ticket, std::chrono::seconds(1), &stop_error)); - EXPECT_FALSE(stop_error.empty()); - EXPECT_FALSE(coordinator.finishStopAll(failed_ticket, false)); - - api::ProfilePositionRequest blocked_request; - *blocked_request.mutable_target() = makeTarget(); - blocked_request.set_target_position_rad(1.0); - blocked_request.set_max_velocity_rad_s(1.0); - blocked_request.set_acceleration_rad_s2(1.0); - grpc::ServerContext blocked_context; - api::MotorCommandResponse blocked_response; - const auto blocked_status = service_->profilePosition( - &blocked_context, &blocked_request, &blocked_response); - EXPECT_EQ(blocked_status.error_code(), grpc::StatusCode::ABORTED); - EXPECT_NE(blocked_status.error_message().find("StopAll"), - std::string::npos); - - protocol_->quick_stop_success_ = true; - const auto recovery_ticket = coordinator.beginStopAll(); - ASSERT_TRUE(recovery_ticket.valid()); - stop_error.clear(); - ASSERT_TRUE(coordinator.stopAndWait( - recovery_ticket, std::chrono::seconds(1), &stop_error)) - << stop_error; - ASSERT_TRUE(coordinator.finishStopAll(recovery_ticket, true)); - - blocked_request.mutable_wait()->set_settle_sample_count(1); - grpc::ServerContext resumed_context; - api::MotorCommandResponse resumed_response; - const auto resumed_status = service_->profilePosition( - &resumed_context, &blocked_request, &resumed_response); - ASSERT_TRUE(resumed_status.ok()) << resumed_status.error_message(); - EXPECT_TRUE(resumed_response.header().success()); - EXPECT_FALSE(resumed_response.status().emergency_stopped()); -} - -} // namespace -} // namespace cmvr::service diff --git a/cmvr-es/service/grpc/server/tests/grpc_robot_arm_teleop_backend_test.cpp b/cmvr-es/service/grpc/server/tests/grpc_robot_arm_teleop_backend_test.cpp deleted file mode 100644 index b320b3b4..00000000 --- a/cmvr-es/service/grpc/server/tests/grpc_robot_arm_teleop_backend_test.cpp +++ /dev/null @@ -1,525 +0,0 @@ -#include "service/grpc/server/include/grpc_robot_arm_teleop_backend.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace cmvr::service { -namespace { - -class FakeRobotArm final : public device::RobotArm { -public: - FakeRobotArm() - { - id_ = "right_arm"; - model_.name = id_; - model_.dof = 2; - model_.joint_names = {"joint_1", "joint_2"}; - model_.joint_limits = { - {-1.0, 1.0, 2.0, 5.0, 10.0}, - {-0.5, 0.5, 3.0, 6.0, 10.0}}; - - state_.connected = true; - state_.powered_on = true; - state_.robot_mode = device::RobotMode::Idle; - state_.safety_mode = device::SafetyMode::Normal; - state_.actual_joint_state.position = {0.0, 0.0}; - state_.actual_joint_state.velocity = {0.0, 0.0}; - state_.actual_joint_state.effort = {1.0, 2.0}; - state_.actual_joint_state.sequence = 7; - state_.actual_joint_state.position_valid = true; - state_.actual_joint_state.velocity_valid = true; - state_.actual_joint_state.effort_valid = true; - } - - std::string typeName() const override { return "FakeRobotArm"; } - device::RobotModel getRobotModel() const override { return model_; } - std::size_t getDof() const override { return model_.dof; } - device::ArmState getRobotState() const override - { - ++get_state_calls; - return state_; - } - device::JointGroupState getJointState() const override - { - return state_.actual_joint_state; - } - device::CartesianPose getTcpPose( - device::FrameType = device::FrameType::Base) const override - { - return {}; - } - device::RobotMode getRobotMode() const override - { - return state_.robot_mode; - } - device::SafetyMode getSafetyMode() const override - { - return state_.safety_mode; - } - device::ControlMode getControlMode() const override - { - return device::ControlMode::Servo; - } - bool supportsTeleopGroupServo() const noexcept override - { - return group_servo_capability; - } - device::JointEffortSource jointEffortSource() const noexcept override - { - return effort_source; - } - - device::Result torqueOn() override - { - ++torque_on_calls; - return device::Result::success(); - } - device::Result torqueOff() override { return device::Result::success(); } - device::Result calibrateZeroQ(const std::string&) override - { - return device::Result::success(); - } - device::Result emergencyStop() override - { - return device::Result::success(); - } - device::Result protectiveStop() override - { - return device::Result::success(); - } - device::Result setSpeedScaling(double) override - { - return device::Result::success(); - } - double getSpeedScaling() const override { return 1.0; } - bool isProtectiveStopped() const override { return false; } - bool isEmergencyStopped() const override { return false; } - bool isFault() const override { return state_.fault; } - - device::Result moveJ( - const device::JointPositionCommand&, - const device::MotionOptions&) override - { - return device::Result::success(); - } - device::Result speedJ( - const device::JointVelocityCommand&, double, double) override - { - return device::Result::success(); - } - device::Result stopJ(double) override - { - return device::Result::success(); - } - device::Result moveL( - const device::CartesianPose&, - const device::MotionOptions&, - device::FrameType = device::FrameType::Base) override - { - return device::Result::success(); - } - device::Result speedL( - const device::CartesianVelocity&, - double, - double, - device::FrameType = device::FrameType::Base) override - { - return device::Result::success(); - } - device::Result stopL(std::optional = std::nullopt) override - { - return device::Result::success(); - } - device::Result stopMotion() override - { - ++stop_motion_calls; - return stop_motion_result; - } - - device::Result startServoMode( - const device::ServoOptions& options) override - { - ++start_servo_calls; - last_servo_period = options.period; - return start_servo_result; - } - device::Result servoJ( - const device::JointPositionCommand& target) override - { - ++servo_j_calls; - last_command = target.position; - if (servo_sleep.count() > 0) { - std::this_thread::sleep_for(servo_sleep); - } - return servo_j_result; - } - device::Result servoL( - const device::CartesianPose&, - device::FrameType = device::FrameType::Base) override - { - return device::Result::success(); - } - device::Result servoSpeedJ( - const device::JointVelocityCommand&) override - { - return device::Result::success(); - } - device::Result servoSpeedL( - const device::CartesianVelocity&, - device::FrameType = device::FrameType::Base) override - { - return device::Result::success(); - } - device::Result stopServoMode() override - { - ++stop_servo_calls; - return stop_servo_result; - } - - device::Result connect(const std::string&, int) override - { - return device::Result::success(); - } - device::Result disconnect() override - { - return device::Result::success(); - } - bool isConnected() const override { return state_.connected; } - device::Result powerOn() override { return torqueOn(); } - device::Result powerOff() override { return torqueOff(); } - device::Result brakeRelease() override - { - return device::Result::success(); - } - device::Result shutdown() override - { - return device::Result::success(); - } - device::Result clearFault() override - { - return device::Result::success(); - } - device::Result unlockProtectiveStop() override - { - return device::Result::success(); - } - device::Result loadProgram(const std::string&) override - { - return device::Result::success(); - } - device::Result playProgram() override - { - return device::Result::success(); - } - device::Result pauseProgram() override - { - return device::Result::success(); - } - device::Result stopProgram() override - { - return device::Result::success(); - } - std::vector ik( - const std::string&, - const std::string&, - const device::CartesianPose&) override - { - return {}; - } - std::shared_ptr kinematicsSolver() const override - { - return nullptr; - } - device::CartesianPose fk( - const std::string&, const std::string&) override - { - return {}; - } - device::CartesianPose fk(bool = true) override { return {}; } - device::CartesianVelocity getSpeedLCommandTwistBase() const override - { - return {}; - } - bool busy() const override { return false; } - - bool group_servo_capability{true}; - device::JointEffortSource effort_source{ - device::JointEffortSource::Unspecified}; - mutable int get_state_calls{0}; - int torque_on_calls{0}; - int start_servo_calls{0}; - int servo_j_calls{0}; - int stop_motion_calls{0}; - int stop_servo_calls{0}; - double last_servo_period{0.0}; - std::vector last_command; - std::chrono::microseconds servo_sleep{0}; - device::Result start_servo_result{device::Result::success()}; - device::Result servo_j_result{device::Result::success()}; - device::Result stop_motion_result{device::Result::success()}; - device::Result stop_servo_result{device::Result::success()}; - device::RobotModel model_; - device::ArmState state_; -}; - -config::ArmTeleopBackendConfig validConfig() -{ - config::ArmTeleopBackendConfig config; - config.set_enable(true); - config.set_device_id("right_arm"); - config.set_model_sha256(std::string(64, 'a')); - config.set_calibration_sha256(std::string(64, 'b')); - config.set_base_frame("base_link"); - config.set_tool_frame("tool_link"); - config.set_servo_period_s(0.01); - config.set_max_apply_duration_us(5000); - config.set_require_powered(true); - config.set_max_initial_position_step_rad(0.2); - config.set_max_position_step_rad(0.015); - return config; -} - -arm_teleop::JointSetpoint setpoint( - const double first, - const double second, - const double first_velocity = 0.0, - const double second_velocity = 0.0) -{ - arm_teleop::JointSetpoint value; - value.set_sequence(1); - value.add_position_rad(first); - value.add_position_rad(second); - value.add_velocity_rad_s(first_velocity); - value.add_velocity_rad_s(second_velocity); - value.set_valid_for_us(5000); - return value; -} - -arm_teleop::OpenSession openRequest() -{ - arm_teleop::OpenSession request; - request.set_requested_command_rate_hz(100); - return request; -} - -std::chrono::steady_clock::time_point liveDeadline() -{ - return std::chrono::steady_clock::now() + - std::chrono::seconds(1); -} - -TEST(RobotArmTeleopBackendTest, RejectsArmWithoutExplicitGroupServoCapability) -{ - auto arm = std::make_shared(); - arm->group_servo_capability = false; - const auto backend = - makeRobotArmTeleopBackend(arm, validConfig()); - - EXPECT_FALSE(backend->available()); - EXPECT_NE( - backend->unavailableReason().find("capability"), - std::string::npos); - EXPECT_EQ(arm->start_servo_calls, 0); -} - -TEST(RobotArmTeleopBackendTest, OpenStartsServoButNeverPowersArm) -{ - auto arm = std::make_shared(); - const auto backend = - makeRobotArmTeleopBackend(arm, validConfig()); - - ASSERT_TRUE(backend->available()) - << backend->unavailableReason(); - EXPECT_TRUE(backend->open(openRequest()).success); - EXPECT_EQ(arm->start_servo_calls, 1); - EXPECT_DOUBLE_EQ(arm->last_servo_period, 0.01); - EXPECT_EQ(arm->torque_on_calls, 0); -} - -TEST(RobotArmTeleopBackendTest, AppliesSetpointAndAlwaysRunsBothStopPaths) -{ - auto arm = std::make_shared(); - const auto backend = - makeRobotArmTeleopBackend(arm, validConfig()); - ASSERT_TRUE(backend->open(openRequest()).success); - - ASSERT_TRUE( - backend->applySetpoint( - setpoint(0.1, 0.1), liveDeadline()).success); - EXPECT_EQ(arm->servo_j_calls, 1); - EXPECT_EQ(arm->last_command, (std::vector{0.1, 0.1})); - - arm->stop_motion_result = device::Result::failure( - device::ArmErrorCode::CommandFailed, "motion stop failed"); - const auto result = backend->stop( - arm_teleop::STOP_REASON_OPERATOR_REQUEST, "test"); - EXPECT_FALSE(result.success); - EXPECT_EQ(arm->stop_motion_calls, 1); - EXPECT_EQ(arm->stop_servo_calls, 1); -} - -TEST(RobotArmTeleopBackendTest, RejectsInitialAndContinuousPositionSteps) -{ - auto arm = std::make_shared(); - const auto backend = - makeRobotArmTeleopBackend(arm, validConfig()); - ASSERT_TRUE(backend->open(openRequest()).success); - - EXPECT_EQ( - backend->applySetpoint( - setpoint(0.21, 0.0), liveDeadline()).status_code, - grpc::StatusCode::OUT_OF_RANGE); - ASSERT_TRUE( - backend->applySetpoint( - setpoint(0.1, 0.1), liveDeadline()).success); - EXPECT_EQ( - backend->applySetpoint( - setpoint(0.12, 0.1), liveDeadline()).status_code, - grpc::StatusCode::OUT_OF_RANGE); - EXPECT_EQ(arm->servo_j_calls, 1); -} - -TEST(RobotArmTeleopBackendTest, RejectsJointPositionAndVelocityLimits) -{ - auto arm = std::make_shared(); - const auto backend = - makeRobotArmTeleopBackend(arm, validConfig()); - ASSERT_TRUE(backend->open(openRequest()).success); - - EXPECT_EQ( - backend->applySetpoint( - setpoint(1.01, 0.0), liveDeadline()).status_code, - grpc::StatusCode::OUT_OF_RANGE); - EXPECT_EQ( - backend->applySetpoint( - setpoint(0.0, 0.0, 2.01, 0.0), liveDeadline()) - .status_code, - grpc::StatusCode::OUT_OF_RANGE); - EXPECT_EQ(arm->servo_j_calls, 0); -} - -TEST(RobotArmTeleopBackendTest, DetectsServoApplyTimeout) -{ - auto arm = std::make_shared(); - auto config = validConfig(); - config.set_max_apply_duration_us(500); - const auto backend = - makeRobotArmTeleopBackend(arm, config); - ASSERT_TRUE(backend->open(openRequest()).success); - arm->servo_sleep = std::chrono::microseconds(1500); - - const auto result = - backend->applySetpoint( - setpoint(0.1, 0.1), liveDeadline()); - EXPECT_FALSE(result.success); - EXPECT_EQ( - result.status_code, - grpc::StatusCode::DEADLINE_EXCEEDED); - EXPECT_EQ(arm->servo_j_calls, 1); -} - -TEST(RobotArmTeleopBackendTest, RejectsInsufficientDeadlineBudgetBeforeDispatch) -{ - auto arm = std::make_shared(); - const auto backend = - makeRobotArmTeleopBackend(arm, validConfig()); - ASSERT_TRUE(backend->open(openRequest()).success); - - const auto result = backend->applySetpoint( - setpoint(0.1, 0.1), - std::chrono::steady_clock::now() + - std::chrono::microseconds(100)); - EXPECT_FALSE(result.success); - EXPECT_EQ( - result.status_code, - grpc::StatusCode::DEADLINE_EXCEEDED); - EXPECT_EQ(arm->servo_j_calls, 0); -} - -TEST(RobotArmTeleopBackendTest, ExpiredDeadlineNeverDispatchesServoCommand) -{ - auto arm = std::make_shared(); - const auto backend = - makeRobotArmTeleopBackend(arm, validConfig()); - ASSERT_TRUE(backend->open(openRequest()).success); - - const auto result = backend->applySetpoint( - setpoint(0.1, 0.1), - std::chrono::steady_clock::now()); - EXPECT_FALSE(result.success); - EXPECT_EQ( - result.status_code, - grpc::StatusCode::DEADLINE_EXCEEDED); - EXPECT_EQ(arm->servo_j_calls, 0); -} - -TEST(RobotArmTeleopBackendTest, RejectsUnsupportedRateAndEarlyRedispatch) -{ - auto arm = std::make_shared(); - const auto backend = - makeRobotArmTeleopBackend(arm, validConfig()); - auto too_fast = openRequest(); - too_fast.set_requested_command_rate_hz(101); - EXPECT_EQ( - backend->open(too_fast).status_code, - grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_EQ(arm->start_servo_calls, 0); - - ASSERT_TRUE(backend->open(openRequest()).success); - ASSERT_TRUE( - backend->applySetpoint( - setpoint(0.1, 0.1), liveDeadline()).success); - EXPECT_EQ( - backend->applySetpoint( - setpoint(0.105, 0.105), liveDeadline()).status_code, - grpc::StatusCode::RESOURCE_EXHAUSTED); - EXPECT_EQ(arm->servo_j_calls, 1); -} - -TEST(RobotArmTeleopBackendTest, SnapshotUsesCacheAndHidesUnverifiedEffort) -{ - auto arm = std::make_shared(); - const auto backend = - makeRobotArmTeleopBackend(arm, validConfig()); - ASSERT_TRUE(backend->open(openRequest()).success); - const int calls_after_open = arm->get_state_calls; - - const auto first = backend->snapshot(); - const auto second = backend->snapshot(); - EXPECT_EQ(arm->get_state_calls, calls_after_open); - EXPECT_TRUE(first.joint_state.position_valid()); - EXPECT_TRUE(first.joint_state.velocity_valid()); - EXPECT_FALSE(first.joint_state.effort_valid()); - EXPECT_EQ(first.joint_state.effort_nm_size(), 0); - EXPECT_EQ( - second.joint_state.effort_source(), - arm_teleop::EFFORT_SOURCE_UNSPECIFIED); -} - -TEST(RobotArmTeleopBackendTest, PublishesEffortOnlyWithExplicitSource) -{ - auto arm = std::make_shared(); - arm->effort_source = device::JointEffortSource::JointSensor; - const auto backend = - makeRobotArmTeleopBackend(arm, validConfig()); - ASSERT_TRUE(backend->open(openRequest()).success); - - const auto snapshot = backend->snapshot(); - EXPECT_TRUE(backend->supportsForceFeedback()); - EXPECT_TRUE(snapshot.joint_state.effort_valid()); - EXPECT_EQ(snapshot.joint_state.effort_nm_size(), 2); - EXPECT_EQ( - snapshot.joint_state.effort_source(), - arm_teleop::EFFORT_SOURCE_JOINT_SENSOR); -} - -} // namespace -} // namespace cmvr::service diff --git a/cmvr-es/service/grpc/server/tests/grpc_security_test.cpp b/cmvr-es/service/grpc/server/tests/grpc_security_test.cpp deleted file mode 100644 index 17b1e1f7..00000000 --- a/cmvr-es/service/grpc/server/tests/grpc_security_test.cpp +++ /dev/null @@ -1,294 +0,0 @@ -#include "service/grpc/server/include/grpc_security.h" - -#include -#include -#include -#include - -#include -#include - -#include "cmvr/api/agv_service.pb.h" -#include "cmvr/api/arm_service.pb.h" -#include "cmvr/api/arm_teleop_v1.pb.h" -#include "cmvr/api/biohead_service.pb.h" -#include "cmvr/api/camera_service.pb.h" -#include "cmvr/api/dexhand_service.pb.h" -#include "cmvr/api/hlc_service.pb.h" -#include "cmvr/api/microphone_service.pb.h" -#include "cmvr/api/motor_service.pb.h" -#include "cmvr/api/speaker_service.pb.h" -#include "cmvr/api/system_service.pb.h" -#include "cmvr/api/test_service.pb.h" - -namespace cmvr::service { -namespace { - -GrpcMethodPolicy readPolicy() -{ - return { - "/cmvr.api.SystemService/GetSystemInfo", - GrpcAccessClass::Read, - GrpcRole::Observer}; -} - -GrpcMethodPolicy recoveryPolicy() -{ - return { - "/cmvr.api.SystemService/RecoverSafetyState", - GrpcAccessClass::Recover, - GrpcRole::SafetyAdmin}; -} - -class SafetyAdminProvider final : public GrpcAuthenticationProvider { -public: - GrpcAuthenticationResult authenticate(const GrpcCallFacts&) const override - { - GrpcPrincipal principal; - principal.id = "maintenance"; - principal.method = GrpcAuthenticationMethod::StaticToken; - principal.authenticated = true; - principal.roles = {GrpcRole::SafetyAdmin}; - return {std::move(principal), grpc::Status::OK}; - } -}; - -TEST(GrpcSecurityConfigTest, - LegacyConfigPreservesAnonymousAccessButDisablesRecovery) -{ - config::GRPCServerConfig config; - const auto result = resolveGrpcSecurityConfig(config, "0.0.0.0"); - - ASSERT_TRUE(result.valid) << result.error; - EXPECT_TRUE(result.config.legacy_compatibility); - EXPECT_TRUE(result.config.insecure_non_loopback); - EXPECT_EQ( - result.config.authentication, GrpcAuthenticationMethod::Disabled); - EXPECT_EQ( - result.config.recovery_exposure, GrpcRecoveryExposure::Disabled); - EXPECT_FALSE(result.warnings.empty()); -} - -TEST(GrpcSecurityConfigTest, - ExplicitNonLoopbackInsecureRequiresAcknowledgement) -{ - config::GRPCServerConfig config; - auto* security = config.mutable_security(); - security->set_transport_mode(config::GRPCSecurityConfig::INSECURE); - security->set_authentication_mode(config::GRPCSecurityConfig::DISABLED); - security->set_recovery_exposure( - config::GRPCSecurityConfig::RECOVERY_DISABLED); - - const auto rejected = resolveGrpcSecurityConfig(config, "0.0.0.0"); - EXPECT_FALSE(rejected.valid); - - security->set_allow_insecure_non_loopback(true); - const auto accepted = resolveGrpcSecurityConfig(config, "0.0.0.0"); - ASSERT_TRUE(accepted.valid) << accepted.error; - EXPECT_TRUE(accepted.config.insecure_non_loopback); -} - -TEST(GrpcSecurityConfigTest, - UnsupportedAuthenticationNeverFallsBackToDisabled) -{ - config::GRPCServerConfig config; - auto* security = config.mutable_security(); - security->set_transport_mode(config::GRPCSecurityConfig::INSECURE); - security->set_authentication_mode( - config::GRPCSecurityConfig::STATIC_TOKEN); - security->set_recovery_exposure( - config::GRPCSecurityConfig::RECOVERY_AUTHORIZED); - - const auto result = resolveGrpcSecurityConfig(config, "127.0.0.1"); - EXPECT_FALSE(result.valid); - EXPECT_NE(result.error.find("DISABLED"), std::string::npos); -} - -TEST(GrpcSecurityConfigTest, EnabledRecoveryRequiresPersistentAuditFile) -{ - config::GRPCServerConfig config; - auto* security = config.mutable_security(); - security->set_transport_mode(config::GRPCSecurityConfig::INSECURE); - security->set_authentication_mode(config::GRPCSecurityConfig::DISABLED); - security->set_recovery_exposure( - config::GRPCSecurityConfig::RECOVERY_LOCAL_ONLY); - - const auto rejected = - resolveGrpcSecurityConfig(config, "127.0.0.1"); - EXPECT_FALSE(rejected.valid); - EXPECT_NE(rejected.error.find("audit_file"), std::string::npos); - - security->set_audit_file("/var/lib/cmvr-es/recovery-audit.jsonl"); - const auto accepted = - resolveGrpcSecurityConfig(config, "127.0.0.1"); - ASSERT_TRUE(accepted.valid) << accepted.error; - EXPECT_EQ( - accepted.config.recovery_audit_file, - "/var/lib/cmvr-es/recovery-audit.jsonl"); -} - -TEST(GrpcSecurityGatewayTest, DisabledProviderDoesNotTrustIdentityMetadata) -{ - auto gateway = makeDefaultGrpcSecurityGateway(); - GrpcCallFacts facts; - facts.peer = "ipv4:10.0.0.5:12345"; - facts.metadata.emplace("principal", "safety-admin"); - facts.metadata.emplace("role", "SafetyAdmin"); - - const auto call = gateway->beginCall(std::move(facts), readPolicy()); - - ASSERT_TRUE(call.allowed()) << call.status().error_message(); - EXPECT_EQ(call.context().principal.id, "anonymous"); - EXPECT_FALSE(call.context().principal.authenticated); - ASSERT_EQ(call.context().principal.roles.size(), 1U); - EXPECT_EQ(call.context().principal.roles.front(), GrpcRole::Anonymous); -} - -TEST(GrpcSecurityGatewayTest, RecoveryIsDisabledBeforeLedgerAdmission) -{ - auto gateway = makeDefaultGrpcSecurityGateway(); - const auto call = gateway->beginCall(GrpcCallFacts{}, recoveryPolicy()); - - EXPECT_FALSE(call.allowed()); - EXPECT_EQ( - call.status().error_code(), grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_EQ(call.status().error_message(), "RECOVERY_RPC_DISABLED"); -} - -TEST(GrpcSecurityGatewayTest, LocalOnlyRecoveryUsesActualPeerClassification) -{ - GrpcSecurityRuntimeConfig config; - config.recovery_exposure = GrpcRecoveryExposure::LocalOnly; - auto gateway = makeGrpcSecurityGateway(config); - - GrpcCallFacts remote; - remote.peer = "ipv4:192.168.1.20:42000"; - EXPECT_FALSE(gateway->beginCall(remote, recoveryPolicy()).allowed()); - - GrpcCallFacts local; - local.peer = "ipv4:127.0.0.1:42000"; - EXPECT_TRUE(gateway->beginCall(local, recoveryPolicy()).allowed()); - - EXPECT_TRUE(isLocalGrpcPeer("ipv6:[::1]")); - EXPECT_TRUE(isLocalGrpcPeer("unix:/run/cmvr-es.sock")); - EXPECT_FALSE(isLocalGrpcPeer("ipv4:10.0.0.1:50051")); -} - -TEST(GrpcSecurityGatewayTest, AuthorizedRecoveryAcceptsSafetyAdminProvider) -{ - GrpcSecurityRuntimeConfig config; - config.authentication = GrpcAuthenticationMethod::StaticToken; - config.recovery_exposure = GrpcRecoveryExposure::Authorized; - auto gateway = std::make_shared( - config, - std::make_shared(), - std::make_shared( - GrpcRecoveryExposure::Authorized)); - - const auto call = gateway->beginCall(GrpcCallFacts{}, recoveryPolicy()); - ASSERT_TRUE(call.allowed()) << call.status().error_message(); - EXPECT_EQ(call.context().principal.id, "maintenance"); -} - -TEST(GrpcSecurityGatewayTest, AuditUsesEffectiveServerPrincipal) -{ - std::vector records; - GrpcSecurityRuntimeConfig config; - auto gateway = makeGrpcSecurityGateway( - config, - [&records](const GrpcSecurityAuditRecord& record) { - records.push_back(record); - }); - - GrpcCallFacts facts; - facts.metadata.emplace("x-correlation-id", "request-42"); - ASSERT_TRUE(gateway->beginCall(std::move(facts), readPolicy()).allowed()); - - ASSERT_EQ(records.size(), 1U); - EXPECT_EQ(records.front().correlation_id, "request-42"); - EXPECT_EQ(records.front().principal_id, "anonymous"); - EXPECT_FALSE(records.front().authenticated); -} - -TEST(GrpcMethodPolicyRegistryTest, RejectsDuplicatesAndSortsSnapshot) -{ - GrpcMethodPolicyRegistry registry; - EXPECT_TRUE(registry.registerPolicy(recoveryPolicy())); - EXPECT_TRUE(registry.registerPolicy(readPolicy())); - EXPECT_FALSE(registry.registerPolicy(readPolicy())); - - const auto policies = registry.snapshot(); - ASSERT_EQ(policies.size(), 2U); - EXPECT_LT(policies[0].full_method_name, policies[1].full_method_name); - EXPECT_TRUE(registry.find(readPolicy().full_method_name).has_value()); - EXPECT_FALSE(registry.find("/unknown/method").has_value()); -} - -TEST(GrpcMethodPolicyRegistryTest, - DefaultRegistryCoversEveryCompiledApiMethod) -{ - const auto& registry = defaultGrpcMethodPolicyRegistry(); - const auto* pool = google::protobuf::DescriptorPool::generated_pool(); - const std::vector services{ - "cmvr.api.AgvService", - "cmvr.api.ArmService", - "cmvr.api.armteleop.v1.ArmTeleopService", - "cmvr.api.BioHeadService", - "cmvr.api.CameraService", - "cmvr.api.DexHandService", - "cmvr.api.HlcService", - "cmvr.api.MicPhoneService", - "cmvr.api.MotorService", - "cmvr.api.SpeakerService", - "cmvr.api.SystemService", - "cmvr.api.TestService"}; - - std::size_t method_count = 0; - for (const auto& service_name : services) { - const auto* service = pool->FindServiceByName(service_name); - ASSERT_NE(service, nullptr) << service_name; - for (int index = 0; index < service->method_count(); ++index) { - const auto* method = service->method(index); - const std::string full_name = - "/" + service_name + "/" + - std::string(method->name()); - const auto policy = registry.find(full_name); - ASSERT_TRUE(policy.has_value()) << full_name; - EXPECT_EQ( - policy->mutating, - policy->access != GrpcAccessClass::Read) << full_name; - if (policy->mutating) { - EXPECT_NE( - policy->command_intent, - safety::CommandIntent::Observe) << full_name; - } - ++method_count; - } - } - EXPECT_EQ(registry.snapshot().size(), method_count); -} - -TEST(GrpcMethodPolicyRegistryTest, - TouchIsAControlActuationRatherThanAReadOnlySensorCall) -{ - const auto policy = defaultGrpcMethodPolicyRegistry().find( - "/cmvr.api.HlcService/touch"); - ASSERT_TRUE(policy.has_value()); - EXPECT_EQ(policy->access, GrpcAccessClass::Mutate); - EXPECT_EQ(policy->command_intent, safety::CommandIntent::Actuate); - EXPECT_EQ(policy->policy_family, safety::SafetyPolicyFamily::Control); - EXPECT_TRUE(policy->mutating); - EXPECT_FALSE(policy->safety_lane); -} - -TEST(GrpcMethodPolicyRegistryTest, UnregisteredMethodFailsClosed) -{ - const auto call = beginRegisteredGrpcCall( - makeDefaultGrpcSecurityGateway(), nullptr, - "/cmvr.api.UnknownService/Mutate"); - EXPECT_FALSE(call.allowed()); - EXPECT_EQ(call.status().error_code(), grpc::StatusCode::INTERNAL); -} - -} // namespace -} // namespace cmvr::service diff --git a/cmvr-es/service/grpc/server/tests/grpc_system_service_test.cpp b/cmvr-es/service/grpc/server/tests/grpc_system_service_test.cpp deleted file mode 100644 index 227355bd..00000000 --- a/cmvr-es/service/grpc/server/tests/grpc_system_service_test.cpp +++ /dev/null @@ -1,3612 +0,0 @@ -#include "service/grpc/server/include/grpc_system_service.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "cmvr/config/device_manager_config/device_manager_config.pb.h" -#include "cmvr/config/task_manager_config/task_manager_config.pb.h" -#include "devices/agv/abstract_agv.h" -#include "devices/arm/robot_arm.h" -#include "devices/camera/abstract_camera.h" -#include "devices/microphone/abstract_microphone.h" -#include "devices/speaker/abstract_speaker.h" -#include "manager/control_authority_manager/include/control_authority_manager.h" -#include "manager/device_manager/include/device_manager.h" -#include "manager/media_source_manager/include/device_media_source_adapter.h" -#include "manager/task_manager/include/task_manager.h" -#include "service/grpc/action/include/action_queue_executor.h" -#include "service/grpc/server/include/camera_operational_activity_registry.h" -#include "service/grpc/server/include/camera_ptz_activity_registry.h" -#include "service/grpc/server/include/grpc_camera_service.h" -#include "service/grpc/server/include/grpc_recovery_audit.h" -#include "service/grpc/server/include/grpc_security.h" -#include "service/grpc/server/include/media_activity_coordinator.h" -#include "service/grpc/server/include/motor_activity_coordinator.h" -#include "service/grpc/stop_all/include/stop_all_admission_gate.h" -#include "task/task_factory.h" - -namespace cmvr::service { -namespace { - -class AllowAllAuthorizationPolicy final : public GrpcAuthorizationPolicy { -public: - GrpcAuthorizationDecision authorize( - const GrpcRequestContext&, - const GrpcMethodPolicy&) const override - { - return {true, grpc::Status::OK}; - } -}; - -class MemoryRecoveryAuditSink final : public RecoveryAuditSink { -public: - bool append( - const RecoveryAuditRecord& record, - std::string* error) noexcept override - { - if (fail) { - if (error) { - *error = "injected audit failure"; - } - return false; - } - records.push_back(record); - return true; - } - - bool fail{false}; - std::vector records; -}; - -std::shared_ptr makeAllowAllRecoveryGateway() -{ - GrpcSecurityRuntimeConfig config; - config.recovery_exposure = GrpcRecoveryExposure::LocalOnly; - return std::make_shared( - config, - std::make_shared(), - std::make_shared()); -} - -class SnapshotDevice final : public device::AbstractDevice { -public: - SnapshotDevice(std::string id, - device::DeviceKind kind, - std::string type_name, - device::DeviceHealthSnapshot health = {}) - : AbstractDevice(std::move(id)), - kind_(kind), - type_name_(std::move(type_name)), - health_(std::move(health)) - { - } - - device::DeviceKind kind() const noexcept override { return kind_; } - std::string typeName() const override { return type_name_; } - device::DeviceHealthSnapshot healthSnapshot() override - { - return health_; - } - bool stop() override - { - std::unique_lock lock(stop_mutex_); - ++stop_calls_; - if (block_next_stop_) { - block_next_stop_ = false; - stop_started_ = true; - stop_started_cv_.notify_all(); - stop_release_cv_.wait( - lock, - [this]() { return release_stop_; }); - } - return true; - } - int stopCalls() const - { - std::lock_guard lock(stop_mutex_); - return stop_calls_; - } - void blockNextStop() - { - std::lock_guard lock(stop_mutex_); - block_next_stop_ = true; - stop_started_ = false; - release_stop_ = false; - } - bool waitForStop(const std::chrono::milliseconds timeout) - { - std::unique_lock lock(stop_mutex_); - return stop_started_cv_.wait_for( - lock, timeout, [this]() { return stop_started_; }); - } - void releaseStop() - { - { - std::lock_guard lock(stop_mutex_); - release_stop_ = true; - } - stop_release_cv_.notify_all(); - } - -private: - device::DeviceKind kind_; - std::string type_name_; - device::DeviceHealthSnapshot health_; - mutable std::mutex stop_mutex_; - std::condition_variable stop_started_cv_; - std::condition_variable stop_release_cv_; - int stop_calls_{0}; - bool block_next_stop_{false}; - bool stop_started_{false}; - bool release_stop_{false}; -}; - -class StopAllTestCamera final : public device::AbstractCamera { -public: - StopAllTestCamera(std::string id, - const bool stop_clears_recording = true, - const bool stop_throws = false) - : stop_clears_recording_(stop_clears_recording), - stop_throws_(stop_throws) - { - id_ = std::move(id); - state_.is_initialized = true; - state_.is_recording = true; - } - - std::string typeName() const override { return "StopAllTestCamera"; } - - void getState(device::CameraState& state) override - { - std::lock_guard lock(mutex_); - state = state_; - } - - void stopRecording() override - { - { - std::lock_guard lock(mutex_); - ++stop_recording_calls_; - if (stop_throws_) { - stop_recording_condition_.notify_all(); - throw std::runtime_error( - "injected camera recording stop failure"); - } - if (stop_clears_recording_) { - state_.is_recording = false; - } - } - stop_recording_condition_.notify_all(); - } - - bool startOperationalActivity() override - { - std::lock_guard lock(mutex_); - operational_active_ = true; - return true; - } - - bool stopOperationalActivity() override - { - std::lock_guard lock(mutex_); - ++operational_stop_calls_; - if (state_.is_recording) { - return false; - } - operational_active_ = false; - return true; - } - - bool controlPtz(device::PtzCommand, - const bool stop, - int) override - { - std::lock_guard lock(mutex_); - ++ptz_calls_; - ptz_active_ = !stop; - return true; - } - - bool stop() override - { - std::lock_guard lock(mutex_); - ++lifecycle_stop_calls_; - return true; - } - - bool isRecording() const - { - std::lock_guard lock(mutex_); - return state_.is_recording; - } - - void setRecording(const bool recording) - { - std::lock_guard lock(mutex_); - state_.is_recording = recording; - } - - void startRecording(const std::string&) override - { - { - std::unique_lock lock(start_recording_control_mutex_); - if (block_next_start_recording_) { - block_next_start_recording_ = false; - start_recording_entered_ = true; - start_recording_entered_condition_.notify_all(); - start_recording_release_condition_.wait( - lock, [this] { return release_start_recording_; }); - } - } - { - std::lock_guard lock(mutex_); - state_.is_recording = true; - ++start_recording_calls_; - } - start_recording_condition_.notify_all(); - } - - void blockNextStartRecording() - { - std::lock_guard lock(start_recording_control_mutex_); - block_next_start_recording_ = true; - start_recording_entered_ = false; - release_start_recording_ = false; - } - - bool waitForStartRecordingEntered( - const std::chrono::milliseconds timeout) - { - std::unique_lock lock(start_recording_control_mutex_); - return start_recording_entered_condition_.wait_for( - lock, timeout, [this] { return start_recording_entered_; }); - } - - void releaseBlockedStartRecording() - { - { - std::lock_guard lock(start_recording_control_mutex_); - release_start_recording_ = true; - } - start_recording_release_condition_.notify_all(); - } - - bool waitForStartRecordingCalls( - const int expected, - const std::chrono::milliseconds timeout) - { - std::unique_lock lock(mutex_); - return start_recording_condition_.wait_for( - lock, - timeout, - [this, expected] { - return start_recording_calls_ >= expected; - }); - } - - int stopRecordingCalls() const - { - std::lock_guard lock(mutex_); - return stop_recording_calls_; - } - - bool waitForStopRecordingCalls( - const int expected, - const std::chrono::milliseconds timeout) - { - std::unique_lock lock(mutex_); - return stop_recording_condition_.wait_for( - lock, - timeout, - [this, expected] { - return stop_recording_calls_ >= expected; - }); - } - - int lifecycleStopCalls() const - { - std::lock_guard lock(mutex_); - return lifecycle_stop_calls_; - } - - int operationalStopCalls() const - { - std::lock_guard lock(mutex_); - return operational_stop_calls_; - } - - bool operationalActive() const - { - std::lock_guard lock(mutex_); - return operational_active_; - } - - bool ptzActive() const - { - std::lock_guard lock(mutex_); - return ptz_active_; - } - - int ptzCalls() const - { - std::lock_guard lock(mutex_); - return ptz_calls_; - } - -private: - mutable std::mutex mutex_; - std::condition_variable stop_recording_condition_; - std::condition_variable start_recording_condition_; - mutable std::mutex start_recording_control_mutex_; - std::condition_variable start_recording_entered_condition_; - std::condition_variable start_recording_release_condition_; - int start_recording_calls_{0}; - int stop_recording_calls_{0}; - int lifecycle_stop_calls_{0}; - int operational_stop_calls_{0}; - int ptz_calls_{0}; - bool operational_active_{false}; - bool ptz_active_{false}; - bool block_next_start_recording_{false}; - bool start_recording_entered_{false}; - bool release_start_recording_{false}; - bool stop_clears_recording_{true}; - bool stop_throws_{false}; -}; - -class StopAllTestMicrophone final : public device::AbstractMicrophone { -public: - StopAllTestMicrophone(std::string id, - const bool stop_clears_recording = true, - const bool stop_throws = false) - : stop_clears_recording_(stop_clears_recording), - stop_throws_(stop_throws) - { - id_ = std::move(id); - state_.is_initialized = true; - state_.is_recording = true; - } - - std::string typeName() const override - { - return "StopAllTestMicrophone"; - } - - void getState(device::MicrophoneState& state) override - { - std::lock_guard lock(mutex_); - state = state_; - } - - void stopRecording() override - { - std::lock_guard lock(mutex_); - ++stop_recording_calls_; - if (stop_throws_) { - throw std::runtime_error( - "injected microphone recording stop failure"); - } - if (stop_clears_recording_) { - state_.is_recording = false; - } - } - - bool stop() override - { - std::lock_guard lock(mutex_); - ++lifecycle_stop_calls_; - return true; - } - - bool isRecording() const - { - std::lock_guard lock(mutex_); - return state_.is_recording; - } - - int stopRecordingCalls() const - { - std::lock_guard lock(mutex_); - return stop_recording_calls_; - } - - int lifecycleStopCalls() const - { - std::lock_guard lock(mutex_); - return lifecycle_stop_calls_; - } - -private: - mutable std::mutex mutex_; - int stop_recording_calls_{0}; - int lifecycle_stop_calls_{0}; - bool stop_clears_recording_{true}; - bool stop_throws_{false}; -}; - -class StopAllTestSpeaker final : public device::AbstractSpeaker { -public: - explicit StopAllTestSpeaker(std::string id, - const bool playback_stop_result = true) - : playback_stop_result_(playback_stop_result) - { - id_ = std::move(id); - state_.is_initialized = true; - state_.is_running = true; - state_.is_decoding = true; - } - - std::string typeName() const override { return "StopAllTestSpeaker"; } - - void getState(device::SpeakerState& state) override - { - std::lock_guard lock(mutex_); - state = state_; - } - - bool stopPlayback() override - { - std::lock_guard lock(mutex_); - ++stop_playback_calls_; - if (playback_stop_result_) { - state_.is_running = false; - state_.is_decoding = false; - } - return playback_stop_result_; - } - - bool stop() override - { - std::lock_guard lock(mutex_); - ++lifecycle_stop_calls_; - return true; - } - - int stopPlaybackCalls() const - { - std::lock_guard lock(mutex_); - return stop_playback_calls_; - } - - int lifecycleStopCalls() const - { - std::lock_guard lock(mutex_); - return lifecycle_stop_calls_; - } - -private: - mutable std::mutex mutex_; - int stop_playback_calls_{0}; - int lifecycle_stop_calls_{0}; - bool playback_stop_result_{true}; -}; - -class BlockingStopTask final : public task::Task { -public: - explicit BlockingStopTask(std::string id) - : id_(std::move(id)) - { - } - - const std::string& id() const override { return id_; } - task::TaskRunMode runMode() const override - { - return task::TaskRunMode::BLOCKING_SERVICE; - } - bool init() override { return true; } - bool step(double) override { return true; } - void stop() override { lifecycle_stop_calls_.fetch_add(1); } - bool stopActivity() override - { - std::unique_lock lock(mutex_); - ++stop_activity_calls_; - stop_entered_ = true; - condition_.notify_all(); - condition_.wait(lock, [this] { return release_stop_; }); - return true; - } - task::TaskState state() const override - { - return task::TaskState::IDLE; - } - bool isBusy() const override { return false; } - bool isFinished() const override { return false; } - bool isFailed() const override { return false; } - std::string stateString() const override { return "IDLE"; } - std::string detailStatusString() const override { return "IDLE"; } - - bool waitForStopActivity(const std::chrono::milliseconds timeout) - { - std::unique_lock lock(mutex_); - return condition_.wait_for( - lock, timeout, [this] { return stop_entered_; }); - } - - void releaseStopActivity() - { - { - std::lock_guard lock(mutex_); - release_stop_ = true; - } - condition_.notify_all(); - } - - int stopActivityCalls() const - { - std::lock_guard lock(mutex_); - return stop_activity_calls_; - } - - int lifecycleStopCalls() const - { - return lifecycle_stop_calls_.load(); - } - -private: - std::string id_; - mutable std::mutex mutex_; - std::condition_variable condition_; - std::atomic lifecycle_stop_calls_{0}; - int stop_activity_calls_{0}; - bool stop_entered_{false}; - bool release_stop_{false}; -}; - -std::shared_ptr blocking_stop_task; - -class ActionTrace final { -public: - using TimePoint = std::chrono::steady_clock::time_point; - - struct Entry { - std::string name; - TimePoint time; - }; - - void add(std::string name) - { - std::lock_guard lock(mutex_); - entries_.push_back({std::move(name), std::chrono::steady_clock::now()}); - } - - std::vector names() const - { - std::lock_guard lock(mutex_); - std::vector result; - result.reserve(entries_.size()); - for (const auto& entry : entries_) { - result.push_back(entry.name); - } - return result; - } - - std::optional firstTime(const std::string& name) const - { - std::lock_guard lock(mutex_); - const auto found = std::find_if( - entries_.begin(), entries_.end(), - [&name](const Entry& entry) { return entry.name == name; }); - return found == entries_.end() - ? std::nullopt - : std::optional(found->time); - } - -private: - mutable std::mutex mutex_; - std::vector entries_; -}; - -class ActionTestArm final : public device::RobotArm { -public: - ActionTestArm(std::string id, std::shared_ptr trace) - : trace_(std::move(trace)) - { - id_ = std::move(id); - } - - std::string typeName() const override { return "ActionTestArm"; } - bool stop() override - { - lifecycle_stop_calls_.fetch_add(1, std::memory_order_relaxed); - return true; - } - device::DeviceHealthSnapshot healthSnapshot() override - { - std::unique_lock lock(health_mutex_); - ++health_snapshot_calls_; - health_snapshot_entered_ = true; - health_condition_.notify_all(); - health_condition_.wait( - lock, [this] { return !block_health_snapshot_; }); - return {device::DeviceHealthState::Healthy, {}}; - } - bool supportsActionQueueMotion() const noexcept override { return true; } - device::RobotModel getRobotModel() const override - { - device::RobotModel model; - model.name = "ActionTestArm"; - model.dof = kDof; - model.joint_names.assign(kDof, "joint"); - return model; - } - std::size_t getDof() const override { return kDof; } - device::ArmState getRobotState() const override - { - std::lock_guard lock(mutex_); - auto state = reported_state_; - state.moving = state.moving || active_motions_ != 0; - return state; - } - device::JointGroupState getJointState() const override { return {}; } - device::CartesianPose getTcpPose( - device::FrameType = device::FrameType::Base) const override - { - return {}; - } - device::RobotMode getRobotMode() const override - { - return device::RobotMode::Idle; - } - device::SafetyMode getSafetyMode() const override - { - return device::SafetyMode::Normal; - } - device::ControlMode getControlMode() const override - { - return device::ControlMode::Position; - } - - device::Result torqueOn() override { return device::Result::success(); } - device::Result torqueOff() override { return device::Result::success(); } - device::Result calibrateZeroQ(const std::string&) override - { - return device::Result::success(); - } - device::Result emergencyStop() override - { - return device::Result::success(); - } - device::Result protectiveStop() override - { - return device::Result::success(); - } - device::Result setSpeedScaling(double) override - { - return device::Result::success(); - } - double getSpeedScaling() const override { return 1.0; } - bool isProtectiveStopped() const override { return false; } - bool isEmergencyStopped() const override { return false; } - bool isFault() const override { return false; } - - device::Result moveJ(const device::JointPositionCommand&, - const device::MotionOptions& options) override - { - return performMotion("arm:J", options); - } - device::Result speedJ(const device::JointVelocityCommand&, - double, - double) override - { - return device::Result::success(); - } - device::Result stopJ(double) override { return stopMotion(); } - device::Result moveL( - const device::CartesianPose& target, - const device::MotionOptions& options, - device::FrameType = device::FrameType::Base) override - { - return performMotion( - "arm:L:" + std::to_string(static_cast(target.x)), - options); - } - device::Result speedL( - const device::CartesianVelocity&, - double, - double, - device::FrameType = device::FrameType::Base) override - { - return device::Result::success(); - } - device::Result stopL(std::optional = std::nullopt) override - { - return stopMotion(); - } - device::Result stopMotion() override - { - bool fail = false; - { - std::unique_lock lock(mutex_); - ++stop_motion_calls_; - stop_requested_ = true; - fail = stop_motion_fails_; - motion_condition_.notify_all(); - if (block_next_stop_motion_) { - block_next_stop_motion_ = false; - stop_motion_blocked_ = true; - stop_motion_blocked_condition_.notify_all(); - stop_motion_release_condition_.wait( - lock, - [this]() { return release_blocked_stop_motion_; }); - } - } - trace_->add("arm:stop:" + id_); - motion_condition_.notify_all(); - return fail - ? device::Result::failure( - device::ArmErrorCode::CommandFailed, - "injected RobotArm stop failure") - : device::Result::success(); - } - - device::Result startServoMode(const device::ServoOptions&) override - { - return device::Result::success(); - } - device::Result servoJ(const device::JointPositionCommand&) override - { - return device::Result::success(); - } - device::Result servoL( - const device::CartesianPose&, - device::FrameType = device::FrameType::Base) override - { - return device::Result::success(); - } - device::Result servoSpeedJ( - const device::JointVelocityCommand&) override - { - return device::Result::success(); - } - device::Result servoSpeedL( - const device::CartesianVelocity&, - device::FrameType = device::FrameType::Base) override - { - return device::Result::success(); - } - device::Result stopServoMode() override - { - return device::Result::success(); - } - - device::Result connect(const std::string&, int) override - { - return device::Result::success(); - } - device::Result disconnect() override { return device::Result::success(); } - bool isConnected() const override { return true; } - device::Result powerOn() override { return device::Result::success(); } - device::Result powerOff() override { return device::Result::success(); } - device::Result brakeRelease() override { return device::Result::success(); } - device::Result shutdown() override - { - shutdown_calls_.fetch_add(1, std::memory_order_relaxed); - return device::Result::success(); - } - device::Result clearFault() override - { - std::lock_guard lock(mutex_); - ++clear_fault_calls_; - reported_state_.connected = true; - reported_state_.powered_on = true; - reported_state_.moving = false; - reported_state_.program_running = false; - reported_state_.fault = false; - reported_state_.emergency_stopped = false; - reported_state_.protective_stopped = false; - return device::Result::success(); - } - device::Result unlockProtectiveStop() override - { - return device::Result::success(); - } - device::Result loadProgram(const std::string&) override - { - return device::Result::success(); - } - device::Result playProgram() override { return device::Result::success(); } - device::Result pauseProgram() override { return device::Result::success(); } - device::Result stopProgram() override { return device::Result::success(); } - std::vector ik(const std::string&, - const std::string&, - const device::CartesianPose&) override - { - return {}; - } - std::shared_ptr kinematicsSolver() const override - { - return nullptr; - } - device::CartesianPose fk(const std::string&, - const std::string&) override - { - return {}; - } - device::CartesianPose fk(bool = true) override { return {}; } - device::CartesianVelocity getSpeedLCommandTwistBase() const override - { - return {}; - } - bool busy() const override - { - std::lock_guard lock(mutex_); - if (busy_throws_after_stop_ && stop_motion_calls_ != 0) { - throw std::runtime_error( - "injected RobotArm busy-state failure"); - } - return active_motions_ != 0; - } - - void blockNextMotion() - { - std::lock_guard lock(mutex_); - block_next_motion_ = true; - release_blocked_motion_ = false; - stop_requested_ = false; - } - - void blockCanceledMotionReturn() - { - std::lock_guard lock(mutex_); - block_canceled_motion_return_ = true; - canceled_motion_return_blocked_ = false; - release_canceled_motion_return_ = false; - } - - bool waitForCanceledMotionReturn( - const std::chrono::milliseconds timeout) - { - std::unique_lock lock(mutex_); - return canceled_motion_return_condition_.wait_for( - lock, - timeout, - [this]() { return canceled_motion_return_blocked_; }); - } - - void releaseCanceledMotionReturn() - { - { - std::lock_guard lock(mutex_); - release_canceled_motion_return_ = true; - } - motion_condition_.notify_all(); - } - - void releaseBlockedMotion() - { - { - std::lock_guard lock(mutex_); - release_blocked_motion_ = true; - } - motion_condition_.notify_all(); - } - - void failOnMotionCall(const int call_index) - { - std::lock_guard lock(mutex_); - fail_on_motion_call_ = call_index; - } - - void failStopAndBusyConfirmation() - { - std::lock_guard lock(mutex_); - stop_motion_fails_ = true; - busy_throws_after_stop_ = true; - } - - void blockNextStopMotion() - { - std::lock_guard lock(mutex_); - block_next_stop_motion_ = true; - stop_motion_blocked_ = false; - release_blocked_stop_motion_ = false; - } - - bool waitForBlockedStopMotion( - const std::chrono::milliseconds timeout) - { - std::unique_lock lock(mutex_); - return stop_motion_blocked_condition_.wait_for( - lock, timeout, [this]() { return stop_motion_blocked_; }); - } - - void releaseBlockedStopMotion() - { - { - std::lock_guard lock(mutex_); - release_blocked_stop_motion_ = true; - } - stop_motion_release_condition_.notify_all(); - } - - bool waitForMotionCalls( - const int expected, - const std::chrono::milliseconds timeout) - { - std::unique_lock lock(mutex_); - return motion_started_condition_.wait_for( - lock, timeout, - [this, expected]() { return motion_calls_ >= expected; }); - } - - int motionCalls() const - { - std::lock_guard lock(mutex_); - return motion_calls_; - } - - int stopMotionCalls() const - { - std::lock_guard lock(mutex_); - return stop_motion_calls_; - } - - int lifecycleStopCalls() const - { - return lifecycle_stop_calls_.load(std::memory_order_relaxed); - } - - int shutdownCalls() const - { - return shutdown_calls_.load(std::memory_order_relaxed); - } - - int clearFaultCalls() const - { - std::lock_guard lock(mutex_); - return clear_fault_calls_; - } - - void setReportedState(const device::ArmState& state) - { - std::lock_guard lock(mutex_); - reported_state_ = state; - } - - void blockHealthSnapshot() - { - std::lock_guard lock(health_mutex_); - block_health_snapshot_ = true; - health_snapshot_entered_ = false; - } - - bool waitForHealthSnapshot( - const std::chrono::milliseconds timeout) - { - std::unique_lock lock(health_mutex_); - return health_condition_.wait_for( - lock, timeout, [this] { return health_snapshot_entered_; }); - } - - void releaseHealthSnapshot() - { - { - std::lock_guard lock(health_mutex_); - block_health_snapshot_ = false; - } - health_condition_.notify_all(); - } - - int healthSnapshotCalls() const - { - std::lock_guard lock(health_mutex_); - return health_snapshot_calls_; - } - - bool waitForStopMotionCalls( - const int expected, - const std::chrono::milliseconds timeout) - { - std::unique_lock lock(mutex_); - return motion_condition_.wait_for( - lock, timeout, - [this, expected]() { return stop_motion_calls_ >= expected; }); - } - - int maxActiveMotions() const - { - std::lock_guard lock(mutex_); - return max_active_motions_; - } - -private: - device::Result performMotion( - const std::string& event, - const device::MotionOptions& options) - { - bool block = false; - bool fail = false; - { - std::lock_guard lock(mutex_); - ++motion_calls_; - ++active_motions_; - max_active_motions_ = std::max( - max_active_motions_, active_motions_); - block = block_next_motion_; - block_next_motion_ = false; - fail = motion_calls_ == fail_on_motion_call_; - } - trace_->add(event); - motion_started_condition_.notify_all(); - - bool canceled = false; - bool safety_timeout = false; - if (block) { - const auto safety_deadline = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - std::unique_lock lock(mutex_); - while (!release_blocked_motion_ && !stop_requested_ && - !(options.cancellation_requested && - options.cancellation_requested())) { - if (std::chrono::steady_clock::now() >= safety_deadline) { - safety_timeout = true; - break; - } - motion_condition_.wait_for(lock, std::chrono::milliseconds(1)); - } - canceled = stop_requested_ || - (options.cancellation_requested && - options.cancellation_requested()); - } - - { - std::unique_lock lock(mutex_); - --active_motions_; - if (canceled && block_canceled_motion_return_) { - block_canceled_motion_return_ = false; - canceled_motion_return_blocked_ = true; - canceled_motion_return_condition_.notify_all(); - motion_condition_.wait( - lock, - [this]() { return release_canceled_motion_return_; }); - } - } - if (safety_timeout) { - return device::Result::failure( - device::ArmErrorCode::Timeout, - "test arm safety wait expired"); - } - if (canceled) { - return device::Result::failure( - device::ArmErrorCode::CommandRejected, - "test arm motion canceled"); - } - if (fail) { - return device::Result::failure( - device::ArmErrorCode::CommandFailed, - "injected RobotArm failure"); - } - return device::Result::success(); - } - - static constexpr std::size_t kDof = 6U; - std::shared_ptr trace_; - mutable std::mutex mutex_; - std::condition_variable motion_condition_; - std::condition_variable motion_started_condition_; - std::condition_variable canceled_motion_return_condition_; - std::condition_variable stop_motion_blocked_condition_; - std::condition_variable stop_motion_release_condition_; - mutable std::mutex health_mutex_; - std::condition_variable health_condition_; - std::atomic lifecycle_stop_calls_{0}; - std::atomic shutdown_calls_{0}; - int motion_calls_{0}; - int stop_motion_calls_{0}; - int active_motions_{0}; - int max_active_motions_{0}; - int fail_on_motion_call_{-1}; - bool block_next_motion_{false}; - bool release_blocked_motion_{false}; - bool stop_requested_{false}; - bool block_canceled_motion_return_{false}; - bool canceled_motion_return_blocked_{false}; - bool release_canceled_motion_return_{false}; - bool stop_motion_fails_{false}; - bool busy_throws_after_stop_{false}; - bool block_next_stop_motion_{false}; - bool stop_motion_blocked_{false}; - bool release_blocked_stop_motion_{false}; - int health_snapshot_calls_{0}; - bool block_health_snapshot_{false}; - bool health_snapshot_entered_{false}; - device::ArmState reported_state_{}; - int clear_fault_calls_{0}; -}; - -class ActionTestAgv final : public device::AbstractAGV { -public: - ActionTestAgv(std::string id, std::shared_ptr trace) - : trace_(std::move(trace)) - { - id_ = std::move(id); - } - - std::string typeName() const override { return "ActionTestAgv"; } - bool supportsSynchronousAction(device::AgvActionKind) const noexcept override - { - return supports_synchronous_.load(std::memory_order_acquire); - } - device::AgvRuntimeState runtimeState() const override { return {}; } - device::AgvNavigationStatus navigationStatus() const override { return {}; } - device::AgvResult navigateToPose( - const math::Pose2d& pose, - const device::AgvMotionOptions&, - const device::AgvAdapterParams&) override - { - { - std::lock_guard lock(parameters_mutex_); - last_pose_ = pose; - } - return record("agv:pose"); - } - device::AgvResult navigateToStation( - const std::string& station_id, - const device::AgvMotionOptions&, - const device::AgvAdapterParams&) override - { - return record("agv:station:" + station_id); - } - device::AgvResult followPath( - const std::vector& path, - const device::AgvMotionOptions&) override - { - { - std::lock_guard lock(parameters_mutex_); - last_path_ = path; - } - return record("agv:path"); - } - device::AgvResult cancelNavigation() override - { - cancel_calls_.fetch_add(1, std::memory_order_relaxed); - trace_->add("agv:cancel"); - return device::AgvResult::success(); - } - device::AgvResult confirmMotionStopped() override - { - return stopped_confirmed_.load(std::memory_order_acquire) - ? device::AgvResult::success() - : device::AgvResult::failure( - device::AgvErrorCode::Timeout, - "test AGV stopped state is unconfirmed"); - } - void setSupportsSynchronous(const bool value) - { - supports_synchronous_.store(value, std::memory_order_release); - } - - void setNavigationFailure(const bool value) - { - fail_navigation_.store(value, std::memory_order_release); - } - - void setStoppedConfirmed(const bool value) - { - stopped_confirmed_.store(value, std::memory_order_release); - } - - int navigationCalls() const - { - return navigation_calls_.load(std::memory_order_relaxed); - } - - math::Pose2d lastPose() const - { - std::lock_guard lock(parameters_mutex_); - return last_pose_; - } - - std::vector lastPath() const - { - std::lock_guard lock(parameters_mutex_); - return last_path_; - } - -private: - device::AgvResult record(std::string event) - { - navigation_calls_.fetch_add(1, std::memory_order_relaxed); - trace_->add(std::move(event)); - if (fail_navigation_.load(std::memory_order_acquire)) { - return device::AgvResult::failure( - device::AgvErrorCode::TaskFailed, - "injected AGV navigation failure"); - } - return device::AgvResult::success(); - } - - std::shared_ptr trace_; - mutable std::mutex parameters_mutex_; - math::Pose2d last_pose_{}; - std::vector last_path_; - std::atomic supports_synchronous_{true}; - std::atomic fail_navigation_{false}; - std::atomic stopped_confirmed_{true}; - std::atomic navigation_calls_{0}; - std::atomic cancel_calls_{0}; -}; - -api::ActionStep* addMoveLStep( - api::ActionQueueCommand_Request& request, - const std::string& step_id, - const std::string& device_id, - const double marker, - const std::uint32_t timeout_ms = 0U, - const bool asynchronous = false) -{ - auto* step = request.add_steps(); - step->set_step_id(step_id); - step->set_timeout_ms(timeout_ms); - auto* command = step->mutable_arm_move_l(); - command->mutable_header()->set_device_id(device_id); - command->mutable_target()->set_x(marker); - command->set_frame(api::ARM_FRAME_BASE); - command->mutable_options()->set_asynchronous(asynchronous); - return step; -} - -api::ActionStep* addMoveJStep( - api::ActionQueueCommand_Request& request, - const std::string& step_id, - const std::string& device_id, - const bool asynchronous = false) -{ - auto* step = request.add_steps(); - step->set_step_id(step_id); - auto* command = step->mutable_arm_move_j(); - command->mutable_header()->set_device_id(device_id); - for (std::size_t index = 0; index < 6U; ++index) { - command->mutable_target()->add_position( - static_cast(index) * 0.1); - } - command->mutable_options()->set_asynchronous(asynchronous); - return step; -} - -api::ActionStep* addAgvStationStep( - api::ActionQueueCommand_Request& request, - const std::string& step_id, - const std::string& device_id, - const std::string& station_id, - const bool asynchronous = false) -{ - auto* step = request.add_steps(); - step->set_step_id(step_id); - auto* command = step->mutable_agv_navigate_to_station(); - command->mutable_header()->set_device_id(device_id); - command->set_station_id(station_id); - command->mutable_options()->set_asynchronous(asynchronous); - return step; -} - -api::ActionStep* addAgvPoseStep( - api::ActionQueueCommand_Request& request, - const std::string& step_id, - const std::string& device_id, - const double x, - const double y, - const double theta) -{ - auto* step = request.add_steps(); - step->set_step_id(step_id); - auto* command = step->mutable_agv_navigate_to_pose(); - command->mutable_header()->set_device_id(device_id); - command->mutable_pose()->set_x(x); - command->mutable_pose()->set_y(y); - command->mutable_pose()->set_theta(theta); - return step; -} - -api::ActionStep* addAgvPathStep( - api::ActionQueueCommand_Request& request, - const std::string& step_id, - const std::string& device_id) -{ - auto* step = request.add_steps(); - step->set_step_id(step_id); - auto* command = step->mutable_agv_follow_path(); - command->mutable_header()->set_device_id(device_id); - auto* first = command->add_path(); - first->set_source_station("start"); - first->set_target_station("middle"); - auto* second = command->add_path(); - second->set_source_station("middle"); - second->set_target_station("finish"); - return step; -} - -api::ActionStep* addDelayStep( - api::ActionQueueCommand_Request& request, - const std::string& step_id, - const std::uint32_t duration_ms) -{ - auto* step = request.add_steps(); - step->set_step_id(step_id); - step->mutable_delay()->set_duration_ms(duration_ms); - return step; -} - -std::uint64_t currentUnixTimeMs() -{ - const auto elapsed = std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()); - return static_cast(elapsed.count()); -} - -const api::SystemDeviceInfo* findDevice( - const api::GetDeviceListCommand_Feedback& response, - const std::string& id) -{ - for (const auto& device : response.device_list()) { - if (device.device_id() == id) { - return &device; - } - } - return nullptr; -} - -const api::SafetyOperationTargetResult* findSafetyTarget( - const api::StopAllCommand_Feedback& response, - const std::string& id) -{ - for (const auto& target : response.targets()) { - if (target.target_id() == id) { - return ⌖ - } - } - return nullptr; -} - -const api::SafetyOperationTargetResult* findSafetyTarget( - const api::RestoreOperationalStateCommand_Feedback& response, - const std::string& id) -{ - for (const auto& target : response.targets()) { - if (target.target_id() == id) { - return ⌖ - } - } - return nullptr; -} - -class GrpcSystemServiceTest : public ::testing::Test { -protected: - void SetUp() override - { - task::TaskManager::destroyInstance(); - blocking_stop_task.reset(); - (void)media::globalMediaSourceManager().stopAllSources(); - control::ControlAuthorityManager::instance().clear(); - globalStopAllAdmissionGate().clearForTesting(); - globalCameraOperationalActivityRegistry().clearForTesting(); - globalCameraPtzActivityRegistry().clearForTesting(); - globalMediaActivityCoordinator().clearForTesting(); - globalMotorActivityCoordinator().clearForTesting(); - device::DeviceManager::destroyInstance(); - } - - void TearDown() override - { - if (blocking_stop_task) { - blocking_stop_task->releaseStopActivity(); - } - service_.reset(); - task::TaskManager::destroyInstance(); - blocking_stop_task.reset(); - action_agv_.reset(); - action_arm_.reset(); - action_trace_.reset(); - owned_devices_.clear(); - device::DeviceManager::destroyInstance(); - control::ControlAuthorityManager::instance().clear(); - globalStopAllAdmissionGate().clearForTesting(); - globalCameraOperationalActivityRegistry().clearForTesting(); - globalCameraPtzActivityRegistry().clearForTesting(); - globalMediaActivityCoordinator().clearForTesting(); - globalMotorActivityCoordinator().clearForTesting(); - (void)media::globalMediaSourceManager().stopAllSources(); - } - - api::GetDeviceListCommand_Feedback getDeviceList() - { - api::GetDeviceListCommand_Request request; - api::GetDeviceListCommand_Feedback response; - grpc::ServerContext context; - - const auto status = service_->GetDeviceList( - &context, &request, &response); - EXPECT_TRUE(status.ok()) << status.error_message(); - return response; - } - - void registerDevice(device::DeviceManager& manager, - std::shared_ptr device) - { - manager.registerDevice(device); - owned_devices_.push_back(std::move(device)); - } - - void initializeActionDevices() - { - config::DeviceManagerConfig config; - auto& manager = device::DeviceManager::getInstance(config); - action_trace_ = std::make_shared(); - action_arm_ = std::make_shared( - "action-arm", action_trace_); - action_agv_ = std::make_shared( - "action-agv", action_trace_); - manager.registerDevice(action_arm_); - manager.registerDevice(action_agv_); - service_ = std::make_unique(); - api::GetSystemInfoCommand_Request info_request; - api::GetSystemInfoCommand_Feedback info_response; - grpc::ServerContext info_context; - const auto info_status = service_->GetSystemInfo( - &info_context, &info_request, &info_response); - ASSERT_TRUE(info_status.ok()) << info_status.error_message(); - service_instance_id_ = info_response.action_service_instance_id(); - ASSERT_FALSE(service_instance_id_.empty()); - } - - api::ActionQueueCommand_Feedback executeAction( - const api::ActionQueueCommand_Request& request) - { - auto bound_request = request; - if (bound_request.expected_service_instance_id().empty()) { - bound_request.set_expected_service_instance_id( - service_instance_id_); - } - api::ActionQueueCommand_Feedback response; - grpc::ServerContext context; - const auto status = service_->ExecuteActionQueue( - &context, &bound_request, &response); - EXPECT_TRUE(status.ok()) << status.error_message(); - return response; - } - - std::unique_ptr service_; - std::vector> owned_devices_; - std::shared_ptr action_trace_; - std::shared_ptr action_arm_; - std::shared_ptr action_agv_; - std::string service_instance_id_; -}; - -TEST_F(GrpcSystemServiceTest, - ReturnsOnlyEnabledDevicesAndPreservesEnabledErrors) -{ - config::DeviceManagerConfig config; - config.set_name("system-service-test"); - config.set_version("9.2"); - config.set_description("GetDeviceList snapshot test"); - - auto* disabled = config.add_devices(); - disabled->set_id("b_disabled_camera"); - disabled->set_type(config::DeviceConfigEntry::DEVICE_TYPE_CAMERA); - disabled->set_enable(false); - - // An enabled unsupported entry remains in the manager snapshot as ERROR. - // GetDeviceList must expose it rather than filtering by lifecycle state. - auto* enabled_error = config.add_devices(); - enabled_error->set_id("c_enabled_error"); - enabled_error->set_type(config::DeviceConfigEntry::DEVICE_TYPE_UNKNOWN); - enabled_error->set_enable(true); - - auto& manager = device::DeviceManager::getInstance(config); - registerDevice( - manager, - std::make_shared( - "z_camera", - device::DeviceKind::Camera, - "VendorCamera", - device::DeviceHealthSnapshot{ - device::DeviceHealthState::Healthy, {}})); - registerDevice( - manager, - std::make_shared( - "a_unknown", - device::DeviceKind::Unknown, - "MysteryDriver", - device::DeviceHealthSnapshot{ - device::DeviceHealthState::Degraded, - "device health is degraded"})); - service_ = std::make_unique(); - - const auto response = getDeviceList(); - - ASSERT_TRUE(response.header().success()) - << response.header().error_message(); - EXPECT_TRUE(response.header().has_timestamp()); - EXPECT_GT(response.header().timestamp().seconds(), 0); - EXPECT_EQ(response.manager_name(), "system-service-test"); - EXPECT_EQ(response.manager_version(), "9.2"); - EXPECT_EQ(response.manager_description(), "GetDeviceList snapshot test"); - ASSERT_EQ(response.device_list_size(), 3); - - // DeviceManager::snapshot() supplies stable device-id ordering, and the - // service must preserve it while filtering disabled entries. - EXPECT_EQ(response.device_list(0).device_id(), "a_unknown"); - EXPECT_EQ(response.device_list(1).device_id(), "c_enabled_error"); - EXPECT_EQ(response.device_list(2).device_id(), "z_camera"); - EXPECT_EQ(findDevice(response, "b_disabled_camera"), nullptr); - - const auto* unknown = findDevice(response, "a_unknown"); - ASSERT_NE(unknown, nullptr); - EXPECT_TRUE(unknown->enabled()); - EXPECT_EQ(unknown->type_name(), "MysteryDriver"); - EXPECT_EQ(unknown->device_type(), - api::SYSTEM_DEVICE_TYPE_UNSPECIFIED); - EXPECT_NE(unknown->device_type(), api::SYSTEM_DEVICE_TYPE_AGV); - EXPECT_EQ(unknown->manager_state(), - api::SYSTEM_DEVICE_STATE_REGISTERED); - EXPECT_EQ(unknown->health(), api::SYSTEM_DEVICE_HEALTH_DEGRADED); - EXPECT_TRUE(unknown->has_error()); - EXPECT_EQ(unknown->error_message(), "device health is degraded"); - EXPECT_GT(unknown->status_updated_at_unix_ms(), 0U); - - const auto* error = findDevice(response, "c_enabled_error"); - ASSERT_NE(error, nullptr); - EXPECT_TRUE(error->enabled()); - EXPECT_EQ(error->type_name(), "Unknown"); - EXPECT_EQ(error->device_type(), api::SYSTEM_DEVICE_TYPE_UNSPECIFIED); - EXPECT_EQ(error->manager_state(), api::SYSTEM_DEVICE_STATE_ERROR); - EXPECT_EQ(error->health(), api::SYSTEM_DEVICE_HEALTH_UNSPECIFIED); - EXPECT_TRUE(error->has_error()); - EXPECT_FALSE(error->error_message().empty()); - EXPECT_GT(error->status_updated_at_unix_ms(), 0U); - - const auto* camera = findDevice(response, "z_camera"); - ASSERT_NE(camera, nullptr); - EXPECT_TRUE(camera->enabled()); - EXPECT_EQ(camera->type_name(), "VendorCamera"); - EXPECT_EQ(camera->device_type(), api::SYSTEM_DEVICE_TYPE_CAMERA); - EXPECT_EQ(camera->manager_state(), - api::SYSTEM_DEVICE_STATE_REGISTERED); - EXPECT_EQ(camera->health(), api::SYSTEM_DEVICE_HEALTH_HEALTHY); - EXPECT_FALSE(camera->has_error()); - EXPECT_TRUE(camera->error_message().empty()); - EXPECT_GT(camera->status_updated_at_unix_ms(), 0U); -} - -TEST_F(GrpcSystemServiceTest, EmptyListReturnsMetadataAndTimestamps) -{ - config::DeviceManagerConfig config; - config.set_name("empty-manager"); - config.set_version("1.2.3"); - config.set_description("manager without devices"); - device::DeviceManager::getInstance(config); - service_ = std::make_unique(); - - const auto before_ms = currentUnixTimeMs(); - const auto response = getDeviceList(); - const auto after_ms = currentUnixTimeMs(); - - ASSERT_TRUE(response.header().success()) - << response.header().error_message(); - EXPECT_TRUE(response.header().has_timestamp()); - EXPECT_GT(response.header().timestamp().seconds(), 0); - EXPECT_EQ(response.device_list_size(), 0); - EXPECT_EQ(response.manager_name(), "empty-manager"); - EXPECT_EQ(response.manager_version(), "1.2.3"); - EXPECT_EQ(response.manager_description(), "manager without devices"); - EXPECT_GE(response.sampled_at_unix_ms(), before_ms); - EXPECT_LE(response.sampled_at_unix_ms(), after_ms); -} - -TEST_F(GrpcSystemServiceTest, SafetyStateUsesCoordinatorMemorySnapshot) -{ - config::DeviceManagerConfig config; - auto& manager = device::DeviceManager::getInstance(config); - registerDevice( - manager, - std::make_shared( - "safety-camera", - device::DeviceKind::Camera, - "SafetyCamera", - device::DeviceHealthSnapshot{ - device::DeviceHealthState::Healthy, {}})); - service_ = std::make_unique(); - - api::GetSafetyStateCommand_Request request; - api::GetSafetyStateCommand_Feedback response; - grpc::ServerContext context; - const auto status = service_->GetSafetyState( - &context, &request, &response); - - ASSERT_TRUE(status.ok()) << status.error_message(); - ASSERT_TRUE(response.header().success()) - << response.header().error_message(); - EXPECT_FALSE(response.control_service_instance_id().empty()); - EXPECT_EQ( - response.header().service_instance_id(), - response.control_service_instance_id()); - EXPECT_GT(response.safety_epoch(), 0U); - ASSERT_EQ(response.devices_size(), 1); - EXPECT_EQ(response.devices(0).device_id(), "safety-camera"); - EXPECT_EQ(response.devices(0).policy_family(), "Sensor"); - ASSERT_GT(response.participants_size(), 0); - EXPECT_FALSE(response.participants(0).participant_id().empty()); - EXPECT_FALSE(response.participants(0).phase().empty()); - EXPECT_TRUE(response.participants(0).registered()); - - api::GetSystemInfoCommand_Request info_request; - api::GetSystemInfoCommand_Feedback info_response; - grpc::ServerContext info_context; - ASSERT_TRUE(service_->GetSystemInfo( - &info_context, &info_request, &info_response).ok()); - EXPECT_EQ( - info_response.control_service_instance_id(), - response.control_service_instance_id()); - EXPECT_EQ(info_response.safety_schema_version(), 1U); -} - -TEST_F(GrpcSystemServiceTest, RecoveryIsDisabledByDefault) -{ - config::DeviceManagerConfig config; - auto& manager = device::DeviceManager::getInstance(config); - service_ = std::make_unique(); - - api::RecoverSafetyStateCommand_Request request; - request.set_recovery_id("recovery-disabled"); - request.mutable_scope()->set_all_devices(true); - request.set_expected_safety_epoch( - manager.safetyManager().snapshot().safety_epoch); - request.set_mode(api::RecoverSafetyStateCommand::VERIFY_ONLY); - request.set_reason("diagnostic verification"); - api::RecoverSafetyStateCommand_Feedback response; - grpc::ServerContext context; - - const auto status = service_->RecoverSafetyState( - &context, &request, &response); - EXPECT_EQ(status.error_code(), grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_EQ(status.error_message(), "RECOVERY_RPC_DISABLED"); -} - -TEST_F(GrpcSystemServiceTest, OperationalRestoreIsDisabledByDefault) -{ - config::DeviceManagerConfig config; - (void)device::DeviceManager::getInstance(config); - service_ = std::make_unique(); - - api::RestoreOperationalStateCommand_Request request; - request.set_recovery_id("restore-disabled"); - request.set_reason("operator requested recovery"); - api::RestoreOperationalStateCommand_Feedback response; - grpc::ServerContext context; - - const auto status = service_->RestoreOperationalState( - &context, &request, &response); - - EXPECT_EQ(status.error_code(), grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_EQ(status.error_message(), "RECOVERY_RPC_DISABLED"); -} - -TEST_F(GrpcSystemServiceTest, RecoveryRequiresDurableAuditBeforeCoordinator) -{ - config::DeviceManagerConfig config; - auto& manager = device::DeviceManager::getInstance(config); - manager.registerDevice(std::make_shared( - "audit-camera", device::DeviceKind::Camera, "AuditCamera")); - auto audit = std::make_shared(); - service_ = std::make_unique( - std::chrono::seconds(1), makeAllowAllRecoveryGateway(), audit); - - api::RecoverSafetyStateCommand_Request request; - request.set_recovery_id("recovery-audited"); - request.mutable_scope()->set_all_devices(true); - request.set_expected_safety_epoch( - manager.safetyManager().snapshot().safety_epoch); - request.set_mode(api::RecoverSafetyStateCommand::VERIFY_ONLY); - request.set_reason("verify the local work cell"); - request.set_timeout_ms(500); - api::RecoverSafetyStateCommand_Feedback response; - grpc::ServerContext context; - - const auto status = service_->RecoverSafetyState( - &context, &request, &response); - ASSERT_TRUE(status.ok()) << status.error_message(); - EXPECT_EQ(audit->records.size(), 2U); - EXPECT_EQ(audit->records.front().stage, "accepted"); - EXPECT_EQ(audit->records.back().stage, "completed"); - EXPECT_EQ(response.recovery_id(), "recovery-audited"); - - const auto epoch_before_failure = - manager.safetyManager().snapshot().safety_epoch; - audit->fail = true; - request.set_recovery_id("recovery-audit-fails"); - request.set_expected_safety_epoch(epoch_before_failure); - response.Clear(); - grpc::ServerContext failed_context; - const auto failed = service_->RecoverSafetyState( - &failed_context, &request, &response); - EXPECT_EQ(failed.error_code(), grpc::StatusCode::FAILED_PRECONDITION); - EXPECT_EQ( - response.header().reason_code(), - api::COMMAND_REASON_CODE_RECOVERY_AUDIT_FAILED); - EXPECT_EQ( - manager.safetyManager().snapshot().safety_epoch, - epoch_before_failure); -} - -TEST_F(GrpcSystemServiceTest, - RestoreOperationalStateRecoversArmAndClearsAdmission) -{ - config::DeviceManagerConfig config; - auto& manager = device::DeviceManager::getInstance(config); - action_trace_ = std::make_shared(); - action_arm_ = std::make_shared( - "restore-arm", action_trace_); - device::ArmState protected_state; - protected_state.connected = true; - protected_state.powered_on = true; - protected_state.moving = true; - protected_state.program_running = true; - protected_state.protective_stopped = true; - action_arm_->setReportedState(protected_state); - manager.registerDevice(action_arm_); - manager.safetyManager().quarantineDevice( - action_arm_->id(), safety::SafetyReason::OutcomeUnknown); - - auto audit = std::make_shared(); - service_ = std::make_unique( - std::chrono::seconds(1), makeAllowAllRecoveryGateway(), audit); - - api::RestoreOperationalStateCommand_Request request; - request.set_recovery_id("restore-whole-system"); - request.set_reason("operator confirmed the work cell is clear"); - request.set_timeout_ms(1000); - api::RestoreOperationalStateCommand_Feedback response; - grpc::ServerContext context; - - const auto status = service_->RestoreOperationalState( - &context, &request, &response); - - ASSERT_TRUE(status.ok()) << status.error_message(); - ASSERT_TRUE(response.header().success()) - << response.header().error_message(); - EXPECT_EQ( - response.result(), api::SAFETY_OPERATION_RESULT_RECOVERED); - EXPECT_EQ( - response.system_state(), api::SYSTEM_ADMISSION_STATE_OPEN); - EXPECT_EQ(action_arm_->clearFaultCalls(), 1); - const auto* arm_target = findSafetyTarget(response, action_arm_->id()); - ASSERT_NE(arm_target, nullptr); - EXPECT_EQ( - arm_target->result(), api::SAFETY_OPERATION_RESULT_SUCCEEDED); - ASSERT_EQ(audit->records.size(), 3U); - EXPECT_EQ(audit->records[0].stage, "accepted"); - EXPECT_EQ(audit->records[1].stage, "restore_commit"); - EXPECT_EQ(audit->records[2].stage, "completed"); - - const auto snapshot = manager.safetyManager().snapshot(); - EXPECT_EQ(snapshot.system_state, safety::SystemAdmissionState::Open); - ASSERT_EQ(snapshot.devices.size(), 1U); - EXPECT_EQ( - snapshot.devices.front().admission_state, - safety::DeviceAdmissionState::Open); -} - -TEST_F(GrpcSystemServiceTest, MapsEveryKnownDeviceKind) -{ - struct ExpectedMapping { - const char* id; - device::DeviceKind source; - api::SystemDeviceType destination; - }; - constexpr std::array mappings{{ - {"01_agv", device::DeviceKind::AGV, - api::SYSTEM_DEVICE_TYPE_AGV}, - {"02_arm", device::DeviceKind::Arm, - api::SYSTEM_DEVICE_TYPE_ARM}, - {"03_battery", device::DeviceKind::Battery, - api::SYSTEM_DEVICE_TYPE_BATTERY}, - {"04_bio_head", device::DeviceKind::BioHead, - api::SYSTEM_DEVICE_TYPE_BIO_HEAD}, - {"05_camera", device::DeviceKind::Camera, - api::SYSTEM_DEVICE_TYPE_CAMERA}, - {"06_can_bus", device::DeviceKind::CanBus, - api::SYSTEM_DEVICE_TYPE_CAN_BUS}, - {"07_dex_hand", device::DeviceKind::DexHand, - api::SYSTEM_DEVICE_TYPE_DEX_HAND}, - {"08_gripper", device::DeviceKind::Gripper, - api::SYSTEM_DEVICE_TYPE_GRIPPER}, - {"09_microphone", device::DeviceKind::Microphone, - api::SYSTEM_DEVICE_TYPE_MICROPHONE}, - {"10_motor", device::DeviceKind::Motor, - api::SYSTEM_DEVICE_TYPE_MOTOR}, - {"11_motor_system", device::DeviceKind::MotorSystem, - api::SYSTEM_DEVICE_TYPE_MOTOR_SYSTEM}, - {"12_mujoco_viewer", device::DeviceKind::MujocoViewer, - api::SYSTEM_DEVICE_TYPE_MUJOCO_VIEWER}, - {"13_mujoco_world", device::DeviceKind::MujocoWorld, - api::SYSTEM_DEVICE_TYPE_MUJOCO_WORLD}, - {"14_robot", device::DeviceKind::Robot, - api::SYSTEM_DEVICE_TYPE_ROBOT}, - {"15_speaker", device::DeviceKind::Speaker, - api::SYSTEM_DEVICE_TYPE_SPEAKER}, - }}; - - config::DeviceManagerConfig config; - auto& manager = device::DeviceManager::getInstance(config); - for (const auto& mapping : mappings) { - registerDevice( - manager, - std::make_shared( - mapping.id, mapping.source, "MappedBackend")); - } - service_ = std::make_unique(); - - const auto response = getDeviceList(); - - ASSERT_TRUE(response.header().success()) - << response.header().error_message(); - ASSERT_EQ(response.device_list_size(), - static_cast(mappings.size())); - for (std::size_t index = 0; index < mappings.size(); ++index) { - SCOPED_TRACE(mappings[index].id); - const auto& actual = response.device_list( - static_cast(index)); - EXPECT_EQ(actual.device_id(), mappings[index].id); - EXPECT_EQ(actual.device_type(), mappings[index].destination); - EXPECT_NE(actual.device_type(), - api::SYSTEM_DEVICE_TYPE_UNSPECIFIED); - } -} - -TEST_F(GrpcSystemServiceTest, ActionQueueExecutesFourMoveLStepsSerially) -{ - initializeActionDevices(); - api::ActionQueueCommand_Request request; - request.set_action_id("four-movel"); - for (int marker = 1; marker <= 4; ++marker) { - addMoveLStep( - request, - "move-" + std::to_string(marker), - action_arm_->id(), - static_cast(marker)); - } - - const auto response = executeAction(request); - - EXPECT_TRUE(response.header().success()) - << response.header().error_message(); - EXPECT_EQ(response.result(), api::ACTION_RESULT_CODE_COMPLETED); - EXPECT_EQ(response.completed_steps(), 4U); - EXPECT_FALSE(response.has_failed_step_index()); - EXPECT_EQ(action_arm_->motionCalls(), 4); - EXPECT_EQ(action_arm_->maxActiveMotions(), 1); - EXPECT_EQ( - action_trace_->names(), - (std::vector{ - "arm:L:1", "arm:L:2", "arm:L:3", "arm:L:4"})); -} - -TEST_F(GrpcSystemServiceTest, - ActionQueueRejectsStaleDeviceGenerationBeforeStepDispatch) -{ - config::DeviceManagerConfig config; - config.mutable_safety()->set_mode( - config::SafetyManagerConfig::ENFORCE_ALL); - auto& manager = device::DeviceManager::getInstance(config); - action_trace_ = std::make_shared(); - action_arm_ = std::make_shared( - "action-arm", action_trace_); - manager.registerDevice(action_arm_); - manager.safetyManager().markStartupComplete(); - std::optional current_device_generation; - const auto snapshot_deadline = - std::chrono::steady_clock::now() + std::chrono::seconds(1); - while (std::chrono::steady_clock::now() < snapshot_deadline) { - const auto safety = manager.safetyManager().snapshot(); - ASSERT_EQ( - safety.system_state, safety::SystemAdmissionState::Open); - const auto safety_device = std::find_if( - safety.devices.begin(), safety.devices.end(), - [this](const auto& device) { - return device.descriptor.device_id == action_arm_->id(); - }); - if (safety_device != safety.devices.end() && - safety_device->safety.fresh) { - current_device_generation = - safety_device->safety.snapshot.device_generation; - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - } - ASSERT_TRUE(current_device_generation.has_value()); - service_ = std::make_unique(); - - api::GetSystemInfoCommand_Request info_request; - api::GetSystemInfoCommand_Feedback info_response; - grpc::ServerContext info_context; - ASSERT_TRUE(service_->GetSystemInfo( - &info_context, &info_request, &info_response).ok()); - - api::ActionQueueCommand_Request request; - request.set_action_id("stale-step-generation"); - request.set_expected_service_instance_id( - info_response.action_service_instance_id()); - auto* step = addMoveLStep( - request, "move", action_arm_->id(), 1.0); - step->mutable_arm_move_l() - ->mutable_header() - ->set_expected_device_generation( - *current_device_generation + 1U); - - api::ActionQueueCommand_Feedback response; - grpc::ServerContext context; - const auto status = service_->ExecuteActionQueue( - &context, &request, &response); - - EXPECT_TRUE(status.ok()) << status.error_message(); - EXPECT_FALSE(response.header().success()); - EXPECT_EQ(response.result(), api::ACTION_RESULT_CODE_REJECTED); - EXPECT_EQ(response.completed_steps(), 0U); - ASSERT_TRUE(response.has_failed_step_index()); - EXPECT_EQ(response.failed_step_index(), 0U); - EXPECT_NE( - response.header().error_message().find("generation"), - std::string::npos) - << response.header().error_message(); - EXPECT_EQ(action_arm_->motionCalls(), 0); - EXPECT_TRUE(action_trace_->names().empty()); -} - -TEST_F(GrpcSystemServiceTest, ActionQueuePreservesArmDelayAgvOrder) -{ - initializeActionDevices(); - api::ActionQueueCommand_Request request; - request.set_action_id("arm-delay-agv"); - addMoveJStep(request, "arm", action_arm_->id()); - addDelayStep(request, "settle", 25U); - addAgvStationStep( - request, "agv", action_agv_->id(), "dock"); - - const auto response = executeAction(request); - const auto arm_time = action_trace_->firstTime("arm:J"); - const auto agv_time = action_trace_->firstTime("agv:station:dock"); - - ASSERT_TRUE(response.header().success()) - << response.header().error_message(); - EXPECT_EQ(response.result(), api::ACTION_RESULT_CODE_COMPLETED); - EXPECT_EQ(response.completed_steps(), 3U); - EXPECT_EQ( - action_trace_->names(), - (std::vector{"arm:J", "agv:station:dock"})); - ASSERT_TRUE(arm_time.has_value()); - ASSERT_TRUE(agv_time.has_value()); - EXPECT_GE( - std::chrono::duration_cast( - *agv_time - *arm_time), - std::chrono::milliseconds(15)); -} - -TEST_F(GrpcSystemServiceTest, ActionQueueExecutesAgvPoseAndPathSteps) -{ - initializeActionDevices(); - api::ActionQueueCommand_Request request; - request.set_action_id("agv-pose-and-path"); - addAgvPoseStep( - request, "pose", action_agv_->id(), 1.0, 2.0, 0.5); - addAgvPathStep(request, "path", action_agv_->id()); - - const auto response = executeAction(request); - - ASSERT_TRUE(response.header().success()) - << response.header().error_message(); - EXPECT_EQ(response.result(), api::ACTION_RESULT_CODE_COMPLETED); - EXPECT_EQ(response.completed_steps(), 2U); - EXPECT_EQ(action_agv_->navigationCalls(), 2); - const auto pose = action_agv_->lastPose(); - EXPECT_DOUBLE_EQ(pose.x, 1.0); - EXPECT_DOUBLE_EQ(pose.y, 2.0); - EXPECT_DOUBLE_EQ(pose.theta, 0.5); - const auto path = action_agv_->lastPath(); - ASSERT_EQ(path.size(), 2U); - EXPECT_EQ(path[0].source_station, "start"); - EXPECT_EQ(path[0].target_station, "middle"); - EXPECT_EQ(path[1].source_station, "middle"); - EXPECT_EQ(path[1].target_station, "finish"); - EXPECT_EQ( - action_trace_->names(), - (std::vector{"agv:pose", "agv:path"})); -} - -TEST_F(GrpcSystemServiceTest, - ActionQueuePrevalidatesAllStepsBeforeAnyDispatch) -{ - initializeActionDevices(); - api::ActionQueueCommand_Request request; - request.set_action_id("prevalidate-all"); - addMoveLStep(request, "valid-first", action_arm_->id(), 1.0); - addAgvStationStep( - request, "missing-second", "missing-agv", "dock"); - - const auto response = executeAction(request); - - EXPECT_FALSE(response.header().success()); - EXPECT_EQ(response.result(), api::ACTION_RESULT_CODE_REJECTED); - EXPECT_EQ(response.completed_steps(), 0U); - ASSERT_TRUE(response.has_failed_step_index()); - EXPECT_EQ(response.failed_step_index(), 1U); - EXPECT_EQ(action_arm_->motionCalls(), 0); - EXPECT_EQ(action_agv_->navigationCalls(), 0); - EXPECT_TRUE(action_trace_->names().empty()); -} - -TEST_F(GrpcSystemServiceTest, ActionQueueRejectsAsynchronousMotion) -{ - initializeActionDevices(); - api::ActionQueueCommand_Request arm_request; - arm_request.set_action_id("async-arm"); - addMoveLStep( - arm_request, "arm", action_arm_->id(), 1.0, 0U, true); - const auto arm_response = executeAction(arm_request); - - api::ActionQueueCommand_Request agv_request; - agv_request.set_action_id("async-agv"); - addAgvStationStep( - agv_request, "agv", action_agv_->id(), "dock", true); - const auto agv_response = executeAction(agv_request); - - EXPECT_EQ(arm_response.result(), api::ACTION_RESULT_CODE_REJECTED); - EXPECT_EQ(agv_response.result(), api::ACTION_RESULT_CODE_REJECTED); - EXPECT_EQ(action_arm_->motionCalls(), 0); - EXPECT_EQ(action_agv_->navigationCalls(), 0); - EXPECT_TRUE(action_trace_->names().empty()); -} - -TEST_F(GrpcSystemServiceTest, - ActionQueueStopsAfterFailureAndReportsFailedStep) -{ - initializeActionDevices(); - action_arm_->failOnMotionCall(2); - api::ActionQueueCommand_Request request; - request.set_action_id("fail-fast"); - addMoveLStep(request, "first", action_arm_->id(), 1.0); - addMoveLStep(request, "fails", action_arm_->id(), 2.0); - addMoveLStep(request, "must-not-run", action_arm_->id(), 3.0); - - const auto response = executeAction(request); - - EXPECT_FALSE(response.header().success()); - EXPECT_EQ(response.result(), api::ACTION_RESULT_CODE_FAILED); - EXPECT_EQ(response.completed_steps(), 1U); - ASSERT_TRUE(response.has_failed_step_index()); - EXPECT_EQ(response.failed_step_index(), 1U); - EXPECT_EQ(action_arm_->motionCalls(), 2); - const auto trace = action_trace_->names(); - ASSERT_GE(trace.size(), 2U); - EXPECT_EQ(trace[0], "arm:L:1"); - EXPECT_EQ(trace[1], "arm:L:2"); - EXPECT_GE(action_arm_->stopMotionCalls(), 1); -} - -TEST_F(GrpcSystemServiceTest, - ActionQueueQuarantinesAgvAfterUnconfirmedFailureStop) -{ - initializeActionDevices(); - action_agv_->setNavigationFailure(true); - action_agv_->setStoppedConfirmed(false); - api::ActionQueueCommand_Request request; - request.set_action_id("agv-unconfirmed-stop"); - addAgvStationStep( - request, "fails", action_agv_->id(), "dock"); - - const auto response = executeAction(request); - - EXPECT_EQ(response.result(), api::ACTION_RESULT_CODE_FAILED); - ASSERT_TRUE(response.has_failed_step_index()); - EXPECT_EQ(response.failed_step_index(), 0U); - EXPECT_NE( - response.header().error_message().find("remain quarantined"), - std::string::npos); - auto& authority = control::ControlAuthorityManager::instance(); - const auto lease = authority.tryAcquire( - action_agv_->id(), - "normal-control-after-unconfirmed-action-stop", - std::chrono::hours(1)); - EXPECT_FALSE(lease.acquired); - - const auto recovery = authority.preemptAcquire( - action_agv_->id(), - "confirmed-agv-recovery", - std::chrono::hours(1)); - ASSERT_TRUE(recovery.acquired) << recovery.detail; - ASSERT_TRUE(authority.waitForPreemptedRelease( - recovery.token, std::chrono::milliseconds::zero())); - ASSERT_TRUE(authority.recoverRetiredSafetyHolders(recovery.token)); - authority.release(recovery.token); - - const auto recovered_lease = authority.tryAcquire( - action_agv_->id(), - "normal-control-after-confirmed-recovery", - std::chrono::hours(1)); - EXPECT_TRUE(recovered_lease.acquired) << recovered_lease.detail; - authority.release(recovered_lease.token); -} - -TEST_F(GrpcSystemServiceTest, - ActionQueueIsIdempotentAndRejectsConflictingPayload) -{ - initializeActionDevices(); - api::ActionQueueCommand_Request request; - request.set_action_id("idempotent-action"); - addMoveLStep(request, "only-step", action_arm_->id(), 1.0); - - const auto first = executeAction(request); - const auto retry = executeAction(request); - auto conflicting = request; - conflicting.mutable_steps(0) - ->mutable_arm_move_l()->mutable_target()->set_x(2.0); - const auto conflict = executeAction(conflicting); - - EXPECT_EQ(first.result(), api::ACTION_RESULT_CODE_COMPLETED); - EXPECT_EQ( - first.deduplication_status(), - api::ACTION_DEDUPLICATION_STATUS_ACCEPTED_NEW); - EXPECT_EQ(retry.result(), api::ACTION_RESULT_CODE_COMPLETED); - EXPECT_EQ( - retry.deduplication_status(), - api::ACTION_DEDUPLICATION_STATUS_CACHED_RESULT); - EXPECT_EQ(retry.completed_steps(), 1U); - EXPECT_EQ(conflict.result(), api::ACTION_RESULT_CODE_REJECTED); - EXPECT_EQ( - conflict.deduplication_status(), - api::ACTION_DEDUPLICATION_STATUS_ACTION_ID_CONFLICT); - EXPECT_EQ(action_arm_->motionCalls(), 1); - EXPECT_EQ( - action_trace_->names(), - (std::vector{"arm:L:1"})); -} - -TEST_F(GrpcSystemServiceTest, - ActionQueueRetryAfterTerminalCacheChurnDoesNotRedispatch) -{ - initializeActionDevices(); - api::ActionQueueCommand_Request original; - original.set_action_id("idempotent-after-cache-churn"); - addMoveLStep(original, "only-step", action_arm_->id(), 1.0); - - const auto first = executeAction(original); - ASSERT_EQ(first.result(), api::ACTION_RESULT_CODE_COMPLETED); - ASSERT_EQ(action_arm_->motionCalls(), 1); - - constexpr int kActionsBeyondTerminalCacheCapacity = 257; - for (int index = 0; index < kActionsBeyondTerminalCacheCapacity; ++index) { - SCOPED_TRACE(index); - api::ActionQueueCommand_Request filler; - filler.set_action_id("terminal-cache-filler-" + std::to_string(index)); - addDelayStep(filler, "delay", 0U); - - const auto response = executeAction(filler); - ASSERT_EQ(response.result(), api::ACTION_RESULT_CODE_COMPLETED) - << response.header().error_message(); - } - - const auto retry = executeAction(original); - - EXPECT_EQ(retry.result(), api::ACTION_RESULT_CODE_COMPLETED); - EXPECT_EQ(retry.completed_steps(), 1U); - EXPECT_EQ(action_arm_->motionCalls(), 1); - - // submitAndWait() may wake before the worker completes terminal-cache - // rotation for the final filler. Advance one additional terminal action so - // the original ID is deterministically present in the retired-ID filter. - constexpr int kTotalActionsToRetireOriginal = 4353; - for (int index = kActionsBeyondTerminalCacheCapacity; - index < kTotalActionsToRetireOriginal; ++index) { - SCOPED_TRACE(index); - api::ActionQueueCommand_Request filler; - filler.set_action_id("terminal-cache-filler-" + std::to_string(index)); - addDelayStep(filler, "delay", 0U); - - const auto response = executeAction(filler); - ASSERT_EQ(response.result(), api::ACTION_RESULT_CODE_COMPLETED) - << response.header().error_message(); - } - - const auto retired_retry = executeAction(original); - - EXPECT_EQ(retired_retry.result(), api::ACTION_RESULT_CODE_REJECTED); - EXPECT_EQ( - retired_retry.deduplication_status(), - api::ACTION_DEDUPLICATION_STATUS_RESULT_EVICTED); - EXPECT_NE( - retired_retry.header().error_message().find("no longer cached"), - std::string::npos); - EXPECT_EQ(action_arm_->motionCalls(), 1); -} - -TEST_F(GrpcSystemServiceTest, - ActionQueueRejectsMissingOrStaleServiceInstance) -{ - initializeActionDevices(); - api::ActionQueueCommand_Request request; - request.set_action_id("service-instance-check"); - addMoveLStep(request, "move", action_arm_->id(), 1.0); - - api::ActionQueueCommand_Feedback missing_response; - grpc::ServerContext missing_context; - const auto missing_status = service_->ExecuteActionQueue( - &missing_context, &request, &missing_response); - - request.set_expected_service_instance_id("stale-instance"); - api::ActionQueueCommand_Feedback stale_response; - grpc::ServerContext stale_context; - const auto stale_status = service_->ExecuteActionQueue( - &stale_context, &request, &stale_response); - - EXPECT_TRUE(missing_status.ok()) << missing_status.error_message(); - EXPECT_EQ( - missing_response.result(), api::ACTION_RESULT_CODE_REJECTED); - EXPECT_EQ(missing_response.service_instance_id(), service_instance_id_); - EXPECT_TRUE(stale_status.ok()) << stale_status.error_message(); - EXPECT_EQ(stale_response.result(), api::ACTION_RESULT_CODE_REJECTED); - EXPECT_EQ( - stale_response.deduplication_status(), - api::ACTION_DEDUPLICATION_STATUS_SERVICE_INSTANCE_MISMATCH); - EXPECT_EQ(stale_response.service_instance_id(), service_instance_id_); - EXPECT_EQ(action_arm_->motionCalls(), 0); -} - -TEST_F(GrpcSystemServiceTest, - ActionQueueServiceRestartRejectsRetryBoundToPriorInstance) -{ - initializeActionDevices(); - api::ActionQueueCommand_Request request; - request.set_action_id("prior-instance-retry"); - request.set_expected_service_instance_id(service_instance_id_); - addMoveLStep(request, "move", action_arm_->id(), 1.0); - const std::string prior_instance = service_instance_id_; - - const auto first = executeAction(request); - ASSERT_EQ(first.result(), api::ACTION_RESULT_CODE_COMPLETED) - << first.header().error_message(); - ASSERT_EQ(action_arm_->motionCalls(), 1); - - service_.reset(); - service_ = std::make_unique(); - api::GetSystemInfoCommand_Request info_request; - api::GetSystemInfoCommand_Feedback info_response; - grpc::ServerContext info_context; - ASSERT_TRUE(service_->GetSystemInfo( - &info_context, &info_request, &info_response).ok()); - service_instance_id_ = info_response.action_service_instance_id(); - ASSERT_FALSE(service_instance_id_.empty()); - ASSERT_NE(service_instance_id_, prior_instance); - - api::ActionQueueCommand_Feedback response; - grpc::ServerContext context; - const auto status = service_->ExecuteActionQueue( - &context, &request, &response); - - EXPECT_TRUE(status.ok()) << status.error_message(); - EXPECT_EQ(response.result(), api::ACTION_RESULT_CODE_REJECTED); - EXPECT_EQ( - response.deduplication_status(), - api::ACTION_DEDUPLICATION_STATUS_SERVICE_INSTANCE_MISMATCH); - EXPECT_EQ(response.service_instance_id(), service_instance_id_); - EXPECT_EQ(action_arm_->motionCalls(), 1); -} - -TEST_F(GrpcSystemServiceTest, - ActionQueueLedgerCapacityRejectsOnlyNewIds) -{ - initializeActionDevices(); - ActionQueueExecutor executor( - device::DeviceManager::getInstance(), 2U); - const auto make_request = [&executor](const std::string& action_id) { - api::ActionQueueCommand_Request request; - request.set_action_id(action_id); - request.set_expected_service_instance_id(executor.instanceId()); - addDelayStep(request, "delay", 0U); - return request; - }; - const auto first_request = make_request("ledger-first"); - const auto second_request = make_request("ledger-second"); - const auto rejected_request = make_request("ledger-third"); - api::ActionQueueCommand_Feedback first; - api::ActionQueueCommand_Feedback second; - api::ActionQueueCommand_Feedback rejected; - api::ActionQueueCommand_Feedback retry; - - EXPECT_EQ( - executor.submitAndWait(first_request, first), - ActionQueueExecutor::WaitResult::Terminal); - EXPECT_EQ( - executor.submitAndWait(second_request, second), - ActionQueueExecutor::WaitResult::Terminal); - EXPECT_EQ( - executor.submitAndWait(rejected_request, rejected), - ActionQueueExecutor::WaitResult::Terminal); - EXPECT_EQ( - executor.submitAndWait(first_request, retry), - ActionQueueExecutor::WaitResult::Terminal); - - EXPECT_EQ(first.result(), api::ACTION_RESULT_CODE_COMPLETED); - EXPECT_EQ(second.result(), api::ACTION_RESULT_CODE_COMPLETED); - EXPECT_EQ(rejected.result(), api::ACTION_RESULT_CODE_REJECTED); - EXPECT_EQ( - rejected.deduplication_status(), - api::ACTION_DEDUPLICATION_STATUS_LEDGER_EXHAUSTED); - EXPECT_EQ(retry.result(), api::ACTION_RESULT_CODE_COMPLETED); - EXPECT_EQ( - retry.deduplication_status(), - api::ACTION_DEDUPLICATION_STATUS_CACHED_RESULT); -} - -TEST_F(GrpcSystemServiceTest, - ActionQueueCanceledWaiterLeavesAcceptedActionRunning) -{ - initializeActionDevices(); - ActionQueueExecutor executor(device::DeviceManager::getInstance()); - action_arm_->blockNextMotion(); - - api::ActionQueueCommand_Request request; - request.set_action_id("canceled-waiter-action-continues"); - request.set_expected_service_instance_id(executor.instanceId()); - request.set_total_timeout_ms(1000U); - addMoveLStep(request, "move", action_arm_->id(), 1.0); - - std::atomic waiter_canceled{false}; - api::ActionQueueCommand_Feedback abandoned_feedback; - auto waiter = std::async( - std::launch::async, - [&executor, &request, &abandoned_feedback, &waiter_canceled]() { - return executor.submitAndWait( - request, - abandoned_feedback, - [&waiter_canceled]() { - return waiter_canceled.load(std::memory_order_acquire); - }); - }); - ASSERT_TRUE(action_arm_->waitForMotionCalls( - 1, std::chrono::milliseconds(500))); - - waiter_canceled.store(true, std::memory_order_release); - const auto waiter_status = waiter.wait_for(std::chrono::milliseconds(500)); - if (waiter_status != std::future_status::ready) { - action_arm_->releaseBlockedMotion(); - } - ASSERT_EQ(waiter_status, std::future_status::ready); - EXPECT_EQ( - waiter.get(), - ActionQueueExecutor::WaitResult::CanceledAfterAdmission); - EXPECT_EQ(action_arm_->motionCalls(), 1); - - action_arm_->releaseBlockedMotion(); - ASSERT_TRUE(executor.waitForIdle(std::chrono::milliseconds(500))); - - api::ActionQueueCommand_Feedback retry_feedback; - const auto retry_result = executor.submitAndWait(request, retry_feedback); - - EXPECT_EQ(retry_result, ActionQueueExecutor::WaitResult::Terminal); - EXPECT_TRUE(retry_feedback.header().success()) - << retry_feedback.header().error_message(); - EXPECT_EQ( - retry_feedback.result(), - api::ACTION_RESULT_CODE_COMPLETED); - EXPECT_EQ(retry_feedback.completed_steps(), 1U); - EXPECT_EQ(action_arm_->motionCalls(), 1); -} - -TEST_F(GrpcSystemServiceTest, - ConcurrentIdenticalActionIdJoinsInFlightExecution) -{ - initializeActionDevices(); - ActionQueueExecutor executor(device::DeviceManager::getInstance()); - action_arm_->blockNextMotion(); - - api::ActionQueueCommand_Request request; - request.set_action_id("join-identical-in-flight-action"); - request.set_expected_service_instance_id(executor.instanceId()); - request.set_total_timeout_ms(1000U); - addMoveLStep(request, "move", action_arm_->id(), 1.0); - - api::ActionQueueCommand_Feedback first_feedback; - api::ActionQueueCommand_Feedback joined_feedback; - auto first = std::async( - std::launch::async, - [&executor, &request, &first_feedback]() { - return executor.submitAndWait(request, first_feedback); - }); - const bool motion_started = action_arm_->waitForMotionCalls( - 1, std::chrono::milliseconds(500)); - - std::atomic joined_wait_polls{0}; - auto joined = std::async( - std::launch::async, - [&executor, &request, &joined_feedback, &joined_wait_polls]() { - return executor.submitAndWait( - request, - joined_feedback, - [&joined_wait_polls]() { - joined_wait_polls.fetch_add( - 1, std::memory_order_acq_rel); - return false; - }); - }); - const auto poll_deadline = - std::chrono::steady_clock::now() + std::chrono::milliseconds(500); - while (joined_wait_polls.load(std::memory_order_acquire) < 2 && - std::chrono::steady_clock::now() < poll_deadline) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - const bool joined_is_waiting = - joined_wait_polls.load(std::memory_order_acquire) >= 2; - action_arm_->releaseBlockedMotion(); - - const auto first_result = first.get(); - const auto joined_result = joined.get(); - - ASSERT_TRUE(motion_started); - ASSERT_TRUE(joined_is_waiting); - EXPECT_EQ(first_result, ActionQueueExecutor::WaitResult::Terminal); - EXPECT_EQ(joined_result, ActionQueueExecutor::WaitResult::Terminal); - EXPECT_EQ(first_feedback.result(), api::ACTION_RESULT_CODE_COMPLETED); - EXPECT_EQ(joined_feedback.result(), api::ACTION_RESULT_CODE_COMPLETED); - EXPECT_EQ( - first_feedback.deduplication_status(), - api::ACTION_DEDUPLICATION_STATUS_ACCEPTED_NEW); - EXPECT_EQ( - joined_feedback.deduplication_status(), - api::ACTION_DEDUPLICATION_STATUS_JOINED_IN_FLIGHT); - EXPECT_EQ(action_arm_->motionCalls(), 1); -} - -TEST_F(GrpcSystemServiceTest, - ConcurrentActionQueuesRemainFifoAndHoldTheControlLease) -{ - initializeActionDevices(); - action_arm_->blockNextMotion(); - - api::ActionQueueCommand_Request first_request; - first_request.set_action_id("fifo-first"); - addMoveLStep(first_request, "first-1", action_arm_->id(), 10.0); - addMoveLStep(first_request, "first-2", action_arm_->id(), 11.0); - api::ActionQueueCommand_Request second_request; - second_request.set_action_id("fifo-second"); - addMoveLStep(second_request, "second-1", action_arm_->id(), 20.0); - - auto first = std::async( - std::launch::async, - [this, first_request]() { return executeAction(first_request); }); - const bool started = action_arm_->waitForMotionCalls( - 1, std::chrono::milliseconds(500)); - auto second = std::async( - std::launch::async, - [this, second_request]() { return executeAction(second_request); }); - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - - const auto competing = - control::ControlAuthorityManager::instance().tryAcquire( - action_arm_->id(), "ordinary-control", - std::chrono::seconds(1)); - if (competing.acquired) { - // Keep a failed assertion from stranding the worker behind this test - // lease and turning the diagnostic into a long timeout. - control::ControlAuthorityManager::instance().release( - competing.token); - } - action_arm_->releaseBlockedMotion(); - const auto first_response = first.get(); - const auto second_response = second.get(); - - EXPECT_TRUE(started); - EXPECT_FALSE(competing.acquired); - EXPECT_EQ(first_response.result(), api::ACTION_RESULT_CODE_COMPLETED); - EXPECT_EQ(second_response.result(), api::ACTION_RESULT_CODE_COMPLETED); - EXPECT_EQ(action_arm_->maxActiveMotions(), 1); - EXPECT_EQ( - action_trace_->names(), - (std::vector{ - "arm:L:10", "arm:L:11", "arm:L:20"})); -} - -TEST_F(GrpcSystemServiceTest, - ActionQueueTotalAndStepTimeoutsIssueTypedArmStop) -{ - initializeActionDevices(); - - action_arm_->blockNextMotion(); - api::ActionQueueCommand_Request total_timeout; - total_timeout.set_action_id("total-timeout"); - total_timeout.set_total_timeout_ms(40U); - addMoveLStep( - total_timeout, "total", action_arm_->id(), 1.0); - const auto total_response = executeAction(total_timeout); - const int stops_after_total = action_arm_->stopMotionCalls(); - - action_arm_->blockNextMotion(); - api::ActionQueueCommand_Request step_timeout; - step_timeout.set_action_id("step-timeout"); - step_timeout.set_total_timeout_ms(500U); - addMoveLStep( - step_timeout, "step", action_arm_->id(), 2.0, 30U); - const auto step_response = executeAction(step_timeout); - - EXPECT_EQ(total_response.result(), api::ACTION_RESULT_CODE_TIMED_OUT); - EXPECT_EQ(total_response.completed_steps(), 0U); - ASSERT_TRUE(total_response.has_failed_step_index()); - EXPECT_EQ(total_response.failed_step_index(), 0U); - EXPECT_GE(stops_after_total, 1); - EXPECT_EQ(step_response.result(), api::ACTION_RESULT_CODE_TIMED_OUT); - EXPECT_EQ(step_response.completed_steps(), 0U); - ASSERT_TRUE(step_response.has_failed_step_index()); - EXPECT_EQ(step_response.failed_step_index(), 0U); - EXPECT_GT(action_arm_->stopMotionCalls(), stops_after_total); -} - -TEST_F(GrpcSystemServiceTest, - ActionQueueRetiresUnconfirmedTimedOutArmStopForRecovery) -{ - initializeActionDevices(); - action_arm_->blockNextMotion(); - action_arm_->failStopAndBusyConfirmation(); - - api::ActionQueueCommand_Request request; - request.set_action_id("unconfirmed-timeout-stop"); - request.set_total_timeout_ms(40U); - addMoveLStep(request, "times-out", action_arm_->id(), 1.0); - - const auto response = executeAction(request); - - EXPECT_EQ(response.result(), api::ACTION_RESULT_CODE_TIMED_OUT); - EXPECT_NE( - response.header().error_message().find("remains quarantined"), - std::string::npos); - auto& authority = control::ControlAuthorityManager::instance(); - EXPECT_FALSE(authority.tryAcquire( - action_arm_->id(), "move-before-recovery", std::chrono::hours(1)) - .acquired); - - const auto recovery = authority.preemptAcquire( - action_arm_->id(), - "confirmed-arm-recovery", - std::chrono::hours(1)); - ASSERT_TRUE(recovery.acquired) << recovery.detail; - ASSERT_TRUE(authority.waitForPreemptedRelease( - recovery.token, std::chrono::milliseconds::zero())); - ASSERT_TRUE(authority.recoverRetiredSafetyHolders(recovery.token)); - authority.release(recovery.token); - - const auto recovered_lease = authority.tryAcquire( - action_arm_->id(), "move-after-recovery", std::chrono::hours(1)); - EXPECT_TRUE(recovered_lease.acquired) << recovered_lease.detail; - authority.release(recovered_lease.token); -} - -TEST_F(GrpcSystemServiceTest, - DelayedActionCancellationCannotStopSuccessorControlLease) -{ - initializeActionDevices(); - action_arm_->blockNextMotion(); - action_arm_->blockCanceledMotionReturn(); - - api::ActionQueueCommand_Request request; - request.set_action_id("stale-action-stop-must-not-preempt-successor"); - request.set_total_timeout_ms(2000U); - addMoveLStep(request, "active", action_arm_->id(), 1.0); - - auto action = std::async( - std::launch::async, - [this, request]() { return executeAction(request); }); - const bool motion_started = action_arm_->waitForMotionCalls( - 1, std::chrono::milliseconds(500)); - - auto& authority = control::ControlAuthorityManager::instance(); - control::ControlAcquireResult direct_stop; - if (motion_started) { - direct_stop = authority.preemptAcquire( - action_arm_->id(), - "direct-stop-before-successor", - std::chrono::seconds(30)); - } - if (direct_stop.acquired) { - (void)action_arm_->stopMotion(); - } else { - action_arm_->releaseBlockedMotion(); - } - const bool old_driver_ready_to_return = - action_arm_->waitForCanceledMotionReturn( - std::chrono::milliseconds(500)); - const auto successor_before_handler_exit = authority.tryAcquire( - action_arm_->id(), - "successor-before-old-handler-exit", - std::chrono::seconds(30)); - action_arm_->releaseCanceledMotionReturn(); - - const auto action_status = action.wait_for(std::chrono::seconds(1)); - if (action_status != std::future_status::ready) { - service_->prepareForShutdown(); - } - ASSERT_EQ(action_status, std::future_status::ready); - const auto response = action.get(); - const bool old_handler_released = direct_stop.acquired && - authority.waitForPreemptedRelease( - direct_stop.token, std::chrono::seconds(1)); - if (direct_stop.acquired) { - authority.release(direct_stop.token); - } - const auto successor = authority.tryAcquire( - action_arm_->id(), - "successor-move", - std::chrono::seconds(30)); - const bool successor_still_current = - successor.acquired && authority.validate(successor.token); - if (successor.acquired) { - authority.release(successor.token); - } - - ASSERT_TRUE(motion_started); - ASSERT_TRUE(direct_stop.acquired) << direct_stop.detail; - ASSERT_TRUE(old_driver_ready_to_return); - EXPECT_FALSE(successor_before_handler_exit.acquired); - EXPECT_TRUE(old_handler_released); - ASSERT_TRUE(successor.acquired) << successor.detail; - EXPECT_EQ(response.result(), api::ACTION_RESULT_CODE_CANCELED); - EXPECT_TRUE(successor_still_current); - EXPECT_EQ(action_arm_->stopMotionCalls(), 1); -} - -TEST_F(GrpcSystemServiceTest, - StopAllCancelsActiveActionAndSkipsRemainingSteps) -{ - initializeActionDevices(); - action_arm_->blockNextMotion(); - api::ActionQueueCommand_Request action_request; - action_request.set_action_id("stop-all-action"); - action_request.set_total_timeout_ms(500U); - addMoveLStep(action_request, "active", action_arm_->id(), 1.0); - addMoveLStep(action_request, "must-not-run", action_arm_->id(), 2.0); - - auto action = std::async( - std::launch::async, - [this, action_request]() { return executeAction(action_request); }); - const bool started = action_arm_->waitForMotionCalls( - 1, std::chrono::milliseconds(500)); - - api::StopAllCommand_Request stop_request; - api::StopAllCommand_Feedback stop_response; - grpc::ServerContext stop_context; - const auto stop_status = service_->StopAll( - &stop_context, &stop_request, &stop_response); - const auto action_response = action.get(); - - api::ActionQueueCommand_Request resumed_request; - resumed_request.set_action_id("action-after-stop-all"); - addMoveLStep( - resumed_request, "resumed", action_arm_->id(), 3.0); - const auto resumed_response = executeAction(resumed_request); - - EXPECT_TRUE(started); - ASSERT_TRUE(stop_status.ok()) << stop_status.error_message(); - EXPECT_TRUE(stop_response.header().success()) - << stop_response.header().error_message(); - EXPECT_EQ(action_response.result(), api::ACTION_RESULT_CODE_CANCELED); - EXPECT_EQ(action_response.completed_steps(), 0U); - ASSERT_TRUE(action_response.has_failed_step_index()); - EXPECT_EQ(action_response.failed_step_index(), 0U); - EXPECT_TRUE(resumed_response.header().success()) - << resumed_response.header().error_message(); - EXPECT_EQ( - resumed_response.result(), api::ACTION_RESULT_CODE_COMPLETED); - EXPECT_EQ(resumed_response.completed_steps(), 1U); - EXPECT_EQ( - resumed_response.service_instance_id(), service_instance_id_); - EXPECT_EQ(action_arm_->motionCalls(), 2); - EXPECT_GE(action_arm_->stopMotionCalls(), 1); -} - -TEST_F(GrpcSystemServiceTest, - StopAllRequestsMotionStopBeforeWaitingForMediaHandlers) -{ - initializeActionDevices(); - auto media_session = globalMediaActivityCoordinator().beginSession(); - ASSERT_TRUE(media_session); - - api::StopAllCommand_Request request; - auto stop_all = std::async(std::launch::async, [this, &request] { - api::StopAllCommand_Feedback response; - grpc::ServerContext context; - const auto status = service_->StopAll(&context, &request, &response); - return std::make_pair(status, response); - }); - - const bool motion_stop_requested = action_arm_->waitForStopMotionCalls( - 1, std::chrono::milliseconds(500)); - const auto status_while_media_active = - stop_all.wait_for(std::chrono::milliseconds(20)); - media_session.reset(); - - ASSERT_EQ( - stop_all.wait_for(std::chrono::seconds(1)), - std::future_status::ready); - const auto [status, response] = stop_all.get(); - - EXPECT_TRUE(motion_stop_requested); - EXPECT_EQ( - status_while_media_active, - std::future_status::timeout); - ASSERT_TRUE(status.ok()) << status.error_message(); - EXPECT_TRUE(response.header().success()) - << response.header().error_message(); -} - -TEST_F(GrpcSystemServiceTest, - StopAllDoesNotReportSuccessWhenAnotherAdmissionParticipantFails) -{ - initializeActionDevices(); - auto media_session = globalMediaActivityCoordinator().beginSession(); - ASSERT_TRUE(media_session); - - api::StopAllCommand_Request request; - auto stop_all = std::async(std::launch::async, [this, &request] { - api::StopAllCommand_Feedback response; - grpc::ServerContext context; - const auto status = service_->StopAll(&context, &request, &response); - return std::make_pair(status, response); - }); - - ASSERT_TRUE(action_arm_->waitForStopMotionCalls( - 1, std::chrono::milliseconds(500))); - auto& admission = globalStopAllAdmissionGate(); - const auto failed_participant = admission.beginStopAll(); - ASSERT_TRUE(failed_participant.valid()); - EXPECT_FALSE(admission.finishStopAll(failed_participant, false)); - media_session.reset(); - - ASSERT_EQ( - stop_all.wait_for(std::chrono::seconds(1)), - std::future_status::ready); - const auto [status, response] = stop_all.get(); - - ASSERT_TRUE(status.ok()) << status.error_message(); - EXPECT_FALSE(response.header().success()); - EXPECT_NE( - response.header().error_message().find( - "could not safely resume system admission"), - std::string::npos); - EXPECT_FALSE(admission.lockAdmission().accepting()); -} - -TEST_F(GrpcSystemServiceTest, - StopAllDoesNotWaitForADeviceHealthSnapshot) -{ - config::DeviceManagerConfig config; - auto& manager = device::DeviceManager::getInstance(config); - auto trace = std::make_shared(); - auto arm = std::make_shared( - "health-blocked-arm", trace); - arm->blockHealthSnapshot(); - auto registration = std::async( - std::launch::async, [&manager, arm] { - manager.registerDevice(arm); - }); - const bool health_call_blocked = arm->waitForHealthSnapshot( - std::chrono::milliseconds(500)); - service_ = std::make_unique(); - - api::StopAllCommand_Request request; - auto stop_all = std::async(std::launch::async, [this, &request] { - api::StopAllCommand_Feedback response; - grpc::ServerContext context; - const auto status = service_->StopAll( - &context, &request, &response); - return std::make_pair(status, response); - }); - - const bool stop_dispatched_while_health_blocked = - arm->waitForStopMotionCalls( - 1, std::chrono::milliseconds(500)); - arm->releaseHealthSnapshot(); - - ASSERT_EQ( - registration.wait_for(std::chrono::seconds(1)), - std::future_status::ready); - registration.get(); - ASSERT_EQ( - stop_all.wait_for(std::chrono::seconds(1)), - std::future_status::ready); - const auto [status, response] = stop_all.get(); - - EXPECT_TRUE(health_call_blocked); - EXPECT_TRUE(stop_dispatched_while_health_blocked); - EXPECT_EQ(arm->healthSnapshotCalls(), 1); - ASSERT_TRUE(status.ok()) << status.error_message(); - EXPECT_TRUE(response.header().success()) - << response.header().error_message(); -} - -TEST_F(GrpcSystemServiceTest, - StopAllDispatchesDeviceStopsWhileTaskActivityStopIsBlocked) -{ - task::TaskFactory::registerCreator( - config::TaskConfigEntry::TASK_TYPE_UME_TELEOP, - [](const config::TaskConfigEntry& entry) { - blocking_stop_task = - std::make_shared(entry.id()); - return blocking_stop_task; - }); - config::TaskManagerConfig task_config; - auto* task_entry = task_config.add_tasks(); - task_entry->set_id("blocking-stop-task"); - task_entry->set_type( - config::TaskConfigEntry::TASK_TYPE_UME_TELEOP); - task_entry->set_enable(true); - task_entry->set_run_mode( - config::TaskConfigEntry::TASK_RUN_MODE_BLOCKING_SERVICE); - auto& task_manager = task::TaskManager::getInstance(task_config); - ASSERT_TRUE(task_manager.initialized()); - ASSERT_NE(blocking_stop_task, nullptr); - - initializeActionDevices(); - auto camera = std::make_shared( - "camera-while-task-stop-blocked"); - device::DeviceManager::getInstance().registerDevice(camera); - api::StopAllCommand_Request request; - auto stop_all = std::async(std::launch::async, [this, &request] { - api::StopAllCommand_Feedback response; - grpc::ServerContext context; - const auto status = service_->StopAll( - &context, &request, &response); - return std::make_pair(status, response); - }); - - const bool task_stop_entered = - blocking_stop_task->waitForStopActivity( - std::chrono::milliseconds(500)); - const bool arm_stop_dispatched = action_arm_->waitForStopMotionCalls( - 1, std::chrono::milliseconds(500)); - const bool camera_stop_dispatched = camera->waitForStopRecordingCalls( - 1, std::chrono::milliseconds(500)); - const auto status_while_task_blocked = - stop_all.wait_for(std::chrono::milliseconds::zero()); - blocking_stop_task->releaseStopActivity(); - - ASSERT_EQ( - stop_all.wait_for(std::chrono::seconds(1)), - std::future_status::ready); - const auto [status, response] = stop_all.get(); - - EXPECT_TRUE(task_stop_entered); - EXPECT_TRUE(arm_stop_dispatched); - EXPECT_TRUE(camera_stop_dispatched); - EXPECT_EQ(status_while_task_blocked, std::future_status::timeout); - EXPECT_EQ(blocking_stop_task->stopActivityCalls(), 1); - EXPECT_EQ(blocking_stop_task->lifecycleStopCalls(), 0); - EXPECT_EQ(camera->lifecycleStopCalls(), 0); - ASSERT_TRUE(status.ok()) << status.error_message(); - EXPECT_TRUE(response.header().success()) - << response.header().error_message(); -} - -TEST_F(GrpcSystemServiceTest, - StopAllDispatchesPeerArmStopWhileAnotherDriverIsBlocked) -{ - config::DeviceManagerConfig config; - auto& manager = device::DeviceManager::getInstance(config); - auto trace = std::make_shared(); - auto blocking_arm = std::make_shared( - "a-blocking-arm", trace); - auto peer_arm = std::make_shared( - "b-peer-arm", trace); - auto peer_camera = std::make_shared( - "c-peer-camera"); - manager.registerDevice(blocking_arm); - manager.registerDevice(peer_arm); - manager.registerDevice(peer_camera); - blocking_arm->blockNextStopMotion(); - service_ = std::make_unique(); - - api::StopAllCommand_Request request; - auto stop_all = std::async(std::launch::async, [this, &request] { - api::StopAllCommand_Feedback response; - grpc::ServerContext context; - const auto status = service_->StopAll( - &context, &request, &response); - return std::make_pair(status, response); - }); - - const bool blocking_stop_entered = - blocking_arm->waitForBlockedStopMotion( - std::chrono::milliseconds(500)); - const bool peer_stop_dispatched = peer_arm->waitForStopMotionCalls( - 1, std::chrono::milliseconds(500)); - const bool peer_camera_stop_dispatched = - peer_camera->waitForStopRecordingCalls( - 1, std::chrono::milliseconds(500)); - const auto status_before_release = - stop_all.wait_for(std::chrono::milliseconds(0)); - blocking_arm->releaseBlockedStopMotion(); - const auto completion_status = - stop_all.wait_for(std::chrono::seconds(1)); - const auto [status, response] = stop_all.get(); - - EXPECT_TRUE(blocking_stop_entered); - EXPECT_TRUE(peer_stop_dispatched); - EXPECT_TRUE(peer_camera_stop_dispatched); - EXPECT_EQ(status_before_release, std::future_status::timeout); - EXPECT_EQ(completion_status, std::future_status::ready); - EXPECT_TRUE(status.ok()) << status.error_message(); - EXPECT_TRUE(response.header().success()) - << response.header().error_message(); - EXPECT_GE(blocking_arm->stopMotionCalls(), 2); - EXPECT_GE(peer_arm->stopMotionCalls(), 2); - EXPECT_EQ(peer_camera->lifecycleStopCalls(), 0); -} - -TEST_F(GrpcSystemServiceTest, - StopAllRoundsAreSerializedAcrossSystemServiceInstances) -{ - initializeActionDevices(); - auto second_service = std::make_unique(); - action_arm_->blockNextStopMotion(); - - api::StopAllCommand_Request request; - auto first_stop = std::async(std::launch::async, [this, &request] { - api::StopAllCommand_Feedback response; - grpc::ServerContext context; - const auto status = service_->StopAll(&context, &request, &response); - return std::make_pair(status, response); - }); - - const bool first_stop_entered = action_arm_->waitForBlockedStopMotion( - std::chrono::milliseconds(500)); - auto second_stop = std::async( - std::launch::async, - [&second_service, &request] { - api::StopAllCommand_Feedback response; - grpc::ServerContext context; - const auto status = second_service->StopAll( - &context, &request, &response); - return std::make_pair(status, response); - }); - - const auto second_before_release = - second_stop.wait_for(std::chrono::milliseconds(50)); - const int stop_calls_before_release = action_arm_->stopMotionCalls(); - action_arm_->releaseBlockedStopMotion(); - - EXPECT_TRUE(first_stop_entered); - EXPECT_EQ(second_before_release, std::future_status::timeout); - EXPECT_EQ(stop_calls_before_release, 1); - - const auto [first_status, first_response] = first_stop.get(); - const auto [second_status, second_response] = second_stop.get(); - EXPECT_TRUE(first_status.ok()) << first_status.error_message(); - EXPECT_TRUE(first_response.header().success()) - << first_response.header().error_message(); - EXPECT_TRUE(second_status.ok()) << second_status.error_message(); - EXPECT_TRUE(second_response.header().success()) - << second_response.header().error_message(); - EXPECT_EQ(first_response.operation_id(), second_response.operation_id()); - EXPECT_EQ( - first_response.current_safety_epoch(), - second_response.current_safety_epoch()); - EXPECT_EQ(action_arm_->stopMotionCalls(), 2); -} - -TEST_F(GrpcSystemServiceTest, - PrepareForShutdownDoesNotWaitForBlockedBusinessStopAll) -{ - initializeActionDevices(); - auto media_session = globalMediaActivityCoordinator().beginSession(); - ASSERT_TRUE(media_session); - - api::StopAllCommand_Request request; - auto stop_all = std::async(std::launch::async, [this, &request] { - api::StopAllCommand_Feedback response; - grpc::ServerContext context; - const auto status = service_->StopAll(&context, &request, &response); - return std::make_pair(status, response); - }); - - ASSERT_TRUE(action_arm_->waitForStopMotionCalls( - 1, std::chrono::milliseconds(500))); - ASSERT_EQ( - stop_all.wait_for(std::chrono::milliseconds(20)), - std::future_status::timeout); - - auto shutdown = std::async(std::launch::async, [this] { - service_->prepareForShutdown(); - }); - EXPECT_EQ( - shutdown.wait_for(std::chrono::milliseconds(500)), - std::future_status::ready); - shutdown.get(); - - media_session.reset(); - ASSERT_EQ( - stop_all.wait_for(std::chrono::seconds(1)), - std::future_status::ready); - const auto [status, response] = stop_all.get(); - - ASSERT_TRUE(status.ok()) << status.error_message(); - EXPECT_FALSE(response.header().success()); - EXPECT_NE( - response.header().error_message().find( - "could not safely resume ActionQueue admission"), - std::string::npos); -} - -TEST_F(GrpcSystemServiceTest, - StopAllFailsClosedWhenAgvStoppedStateIsUnconfirmed) -{ - initializeActionDevices(); - action_agv_->setStoppedConfirmed(false); - - api::StopAllCommand_Request request; - api::StopAllCommand_Feedback response; - grpc::ServerContext context; - const auto status = service_->StopAll( - &context, &request, &response); - - ASSERT_TRUE(status.ok()) << status.error_message(); - EXPECT_FALSE(response.header().success()); - const auto* agv_target = findSafetyTarget(response, action_agv_->id()); - ASSERT_NE(agv_target, nullptr); - EXPECT_EQ( - agv_target->reason_code(), - api::COMMAND_REASON_CODE_DEVICE_STILL_MOVING); - EXPECT_EQ( - agv_target->result(), api::SAFETY_OPERATION_RESULT_FAILED); - const auto lease = - control::ControlAuthorityManager::instance().tryAcquire( - action_agv_->id(), - "normal-control-after-unconfirmed-stop-all", - std::chrono::hours(1)); - EXPECT_FALSE(lease.acquired); -} - -TEST_F(GrpcSystemServiceTest, - StopAllAcceptsProtectedArmAsQuiescent) -{ - initializeActionDevices(); - device::ArmState protected_state; - protected_state.connected = true; - protected_state.powered_on = true; - protected_state.moving = true; - protected_state.program_running = true; - protected_state.protective_stopped = true; - action_arm_->setReportedState(protected_state); - - api::StopAllCommand_Request request; - api::StopAllCommand_Feedback response; - grpc::ServerContext context; - const auto status = service_->StopAll( - &context, &request, &response); - - ASSERT_TRUE(status.ok()) << status.error_message(); - EXPECT_TRUE(response.header().success()) - << response.header().error_message(); - const auto* arm_target = findSafetyTarget(response, action_arm_->id()); - ASSERT_NE(arm_target, nullptr); - EXPECT_EQ( - arm_target->result(), api::SAFETY_OPERATION_RESULT_SUCCEEDED); -} - -TEST_F(GrpcSystemServiceTest, - StopAllDoesNotTreatGenericArmFaultAsQuiescent) -{ - initializeActionDevices(); - device::ArmState fault_state; - fault_state.connected = true; - fault_state.powered_on = true; - fault_state.moving = true; - fault_state.program_running = true; - fault_state.fault = true; - action_arm_->setReportedState(fault_state); - - api::StopAllCommand_Request request; - api::StopAllCommand_Feedback response; - grpc::ServerContext context; - const auto status = service_->StopAll( - &context, &request, &response); - - ASSERT_TRUE(status.ok()) << status.error_message(); - EXPECT_FALSE(response.header().success()); - const auto* arm_target = findSafetyTarget(response, action_arm_->id()); - ASSERT_NE(arm_target, nullptr); - EXPECT_EQ( - arm_target->result(), api::SAFETY_OPERATION_RESULT_FAILED); - EXPECT_EQ( - arm_target->reason_code(), - api::COMMAND_REASON_CODE_DEVICE_STILL_MOVING); -} - -TEST_F(GrpcSystemServiceTest, - StopAllStopsActiveMediaWithoutStoppingDeviceLifecycles) -{ - config::DeviceManagerConfig config; - auto& manager = device::DeviceManager::getInstance(config); - auto camera = std::make_shared("recording-camera"); - auto microphone = - std::make_shared("recording-microphone"); - auto speaker = std::make_shared("playing-speaker"); - manager.registerDevice(camera); - manager.registerDevice(microphone); - manager.registerDevice(speaker); - ASSERT_EQ( - globalCameraOperationalActivityRegistry().start( - camera->id(), camera), - CameraOperationalActivityRegistry::DispatchResult::Success); - service_ = std::make_unique(); - - api::StopAllCommand_Request request; - api::StopAllCommand_Feedback response; - grpc::ServerContext context; - const auto status = service_->StopAll( - &context, &request, &response); - - ASSERT_TRUE(status.ok()) << status.error_message(); - ASSERT_TRUE(response.header().success()) - << response.header().error_message(); - EXPECT_EQ(camera->stopRecordingCalls(), 1); - EXPECT_FALSE(camera->isRecording()); - EXPECT_EQ(microphone->stopRecordingCalls(), 2); - EXPECT_FALSE(microphone->isRecording()); - EXPECT_EQ(speaker->stopPlaybackCalls(), 2); - EXPECT_EQ(camera->lifecycleStopCalls(), 0); - EXPECT_GE(camera->operationalStopCalls(), 2); - EXPECT_FALSE(camera->operationalActive()); - EXPECT_EQ(microphone->lifecycleStopCalls(), 0); - EXPECT_EQ(speaker->lifecycleStopCalls(), 0); -} - -TEST_F(GrpcSystemServiceTest, - StopAllStopsUntrackedInventoryCameraOperationalActivity) -{ - config::DeviceManagerConfig config; - auto& manager = device::DeviceManager::getInstance(config); - auto camera = std::make_shared( - "untracked-inventory-camera"); - camera->setRecording(false); - ASSERT_TRUE(camera->startOperationalActivity()); - manager.registerDevice(camera); - service_ = std::make_unique(); - - api::StopAllCommand_Request request; - api::StopAllCommand_Feedback response; - grpc::ServerContext context; - const auto status = service_->StopAll( - &context, &request, &response); - - ASSERT_TRUE(status.ok()) << status.error_message(); - ASSERT_TRUE(response.header().success()) - << response.header().error_message(); - EXPECT_EQ(camera->operationalStopCalls(), 2); - EXPECT_FALSE(camera->operationalActive()); - EXPECT_EQ(camera->lifecycleStopCalls(), 0); -} - -TEST_F(GrpcSystemServiceTest, - StopAllRepeatsOperationalStopAfterAnOldMediaStartFinishes) -{ - config::DeviceManagerConfig config; - auto& manager = device::DeviceManager::getInstance(config); - auto camera = std::make_shared("raced-recording-camera"); - camera->blockNextStartRecording(); - manager.registerDevice(camera); - service_ = std::make_unique(); - - gRPCCameraServiceImpl camera_service; - api::StartCameraRecordingCommand_Request start_request; - start_request.mutable_header()->set_device_id(camera->id()); - start_request.set_video_path("raced.mp4"); - auto old_start = std::async( - std::launch::async, - [&] { - api::StartCameraRecordingCommand_Feedback response; - grpc::ServerContext context; - const auto status = camera_service.StartRecording( - &context, &start_request, &response); - return std::make_pair(status, response); - }); - ASSERT_TRUE(camera->waitForStartRecordingEntered( - std::chrono::milliseconds(500))); - - api::StopAllCommand_Request request; - auto stop_all = std::async(std::launch::async, [this, &request] { - api::StopAllCommand_Feedback response; - grpc::ServerContext context; - const auto status = service_->StopAll(&context, &request, &response); - return std::make_pair(status, response); - }); - - ASSERT_TRUE(camera->waitForStopRecordingCalls( - 1, std::chrono::milliseconds(500))); - EXPECT_EQ( - stop_all.wait_for(std::chrono::milliseconds(20)), - std::future_status::timeout); - camera->releaseBlockedStartRecording(); - - ASSERT_EQ( - old_start.wait_for(std::chrono::seconds(1)), - std::future_status::ready); - const auto [start_status, start_response] = old_start.get(); - ASSERT_TRUE(start_status.ok()) << start_status.error_message(); - EXPECT_TRUE(start_response.header().success()) - << start_response.header().error_message(); - ASSERT_TRUE(camera->waitForStartRecordingCalls( - 1, std::chrono::milliseconds(500))); - ASSERT_EQ( - stop_all.wait_for(std::chrono::seconds(1)), - std::future_status::ready); - const auto [status, response] = stop_all.get(); - - ASSERT_TRUE(status.ok()) << status.error_message(); - ASSERT_TRUE(response.header().success()) - << response.header().error_message(); - EXPECT_EQ(camera->stopRecordingCalls(), 2); - EXPECT_FALSE(camera->isRecording()); - EXPECT_EQ(camera->lifecycleStopCalls(), 0); -} - -TEST_F(GrpcSystemServiceTest, - StopAllStopsMediaActivitiesAbsentFromDeviceManager) -{ - config::DeviceManagerConfig config; - device::DeviceManager::getInstance(config); - - constexpr const char* hub_source_id = "orphan-hub-camera"; - constexpr const char* hub_track_id = "orphan-hub-camera/video/color"; - media::TrackDescriptor::Config track_config; - track_config.id = hub_track_id; - track_config.source_id = hub_source_id; - track_config.kind = media::MediaKind::VIDEO; - track_config.time_base = {1, 90000}; - auto descriptor = media::makeTrackDescriptor(std::move(track_config)); - auto hub_stop_calls = std::make_shared>(0); - media::MediaSourceManager::SourceCallbacks callbacks; - callbacks.start = []( - const media::MediaSourceManager::FrameSink&, - const media::MediaSourceManager::CancelPredicate&) { - return true; - }; - callbacks.stop_confirmed = [hub_stop_calls] { - hub_stop_calls->fetch_add(1, std::memory_order_relaxed); - return true; - }; - auto& hub = media::globalMediaSourceManager(); - ASSERT_TRUE(hub.registerSource( - descriptor, std::move(callbacks), 2)); - auto subscription = hub.subscribe(hub_track_id); - ASSERT_TRUE(subscription.valid()); - - auto operational_camera = std::make_shared( - "orphan-operational-camera"); - operational_camera->setRecording(false); - ASSERT_EQ( - globalCameraOperationalActivityRegistry().start( - operational_camera->id(), operational_camera), - CameraOperationalActivityRegistry::DispatchResult::Success); - - auto ptz_camera = std::make_shared( - "orphan-ptz-camera"); - ASSERT_EQ( - globalCameraPtzActivityRegistry().control( - ptz_camera->id(), - ptz_camera, - device::PtzCommand::PanLeft, - false, - 3), - CameraPtzActivityRegistry::DispatchResult::Success); - - service_ = std::make_unique(); - api::StopAllCommand_Request request; - api::StopAllCommand_Feedback response; - grpc::ServerContext context; - const auto status = service_->StopAll( - &context, &request, &response); - - ASSERT_TRUE(status.ok()) << status.error_message(); - ASSERT_TRUE(response.header().success()) - << response.header().error_message(); - EXPECT_EQ(hub_stop_calls->load(std::memory_order_relaxed), 1); - EXPECT_FALSE(subscription.valid()); - EXPECT_TRUE(hub.trackedSourceIds().empty()); - EXPECT_EQ(operational_camera->operationalStopCalls(), 1); - EXPECT_FALSE(operational_camera->operationalActive()); - EXPECT_EQ(operational_camera->lifecycleStopCalls(), 0); - EXPECT_EQ(operational_camera->stopRecordingCalls(), 0); - EXPECT_EQ(ptz_camera->ptzCalls(), 2); - EXPECT_FALSE(ptz_camera->ptzActive()); - EXPECT_EQ(ptz_camera->lifecycleStopCalls(), 0); - EXPECT_EQ(ptz_camera->stopRecordingCalls(), 0); -} - -TEST_F(GrpcSystemServiceTest, - StopAllMediaFailuresLeaveActionQueuePaused) -{ - initializeActionDevices(); - auto& manager = device::DeviceManager::getInstance(); - auto camera = std::make_shared( - "camera-remains-recording", false); - auto microphone = std::make_shared( - "microphone-stop-throws", true, true); - auto speaker = std::make_shared( - "speaker-stop-fails", false); - manager.registerDevice(camera); - manager.registerDevice(microphone); - manager.registerDevice(speaker); - - api::StopAllCommand_Request stop_request; - api::StopAllCommand_Feedback stop_response; - grpc::ServerContext stop_context; - const auto stop_status = service_->StopAll( - &stop_context, &stop_request, &stop_response); - - api::ActionQueueCommand_Request action_request; - action_request.set_action_id("action-after-media-stop-failure"); - addMoveLStep( - action_request, "must-not-run", action_arm_->id(), 1.0); - const auto action_response = executeAction(action_request); - - ASSERT_TRUE(stop_status.ok()) << stop_status.error_message(); - EXPECT_FALSE(stop_response.header().success()); - const auto* camera_target = findSafetyTarget( - stop_response, camera->id()); - ASSERT_NE(camera_target, nullptr); - EXPECT_EQ( - camera_target->reason_code(), - api::COMMAND_REASON_CODE_STOP_UNCONFIRMED); - EXPECT_EQ(camera->stopRecordingCalls(), 2); - EXPECT_TRUE(camera->isRecording()); - EXPECT_EQ(microphone->stopRecordingCalls(), 2); - EXPECT_TRUE(microphone->isRecording()); - EXPECT_EQ(speaker->stopPlaybackCalls(), 2); - EXPECT_EQ(camera->lifecycleStopCalls(), 0); - EXPECT_EQ(microphone->lifecycleStopCalls(), 0); - EXPECT_EQ(speaker->lifecycleStopCalls(), 0); - EXPECT_FALSE(action_response.header().success()); - EXPECT_EQ( - action_response.result(), api::ACTION_RESULT_CODE_REJECTED); - EXPECT_NE( - action_response.header().error_message().find( - "temporarily paused by StopAll"), - std::string::npos); - EXPECT_EQ(action_arm_->motionCalls(), 0); -} - -TEST_F(GrpcSystemServiceTest, - ActionQueueCancellationStopsActiveLaterArmBeforeEarlierArm) -{ - config::DeviceManagerConfig config; - auto& manager = device::DeviceManager::getInstance(config); - action_trace_ = std::make_shared(); - auto earlier_arm = std::make_shared( - "earlier-arm", action_trace_); - auto active_arm = std::make_shared( - "active-arm", action_trace_); - manager.registerDevice(earlier_arm); - manager.registerDevice(active_arm); - service_ = std::make_unique(); - api::GetSystemInfoCommand_Request info_request; - api::GetSystemInfoCommand_Feedback info_response; - grpc::ServerContext info_context; - ASSERT_TRUE(service_->GetSystemInfo( - &info_context, &info_request, &info_response).ok()); - service_instance_id_ = info_response.action_service_instance_id(); - ASSERT_FALSE(service_instance_id_.empty()); - - active_arm->blockNextMotion(); - api::ActionQueueCommand_Request request; - request.set_action_id("cancel-active-later-arm-first"); - request.set_total_timeout_ms(1000U); - addMoveLStep(request, "earlier-completes", earlier_arm->id(), 1.0); - addMoveLStep(request, "active-blocks", active_arm->id(), 2.0); - - auto action = std::async( - std::launch::async, - [this, request]() { return executeAction(request); }); - const bool active_started = active_arm->waitForMotionCalls( - 1, std::chrono::milliseconds(500)); - - service_->prepareForShutdown(); - const auto response = action.get(); - - api::ActionQueueCommand_Request rejected_request; - rejected_request.set_action_id("action-after-service-shutdown"); - addMoveLStep( - rejected_request, "must-not-run", earlier_arm->id(), 3.0); - const auto rejected_response = executeAction(rejected_request); - - const auto trace = action_trace_->names(); - const auto active_stop = std::find( - trace.begin(), trace.end(), "arm:stop:active-arm"); - const auto earlier_stop = std::find( - trace.begin(), trace.end(), "arm:stop:earlier-arm"); - - ASSERT_TRUE(active_started); - EXPECT_EQ(response.result(), api::ACTION_RESULT_CODE_CANCELED); - EXPECT_EQ(response.completed_steps(), 1U); - ASSERT_TRUE(response.has_failed_step_index()); - EXPECT_EQ(response.failed_step_index(), 1U); - ASSERT_NE(active_stop, trace.end()); - ASSERT_NE(earlier_stop, trace.end()); - EXPECT_LT(active_stop, earlier_stop); - EXPECT_FALSE(rejected_response.header().success()); - EXPECT_EQ( - rejected_response.result(), api::ACTION_RESULT_CODE_REJECTED); - EXPECT_NE( - rejected_response.header().error_message().find("shutting down"), - std::string::npos); - EXPECT_EQ(earlier_arm->motionCalls(), 1); - EXPECT_EQ(active_arm->motionCalls(), 1); -} - -TEST_F(GrpcSystemServiceTest, - RetriedStopAllReusesTimedOutArmBarrierAndCanRecover) -{ - config::DeviceManagerConfig config; - auto& manager = device::DeviceManager::getInstance(config); - auto trace = std::make_shared(); - auto arm = std::make_shared( - "preempted-handler-arm", trace); - manager.registerDevice(arm); - - auto& authority = control::ControlAuthorityManager::instance(); - const auto old_handler = authority.tryAcquire( - arm->id(), "blocked-control-handler", std::chrono::seconds(30)); - ASSERT_TRUE(old_handler.acquired) << old_handler.detail; - service_ = std::make_unique( - std::chrono::milliseconds(300)); - - api::StopAllCommand_Request request; - auto stop_all = std::async(std::launch::async, [this, &request] { - api::StopAllCommand_Feedback response; - grpc::ServerContext context; - const auto status = service_->StopAll( - &context, &request, &response); - return std::make_pair(status, response); - }); - - const bool initial_stop_completed = arm->waitForStopMotionCalls( - 1, std::chrono::milliseconds(500)); - if (initial_stop_completed) { - arm->blockNextStopMotion(); - } - const auto completion = stop_all.wait_for(std::chrono::seconds(1)); - const bool final_stop_started = initial_stop_completed && - arm->waitForBlockedStopMotion(std::chrono::milliseconds(500)); - - ASSERT_EQ(completion, std::future_status::ready); - const auto [status, response] = stop_all.get(); - const auto stop_calls_before_retry = arm->stopMotionCalls(); - const auto control_while_failed_closed = authority.tryAcquire( - arm->id(), "control-after-timed-out-stop-all", - std::chrono::seconds(30)); - - // Let the deadline-overrunning final typed stop finish before retrying the - // retained barrier. The old control owner is then allowed to drain. - arm->releaseBlockedStopMotion(); - authority.release(old_handler.token); - - auto second_service = std::make_unique( - std::chrono::seconds(1)); - api::StopAllCommand_Feedback second_response; - grpc::ServerContext second_context; - const auto second_status = second_service->StopAll( - &second_context, &request, &second_response); - const auto recovered_control = authority.tryAcquire( - arm->id(), "control-after-retried-stop-all", - std::chrono::seconds(30)); - if (recovered_control.acquired) { - authority.release(recovered_control.token); - } - - EXPECT_TRUE(initial_stop_completed); - EXPECT_TRUE(final_stop_started); - ASSERT_TRUE(status.ok()) << status.error_message(); - EXPECT_FALSE(response.header().success()); - const auto* failed_arm = findSafetyTarget(response, arm->id()); - ASSERT_NE(failed_arm, nullptr); - EXPECT_EQ( - failed_arm->reason_code(), - api::COMMAND_REASON_CODE_PARTICIPANT_TIMEOUT); - ASSERT_TRUE(second_status.ok()) << second_status.error_message(); - EXPECT_TRUE(second_response.header().success()) - << second_response.header().error_message(); - EXPECT_EQ(stop_calls_before_retry, 2); - EXPECT_GE(arm->stopMotionCalls(), 4); - EXPECT_FALSE(control_while_failed_closed.acquired); - EXPECT_TRUE(recovered_control.acquired) << recovered_control.detail; -} - -TEST_F(GrpcSystemServiceTest, - StopAllDoesNotStopDeviceLifecyclesAndRevokesOnlyArmLease) -{ - config::DeviceManagerConfig config; - auto& manager = device::DeviceManager::getInstance(config); - auto trace = std::make_shared(); - auto arm = std::make_shared("leased_arm", trace); - auto camera = std::make_shared("leased_camera"); - auto already_stopping_arm = std::make_shared( - "already_stopping_arm", trace); - manager.registerDevice(arm); - manager.registerDevice(camera); - manager.registerDevice(already_stopping_arm); - - auto& authority = control::ControlAuthorityManager::instance(); - const auto arm_lease = authority.tryAcquire( - arm->id(), "arm-session", std::chrono::seconds(30)); - const auto camera_lease = authority.tryAcquire( - camera->id(), "camera-session", std::chrono::seconds(30)); - const auto existing_stop_barrier = authority.preemptAcquire( - already_stopping_arm->id(), - "existing-stop", - std::chrono::seconds(30)); - ASSERT_TRUE(arm_lease.acquired) << arm_lease.detail; - ASSERT_TRUE(camera_lease.acquired) << camera_lease.detail; - ASSERT_TRUE(existing_stop_barrier.acquired) - << existing_stop_barrier.detail; - ASSERT_TRUE(authority.validate(arm_lease.token)); - ASSERT_TRUE(authority.validate(camera_lease.token)); - - service_ = std::make_unique(); - api::StopAllCommand_Request request; - auto stop_all = std::async(std::launch::async, [this, &request] { - api::StopAllCommand_Feedback response; - grpc::ServerContext context; - const auto status = service_->StopAll( - &context, &request, &response); - return std::make_pair(status, response); - }); - ASSERT_TRUE(arm->waitForStopMotionCalls( - 1, std::chrono::milliseconds(500))); - EXPECT_FALSE(authority.validate(arm_lease.token)); - EXPECT_EQ( - stop_all.wait_for(std::chrono::milliseconds(20)), - std::future_status::timeout); - authority.release(arm_lease.token); - ASSERT_EQ( - stop_all.wait_for(std::chrono::seconds(1)), - std::future_status::ready); - const auto [status, response] = stop_all.get(); - - ASSERT_TRUE(status.ok()) << status.error_message(); - ASSERT_TRUE(response.header().success()) - << response.header().error_message(); - EXPECT_GE(arm->stopMotionCalls(), 2); - EXPECT_EQ(arm->lifecycleStopCalls(), 0); - EXPECT_EQ(arm->shutdownCalls(), 0); - EXPECT_EQ(camera->lifecycleStopCalls(), 0); - EXPECT_EQ(camera->stopRecordingCalls(), 1); - EXPECT_FALSE(camera->isRecording()); - EXPECT_GE(already_stopping_arm->stopMotionCalls(), 2); - EXPECT_EQ(already_stopping_arm->lifecycleStopCalls(), 0); - EXPECT_EQ(already_stopping_arm->shutdownCalls(), 0); - EXPECT_FALSE(authority.validate(arm_lease.token)); - EXPECT_FALSE(authority.isLeased(arm->id())); - EXPECT_TRUE(authority.validate(camera_lease.token)); - EXPECT_TRUE(authority.isLeased(camera->id())); - EXPECT_TRUE(authority.validate(existing_stop_barrier.token)); - EXPECT_TRUE(authority.isLeased(already_stopping_arm->id())); - const auto move_after_stop = authority.tryAcquire( - arm->id(), "move-after-stop", std::chrono::seconds(30)); - EXPECT_TRUE(move_after_stop.acquired) << move_after_stop.detail; - authority.release(move_after_stop.token); - authority.release(existing_stop_barrier.token); -} - -} // namespace -} // namespace cmvr::service diff --git a/cmvr-es/service/grpc/server/tests/media_activity_coordinator_test.cpp b/cmvr-es/service/grpc/server/tests/media_activity_coordinator_test.cpp deleted file mode 100644 index 17ca7db1..00000000 --- a/cmvr-es/service/grpc/server/tests/media_activity_coordinator_test.cpp +++ /dev/null @@ -1,279 +0,0 @@ -#include "service/grpc/server/include/media_activity_coordinator.h" - -#include -#include -#include -#include -#include -#include - -namespace { - -bool check(const bool condition, const char* expression, const int line) -{ - if (condition) { - return true; - } - std::cerr << "CHECK failed at line " << line << ": " << expression << '\n'; - return false; -} - -#define CHECK_TRUE(expression) \ - do { \ - if (!check(static_cast(expression), #expression, __LINE__)) { \ - return 1; \ - } \ - } while (false) - -} // namespace - -int main() -{ - using namespace std::chrono_literals; - - { - cmvr::service::MediaActivityCoordinator dispatch_coordinator; - auto dispatch_session = dispatch_coordinator.beginSession(); - CHECK_TRUE(dispatch_session); - - std::promise dispatch_entered; - auto dispatch_entered_future = dispatch_entered.get_future(); - std::promise release_dispatch; - auto release_dispatch_future = release_dispatch.get_future(); - auto dispatch_future = std::async(std::launch::async, [&] { - return dispatch_session.runIfCurrent([&] { - dispatch_entered.set_value(); - release_dispatch_future.wait(); - }); - }); - dispatch_entered_future.wait(); - - const auto dispatch_ticket = dispatch_coordinator.beginStopAll(); - CHECK_TRUE(dispatch_ticket.valid()); - CHECK_TRUE(!dispatch_coordinator.waitForStopped( - dispatch_ticket, 20ms)); - - release_dispatch.set_value(); - CHECK_TRUE(dispatch_future.get()); - - dispatch_session.reset(); - CHECK_TRUE(dispatch_coordinator.waitForStopped(dispatch_ticket, 100ms)); - CHECK_TRUE(dispatch_coordinator.finishStopAll(dispatch_ticket, true)); - } - - { - cmvr::service::MediaActivityCoordinator generation_coordinator; - auto old_generation_session = generation_coordinator.beginSession(); - CHECK_TRUE(old_generation_session); - - const auto generation_ticket = generation_coordinator.beginStopAll(); - CHECK_TRUE(generation_ticket.valid()); - - std::atomic dispatched_operations{0}; - CHECK_TRUE(!old_generation_session.runIfCurrent( - [&] { ++dispatched_operations; })); - CHECK_TRUE(dispatched_operations.load(std::memory_order_acquire) == 0); - - old_generation_session.reset(); - CHECK_TRUE( - generation_coordinator.waitForStopped(generation_ticket, 100ms)); - CHECK_TRUE(generation_coordinator.finishStopAll(generation_ticket, true)); - - auto current_generation_session = generation_coordinator.beginSession(); - CHECK_TRUE(current_generation_session); - CHECK_TRUE(current_generation_session.runIfCurrent( - [&] { ++dispatched_operations; })); - CHECK_TRUE(dispatched_operations.load(std::memory_order_acquire) == 1); - } - - { - cmvr::service::MediaActivityCoordinator deferred_coordinator; - std::atomic deferred_cancel_calls{0}; - auto deferred_session = deferred_coordinator.beginSession( - [&] { ++deferred_cancel_calls; }); - CHECK_TRUE(deferred_session); - - const auto deferred_ticket = - deferred_coordinator.beginStopAll(true); - CHECK_TRUE(deferred_ticket.valid()); - CHECK_TRUE(deferred_session.cancelled()); - CHECK_TRUE(!deferred_session.runIfCurrent([] {})); - CHECK_TRUE( - deferred_cancel_calls.load(std::memory_order_acquire) == 0); - CHECK_TRUE( - deferred_coordinator.requestCancellation(deferred_ticket)); - CHECK_TRUE( - deferred_cancel_calls.load(std::memory_order_acquire) == 1); - CHECK_TRUE( - deferred_coordinator.requestCancellation(deferred_ticket)); - CHECK_TRUE( - deferred_cancel_calls.load(std::memory_order_acquire) == 1); - - deferred_session.reset(); - CHECK_TRUE( - deferred_coordinator.waitForStopped(deferred_ticket, 100ms)); - CHECK_TRUE( - deferred_coordinator.finishStopAll(deferred_ticket, true)); - CHECK_TRUE( - !deferred_coordinator.requestCancellation(deferred_ticket)); - } - - { - cmvr::service::MediaActivityCoordinator parallel_coordinator; - std::promise blocked_cancel_entered; - auto blocked_cancel_entered_future = - blocked_cancel_entered.get_future(); - std::promise release_blocked_cancel; - auto release_blocked_cancel_future = - release_blocked_cancel.get_future().share(); - std::promise peer_cancel_entered; - auto peer_cancel_entered_future = peer_cancel_entered.get_future(); - std::atomic blocked_cancel_calls{0}; - std::atomic peer_cancel_calls{0}; - - auto blocked_session = parallel_coordinator.beginSession([&] { - ++blocked_cancel_calls; - blocked_cancel_entered.set_value(); - release_blocked_cancel_future.wait(); - }); - auto peer_session = parallel_coordinator.beginSession([&] { - ++peer_cancel_calls; - peer_cancel_entered.set_value(); - }); - CHECK_TRUE(blocked_session && peer_session); - - const auto ticket = parallel_coordinator.beginStopAll(true); - std::vector operations; - std::string collect_error; - CHECK_TRUE(parallel_coordinator.collectCancellationOperations( - ticket, operations, &collect_error)); - CHECK_TRUE(collect_error.empty()); - CHECK_TRUE(operations.size() == 2); - CHECK_TRUE(operations[0].resource_key != operations[1].resource_key); - - auto first = std::async(std::launch::async, operations[0].operation); - auto second = std::async(std::launch::async, operations[1].operation); - CHECK_TRUE(blocked_cancel_entered_future.wait_for(100ms) == - std::future_status::ready); - CHECK_TRUE(peer_cancel_entered_future.wait_for(100ms) == - std::future_status::ready); - release_blocked_cancel.set_value(); - CHECK_TRUE(first.get().success); - CHECK_TRUE(second.get().success); - CHECK_TRUE(operations[0].operation().success); - CHECK_TRUE(operations[1].operation().success); - CHECK_TRUE(blocked_cancel_calls.load() == 1); - CHECK_TRUE(peer_cancel_calls.load() == 1); - - blocked_session.reset(); - peer_session.reset(); - CHECK_TRUE(parallel_coordinator.waitForStopped(ticket, 100ms)); - CHECK_TRUE(parallel_coordinator.finishStopAll(ticket, true)); - CHECK_TRUE(!parallel_coordinator.collectCancellationOperations( - ticket, operations, &collect_error)); - CHECK_TRUE(!collect_error.empty()); - } - - { - cmvr::service::MediaActivityCoordinator exception_coordinator; - std::atomic throwing_cancel_calls{0}; - auto throwing_session = exception_coordinator.beginSession([&] { - ++throwing_cancel_calls; - throw std::runtime_error("cancel failed"); - }); - CHECK_TRUE(throwing_session); - const auto ticket = exception_coordinator.beginStopAll(true); - std::vector operations; - CHECK_TRUE(exception_coordinator.collectCancellationOperations( - ticket, operations)); - CHECK_TRUE(operations.size() == 1); - const auto result = operations[0].operation(); - const auto cached_result = operations[0].operation(); - CHECK_TRUE(!result.success); - CHECK_TRUE(result.detail.find("cancel failed") != std::string::npos); - CHECK_TRUE(cached_result.detail == result.detail); - CHECK_TRUE(throwing_cancel_calls.load() == 1); - throwing_session.reset(); - CHECK_TRUE(exception_coordinator.waitForStopped(ticket, 100ms)); - CHECK_TRUE(!exception_coordinator.finishStopAll(ticket, false)); - } - - { - cmvr::service::DeferredStopOperation detached_operation; - cmvr::service::MediaActivityCoordinator::Session retained_session; - std::atomic detached_cancel_calls{0}; - { - cmvr::service::MediaActivityCoordinator ephemeral_coordinator; - retained_session = ephemeral_coordinator.beginSession( - [&] { ++detached_cancel_calls; }); - const auto ticket = - ephemeral_coordinator.beginStopAll(true); - std::vector operations; - CHECK_TRUE( - ephemeral_coordinator.collectCancellationOperations( - ticket, operations)); - CHECK_TRUE(operations.size() == 1); - detached_operation = std::move(operations[0]); - } - CHECK_TRUE(detached_operation.operation().success); - CHECK_TRUE(detached_cancel_calls.load() == 1); - retained_session.reset(); - } - - cmvr::service::MediaActivityCoordinator coordinator; - std::atomic cancel_calls{0}; - - auto old_session = coordinator.beginSession([&] { ++cancel_calls; }); - CHECK_TRUE(old_session); - CHECK_TRUE(old_session.claimExclusiveResource("speaker:test")); - - auto competing_session = coordinator.beginSession(); - CHECK_TRUE(competing_session); - CHECK_TRUE(!competing_session.claimExclusiveResource("speaker:test")); - competing_session.reset(); - - const auto ticket = coordinator.beginStopAll(); - CHECK_TRUE(ticket.valid()); - CHECK_TRUE(cancel_calls.load(std::memory_order_acquire) == 1); - CHECK_TRUE(old_session.cancelled()); - CHECK_TRUE(!old_session.runIfCurrent([] {})); - CHECK_TRUE(!coordinator.beginSession()); - CHECK_TRUE(!coordinator.waitForStopped(ticket, 5ms)); - - old_session.reset(); - CHECK_TRUE(coordinator.waitForStopped(ticket, 100ms)); - CHECK_TRUE(coordinator.finishStopAll(ticket, true)); - - auto resumed_session = coordinator.beginSession(); - CHECK_TRUE(resumed_session); - CHECK_TRUE(resumed_session.claimExclusiveResource("speaker:test")); - - const auto concurrent_ticket_a = coordinator.beginStopAll(); - const auto concurrent_ticket_b = coordinator.beginStopAll(); - resumed_session.reset(); - CHECK_TRUE(coordinator.waitForStopped(concurrent_ticket_a, 100ms)); - CHECK_TRUE(coordinator.finishStopAll(concurrent_ticket_a, true)); - CHECK_TRUE(!coordinator.beginSession()); - CHECK_TRUE(coordinator.finishStopAll(concurrent_ticket_b, true)); - CHECK_TRUE(coordinator.beginSession()); - - { - cmvr::service::MediaActivityCoordinator detailed_coordinator; - const auto first = detailed_coordinator.beginStopAll(true); - const auto second = detailed_coordinator.beginStopAll(true); - const auto first_result = - detailed_coordinator.finishStopAllDetailed(first, true); - CHECK_TRUE(first_result.ticket_consumed); - CHECK_TRUE(first_result.participant_stopped); - CHECK_TRUE(!first_result.admission_resumed); - const auto second_result = - detailed_coordinator.finishStopAllDetailed(second, true); - CHECK_TRUE(second_result.ticket_consumed); - CHECK_TRUE(second_result.participant_stopped); - CHECK_TRUE(second_result.admission_resumed); - CHECK_TRUE(detailed_coordinator.beginSession()); - } - - std::cout << "media_activity_coordinator_test: PASS\n"; - return 0; -} diff --git a/cmvr-es/service/grpc/server/tests/motor_activity_coordinator_test.cpp b/cmvr-es/service/grpc/server/tests/motor_activity_coordinator_test.cpp deleted file mode 100644 index 35d430f6..00000000 --- a/cmvr-es/service/grpc/server/tests/motor_activity_coordinator_test.cpp +++ /dev/null @@ -1,283 +0,0 @@ -#include "service/grpc/server/include/motor_activity_coordinator.h" - -#include -#include -#include -#include -#include -#include - -namespace { - -bool check(const bool condition, const char* expression, const int line) -{ - if (condition) { - return true; - } - std::cerr << "CHECK failed at line " << line << ": " << expression << '\n'; - return false; -} - -#define CHECK_TRUE(expression) \ - do { \ - if (!check(static_cast(expression), #expression, __LINE__)) { \ - return 1; \ - } \ - } while (false) - -} // namespace - -int main() -{ - using namespace std::chrono_literals; - using cmvr::service::MotorActivityCoordinator; - - MotorActivityCoordinator coordinator; - std::atomic cancel_calls{0}; - std::atomic quick_stop_calls{0}; - std::atomic busy{true}; - - auto registration = coordinator.registerControl( - [&] { ++cancel_calls; }, - [&] { - ++quick_stop_calls; - return true; - }, - [&] { return !busy.load(std::memory_order_acquire); }, - "test motor"); - CHECK_TRUE(registration); - - const auto ticket = coordinator.beginStopAll(); - CHECK_TRUE(ticket.valid()); - CHECK_TRUE(cancel_calls.load(std::memory_order_acquire) == 1); - CHECK_TRUE(!coordinator.lockAdmission().accepting()); - - std::string initial_error; - CHECK_TRUE(coordinator.requestStop(ticket, &initial_error)); - CHECK_TRUE(initial_error.empty()); - CHECK_TRUE(quick_stop_calls.load(std::memory_order_acquire) == 1); - - auto stop_future = std::async(std::launch::async, [&] { - std::string error; - return coordinator.waitForStopped(ticket, 1s, &error); - }); - CHECK_TRUE(stop_future.wait_for(20ms) == std::future_status::timeout); - - busy.store(false, std::memory_order_release); - coordinator.notifyStateChanged(); - CHECK_TRUE(stop_future.get()); - CHECK_TRUE(coordinator.finishStopAll(ticket, true)); - CHECK_TRUE(coordinator.lockAdmission().accepting()); - - std::atomic quick_stops_in_flight{0}; - std::atomic maximum_quick_stops{0}; - auto make_serial_registration = [&](const char* description) { - return coordinator.registerControl( - [] {}, - [&] { - const int active = ++quick_stops_in_flight; - int maximum = maximum_quick_stops.load(); - while (maximum < active && - !maximum_quick_stops.compare_exchange_weak( - maximum, active)) { - } - std::this_thread::sleep_for(5ms); - --quick_stops_in_flight; - return true; - }, - [] { return true; }, - description); - }; - auto serial_a = make_serial_registration("serial motor a"); - auto serial_b = make_serial_registration("serial motor b"); - CHECK_TRUE(serial_a && serial_b); - - const auto serial_ticket = coordinator.beginStopAll(); - CHECK_TRUE(serial_ticket.valid()); - CHECK_TRUE(coordinator.stopAndWait(serial_ticket, 1s)); - CHECK_TRUE(maximum_quick_stops.load(std::memory_order_acquire) == 1); - CHECK_TRUE(coordinator.finishStopAll(serial_ticket, true)); - - { - MotorActivityCoordinator parallel_coordinator; - std::promise blocked_stop_entered; - auto blocked_stop_entered_future = - blocked_stop_entered.get_future(); - std::promise release_blocked_stop; - auto release_blocked_stop_future = - release_blocked_stop.get_future().share(); - std::promise peer_stop_entered; - auto peer_stop_entered_future = peer_stop_entered.get_future(); - std::atomic blocked_cancel_calls{0}; - std::atomic blocked_stop_calls{0}; - std::atomic peer_cancel_calls{0}; - std::atomic peer_stop_calls{0}; - - auto blocked = parallel_coordinator.registerControl( - [&] { ++blocked_cancel_calls; }, - [&] { - if (blocked_cancel_calls.load() != 1) { - return false; - } - ++blocked_stop_calls; - blocked_stop_entered.set_value(); - release_blocked_stop_future.wait(); - return true; - }, - [] { return true; }, - "blocked motor"); - auto peer = parallel_coordinator.registerControl( - [&] { ++peer_cancel_calls; }, - [&] { - if (peer_cancel_calls.load() != 1) { - return false; - } - ++peer_stop_calls; - peer_stop_entered.set_value(); - return true; - }, - [] { return true; }, - "peer motor"); - CHECK_TRUE(blocked && peer); - - const auto parallel_ticket = - parallel_coordinator.beginStopAll(true); - CHECK_TRUE(parallel_ticket.valid()); - CHECK_TRUE(blocked_cancel_calls.load() == 0); - CHECK_TRUE(peer_cancel_calls.load() == 0); - std::vector operations; - std::string collect_error; - CHECK_TRUE(parallel_coordinator.collectStopOperations( - parallel_ticket, operations, &collect_error)); - CHECK_TRUE(collect_error.empty()); - CHECK_TRUE(operations.size() == 2); - CHECK_TRUE(operations[0].resource_key != operations[1].resource_key); - - auto first = std::async(std::launch::async, operations[0].operation); - auto second = std::async(std::launch::async, operations[1].operation); - CHECK_TRUE(blocked_stop_entered_future.wait_for(100ms) == - std::future_status::ready); - CHECK_TRUE(peer_stop_entered_future.wait_for(100ms) == - std::future_status::ready); - release_blocked_stop.set_value(); - CHECK_TRUE(first.get().success); - CHECK_TRUE(second.get().success); - CHECK_TRUE(operations[0].operation().success); - CHECK_TRUE(operations[1].operation().success); - CHECK_TRUE(blocked_cancel_calls.load() == 1); - CHECK_TRUE(blocked_stop_calls.load() == 1); - CHECK_TRUE(peer_cancel_calls.load() == 1); - CHECK_TRUE(peer_stop_calls.load() == 1); - CHECK_TRUE(parallel_coordinator.finishStopAll( - parallel_ticket, true)); - } - - { - MotorActivityCoordinator exception_coordinator; - std::atomic cancel_calls_for_exception{0}; - std::atomic stop_calls_after_exception{0}; - auto throwing = exception_coordinator.registerControl( - [&] { - ++cancel_calls_for_exception; - throw std::runtime_error("cancel failed"); - }, - [&] { - ++stop_calls_after_exception; - throw std::runtime_error("quick-stop failed"); - return false; - }, - [] { return true; }, - "throwing motor"); - CHECK_TRUE(throwing); - const auto exception_ticket = - exception_coordinator.beginStopAll(true); - std::vector operations; - CHECK_TRUE(exception_coordinator.collectStopOperations( - exception_ticket, operations)); - CHECK_TRUE(operations.size() == 1); - const auto first_result = operations[0].operation(); - const auto cached_result = operations[0].operation(); - CHECK_TRUE(!first_result.success); - CHECK_TRUE(first_result.detail.find("cancel failed") != - std::string::npos); - CHECK_TRUE(first_result.detail.find("quick-stop failed") != - std::string::npos); - CHECK_TRUE(cached_result.detail == first_result.detail); - CHECK_TRUE(cancel_calls_for_exception.load() == 1); - CHECK_TRUE(stop_calls_after_exception.load() == 1); - CHECK_TRUE(!exception_coordinator.finishStopAll( - exception_ticket, false)); - } - - { - cmvr::service::DeferredStopOperation detached_operation; - MotorActivityCoordinator::Registration retained_registration; - std::atomic detached_cancel_calls{0}; - std::atomic detached_stop_calls{0}; - { - MotorActivityCoordinator ephemeral_coordinator; - retained_registration = ephemeral_coordinator.registerControl( - [&] { ++detached_cancel_calls; }, - [&] { - ++detached_stop_calls; - return true; - }, - [] { return true; }, - "detached motor"); - const auto ticket = - ephemeral_coordinator.beginStopAll(true); - std::vector operations; - CHECK_TRUE(ephemeral_coordinator.collectStopOperations( - ticket, operations)); - CHECK_TRUE(operations.size() == 1); - detached_operation = std::move(operations[0]); - } - CHECK_TRUE(detached_operation.operation().success); - CHECK_TRUE(detached_cancel_calls.load() == 1); - CHECK_TRUE(detached_stop_calls.load() == 1); - retained_registration.reset(); - } - - std::atomic stop_succeeds{false}; - auto failing = coordinator.registerControl( - [] {}, - [&] { return stop_succeeds.load(std::memory_order_acquire); }, - [] { return true; }, - "failing motor"); - CHECK_TRUE(failing); - - const auto failed_ticket = coordinator.beginStopAll(); - CHECK_TRUE(failed_ticket.valid()); - std::string error; - CHECK_TRUE(!coordinator.stopAndWait(failed_ticket, 100ms, &error)); - CHECK_TRUE(!error.empty()); - CHECK_TRUE(!coordinator.finishStopAll(failed_ticket, false)); - CHECK_TRUE(!coordinator.lockAdmission().accepting()); - - stop_succeeds.store(true, std::memory_order_release); - const auto recovery_ticket = coordinator.beginStopAll(); - CHECK_TRUE(recovery_ticket.valid()); - CHECK_TRUE(coordinator.stopAndWait(recovery_ticket, 1s, &error)); - CHECK_TRUE(coordinator.finishStopAll(recovery_ticket, true)); - CHECK_TRUE(coordinator.lockAdmission().accepting()); - - { - MotorActivityCoordinator detailed_coordinator; - const auto first = detailed_coordinator.beginStopAll(true); - const auto second = detailed_coordinator.beginStopAll(true); - const auto first_result = - detailed_coordinator.finishStopAllDetailed(first, true); - CHECK_TRUE(first_result.ticket_consumed); - CHECK_TRUE(first_result.participant_stopped); - CHECK_TRUE(!first_result.admission_resumed); - const auto second_result = - detailed_coordinator.finishStopAllDetailed(second, true); - CHECK_TRUE(second_result.ticket_consumed); - CHECK_TRUE(second_result.participant_stopped); - CHECK_TRUE(second_result.admission_resumed); - CHECK_TRUE(detailed_coordinator.lockAdmission().accepting()); - } - - std::cout << "motor_activity_coordinator_test: PASS\n"; - return 0; -} diff --git a/cmvr-es/service/grpc/stop_all/tests/stop_all_admission_gate_test.cpp b/cmvr-es/service/grpc/stop_all/tests/stop_all_admission_gate_test.cpp deleted file mode 100644 index 21990915..00000000 --- a/cmvr-es/service/grpc/stop_all/tests/stop_all_admission_gate_test.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include "service/grpc/stop_all/include/stop_all_admission_gate.h" - -#include - -namespace cmvr::service { -namespace { - -TEST(StopAllAdmissionGateTest, SuccessfulRoundReopensAdmission) -{ - StopAllAdmissionGate gate; - { - const auto before = gate.lockAdmission(); - EXPECT_TRUE(before.accepting()); - } - - const auto ticket = gate.beginStopAll(); - ASSERT_TRUE(ticket.valid()); - { - const auto blocked = gate.lockAdmission(); - EXPECT_FALSE(blocked.accepting()); - EXPECT_EQ(blocked.generation(), ticket.generation); - } - EXPECT_TRUE(gate.finishStopAll(ticket, true)); - EXPECT_TRUE(gate.lockAdmission().accepting()); -} - -TEST(StopAllAdmissionGateTest, FailedRoundStaysClosedAndCanBeRecovered) -{ - StopAllAdmissionGate gate; - const auto failed_ticket = gate.beginStopAll(); - ASSERT_TRUE(failed_ticket.valid()); - EXPECT_FALSE(gate.finishStopAll(failed_ticket, false)); - EXPECT_FALSE(gate.lockAdmission().accepting()); - - const auto recovery_ticket = gate.beginStopAll(); - ASSERT_TRUE(recovery_ticket.valid()); - EXPECT_TRUE(gate.finishStopAll(recovery_ticket, true)); - EXPECT_TRUE(gate.lockAdmission().accepting()); -} - -TEST(StopAllAdmissionGateTest, EveryConcurrentParticipantMustSucceed) -{ - StopAllAdmissionGate gate; - const auto first = gate.beginStopAll(); - const auto second = gate.beginStopAll(); - ASSERT_TRUE(first.valid()); - ASSERT_TRUE(second.valid()); - - EXPECT_TRUE(gate.finishStopAll(first, true)); - EXPECT_FALSE(gate.lockAdmission().accepting()); - EXPECT_FALSE(gate.finishStopAll(second, false)); - EXPECT_FALSE(gate.lockAdmission().accepting()); -} - -TEST(StopAllAdmissionGateTest, - DetailedFinishDoesNotReportRecoveryAfterAnotherParticipantFailed) -{ - StopAllAdmissionGate gate; - const auto system_ticket = gate.beginStopAll(); - const auto failed_participant = gate.beginStopAll(); - - const auto failed_result = - gate.finishStopAllDetailed(failed_participant, false); - EXPECT_TRUE(failed_result.ticket_consumed); - EXPECT_FALSE(failed_result.admission_reopened); - - const auto system_result = - gate.finishStopAllDetailed(system_ticket, true); - EXPECT_TRUE(system_result.ticket_consumed); - EXPECT_FALSE(system_result.admission_reopened); - EXPECT_FALSE(gate.lockAdmission().accepting()); -} - -TEST(StopAllAdmissionGateTest, - DetailedFinishSeparatesConsumptionFromOutstandingParticipants) -{ - StopAllAdmissionGate gate; - const auto first = gate.beginStopAll(); - const auto second = gate.beginStopAll(); - - const auto first_result = gate.finishStopAllDetailed(first, true); - EXPECT_TRUE(first_result.ticket_consumed); - EXPECT_FALSE(first_result.admission_reopened); - - const auto second_result = gate.finishStopAllDetailed(second, true); - EXPECT_TRUE(second_result.ticket_consumed); - EXPECT_TRUE(second_result.admission_reopened); - EXPECT_TRUE(gate.lockAdmission().accepting()); -} - -TEST(StopAllAdmissionGateTest, TestClearInvalidatesOutstandingTickets) -{ - StopAllAdmissionGate gate; - const auto stale = gate.beginStopAll(); - ASSERT_TRUE(stale.valid()); - - gate.clearForTesting(); - - EXPECT_TRUE(gate.lockAdmission().accepting()); - EXPECT_FALSE(gate.finishStopAll(stale, true)); -} - -} // namespace -} // namespace cmvr::service diff --git a/cmvr-es/service/grpc/stop_all/tests/stop_operation_dispatcher_test.cpp b/cmvr-es/service/grpc/stop_all/tests/stop_operation_dispatcher_test.cpp deleted file mode 100644 index 562cd05b..00000000 --- a/cmvr-es/service/grpc/stop_all/tests/stop_operation_dispatcher_test.cpp +++ /dev/null @@ -1,399 +0,0 @@ -#include "service/grpc/stop_all/include/stop_operation_dispatcher.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace cmvr::service { -namespace { - -using namespace std::chrono_literals; - -TEST(StopOperationDispatcherTest, RejectsEmptyKeysAndOperations) -{ - StopOperationDispatcher dispatcher; - StopOperationDispatcher::Operation empty_operation; - - const auto empty_key = dispatcher.submit("", [] { - return StopOperationDispatcher::OperationResult{true, {}}; - }); - const auto empty_callback = dispatcher.submit( - "arm:one", std::move(empty_operation)); - - EXPECT_FALSE(empty_key.valid()); - EXPECT_FALSE(empty_callback.valid()); - const auto invalid_result = empty_key.waitUntil( - StopOperationDispatcher::Clock::now()); - EXPECT_FALSE(invalid_result.completed); - EXPECT_FALSE(invalid_result.result); - EXPECT_FALSE(invalid_result.detail.empty()); -} - -TEST(StopOperationDispatcherTest, ReturnsOperationOutcome) -{ - StopOperationDispatcher dispatcher; - const auto handle = dispatcher.submit("arm:one", [] { - return StopOperationDispatcher::OperationResult{ - false, "driver did not confirm idle"}; - }); - - ASSERT_TRUE(handle.valid()); - const auto result = handle.waitUntil( - StopOperationDispatcher::Clock::now() + 1s); - EXPECT_TRUE(result.completed); - EXPECT_FALSE(result.result); - EXPECT_EQ(result.detail, "driver did not confirm idle"); -} - -TEST(StopOperationDispatcherTest, TimeoutDoesNotCancelTheJob) -{ - StopOperationDispatcher dispatcher; - std::promise release; - auto released = release.get_future().share(); - const auto handle = dispatcher.submit("agv:one", [released] { - released.wait(); - return StopOperationDispatcher::OperationResult{true, "stopped"}; - }); - - const auto timed_out = handle.waitUntil( - StopOperationDispatcher::Clock::now() + 20ms); - EXPECT_FALSE(timed_out.completed); - EXPECT_FALSE(timed_out.result); - - release.set_value(); - const auto completed = handle.waitUntil( - StopOperationDispatcher::Clock::now() + 1s); - EXPECT_TRUE(completed.completed); - EXPECT_TRUE(completed.result); - EXPECT_EQ(completed.detail, "stopped"); -} - -TEST(StopOperationDispatcherTest, - RunningJobKeepsItsOriginalTimeoutDetailProvider) -{ - StopOperationDispatcher dispatcher; - std::promise release; - auto released = release.get_future().share(); - std::atomic first_operation_calls{0}; - std::atomic duplicate_operation_calls{0}; - std::atomic first_provider_calls{0}; - std::atomic duplicate_provider_calls{0}; - - const auto first = dispatcher.submit( - "arm:one", - [&] { - ++first_operation_calls; - released.wait(); - return StopOperationDispatcher::OperationResult{true, {}}; - }, - [&] { - ++first_provider_calls; - return std::string("first job is waiting for its handler"); - }); - const auto duplicate = dispatcher.submit( - "arm:one", - [&] { - ++duplicate_operation_calls; - return StopOperationDispatcher::OperationResult{true, {}}; - }, - [&] { - ++duplicate_provider_calls; - return std::string("duplicate submission detail"); - }); - - const auto first_timeout = first.waitUntil( - StopOperationDispatcher::Clock::now() + 20ms); - const auto duplicate_timeout = duplicate.waitUntil( - StopOperationDispatcher::Clock::now() + 20ms); - release.set_value(); - const auto completed = first.waitUntil( - StopOperationDispatcher::Clock::now() + 1s); - - EXPECT_FALSE(first_timeout.completed); - EXPECT_EQ( - first_timeout.detail, "first job is waiting for its handler"); - EXPECT_FALSE(duplicate_timeout.completed); - EXPECT_EQ( - duplicate_timeout.detail, "first job is waiting for its handler"); - EXPECT_TRUE(completed.completed); - EXPECT_TRUE(completed.result); - EXPECT_EQ(first_operation_calls.load(), 1); - EXPECT_EQ(duplicate_operation_calls.load(), 0); - EXPECT_EQ(first_provider_calls.load(), 2); - EXPECT_EQ(duplicate_provider_calls.load(), 0); -} - -TEST(StopOperationDispatcherTest, - ThrowingTimeoutDetailProviderFallsBackToGenericDetail) -{ - StopOperationDispatcher dispatcher; - std::promise release; - auto released = release.get_future().share(); - const auto handle = dispatcher.submit( - "arm:one", - [released] { - released.wait(); - return StopOperationDispatcher::OperationResult{true, {}}; - }, - []() -> std::string { - throw std::runtime_error("diagnostic provider failed"); - }); - - const auto timed_out = handle.waitUntil( - StopOperationDispatcher::Clock::now() + 20ms); - release.set_value(); - - EXPECT_FALSE(timed_out.completed); - EXPECT_FALSE(timed_out.result); - EXPECT_EQ( - timed_out.detail, - "stop operation did not complete before the deadline"); -} - -TEST(StopOperationDispatcherTest, RunningSubmissionsForAKeyShareOneJob) -{ - StopOperationDispatcher dispatcher; - std::promise started; - std::promise release; - auto released = release.get_future().share(); - std::atomic first_calls{0}; - std::atomic duplicate_calls{0}; - - const auto first = dispatcher.submit("arm:one", [&] { - ++first_calls; - started.set_value(); - released.wait(); - return StopOperationDispatcher::OperationResult{true, "first"}; - }); - ASSERT_EQ(started.get_future().wait_for(1s), std::future_status::ready); - - const auto duplicate = dispatcher.submit("arm:one", [&] { - ++duplicate_calls; - return StopOperationDispatcher::OperationResult{false, "duplicate"}; - }); - release.set_value(); - - const auto first_result = first.waitUntil( - StopOperationDispatcher::Clock::now() + 1s); - const auto duplicate_result = duplicate.waitUntil( - StopOperationDispatcher::Clock::now() + 1s); - EXPECT_TRUE(first_result.completed); - EXPECT_TRUE(first_result.result); - EXPECT_EQ(first_result.detail, "first"); - EXPECT_TRUE(duplicate_result.completed); - EXPECT_TRUE(duplicate_result.result); - EXPECT_EQ(duplicate_result.detail, "first"); - EXPECT_EQ(first_calls.load(), 1); - EXPECT_EQ(duplicate_calls.load(), 0); -} - -TEST(StopOperationDispatcherTest, ConcurrentSubmissionsForAKeyShareOneJob) -{ - StopOperationDispatcher dispatcher; - constexpr int submitter_count = 12; - std::promise release; - auto released = release.get_future().share(); - std::atomic operation_calls{0}; - std::mutex handles_mutex; - std::vector handles; - std::vector submitters; - handles.reserve(submitter_count); - submitters.reserve(submitter_count); - - for (int index = 0; index < submitter_count; ++index) { - submitters.emplace_back([&] { - auto handle = dispatcher.submit("dexhand:one", [&] { - ++operation_calls; - released.wait(); - return StopOperationDispatcher::OperationResult{true, {}}; - }); - std::lock_guard lock(handles_mutex); - handles.emplace_back(std::move(handle)); - }); - } - for (auto& submitter : submitters) { - submitter.join(); - } - release.set_value(); - - ASSERT_EQ(handles.size(), static_cast(submitter_count)); - const auto deadline = StopOperationDispatcher::Clock::now() + 1s; - for (const auto& handle : handles) { - const auto result = handle.waitUntil(deadline); - EXPECT_TRUE(result.completed); - EXPECT_TRUE(result.result); - } - EXPECT_EQ(operation_calls.load(), 1); -} - -TEST(StopOperationDispatcherTest, CompletedJobIsReapedBeforeNextSubmission) -{ - StopOperationDispatcher dispatcher; - std::atomic calls{0}; - - const auto first = dispatcher.submit("arm:one", [&] { - ++calls; - return StopOperationDispatcher::OperationResult{true, "round one"}; - }); - const auto first_result = first.waitUntil( - StopOperationDispatcher::Clock::now() + 1s); - ASSERT_TRUE(first_result.completed); - ASSERT_TRUE(first_result.result); - - const auto second = dispatcher.submit("arm:one", [&] { - ++calls; - return StopOperationDispatcher::OperationResult{true, "round two"}; - }); - const auto second_result = second.waitUntil( - StopOperationDispatcher::Clock::now() + 1s); - - EXPECT_TRUE(second_result.completed); - EXPECT_TRUE(second_result.result); - EXPECT_EQ(second_result.detail, "round two"); - EXPECT_EQ(calls.load(), 2); - EXPECT_EQ(first.waitUntil( - StopOperationDispatcher::Clock::now()).detail, "round one"); -} - -TEST(StopOperationDispatcherTest, SubmissionReapsAllCompletedJobs) -{ - StopOperationDispatcher dispatcher; - constexpr int completed_job_count = 24; - std::promise release; - auto released = release.get_future().share(); - std::vector handles; - handles.reserve(completed_job_count); - - for (int index = 0; index < completed_job_count; ++index) { - handles.emplace_back(dispatcher.submit( - "arm:" + std::to_string(index), [released] { - released.wait(); - return StopOperationDispatcher::OperationResult{true, {}}; - })); - } - ASSERT_EQ(dispatcher.jobCountForTesting(), - static_cast(completed_job_count)); - - release.set_value(); - const auto deadline = StopOperationDispatcher::Clock::now() + 1s; - for (const auto& handle : handles) { - ASSERT_TRUE(handle.waitUntil(deadline).completed); - } - ASSERT_EQ(dispatcher.jobCountForTesting(), - static_cast(completed_job_count)); - - std::promise trigger_started; - std::promise release_trigger; - auto trigger_released = release_trigger.get_future().share(); - const auto trigger = dispatcher.submit( - "agv:cleanup-trigger", [&] { - trigger_started.set_value(); - trigger_released.wait(); - return StopOperationDispatcher::OperationResult{true, {}}; - }); - - ASSERT_EQ(trigger_started.get_future().wait_for(1s), - std::future_status::ready); - EXPECT_EQ(dispatcher.jobCountForTesting(), 1U); - - release_trigger.set_value(); - EXPECT_TRUE(trigger.waitUntil( - StopOperationDispatcher::Clock::now() + 1s).result); -} - -TEST(StopOperationDispatcherTest, DifferentKeysRunIndependently) -{ - StopOperationDispatcher dispatcher; - std::promise release_first; - auto first_released = release_first.get_future().share(); - std::promise second_started; - - const auto first = dispatcher.submit("camera:one", [first_released] { - first_released.wait(); - return StopOperationDispatcher::OperationResult{true, {}}; - }); - const auto second = dispatcher.submit("speaker:one", [&] { - second_started.set_value(); - return StopOperationDispatcher::OperationResult{true, {}}; - }); - - EXPECT_EQ( - second_started.get_future().wait_for(1s), - std::future_status::ready); - const auto second_result = second.waitUntil( - StopOperationDispatcher::Clock::now() + 1s); - EXPECT_TRUE(second_result.completed); - EXPECT_TRUE(second_result.result); - - release_first.set_value(); - EXPECT_TRUE(first.waitUntil( - StopOperationDispatcher::Clock::now() + 1s).result); -} - -TEST(StopOperationDispatcherTest, ConvertsOperationExceptionsToFailures) -{ - StopOperationDispatcher dispatcher; - const auto standard = dispatcher.submit("arm:one", []() - -> StopOperationDispatcher::OperationResult { - throw std::runtime_error("transport failed"); - }); - const auto unknown = dispatcher.submit("agv:one", []() - -> StopOperationDispatcher::OperationResult { - throw 42; - }); - - const auto deadline = StopOperationDispatcher::Clock::now() + 1s; - const auto standard_result = standard.waitUntil(deadline); - const auto unknown_result = unknown.waitUntil(deadline); - EXPECT_TRUE(standard_result.completed); - EXPECT_FALSE(standard_result.result); - EXPECT_NE(standard_result.detail.find("transport failed"), - std::string::npos); - EXPECT_TRUE(unknown_result.completed); - EXPECT_FALSE(unknown_result.result); - EXPECT_NE(unknown_result.detail.find("unknown exception"), - std::string::npos); -} - -TEST(StopOperationDispatcherTest, - DestructorWaitsForOutstandingWorkers) -{ - auto dispatcher = std::make_unique(); - std::promise started; - std::promise release; - auto released = release.get_future().share(); - const auto handle = dispatcher->submit("arm:one", [&] { - started.set_value(); - released.wait(); - return StopOperationDispatcher::OperationResult{ - true, "completed after dispatcher destruction"}; - }); - ASSERT_EQ(started.get_future().wait_for(1s), std::future_status::ready); - - auto destroy = std::async(std::launch::async, [&] { - dispatcher.reset(); - }); - EXPECT_EQ(destroy.wait_for(20ms), std::future_status::timeout); - - release.set_value(); - EXPECT_EQ(destroy.wait_for(1s), std::future_status::ready); - destroy.get(); - const auto result = handle.waitUntil( - StopOperationDispatcher::Clock::now() + 1s); - EXPECT_TRUE(result.completed); - EXPECT_TRUE(result.result); - EXPECT_EQ(result.detail, "completed after dispatcher destruction"); -} - -} // namespace -} // namespace cmvr::service diff --git a/cmvr-es/task/CMakeLists.txt b/cmvr-es/task/CMakeLists.txt index 05d0896d..deeb62fd 100644 --- a/cmvr-es/task/CMakeLists.txt +++ b/cmvr-es/task/CMakeLists.txt @@ -22,34 +22,6 @@ target_link_libraries(task add_library(cmvr_es::task ALIAS task) install(TARGETS task LIBRARY DESTINATION lib) -if(BUILD_TESTING) - add_executable(touch_screen_admission_test - touch_screen_task/src/touch_screen_admission_test.cpp - ) - target_link_libraries(touch_screen_admission_test PRIVATE - cmvr_es::task - cmvr_es::device_manager - cmvr_es::stop_all_admission_gate - cmvr_es::camera_operational_activity_registry - gtest - gtest_main - pthread - ) - add_test( - NAME touch_screen_admission_test - COMMAND touch_screen_admission_test - ) - set(_touch_screen_admission_test_environment - "LD_LIBRARY_PATH=${CMVR_TEST_EXTERNAL_LIBRARY_PATH}") - if(CMVR_TEST_SYSTEM_LIBSTDCXX) - list(APPEND _touch_screen_admission_test_environment - "LD_PRELOAD=${CMVR_TEST_SYSTEM_LIBSTDCXX}") - endif() - set_tests_properties(touch_screen_admission_test PROPERTIES - TIMEOUT 10 - ENVIRONMENT "${_touch_screen_admission_test_environment}") -endif() - #add_executable(touch_screen_task_test # touch_screen_task/src/touch_screen_task_test.cpp #) diff --git a/cmvr-es/task/touch_screen_task/src/touch_screen_admission_test.cpp b/cmvr-es/task/touch_screen_task/src/touch_screen_admission_test.cpp deleted file mode 100644 index f02cd579..00000000 --- a/cmvr-es/task/touch_screen_task/src/touch_screen_admission_test.cpp +++ /dev/null @@ -1,559 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "manager/device_manager/include/device_manager.h" -#include "service/grpc/server/include/camera_operational_activity_registry.h" -#include "service/grpc/stop_all/include/stop_all_admission_gate.h" -#include "task/touch_screen_task/include/touch_screen_task.h" - -namespace cmvr::task { - -class TouchScreenTaskAdmissionTestPeer final { -public: - static void prepare( - TouchScreenTask& task, - const std::shared_ptr& arm, - const std::shared_ptr& camera) - { - std::lock_guard lock(task.mutex_); - task.arm_ = arm; - { - std::lock_guard arm_lock(task.activity_arm_mutex_); - task.activity_arm_ = arm; - } - task.camera_ = camera; - task.initialized_ = true; - task.phase_ = TouchScreenTask::Phase::IDLE; - task.last_status_ = TouchScreenTask::Status::IDLE; - } - - static void prepareInit( - TouchScreenTask& task, - const std::string& arm_id, - const std::string& dexhand_id, - const std::string& camera_id) - { - std::lock_guard lock(task.mutex_); - task.config_valid_ = true; - auto* devices = task.config_.mutable_devices(); - devices->set_arm_id(arm_id); - devices->set_dexhand_id(dexhand_id); - devices->set_camera_id(camera_id); - task.initialized_ = false; - task.phase_ = TouchScreenTask::Phase::IDLE; - task.last_status_ = TouchScreenTask::Status::NOT_INITIALIZED; - } - - static bool sendJointVelocity(TouchScreenTask& task) - { - std::lock_guard lock(task.mutex_); - return task.sendJointVelocity({}); - } -}; - -} // namespace cmvr::task - -namespace { - -class AdmissionRobotArm final : public cmvr::device::RobotArm { -public: - AdmissionRobotArm() { id_ = "touch-admission-arm"; } - - std::string typeName() const override { return "AdmissionRobotArm"; } - cmvr::device::RobotModel getRobotModel() const override { return {}; } - std::size_t getDof() const override { return 0U; } - cmvr::device::ArmState getRobotState() const override { return {}; } - cmvr::device::JointGroupState getJointState() const override { return {}; } - cmvr::device::CartesianPose getTcpPose( - cmvr::device::FrameType = cmvr::device::FrameType::Base) const override - { - return {}; - } - cmvr::device::RobotMode getRobotMode() const override - { - return cmvr::device::RobotMode::Idle; - } - cmvr::device::SafetyMode getSafetyMode() const override - { - return cmvr::device::SafetyMode::Normal; - } - cmvr::device::ControlMode getControlMode() const override - { - return cmvr::device::ControlMode::None; - } - cmvr::device::Result torqueOn() override { return success(); } - cmvr::device::Result torqueOff() override { return success(); } - cmvr::device::Result calibrateZeroQ(const std::string&) override - { - return success(); - } - cmvr::device::Result emergencyStop() override { return success(); } - cmvr::device::Result protectiveStop() override { return success(); } - cmvr::device::Result setSpeedScaling(double) override { return success(); } - double getSpeedScaling() const override { return 1.0; } - bool isProtectiveStopped() const override { return false; } - bool isEmergencyStopped() const override { return false; } - bool isFault() const override { return false; } - cmvr::device::Result moveJ( - const cmvr::device::JointPositionCommand&, - const cmvr::device::MotionOptions&) override - { - return success(); - } - cmvr::device::Result speedJ( - const cmvr::device::JointVelocityCommand&, double, double) override - { - ++speed_j_calls_; - return success(); - } - cmvr::device::Result stopJ(double) override { return success(); } - cmvr::device::Result moveL( - const cmvr::device::CartesianPose&, - const cmvr::device::MotionOptions&, - cmvr::device::FrameType = cmvr::device::FrameType::Base) override - { - return success(); - } - cmvr::device::Result speedL( - const cmvr::device::CartesianVelocity&, - double, - double, - cmvr::device::FrameType = cmvr::device::FrameType::Base) override - { - return success(); - } - cmvr::device::Result stopL(std::optional = std::nullopt) override - { - return success(); - } - cmvr::device::Result stopMotion() override - { - ++stop_motion_calls_; - return success(); - } - cmvr::device::Result startServoMode( - const cmvr::device::ServoOptions&) override - { - return success(); - } - cmvr::device::Result servoJ( - const cmvr::device::JointPositionCommand&) override - { - return success(); - } - cmvr::device::Result servoL( - const cmvr::device::CartesianPose&, - cmvr::device::FrameType = cmvr::device::FrameType::Base) override - { - return success(); - } - cmvr::device::Result servoSpeedJ( - const cmvr::device::JointVelocityCommand&) override - { - return success(); - } - cmvr::device::Result servoSpeedL( - const cmvr::device::CartesianVelocity&, - cmvr::device::FrameType = cmvr::device::FrameType::Base) override - { - return success(); - } - cmvr::device::Result stopServoMode() override { return success(); } - cmvr::device::Result connect(const std::string&, int) override - { - return success(); - } - cmvr::device::Result disconnect() override { return success(); } - bool isConnected() const override { return true; } - cmvr::device::Result powerOn() override { return success(); } - cmvr::device::Result powerOff() override { return success(); } - cmvr::device::Result brakeRelease() override { return success(); } - cmvr::device::Result shutdown() override { return success(); } - cmvr::device::Result clearFault() override { return success(); } - cmvr::device::Result unlockProtectiveStop() override { return success(); } - cmvr::device::Result loadProgram(const std::string&) override - { - return success(); - } - cmvr::device::Result playProgram() override { return success(); } - cmvr::device::Result pauseProgram() override { return success(); } - cmvr::device::Result stopProgram() override { return success(); } - std::vector ik( - const std::string&, - const std::string&, - const cmvr::device::CartesianPose&) override - { - return {}; - } - std::shared_ptr kinematicsSolver() const override - { - return nullptr; - } - cmvr::device::CartesianPose fk( - const std::string&, const std::string&) override - { - return {}; - } - cmvr::device::CartesianPose fk(bool = true) override { return {}; } - cmvr::device::CartesianVelocity getSpeedLCommandTwistBase() const override - { - return {}; - } - bool busy() const override { return false; } - - int speedJCalls() const noexcept { return speed_j_calls_.load(); } - int stopMotionCalls() const noexcept - { - return stop_motion_calls_.load(); - } - -private: - static cmvr::device::Result success() - { - return cmvr::device::Result::success(); - } - - std::atomic speed_j_calls_{0}; - std::atomic stop_motion_calls_{0}; -}; - -class AdmissionCamera final : public cmvr::device::AbstractCamera { -public: - explicit AdmissionCamera(std::string id) - { - id_ = std::move(id); - state_.is_initialized = true; - } - - std::string typeName() const override { return "AdmissionCamera"; } - - void getState(cmvr::device::CameraState& state) override - { - std::lock_guard lock(mutex_); - state = state_; - } - - bool start() override - { - ++lifecycle_start_calls_; - return true; - } - - bool stop() override - { - ++lifecycle_stop_calls_; - std::lock_guard lock(mutex_); - operational_active_ = false; - state_.is_opened = false; - return true; - } - - bool startOperationalActivity() override - { - ++operational_start_calls_; - std::unique_lock lock(mutex_); - start_entered_ = true; - condition_.notify_all(); - condition_.wait(lock, [this] { return !block_start_; }); - operational_active_ = true; - state_.is_opened = true; - return true; - } - - bool stopOperationalActivity() override - { - ++operational_stop_calls_; - std::lock_guard lock(mutex_); - operational_active_ = false; - state_.is_opened = false; - return true; - } - - void blockStart() - { - std::lock_guard lock(mutex_); - block_start_ = true; - start_entered_ = false; - } - - void waitForStartEntered() - { - std::unique_lock lock(mutex_); - condition_.wait(lock, [this] { return start_entered_; }); - } - - void releaseStart() - { - { - std::lock_guard lock(mutex_); - block_start_ = false; - } - condition_.notify_all(); - } - - bool operationalActive() const - { - std::lock_guard lock(mutex_); - return operational_active_; - } - - int lifecycleStartCalls() const { return lifecycle_start_calls_; } - int lifecycleStopCalls() const { return lifecycle_stop_calls_; } - int operationalStartCalls() const { return operational_start_calls_; } - int operationalStopCalls() const { return operational_stop_calls_; } - -private: - mutable std::mutex mutex_; - std::condition_variable condition_; - bool block_start_{false}; - bool start_entered_{false}; - bool operational_active_{false}; - std::atomic lifecycle_start_calls_{0}; - std::atomic lifecycle_stop_calls_{0}; - std::atomic operational_start_calls_{0}; - std::atomic operational_stop_calls_{0}; -}; - -class TouchScreenAdmissionTest : public ::testing::Test { -protected: - void SetUp() override - { - cmvr::service::globalCameraOperationalActivityRegistry() - .clearForTesting(); - cmvr::device::DeviceManager::destroyInstance(); - cmvr::service::globalStopAllAdmissionGate().clearForTesting(); - cmvr::control::ControlAuthorityManager::instance().clear(); - } - - void TearDown() override - { - cmvr::service::globalCameraOperationalActivityRegistry() - .clearForTesting(); - cmvr::device::DeviceManager::destroyInstance(); - cmvr::service::globalStopAllAdmissionGate().clearForTesting(); - cmvr::control::ControlAuthorityManager::instance().clear(); - } -}; - -TEST_F(TouchScreenAdmissionTest, - DirectTouchAndStartFromPixelHonorFailClosedAdmissionAndRecovery) -{ - auto arm = std::make_shared(); - auto camera = std::make_shared( - "touch-admission-camera"); - cmvr::task::TouchScreenTask task(cmvr::config::TouchScreenTaskConfig{}); - cmvr::task::TouchScreenTaskAdmissionTestPeer::prepare( - task, arm, camera); - auto& gate = cmvr::service::globalStopAllAdmissionGate(); - - auto ticket = gate.beginStopAll(); - EXPECT_FALSE(task.touch(10, 20)); - EXPECT_FALSE(task.startFromPixel(10, 20)); - EXPECT_FALSE(task.isBusy()); - - EXPECT_TRUE(gate.finishStopAll(ticket, true)); - ASSERT_TRUE(task.touch(10, 20)); - EXPECT_TRUE(task.isBusy()); - EXPECT_TRUE(task.stopActivity()); - - ticket = gate.beginStopAll(); - EXPECT_FALSE(gate.finishStopAll(ticket, false)); - EXPECT_FALSE(task.touch(10, 20)); - EXPECT_FALSE(task.startFromPixel(10, 20)); - - ticket = gate.beginStopAll(); - EXPECT_TRUE(gate.finishStopAll(ticket, true)); - EXPECT_TRUE(task.startFromPixel(30, 40)); - EXPECT_TRUE(task.stopActivity()); -} - -TEST_F(TouchScreenAdmissionTest, - SafetyHooksFenceEveryArmActuation) -{ - auto arm = std::make_shared(); - auto camera = std::make_shared( - "touch-safety-hooks-camera"); - cmvr::task::TouchScreenTask task(cmvr::config::TouchScreenTaskConfig{}); - cmvr::task::TouchScreenTaskAdmissionTestPeer::prepare( - task, arm, camera); - - bool admitted = true; - int revalidations = 0; - int dispatches = 0; - cmvr::task::TouchScreenTask::SafetyHooks hooks; - hooks.revalidate = [&] { - ++revalidations; - return admitted; - }; - hooks.dispatch_actuation = [&](const auto& operation) { - ++dispatches; - return operation(); - }; - hooks.dispatch_stop = [](const auto& operation) { - return operation(); - }; - - ASSERT_TRUE(task.touchIfCurrent( - 10, 20, [] { return true; }, std::move(hooks))); - EXPECT_TRUE( - cmvr::task::TouchScreenTaskAdmissionTestPeer::sendJointVelocity(task)); - EXPECT_EQ(arm->speedJCalls(), 1); - EXPECT_EQ(dispatches, 1); - EXPECT_GE(revalidations, 2); - - admitted = false; - EXPECT_FALSE( - cmvr::task::TouchScreenTaskAdmissionTestPeer::sendJointVelocity(task)); - EXPECT_EQ(arm->speedJCalls(), 1); - EXPECT_EQ(dispatches, 1); - EXPECT_TRUE(task.stopActivity()); -} - -TEST_F(TouchScreenAdmissionTest, - RevokedSafetySessionStopsActivityThroughStopLane) -{ - auto arm = std::make_shared(); - auto camera = std::make_shared( - "touch-revoked-safety-camera"); - cmvr::task::TouchScreenTask task(cmvr::config::TouchScreenTaskConfig{}); - cmvr::task::TouchScreenTaskAdmissionTestPeer::prepare( - task, arm, camera); - - bool admitted = true; - int stop_dispatches = 0; - cmvr::task::TouchScreenTask::SafetyHooks hooks; - hooks.revalidate = [&] { return admitted; }; - hooks.dispatch_actuation = [](const auto& operation) { - return operation(); - }; - hooks.dispatch_stop = [&](const auto& operation) { - ++stop_dispatches; - return operation(); - }; - - ASSERT_TRUE(task.touchIfCurrent( - 10, 20, [] { return true; }, std::move(hooks))); - admitted = false; - EXPECT_FALSE(task.step(0.01)); - EXPECT_EQ(task.phase(), cmvr::task::TouchScreenTask::Phase::FAILED); - EXPECT_EQ( - task.lastStatus(), - cmvr::task::TouchScreenTask::Status::SAFETY_ADMISSION_REVOKED); - EXPECT_EQ(stop_dispatches, 1); - EXPECT_EQ(arm->stopMotionCalls(), 1); -} - -TEST_F(TouchScreenAdmissionTest, - StopAllStopsCameraActivityAndNextTouchRestartsIt) -{ - auto arm = std::make_shared(); - auto camera = std::make_shared( - "touch-restart-camera"); - cmvr::task::TouchScreenTask task(cmvr::config::TouchScreenTaskConfig{}); - cmvr::task::TouchScreenTaskAdmissionTestPeer::prepare( - task, arm, camera); - auto& gate = cmvr::service::globalStopAllAdmissionGate(); - auto& registry = - cmvr::service::globalCameraOperationalActivityRegistry(); - - ASSERT_TRUE(task.touch(10, 20)); - EXPECT_TRUE(camera->operationalActive()); - EXPECT_EQ(camera->operationalStartCalls(), 1); - - const auto ticket = gate.beginStopAll(); - ASSERT_TRUE(ticket.valid()); - EXPECT_TRUE(task.stopActivity()); - EXPECT_TRUE(registry.stopAllActivities()); - EXPECT_FALSE(camera->operationalActive()); - EXPECT_EQ(camera->operationalStopCalls(), 1); - EXPECT_EQ(camera->lifecycleStopCalls(), 0); - ASSERT_TRUE(gate.finishStopAll(ticket, true)); - - ASSERT_TRUE(task.touch(30, 40)); - EXPECT_TRUE(camera->operationalActive()); - EXPECT_EQ(camera->operationalStartCalls(), 2); - EXPECT_EQ(camera->lifecycleStartCalls(), 0); - EXPECT_TRUE(task.stopActivity()); -} - -TEST_F(TouchScreenAdmissionTest, - TouchRollsBackCameraStartThatCrossesStopAllGeneration) -{ - auto arm = std::make_shared(); - auto camera = std::make_shared( - "touch-racing-camera"); - cmvr::task::TouchScreenTask task(cmvr::config::TouchScreenTaskConfig{}); - cmvr::task::TouchScreenTaskAdmissionTestPeer::prepare( - task, arm, camera); - camera->blockStart(); - - bool touch_result = true; - std::thread touch_thread([&] { - touch_result = task.touch(10, 20); - }); - camera->waitForStartEntered(); - - auto& gate = cmvr::service::globalStopAllAdmissionGate(); - const auto ticket = gate.beginStopAll(); - EXPECT_TRUE(ticket.valid()); - camera->releaseStart(); - touch_thread.join(); - - EXPECT_FALSE(touch_result); - EXPECT_FALSE(task.isBusy()); - EXPECT_FALSE(camera->operationalActive()); - EXPECT_EQ(camera->operationalStartCalls(), 1); - EXPECT_EQ(camera->operationalStopCalls(), 1); - EXPECT_EQ(camera->lifecycleStopCalls(), 0); - EXPECT_TRUE(gate.finishStopAll(ticket, true)); -} - -TEST_F(TouchScreenAdmissionTest, - InitRollsBackCameraStartThatCrossesStopAllGeneration) -{ - cmvr::config::DeviceManagerConfig manager_config; - auto& manager = - cmvr::device::DeviceManager::getInstance(manager_config); - auto camera = std::make_shared( - "touch-init-racing-camera"); - manager.registerDevice(camera); - - cmvr::task::TouchScreenTask task(cmvr::config::TouchScreenTaskConfig{}); - cmvr::task::TouchScreenTaskAdmissionTestPeer::prepareInit( - task, - "missing-arm", - "missing-dexhand", - camera->id()); - camera->blockStart(); - - bool init_result = true; - std::thread init_thread([&] { - init_result = task.init(); - }); - camera->waitForStartEntered(); - - auto& gate = cmvr::service::globalStopAllAdmissionGate(); - const auto ticket = gate.beginStopAll(); - EXPECT_TRUE(ticket.valid()); - camera->releaseStart(); - init_thread.join(); - - EXPECT_FALSE(init_result); - EXPECT_EQ(task.state(), cmvr::task::TaskState::UNINITIALIZED); - EXPECT_FALSE(camera->operationalActive()); - EXPECT_EQ(camera->operationalStartCalls(), 1); - EXPECT_EQ(camera->operationalStopCalls(), 1); - EXPECT_EQ(camera->lifecycleStopCalls(), 0); - EXPECT_TRUE(gate.finishStopAll(ticket, true)); -} - -} // namespace diff --git a/cmvr-es/task/ume_teleop_task/CMakeLists.txt b/cmvr-es/task/ume_teleop_task/CMakeLists.txt index 1b3b6362..d1d1b8b5 100644 --- a/cmvr-es/task/ume_teleop_task/CMakeLists.txt +++ b/cmvr-es/task/ume_teleop_task/CMakeLists.txt @@ -18,26 +18,3 @@ target_link_libraries(ume_teleop_task add_library(cmvr_es::ume_teleop_task ALIAS ume_teleop_task) install(TARGETS ume_teleop_task ARCHIVE DESTINATION lib) - -if(BUILD_TESTING) - add_executable(ume_teleop_task_test - tests/ume_teleop_task_test.cpp - ) - target_compile_features(ume_teleop_task_test PRIVATE cxx_std_17) - target_link_libraries(ume_teleop_task_test - PRIVATE - cmvr_es::ume_teleop_task - cmvr_es::stop_all_admission_gate - Threads::Threads - ) - add_test(NAME ume_teleop_task_test COMMAND ume_teleop_task_test) - set(_ume_teleop_task_test_environment - "LD_LIBRARY_PATH=${CMVR_TEST_EXTERNAL_LIBRARY_PATH}") - if(CMVR_TEST_SYSTEM_LIBSTDCXX) - list(APPEND _ume_teleop_task_test_environment - "LD_PRELOAD=${CMVR_TEST_SYSTEM_LIBSTDCXX}") - endif() - set_tests_properties(ume_teleop_task_test PROPERTIES - TIMEOUT 10 - ENVIRONMENT "${_ume_teleop_task_test_environment}") -endif() diff --git a/cmvr-es/task/ume_teleop_task/tests/ume_teleop_task_test.cpp b/cmvr-es/task/ume_teleop_task/tests/ume_teleop_task_test.cpp deleted file mode 100644 index 67766831..00000000 --- a/cmvr-es/task/ume_teleop_task/tests/ume_teleop_task_test.cpp +++ /dev/null @@ -1,530 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "cmvr/api/arm_teleop_v1.grpc.pb.h" -#include "service/grpc/client/include/grpc_arm_teleop_client.h" -#include "service/grpc/stop_all/include/stop_all_admission_gate.h" -#include "task/ume_teleop_task/include/ume_teleop_task.h" - -namespace { - -using namespace std::chrono_literals; -namespace api = cmvr::api::armteleop::v1; - -class WatchdogArmTeleopService final : public api::ArmTeleopService::Service { -public: - explicit WatchdogArmTeleopService( - const std::chrono::milliseconds watchdog) - : watchdog_(watchdog) - { - } - - grpc::Status Teleoperate( - grpc::ServerContext* context, - grpc::ServerReaderWriter* stream) override - { - api::ClientFrame frame; - if (!stream->Read(&frame) || !frame.has_open()) { - return grpc::Status( - grpc::StatusCode::INVALID_ARGUMENT, - "OpenSession must be first"); - } - { - std::lock_guard lock(mutex_); - open_received_ = true; - ++open_count_; - reader_finished_ = false; - last_sequence_ = 0; - last_activity_ = std::chrono::steady_clock::now(); - } - condition_.notify_all(); - - api::ServerFrame opened; - opened.mutable_status()->set_session_id("task-test-session"); - opened.mutable_status()->set_phase(api::SESSION_PHASE_OPENED); - opened.mutable_status()->set_negotiated_watchdog_ms( - static_cast(watchdog_.count())); - if (!stream->Write(opened)) { - return grpc::Status::OK; - } - - api::ServerFrame ready; - ready.mutable_status()->set_session_id("task-test-session"); - ready.mutable_status()->set_phase(api::SESSION_PHASE_READY); - ready.mutable_status()->set_negotiated_watchdog_ms( - static_cast(watchdog_.count())); - if (!stream->Write(ready)) { - return grpc::Status::OK; - } - - std::thread reader([&] { - api::ClientFrame incoming; - while (stream->Read(&incoming)) { - const auto arrived = std::chrono::steady_clock::now(); - bool terminal = false; - { - std::lock_guard lock(mutex_); - if (incoming.has_heartbeat() || - incoming.has_setpoint()) { - const std::uint64_t sequence = - incoming.has_heartbeat() - ? incoming.heartbeat().sequence() - : incoming.setpoint().sequence(); - if (sequence == 0 || sequence <= last_sequence_) { - sequence_valid_ = false; - } - last_sequence_ = sequence; - last_activity_ = arrived; - ++activity_version_; - if (incoming.has_heartbeat()) { - ++heartbeat_count_; - } else { - setpoints_.push_back(incoming.setpoint()); - } - } else if (incoming.has_stop()) { - stop_received_ = true; - ++stop_count_; - terminal = true; - } - if (terminal) { - reader_finished_ = true; - } - } - condition_.notify_all(); - incoming.Clear(); - if (terminal) { - break; - } - } - { - std::lock_guard lock(mutex_); - reader_finished_ = true; - } - condition_.notify_all(); - }); - - bool expired = false; - { - std::unique_lock lock(mutex_); - std::uint64_t observed_activity = activity_version_; - while (!reader_finished_) { - const auto deadline = last_activity_ + watchdog_; - if (!condition_.wait_until( - lock, - deadline, - [&] { - return reader_finished_ || - activity_version_ != observed_activity; - })) { - watchdog_expired_ = true; - expired = true; - break; - } - observed_activity = activity_version_; - } - } - if (expired) { - context->TryCancel(); - } - if (reader.joinable()) { - reader.join(); - } - { - std::lock_guard lock(mutex_); - handler_finished_ = true; - ++handler_finish_count_; - } - condition_.notify_all(); - return expired - ? grpc::Status( - grpc::StatusCode::DEADLINE_EXCEEDED, - "test watchdog expired") - : grpc::Status::OK; - } - - bool waitForOpen(const std::chrono::milliseconds timeout) - { - return waitForOpenCount(1, timeout); - } - - bool waitForOpenCount( - const std::size_t count, - const std::chrono::milliseconds timeout) - { - std::unique_lock lock(mutex_); - return condition_.wait_for( - lock, timeout, [&] { return open_count_ >= count; }); - } - - bool waitForHandlerFinish(const std::chrono::milliseconds timeout) - { - return waitForHandlerFinishCount(1, timeout); - } - - bool waitForHandlerFinishCount( - const std::size_t count, - const std::chrono::milliseconds timeout) - { - std::unique_lock lock(mutex_); - return condition_.wait_for( - lock, timeout, [&] { return handler_finish_count_ >= count; }); - } - - bool waitForHeartbeatCount( - const std::size_t count, - const std::chrono::milliseconds timeout) - { - std::unique_lock lock(mutex_); - return condition_.wait_for( - lock, timeout, [&] { return heartbeat_count_ >= count; }); - } - - bool waitForSetpointCount( - const std::size_t count, - const std::chrono::milliseconds timeout) - { - std::unique_lock lock(mutex_); - return condition_.wait_for( - lock, timeout, [&] { return setpoints_.size() >= count; }); - } - - std::size_t setpointCount() const - { - std::lock_guard lock(mutex_); - return setpoints_.size(); - } - - std::size_t heartbeatCount() const - { - std::lock_guard lock(mutex_); - return heartbeat_count_; - } - - std::size_t stopCount() const - { - std::lock_guard lock(mutex_); - return stop_count_; - } - - api::JointSetpoint lastSetpoint() const - { - std::lock_guard lock(mutex_); - return setpoints_.empty() - ? api::JointSetpoint{} - : setpoints_.back(); - } - - bool watchdogExpired() const - { - std::lock_guard lock(mutex_); - return watchdog_expired_; - } - - bool sequenceValid() const - { - std::lock_guard lock(mutex_); - return sequence_valid_; - } - - bool stopReceived() const - { - std::lock_guard lock(mutex_); - return stop_received_; - } - -private: - const std::chrono::milliseconds watchdog_; - mutable std::mutex mutex_; - std::condition_variable condition_; - bool open_received_{false}; - bool reader_finished_{false}; - bool handler_finished_{false}; - bool watchdog_expired_{false}; - bool sequence_valid_{true}; - bool stop_received_{false}; - std::size_t open_count_{0}; - std::size_t handler_finish_count_{0}; - std::size_t stop_count_{0}; - std::uint64_t activity_version_{0}; - std::uint64_t last_sequence_{0}; - std::size_t heartbeat_count_{0}; - std::vector setpoints_; - std::chrono::steady_clock::time_point last_activity_{}; -}; - -cmvr::config::UmeTeleopConfig validConfig(const std::string& endpoint) -{ - cmvr::config::UmeTeleopConfig config; - config.set_id("ume_teleop_test"); - config.set_server_address(endpoint); - config.set_allow_insecure(true); - - auto* open = config.mutable_open_session(); - open->set_protocol_major(1); - open->set_protocol_minor(0); - open->set_client_instance_id("ume-task-test"); - open->set_requested_command_rate_hz(20); - open->set_requested_state_rate_hz(250); - open->set_watchdog_timeout_ms(120); - open->set_requested_lease_ms(500); - open->mutable_expected_robot()->set_robot_id("test-arm"); - open->mutable_expected_robot()->add_joint_names("joint1"); - - config.mutable_reconnect()->set_initial_delay_ms(10); - config.mutable_reconnect()->set_maximum_delay_ms(50); - config.mutable_reconnect()->set_multiplier(2.0); - return config; -} - -int fail(const std::string& detail) -{ - std::cerr << "ume_teleop_task_test: " << detail << '\n'; - return 1; -} - -} // namespace - -int main() -{ - auto& admission = cmvr::service::globalStopAllAdmissionGate(); - admission.clearForTesting(); - - { - cmvr::config::UmeTeleopConfig invalid; - invalid.set_id("invalid"); - cmvr::task::UmeTeleopTask task(invalid); - if (task.init() || task.state() != cmvr::task::TaskState::FAILED) { - return fail("invalid transport configuration was not rejected"); - } - task.stop(); - if (task.state() != cmvr::task::TaskState::FAILED) { - return fail("stop did not preserve an initialization failure"); - } - } - - { - // Exercise the start/stop race before a synchronous stream necessarily - // publishes its ClientContext. The Task's cancellation predicate closes - // this gap, while tryCancel() interrupts it once the context is visible. - const std::string unavailable_endpoint = - "unix:/tmp/cmvr_ume_teleop_unavailable_" + - std::to_string(static_cast(::getpid())) + ".sock"; - auto channel = grpc::CreateChannel( - unavailable_endpoint, - grpc::InsecureChannelCredentials()); - auto client = - std::make_shared(channel); - cmvr::task::UmeTeleopTask task( - validConfig(unavailable_endpoint), client); - if (!task.init() || !task.start()) { - return fail("immediate-stop task did not initialize and start"); - } - api::JointSetpoint disconnected_setpoint; - disconnected_setpoint.add_position_rad(1.0); - disconnected_setpoint.set_valid_for_us(100000); - if (task.submitSetpoint(disconnected_setpoint)) { - task.stop(); - return fail( - "task accepted a motion command without a ready session"); - } - const auto stop_begin = std::chrono::steady_clock::now(); - task.stop(); - if (std::chrono::steady_clock::now() - stop_begin > 2s || - task.state() != cmvr::task::TaskState::STOPPED) { - return fail("immediate Task stop did not cancel and join promptly"); - } - } - - WatchdogArmTeleopService service(120ms); - grpc::ServerBuilder builder; - int selected_port = 0; - builder.AddListeningPort( - "127.0.0.1:0", - grpc::InsecureServerCredentials(), - &selected_port); - builder.RegisterService(&service); - std::unique_ptr server = builder.BuildAndStart(); - if (!server || selected_port == 0) { - return fail("failed to start in-process gRPC server"); - } - const std::string endpoint = - "127.0.0.1:" + std::to_string(selected_port); - - auto channel = grpc::CreateChannel( - endpoint, - grpc::InsecureChannelCredentials()); - auto client = - std::make_shared(channel); - cmvr::task::UmeTeleopTask task(validConfig(endpoint), client); - - if (task.runMode() != cmvr::task::TaskRunMode::BLOCKING_SERVICE) { - server->Shutdown(); - return fail("task is not a BLOCKING_SERVICE"); - } - if (!task.init()) { - server->Shutdown(); - return fail("valid task did not initialize"); - } - - auto admission_ticket = admission.beginStopAll(); - if (task.start() || task.isBusy()) { - server->Shutdown(); - return fail("public start bypassed closed StopAll admission"); - } - if (!admission.finishStopAll(admission_ticket, true) || !task.start()) { - server->Shutdown(); - return fail("explicit start was not restored after successful StopAll"); - } - if (!service.waitForOpen(2s)) { - task.stop(); - server->Shutdown(); - return fail("task worker did not open the teleoperation stream"); - } - - // No application commands are submitted here. Heartbeats alone must keep - // the session alive for longer than the negotiated watchdog. - if (!service.waitForHeartbeatCount(4, 2s) || - service.watchdogExpired() || !task.isBusy()) { - task.stop(); - server->Shutdown(); - return fail("silent command stream did not survive via heartbeats"); - } - - api::JointSetpoint first; - first.set_sequence(999); // Task must replace caller-owned sequence values. - first.add_position_rad(1.0); - first.add_velocity_rad_s(0.0); - first.set_valid_for_us(100000); - if (!task.submitSetpoint(first) || - !service.waitForSetpointCount(1, 2s)) { - task.stop(); - server->Shutdown(); - return fail("first mailbox setpoint was not sent"); - } - - // The sender rate is 20 Hz. These arrive inside one command period, so the - // capacity-one mailbox must publish only the newest value. - for (int value = 2; value <= 4; ++value) { - api::JointSetpoint setpoint; - setpoint.set_sequence(1000 + value); - setpoint.add_position_rad(static_cast(value)); - setpoint.add_velocity_rad_s(0.0); - setpoint.set_valid_for_us(100000); - if (!task.submitSetpoint(setpoint)) { - task.stop(); - server->Shutdown(); - return fail("latest-only mailbox rejected a valid setpoint"); - } - } - if (!service.waitForSetpointCount(2, 2s)) { - task.stop(); - server->Shutdown(); - return fail("latest mailbox setpoint was not sent"); - } - std::this_thread::sleep_for(70ms); - const api::JointSetpoint latest = service.lastSetpoint(); - if (service.setpointCount() != 2 || - latest.position_rad_size() != 1 || - latest.position_rad(0) != 4.0 || - latest.sequence() == 0 || - latest.sequence() >= 1000) { - task.stop(); - server->Shutdown(); - return fail("mailbox did not collapse queued commands to the latest value"); - } - - const auto stop_begin = std::chrono::steady_clock::now(); - const bool activity_stopped = task.stopActivity(); - const auto stop_elapsed = std::chrono::steady_clock::now() - stop_begin; - if (!activity_stopped || stop_elapsed > 2s) { - server->Shutdown(); - return fail("stopActivity did not stop and join promptly"); - } - if (task.state() != cmvr::task::TaskState::STOPPED || - task.isBusy() || !task.isFinished()) { - server->Shutdown(); - return fail("task did not reach STOPPED after stopping its activity"); - } - if (!service.waitForHandlerFinish(2s)) { - server->Shutdown(); - return fail("server handler did not observe activity cancellation"); - } - if (!service.stopReceived()) { - server->Shutdown(); - return fail("stopActivity did not send StopSession before TryCancel"); - } - api::JointSetpoint stopped_setpoint; - stopped_setpoint.add_position_rad(5.0); - stopped_setpoint.set_valid_for_us(100000); - if (task.submitSetpoint(stopped_setpoint)) { - server->Shutdown(); - return fail("stopped activity still accepted a setpoint"); - } - const auto heartbeats_after_stop = service.heartbeatCount(); - const auto setpoints_after_stop = service.setpointCount(); - std::this_thread::sleep_for(200ms); - if (service.heartbeatCount() != heartbeats_after_stop || - service.setpointCount() != setpoints_after_stop) { - server->Shutdown(); - return fail("stopped activity continued sending heartbeat or setpoint frames"); - } - - if (!task.start() || - !service.waitForOpenCount(2, 2s) || - !service.waitForHeartbeatCount(heartbeats_after_stop + 1, 2s) || - !task.isBusy()) { - task.stop(); - server->Shutdown(); - return fail("explicit start did not create a new teleoperation activity"); - } - api::JointSetpoint restarted_setpoint; - restarted_setpoint.add_position_rad(6.0); - restarted_setpoint.set_valid_for_us(100000); - if (!task.submitSetpoint(restarted_setpoint) || - !service.waitForSetpointCount(setpoints_after_stop + 1, 2s)) { - task.stop(); - server->Shutdown(); - return fail("restarted activity did not send a setpoint"); - } - if (!task.stopActivity() || - !service.waitForHandlerFinishCount(2, 2s) || - service.stopCount() != 2 || - task.state() != cmvr::task::TaskState::STOPPED) { - server->Shutdown(); - return fail("restarted activity did not stop cleanly"); - } - - admission_ticket = admission.beginStopAll(); - if (admission.finishStopAll(admission_ticket, false) || task.start()) { - server->Shutdown(); - return fail("failed StopAll did not keep public start fail-closed"); - } - admission_ticket = admission.beginStopAll(); - if (!admission.finishStopAll(admission_ticket, true) || - !task.start() || !service.waitForOpenCount(3, 2s) || - !task.stopActivity() || - !service.waitForHandlerFinishCount(3, 2s)) { - server->Shutdown(); - return fail("successful StopAll did not restore a new explicit start"); - } - if (service.watchdogExpired() || !service.sequenceValid()) { - server->Shutdown(); - return fail("heartbeat/setpoint sequence or watchdog contract failed"); - } - - server->Shutdown(); - admission.clearForTesting(); - std::cout << "ume_teleop_task_test: PASS\n"; - return 0; -} diff --git a/compile_commands.json b/compile_commands.json deleted file mode 100644 index f50be0c1..00000000 --- a/compile_commands.json +++ /dev/null @@ -1,986 +0,0 @@ -[ -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/biohead_command.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/biohead_command.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/biohead_command.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/biohead_command.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/biohead_service.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/biohead_service.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/biohead_service.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/biohead_service.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/camera_command.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/camera_command.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/camera_command.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/camera_command.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/camera_service.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/camera_service.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/camera_service.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/camera_service.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/common.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/common.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/common.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/common.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/dexhand_command.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/dexhand_command.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/dexhand_command.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/dexhand_command.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/dexhand_service.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/dexhand_service.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/dexhand_service.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/dexhand_service.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/hlc_command.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/hlc_command.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/hlc_command.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/hlc_command.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/hlc_service.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/hlc_service.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/hlc_service.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/hlc_service.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/humanoid_robot_command.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/humanoid_robot_command.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/humanoid_robot_command.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/humanoid_robot_command.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/humanoid_robot_service.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/humanoid_robot_service.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/humanoid_robot_service.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/humanoid_robot_service.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/microphone_command.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/microphone_command.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/microphone_command.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/microphone_command.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/microphone_service.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/microphone_service.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/microphone_service.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/microphone_service.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/speaker_command.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/speaker_command.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/speaker_command.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/speaker_command.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/speaker_service.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/speaker_service.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/speaker_service.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/speaker_service.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/system_command.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/system_command.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/system_command.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/system_command.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/system_service.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/system_service.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/system_service.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/system_service.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/test_service.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/test_service.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/test_service.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/test_service.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/camera_config/camera_config.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/camera_config/camera_config.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/camera_config/camera_config.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/camera_config/camera_config.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/dexhand_config/dexhand_config.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/dexhand_config/dexhand_config.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/dexhand_config/dexhand_config.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/dexhand_config/dexhand_config.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/microphone_config/microphone_config.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/microphone_config/microphone_config.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/microphone_config/microphone_config.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/microphone_config/microphone_config.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/pinocchio_dls_ik_config.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/pinocchio_dls_ik_config.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/pinocchio_dls_ik_config.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/pinocchio_dls_ik_config.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/pinocchio_qp_ik_solver_config.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/pinocchio_qp_ik_solver_config.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/pinocchio_qp_ik_solver_config.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/pinocchio_qp_ik_solver_config.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/speaker_config/speaker_conifg.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/speaker_config/speaker_conifg.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/speaker_config/speaker_conifg.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/speaker_config/speaker_conifg.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/touch_screen_app_config/touch_screen_app_config.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/touch_screen_app_config/touch_screen_app_config.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/touch_screen_app_config/touch_screen_app_config.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/touch_screen_app_config/touch_screen_app_config.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/can_card_parameter.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/can_card_parameter.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/can_card_parameter.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/can_card_parameter.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/canopen.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/canopen.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/canopen.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/canopen.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/error_code.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/error_code.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/error_code.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/error_code.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/geometry.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/geometry.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/geometry.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/geometry.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/motor.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/motor.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/motor.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/motor.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/robot_detail.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/robot_detail.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/robot_detail.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/robot_detail.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/biohead_command.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/biohead_command.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/biohead_command.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/biohead_command.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/biohead_service.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/biohead_service.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/biohead_service.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/biohead_service.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/camera_command.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/camera_command.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/camera_command.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/camera_command.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/camera_service.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/camera_service.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/camera_service.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/camera_service.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/common.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/common.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/common.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/common.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/dexhand_command.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/dexhand_command.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/dexhand_command.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/dexhand_command.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/dexhand_service.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/dexhand_service.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/dexhand_service.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/dexhand_service.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/hlc_command.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/hlc_command.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/hlc_command.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/hlc_command.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/hlc_service.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/hlc_service.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/hlc_service.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/hlc_service.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/humanoid_robot_command.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/humanoid_robot_command.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/humanoid_robot_command.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/humanoid_robot_command.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/humanoid_robot_service.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/humanoid_robot_service.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/humanoid_robot_service.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/humanoid_robot_service.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/microphone_command.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/microphone_command.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/microphone_command.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/microphone_command.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/microphone_service.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/microphone_service.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/microphone_service.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/microphone_service.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/speaker_command.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/speaker_command.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/speaker_command.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/speaker_command.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/speaker_service.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/speaker_service.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/speaker_service.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/speaker_service.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/system_command.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/system_command.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/system_command.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/system_command.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/system_service.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/system_service.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/system_service.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/system_service.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/test_service.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/test_service.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/api/test_service.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/api/test_service.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/camera_config/camera_config.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/camera_config/camera_config.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/camera_config/camera_config.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/camera_config/camera_config.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/dexhand_config/dexhand_config.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/dexhand_config/dexhand_config.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/dexhand_config/dexhand_config.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/dexhand_config/dexhand_config.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/microphone_config/microphone_config.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/microphone_config/microphone_config.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/microphone_config/microphone_config.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/microphone_config/microphone_config.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/pinocchio_dls_ik_config.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/pinocchio_dls_ik_config.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/pinocchio_dls_ik_config.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/pinocchio_dls_ik_config.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/pinocchio_qp_ik_solver_config.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/pinocchio_qp_ik_solver_config.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/pinocchio_qp_ik_solver_config.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/pinocchio_qp_ik_solver_config.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/speaker_config/speaker_conifg.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/speaker_config/speaker_conifg.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/speaker_config/speaker_conifg.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/speaker_config/speaker_conifg.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/touch_screen_app_config/touch_screen_app_config.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/touch_screen_app_config/touch_screen_app_config.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/config/touch_screen_app_config/touch_screen_app_config.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/config/touch_screen_app_config/touch_screen_app_config.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/can_card_parameter.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/can_card_parameter.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/can_card_parameter.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/can_card_parameter.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/canopen.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/canopen.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/canopen.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/canopen.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/error_code.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/error_code.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/error_code.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/error_code.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/geometry.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/geometry.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/geometry.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/geometry.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/motor.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/motor.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/motor.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/motor.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/robot_detail.grpc.pb.cc.o -c /home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/robot_detail.grpc.pb.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf/cmvr/msgs/robot_detail.grpc.pb.cc", - "output": "CMakeFiles/proto-objects.dir/_protobuf/cmvr/msgs/robot_detail.grpc.pb.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/protos -I/home/lgv/cmvr/cmvr-es/cmvr-es/service -I/home/lgv/cmvr/cmvr-es/cmvr-es/monitor_manager -I/home/lgv/cmvr/cmvr-es/cmvr-es/hardware -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor -I/home/lgv/cmvr/cmvr-es/cmvr-es/controller -I/home/lgv/cmvr/cmvr-es/cmvr-es/perception -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot -I/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager -I/home/lgv/cmvr/cmvr-es/cmvr-es/data_center -I/home/lgv/cmvr/cmvr-es/cmvr-es/applications -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -g -std=gnu++17 -fPIE -o CMakeFiles/cmvr_es.dir/cmvr-es/main.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/main.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/main.cpp", - "output": "CMakeFiles/cmvr_es.dir/cmvr-es/main.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o cmvr-es/utils/CMakeFiles/utils.dir/base/src/thread_pool.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/utils/base/src/thread_pool.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/utils/base/src/thread_pool.cpp", - "output": "cmvr-es/utils/CMakeFiles/utils.dir/base/src/thread_pool.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o cmvr-es/utils/CMakeFiles/utils.dir/base/src/timer.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/utils/base/src/timer.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/utils/base/src/timer.cpp", - "output": "cmvr-es/utils/CMakeFiles/utils.dir/base/src/timer.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o cmvr-es/utils/CMakeFiles/utils.dir/base/src/abstract_interpolation.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/utils/base/src/abstract_interpolation.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/utils/base/src/abstract_interpolation.cpp", - "output": "cmvr-es/utils/CMakeFiles/utils.dir/base/src/abstract_interpolation.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o cmvr-es/utils/CMakeFiles/utils.dir/dynamics/src/inertial.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/utils/dynamics/src/inertial.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/utils/dynamics/src/inertial.cpp", - "output": "cmvr-es/utils/CMakeFiles/utils.dir/dynamics/src/inertial.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o cmvr-es/utils/CMakeFiles/utils.dir/dynamics/src/joint.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/utils/dynamics/src/joint.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/utils/dynamics/src/joint.cpp", - "output": "cmvr-es/utils/CMakeFiles/utils.dir/dynamics/src/joint.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o cmvr-es/utils/CMakeFiles/utils.dir/dynamics/src/link.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/utils/dynamics/src/link.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/utils/dynamics/src/link.cpp", - "output": "cmvr-es/utils/CMakeFiles/utils.dir/dynamics/src/link.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o cmvr-es/utils/CMakeFiles/utils.dir/dynamics/src/robot.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/utils/dynamics/src/robot.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/utils/dynamics/src/robot.cpp", - "output": "cmvr-es/utils/CMakeFiles/utils.dir/dynamics/src/robot.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o cmvr-es/utils/CMakeFiles/utils.dir/math/src/qp_solver.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/utils/math/src/qp_solver.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/utils/math/src/qp_solver.cpp", - "output": "cmvr-es/utils/CMakeFiles/utils.dir/math/src/qp_solver.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o cmvr-es/utils/CMakeFiles/utils.dir/math/src/se2.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/utils/math/src/se2.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/utils/math/src/se2.cpp", - "output": "cmvr-es/utils/CMakeFiles/utils.dir/math/src/se2.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o cmvr-es/utils/CMakeFiles/utils.dir/math/src/se3.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/utils/math/src/se3.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/utils/math/src/se3.cpp", - "output": "cmvr-es/utils/CMakeFiles/utils.dir/math/src/se3.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o cmvr-es/utils/CMakeFiles/utils.dir/math/src/so3.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/utils/math/src/so3.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/utils/math/src/so3.cpp", - "output": "cmvr-es/utils/CMakeFiles/utils.dir/math/src/so3.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -g -std=gnu++17 -fPIC -o cmvr-es/utils/CMakeFiles/utils.dir/controller/src/cartesian_controller.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/utils/controller/src/cartesian_controller.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/utils/controller/src/cartesian_controller.cpp", - "output": "cmvr-es/utils/CMakeFiles/utils.dir/controller/src/cartesian_controller.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Dhardware_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/hardware -g -std=gnu++17 -fPIC -o cmvr-es/hardware/CMakeFiles/hardware.dir/src/serial_interface.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/hardware/src/serial_interface.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/hardware/src/serial_interface.cpp", - "output": "cmvr-es/hardware/CMakeFiles/hardware.dir/src/serial_interface.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Dhardware_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/hardware -g -std=gnu++17 -fPIC -o cmvr-es/hardware/CMakeFiles/hardware.dir/src/esp32_serial_port.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/hardware/src/esp32_serial_port.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/hardware/src/esp32_serial_port.cpp", - "output": "cmvr-es/hardware/CMakeFiles/hardware.dir/src/esp32_serial_port.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Dhardware_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/hardware -g -std=gnu++17 -fPIC -o cmvr-es/hardware/CMakeFiles/hardware.dir/src/posix_serial_transport.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/hardware/src/posix_serial_transport.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/hardware/src/posix_serial_transport.cpp", - "output": "cmvr-es/hardware/CMakeFiles/hardware.dir/src/posix_serial_transport.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Duvc_camera_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/camera/uvc_camera -g -std=gnu++17 -fPIC -o cmvr-es/devices/camera/uvc_camera/CMakeFiles/uvc_camera.dir/src/uvc_camera.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/camera/uvc_camera/src/uvc_camera.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/camera/uvc_camera/src/uvc_camera.cpp", - "output": "cmvr-es/devices/camera/uvc_camera/CMakeFiles/uvc_camera.dir/src/uvc_camera.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Drealsense_camera_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/camera/realsense_camera -I/home/lgv/cmvr/cmvr-es/third_party/gtest/1.17.0/include -g -std=gnu++17 -fPIC -o cmvr-es/devices/camera/realsense_camera/CMakeFiles/realsense_camera.dir/src/realsense_camera.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/camera/realsense_camera/src/realsense_camera.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/camera/realsense_camera/src/realsense_camera.cpp", - "output": "cmvr-es/devices/camera/realsense_camera/CMakeFiles/realsense_camera.dir/src/realsense_camera.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/third_party/gtest/1.17.0/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/camera/realsense_camera -I/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIE -o cmvr-es/devices/camera/realsense_camera/CMakeFiles/realsense_camera_test.dir/src/realsense_camera_test.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/camera/realsense_camera/src/realsense_camera_test.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/camera/realsense_camera/src/realsense_camera_test.cpp", - "output": "cmvr-es/devices/camera/realsense_camera/CMakeFiles/realsense_camera_test.dir/src/realsense_camera_test.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Dmujoco_camera_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/camera/mujoco_camera -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -g -std=gnu++17 -fPIC -o cmvr-es/devices/camera/mujoco_camera/CMakeFiles/mujoco_camera.dir/src/mujoco_camera.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/camera/mujoco_camera/src/mujoco_camera.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/camera/mujoco_camera/src/mujoco_camera.cpp", - "output": "cmvr-es/devices/camera/mujoco_camera/CMakeFiles/mujoco_camera.dir/src/mujoco_camera.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Dffmpeg_speaker_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/speaker/ffmpeg_speaker -g -std=gnu++17 -fPIC -o cmvr-es/devices/speaker/ffmpeg_speaker/CMakeFiles/ffmpeg_speaker.dir/src/ffmpeg_speaker.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/speaker/ffmpeg_speaker/src/ffmpeg_speaker.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/speaker/ffmpeg_speaker/src/ffmpeg_speaker.cpp", - "output": "cmvr-es/devices/speaker/ffmpeg_speaker/CMakeFiles/ffmpeg_speaker.dir/src/ffmpeg_speaker.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Dffmpeg_microphone_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/microphone/ffmpeg_microphone -g -std=gnu++17 -fPIC -o cmvr-es/devices/microphone/ffmpeg_microphone/CMakeFiles/ffmpeg_microphone.dir/src/ffmpeg_microphone.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/microphone/ffmpeg_microphone/src/ffmpeg_microphone.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/microphone/ffmpeg_microphone/src/ffmpeg_microphone.cpp", - "output": "cmvr-es/devices/microphone/ffmpeg_microphone/CMakeFiles/ffmpeg_microphone.dir/src/ffmpeg_microphone.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Drh56dftp_dexhand_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/dexhand/rh56dftp_dexhand -I/home/lgv/cmvr/cmvr-es/cmvr-es/hardware -g -std=gnu++17 -fPIC -o cmvr-es/devices/dexhand/rh56dftp_dexhand/CMakeFiles/rh56dftp_dexhand.dir/src/rh56dftp_dexhand.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/dexhand/rh56dftp_dexhand/src/rh56dftp_dexhand.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/dexhand/rh56dftp_dexhand/src/rh56dftp_dexhand.cpp", - "output": "cmvr-es/devices/dexhand/rh56dftp_dexhand/CMakeFiles/rh56dftp_dexhand.dir/src/rh56dftp_dexhand.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/dexhand/rh56dftp_dexhand -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIE -o cmvr-es/devices/dexhand/rh56dftp_dexhand/CMakeFiles/rh56dftp_dexhand_test.dir/src/rh56dftp_dexhand_test.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/dexhand/rh56dftp_dexhand/src/rh56dftp_dexhand_test.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/dexhand/rh56dftp_dexhand/src/rh56dftp_dexhand_test.cpp", - "output": "cmvr-es/devices/dexhand/rh56dftp_dexhand/CMakeFiles/rh56dftp_dexhand_test.dir/src/rh56dftp_dexhand_test.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dpx_6ax_gen3_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/dexhand/px_6ax_gen3 -I/home/lgv/cmvr/cmvr-es/cmvr-es/hardware -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/devices/dexhand/px_6ax_gen3/CMakeFiles/px_6ax_gen3.dir/src/px_6ax_gen3.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/dexhand/px_6ax_gen3/src/px_6ax_gen3.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/dexhand/px_6ax_gen3/src/px_6ax_gen3.cpp", - "output": "cmvr-es/devices/dexhand/px_6ax_gen3/CMakeFiles/px_6ax_gen3.dir/src/px_6ax_gen3.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/dexhand/px_6ax_gen3 -I/home/lgv/cmvr/cmvr-es/cmvr-es/hardware -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIE -o cmvr-es/devices/dexhand/px_6ax_gen3/CMakeFiles/px_6ax_gen3_test.dir/src/px_6ax_gen3_test.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/dexhand/px_6ax_gen3/src/px_6ax_gen3_test.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/dexhand/px_6ax_gen3/src/px_6ax_gen3_test.cpp", - "output": "cmvr-es/devices/dexhand/px_6ax_gen3/CMakeFiles/px_6ax_gen3_test.dir/src/px_6ax_gen3_test.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Dhead_esp32_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/biohead/biohead_esp32 -I/home/lgv/cmvr/cmvr-es/cmvr-es/hardware -g -std=gnu++17 -fPIC -o cmvr-es/devices/biohead/biohead_esp32/CMakeFiles/head_esp32.dir/src/biohead_esp32.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/biohead/biohead_esp32/src/biohead_esp32.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/biohead/biohead_esp32/src/biohead_esp32.cpp", - "output": "cmvr-es/devices/biohead/biohead_esp32/CMakeFiles/head_esp32.dir/src/biohead_esp32.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dhumanoid_robot_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot -I/home/lgv/cmvr/cmvr-es/cmvr-es/data_center -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/devices/robot/humanoid_robot/CMakeFiles/humanoid_robot.dir/src/humanoid_robot.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot/src/humanoid_robot.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot/src/humanoid_robot.cpp", - "output": "cmvr-es/devices/robot/humanoid_robot/CMakeFiles/humanoid_robot.dir/src/humanoid_robot.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager -I/home/lgv/cmvr/cmvr-es/cmvr-es/controller -I/home/lgv/cmvr/cmvr-es/cmvr-es/perception -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot -I/home/lgv/cmvr/cmvr-es/cmvr-es/data_center -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -g -std=gnu++17 -fPIE -o cmvr-es/devices/robot/humanoid_robot/CMakeFiles/humanoid_robot_test.dir/src/humanoid_robot_test.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot/src/humanoid_robot_test.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot/src/humanoid_robot_test.cpp", - "output": "cmvr-es/devices/robot/humanoid_robot/CMakeFiles/humanoid_robot_test.dir/src/humanoid_robot_test.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dcanbus_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/devices/canbus/CMakeFiles/canbus.dir/can_client/socket/socket_can_client_raw.cc.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus/can_client/socket/socket_can_client_raw.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus/can_client/socket/socket_can_client_raw.cc", - "output": "cmvr-es/devices/canbus/CMakeFiles/canbus.dir/can_client/socket/socket_can_client_raw.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dcanbus_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/devices/canbus/CMakeFiles/canbus.dir/common/byte.cc.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus/common/byte.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus/common/byte.cc", - "output": "cmvr-es/devices/canbus/CMakeFiles/canbus.dir/common/byte.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIE -o cmvr-es/devices/canbus/CMakeFiles/socket_can_client_raw_test.dir/can_client/socket/socket_can_client_raw_test.cc.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus/can_client/socket/socket_can_client_raw_test.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus/can_client/socket/socket_can_client_raw_test.cc", - "output": "cmvr-es/devices/canbus/CMakeFiles/socket_can_client_raw_test.dir/can_client/socket/socket_can_client_raw_test.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIE -o cmvr-es/devices/canbus/CMakeFiles/protocol_data_test.dir/can_comm/protocol_data_test.cc.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus/can_comm/protocol_data_test.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus/can_comm/protocol_data_test.cc", - "output": "cmvr-es/devices/canbus/CMakeFiles/protocol_data_test.dir/can_comm/protocol_data_test.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIE -o cmvr-es/devices/canbus/CMakeFiles/message_manager_test.dir/can_comm/message_manager_test.cc.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus/can_comm/message_manager_test.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus/can_comm/message_manager_test.cc", - "output": "cmvr-es/devices/canbus/CMakeFiles/message_manager_test.dir/can_comm/message_manager_test.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIE -o cmvr-es/devices/canbus/CMakeFiles/can_sender_test.dir/can_comm/can_sender_test.cc.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus/can_comm/can_sender_test.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus/can_comm/can_sender_test.cc", - "output": "cmvr-es/devices/canbus/CMakeFiles/can_sender_test.dir/can_comm/can_sender_test.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIE -o cmvr-es/devices/canbus/CMakeFiles/can_receiver_test.dir/can_comm/can_receiver_test.cc.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus/can_comm/can_receiver_test.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus/can_comm/can_receiver_test.cc", - "output": "cmvr-es/devices/canbus/CMakeFiles/can_receiver_test.dir/can_comm/can_receiver_test.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/third_party/gtest/1.17.0/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIE -o cmvr-es/devices/motor/CMakeFiles/motor_manager_test.dir/motor_manager_test.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/motor_manager_test.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/motor_manager_test.cpp", - "output": "cmvr-es/devices/motor/CMakeFiles/motor_manager_test.dir/motor_manager_test.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Dti5motor_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus -g -std=gnu++17 -fPIC -o cmvr-es/devices/motor/ti5_motor/CMakeFiles/ti5motor.dir/canopen/protocol/ti5_motor_sdo_response.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor/canopen/protocol/ti5_motor_sdo_response.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor/canopen/protocol/ti5_motor_sdo_response.cpp", - "output": "cmvr-es/devices/motor/ti5_motor/CMakeFiles/ti5motor.dir/canopen/protocol/ti5_motor_sdo_response.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Dti5motor_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus -g -std=gnu++17 -fPIC -o cmvr-es/devices/motor/ti5_motor/CMakeFiles/ti5motor.dir/canopen/protocol/ti5_motor_tpdo1.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor/canopen/protocol/ti5_motor_tpdo1.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor/canopen/protocol/ti5_motor_tpdo1.cpp", - "output": "cmvr-es/devices/motor/ti5_motor/CMakeFiles/ti5motor.dir/canopen/protocol/ti5_motor_tpdo1.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Dti5motor_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus -g -std=gnu++17 -fPIC -o cmvr-es/devices/motor/ti5_motor/CMakeFiles/ti5motor.dir/canopen/protocol/ti5_motor_tpdo2.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor/canopen/protocol/ti5_motor_tpdo2.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor/canopen/protocol/ti5_motor_tpdo2.cpp", - "output": "cmvr-es/devices/motor/ti5_motor/CMakeFiles/ti5motor.dir/canopen/protocol/ti5_motor_tpdo2.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Dti5motor_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus -g -std=gnu++17 -fPIC -o cmvr-es/devices/motor/ti5_motor/CMakeFiles/ti5motor.dir/canopen/protocol/ti5_motor_rpdo1.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor/canopen/protocol/ti5_motor_rpdo1.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor/canopen/protocol/ti5_motor_rpdo1.cpp", - "output": "cmvr-es/devices/motor/ti5_motor/CMakeFiles/ti5motor.dir/canopen/protocol/ti5_motor_rpdo1.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Dti5motor_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus -g -std=gnu++17 -fPIC -o cmvr-es/devices/motor/ti5_motor/CMakeFiles/ti5motor.dir/canopen/protocol/ti5_motor_rpdo2.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor/canopen/protocol/ti5_motor_rpdo2.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor/canopen/protocol/ti5_motor_rpdo2.cpp", - "output": "cmvr-es/devices/motor/ti5_motor/CMakeFiles/ti5motor.dir/canopen/protocol/ti5_motor_rpdo2.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Dti5motor_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus -g -std=gnu++17 -fPIC -o cmvr-es/devices/motor/ti5_motor/CMakeFiles/ti5motor.dir/canopen/ti5_motor_canopen_protocol.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor/canopen/ti5_motor_canopen_protocol.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor/canopen/ti5_motor_canopen_protocol.cpp", - "output": "cmvr-es/devices/motor/ti5_motor/CMakeFiles/ti5motor.dir/canopen/ti5_motor_canopen_protocol.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Dti5motor_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus -g -std=gnu++17 -fPIC -o cmvr-es/devices/motor/ti5_motor/CMakeFiles/ti5motor.dir/ti5_motor.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor/ti5_motor.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor/ti5_motor.cpp", - "output": "cmvr-es/devices/motor/ti5_motor/CMakeFiles/ti5motor.dir/ti5_motor.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/camera/uvc_camera -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/speaker/ffmpeg_speaker -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/microphone/ffmpeg_microphone -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/camera/realsense_camera -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/dexhand/rh56dftp_dexhand -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/dexhand/px_6ax_gen3 -I/home/lgv/cmvr/cmvr-es/cmvr-es/hardware -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/biohead/biohead_esp32 -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot -g -std=gnu++17 -fPIC -o cmvr-es/device_manager/CMakeFiles/device_manager.dir/src/device_factory.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/device_manager/src/device_factory.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager/src/device_factory.cpp", - "output": "cmvr-es/device_manager/CMakeFiles/device_manager.dir/src/device_factory.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/camera/uvc_camera -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/speaker/ffmpeg_speaker -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/microphone/ffmpeg_microphone -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/camera/realsense_camera -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/dexhand/rh56dftp_dexhand -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/dexhand/px_6ax_gen3 -I/home/lgv/cmvr/cmvr-es/cmvr-es/hardware -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/biohead/biohead_esp32 -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot -g -std=gnu++17 -fPIC -o cmvr-es/device_manager/CMakeFiles/device_manager.dir/src/device_manager.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/device_manager/src/device_manager.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager/src/device_manager.cpp", - "output": "cmvr-es/device_manager/CMakeFiles/device_manager.dir/src/device_manager.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/camera/uvc_camera -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/speaker/ffmpeg_speaker -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/microphone/ffmpeg_microphone -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/camera/realsense_camera -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/dexhand/rh56dftp_dexhand -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/dexhand/px_6ax_gen3 -I/home/lgv/cmvr/cmvr-es/cmvr-es/hardware -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/biohead/biohead_esp32 -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot -g -std=gnu++17 -fPIC -o cmvr-es/device_manager/CMakeFiles/device_manager.dir/src/system_monitor.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/device_manager/src/system_monitor.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager/src/system_monitor.cpp", - "output": "cmvr-es/device_manager/CMakeFiles/device_manager.dir/src/system_monitor.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Ddisk_monitor_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/monitor/diskmonitor -g -std=gnu++17 -fPIC -o cmvr-es/monitor/diskmonitor/CMakeFiles/disk_monitor.dir/src/disk_monitor.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/monitor/diskmonitor/src/disk_monitor.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/monitor/diskmonitor/src/disk_monitor.cpp", - "output": "cmvr-es/monitor/diskmonitor/CMakeFiles/disk_monitor.dir/src/disk_monitor.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/monitor_manager -I/home/lgv/cmvr/cmvr-es/cmvr-es/monitor/diskmonitor -g -std=gnu++17 -fPIC -o cmvr-es/monitor_manager/CMakeFiles/monitor_manager.dir/src/monitor_factory.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/monitor_manager/src/monitor_factory.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/monitor_manager/src/monitor_factory.cpp", - "output": "cmvr-es/monitor_manager/CMakeFiles/monitor_manager.dir/src/monitor_factory.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/monitor_manager -I/home/lgv/cmvr/cmvr-es/cmvr-es/monitor/diskmonitor -g -std=gnu++17 -fPIC -o cmvr-es/monitor_manager/CMakeFiles/monitor_manager.dir/src/monitor_manager.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/monitor_manager/src/monitor_manager.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/monitor_manager/src/monitor_manager.cpp", - "output": "cmvr-es/monitor_manager/CMakeFiles/monitor_manager.dir/src/monitor_manager.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/service -I/home/lgv/cmvr/cmvr-es/third_party/gtest/1.17.0/include -I/home/lgv/cmvr/cmvr-es/protos -I/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager -I/home/lgv/cmvr/cmvr-es/cmvr-es/controller -I/home/lgv/cmvr/cmvr-es/cmvr-es/perception -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot -I/home/lgv/cmvr/cmvr-es/cmvr-es/applications -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -g -std=gnu++17 -fPIC -o cmvr-es/service/CMakeFiles/service.dir/grpc/src/grpc_camera_service.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/service/grpc/src/grpc_camera_service.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/service/grpc/src/grpc_camera_service.cpp", - "output": "cmvr-es/service/CMakeFiles/service.dir/grpc/src/grpc_camera_service.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/service -I/home/lgv/cmvr/cmvr-es/third_party/gtest/1.17.0/include -I/home/lgv/cmvr/cmvr-es/protos -I/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager -I/home/lgv/cmvr/cmvr-es/cmvr-es/controller -I/home/lgv/cmvr/cmvr-es/cmvr-es/perception -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot -I/home/lgv/cmvr/cmvr-es/cmvr-es/applications -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -g -std=gnu++17 -fPIC -o cmvr-es/service/CMakeFiles/service.dir/grpc/src/grpc_system_service.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/service/grpc/src/grpc_system_service.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/service/grpc/src/grpc_system_service.cpp", - "output": "cmvr-es/service/CMakeFiles/service.dir/grpc/src/grpc_system_service.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/service -I/home/lgv/cmvr/cmvr-es/third_party/gtest/1.17.0/include -I/home/lgv/cmvr/cmvr-es/protos -I/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager -I/home/lgv/cmvr/cmvr-es/cmvr-es/controller -I/home/lgv/cmvr/cmvr-es/cmvr-es/perception -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot -I/home/lgv/cmvr/cmvr-es/cmvr-es/applications -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -g -std=gnu++17 -fPIC -o cmvr-es/service/CMakeFiles/service.dir/grpc/src/grpc_speaker_service.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/service/grpc/src/grpc_speaker_service.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/service/grpc/src/grpc_speaker_service.cpp", - "output": "cmvr-es/service/CMakeFiles/service.dir/grpc/src/grpc_speaker_service.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/service -I/home/lgv/cmvr/cmvr-es/third_party/gtest/1.17.0/include -I/home/lgv/cmvr/cmvr-es/protos -I/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager -I/home/lgv/cmvr/cmvr-es/cmvr-es/controller -I/home/lgv/cmvr/cmvr-es/cmvr-es/perception -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot -I/home/lgv/cmvr/cmvr-es/cmvr-es/applications -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -g -std=gnu++17 -fPIC -o cmvr-es/service/CMakeFiles/service.dir/grpc/src/grpc_microphone_service.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/service/grpc/src/grpc_microphone_service.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/service/grpc/src/grpc_microphone_service.cpp", - "output": "cmvr-es/service/CMakeFiles/service.dir/grpc/src/grpc_microphone_service.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/service -I/home/lgv/cmvr/cmvr-es/third_party/gtest/1.17.0/include -I/home/lgv/cmvr/cmvr-es/protos -I/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager -I/home/lgv/cmvr/cmvr-es/cmvr-es/controller -I/home/lgv/cmvr/cmvr-es/cmvr-es/perception -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot -I/home/lgv/cmvr/cmvr-es/cmvr-es/applications -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -g -std=gnu++17 -fPIC -o cmvr-es/service/CMakeFiles/service.dir/grpc/src/grpc_head_service.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/service/grpc/src/grpc_head_service.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/service/grpc/src/grpc_head_service.cpp", - "output": "cmvr-es/service/CMakeFiles/service.dir/grpc/src/grpc_head_service.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/service -I/home/lgv/cmvr/cmvr-es/third_party/gtest/1.17.0/include -I/home/lgv/cmvr/cmvr-es/protos -I/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager -I/home/lgv/cmvr/cmvr-es/cmvr-es/controller -I/home/lgv/cmvr/cmvr-es/cmvr-es/perception -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot -I/home/lgv/cmvr/cmvr-es/cmvr-es/applications -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -g -std=gnu++17 -fPIC -o cmvr-es/service/CMakeFiles/service.dir/grpc/src/grpc_dexhand_service.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/service/grpc/src/grpc_dexhand_service.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/service/grpc/src/grpc_dexhand_service.cpp", - "output": "cmvr-es/service/CMakeFiles/service.dir/grpc/src/grpc_dexhand_service.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/service -I/home/lgv/cmvr/cmvr-es/third_party/gtest/1.17.0/include -I/home/lgv/cmvr/cmvr-es/protos -I/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager -I/home/lgv/cmvr/cmvr-es/cmvr-es/controller -I/home/lgv/cmvr/cmvr-es/cmvr-es/perception -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot -I/home/lgv/cmvr/cmvr-es/cmvr-es/applications -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -g -std=gnu++17 -fPIC -o cmvr-es/service/CMakeFiles/service.dir/grpc/src/grpc_humanoid_robot_service.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/service/grpc/src/grpc_humanoid_robot_service.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/service/grpc/src/grpc_humanoid_robot_service.cpp", - "output": "cmvr-es/service/CMakeFiles/service.dir/grpc/src/grpc_humanoid_robot_service.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/service -I/home/lgv/cmvr/cmvr-es/third_party/gtest/1.17.0/include -I/home/lgv/cmvr/cmvr-es/protos -I/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager -I/home/lgv/cmvr/cmvr-es/cmvr-es/controller -I/home/lgv/cmvr/cmvr-es/cmvr-es/perception -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot -I/home/lgv/cmvr/cmvr-es/cmvr-es/applications -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -g -std=gnu++17 -fPIC -o cmvr-es/service/CMakeFiles/service.dir/grpc/src/grpc_hlc_service.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/service/grpc/src/grpc_hlc_service.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/service/grpc/src/grpc_hlc_service.cpp", - "output": "cmvr-es/service/CMakeFiles/service.dir/grpc/src/grpc_hlc_service.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/service -I/home/lgv/cmvr/cmvr-es/third_party/gtest/1.17.0/include -I/home/lgv/cmvr/cmvr-es/protos -I/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager -I/home/lgv/cmvr/cmvr-es/cmvr-es/controller -I/home/lgv/cmvr/cmvr-es/cmvr-es/perception -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot -I/home/lgv/cmvr/cmvr-es/cmvr-es/applications -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -g -std=gnu++17 -fPIC -o cmvr-es/service/CMakeFiles/service.dir/grpc/src/server_runner.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/service/grpc/src/server_runner.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/service/grpc/src/server_runner.cpp", - "output": "cmvr-es/service/CMakeFiles/service.dir/grpc/src/server_runner.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/third_party/gtest/1.17.0/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot -I/home/lgv/cmvr/cmvr-es/protos -I/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -g -std=gnu++17 -fPIE -o cmvr-es/service/CMakeFiles/grpc_humanoid_robot_client_test.dir/grpc/src/grpc_humanoid_robot_client_test.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/service/grpc/src/grpc_humanoid_robot_client_test.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/service/grpc/src/grpc_humanoid_robot_client_test.cpp", - "output": "cmvr-es/service/CMakeFiles/grpc_humanoid_robot_client_test.dir/grpc/src/grpc_humanoid_robot_client_test.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/third_party/gtest/1.17.0/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot -I/home/lgv/cmvr/cmvr-es/protos -I/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIE -o cmvr-es/service/CMakeFiles/grpc_hlc_client_test.dir/grpc/src/grpc_hlc_client_test.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/service/grpc/src/grpc_hlc_client_test.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/service/grpc/src/grpc_hlc_client_test.cpp", - "output": "cmvr-es/service/CMakeFiles/grpc_hlc_client_test.dir/grpc/src/grpc_hlc_client_test.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Dperception_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/perception -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -g -std=gnu++17 -fPIC -o cmvr-es/perception/CMakeFiles/perception.dir/src/tag_relative_target_3d.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/perception/src/tag_relative_target_3d.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/perception/src/tag_relative_target_3d.cpp", - "output": "cmvr-es/perception/CMakeFiles/perception.dir/src/tag_relative_target_3d.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Dperception_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/perception -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -g -std=gnu++17 -fPIC -o cmvr-es/perception/CMakeFiles/perception.dir/src/apriltag_perception.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/perception/src/apriltag_perception.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/perception/src/apriltag_perception.cpp", - "output": "cmvr-es/perception/CMakeFiles/perception.dir/src/apriltag_perception.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/perception -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/camera/realsense_camera -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -g -std=gnu++17 -fPIE -o cmvr-es/perception/CMakeFiles/tag_relative_target_3d_test.dir/src/tag_relative_target_3d_test.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/perception/src/tag_relative_target_3d_test.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/perception/src/tag_relative_target_3d_test.cpp", - "output": "cmvr-es/perception/CMakeFiles/tag_relative_target_3d_test.dir/src/tag_relative_target_3d_test.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dcontroller_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/controller -I/home/lgv/cmvr/cmvr-es/cmvr-es/perception -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot -I/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -g -std=gnu++17 -fPIC -o cmvr-es/controller/CMakeFiles/controller.dir/src/ibvs_controller.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/controller/src/ibvs_controller.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/controller/src/ibvs_controller.cpp", - "output": "cmvr-es/controller/CMakeFiles/controller.dir/src/ibvs_controller.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dcontroller_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/controller -I/home/lgv/cmvr/cmvr-es/cmvr-es/perception -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot -I/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -g -std=gnu++17 -fPIC -o cmvr-es/controller/CMakeFiles/controller.dir/src/pid_controller.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/controller/src/pid_controller.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/controller/src/pid_controller.cpp", - "output": "cmvr-es/controller/CMakeFiles/controller.dir/src/pid_controller.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DELPP_NO_DEFAULT_LOG_FILE -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/perception -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -I/home/lgv/cmvr/cmvr-es/cmvr-es/simulate/mujoco/mujoco_viewer -I/home/lgv/cmvr/cmvr-es/cmvr-es/controller -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot -I/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/camera/mujoco_camera -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -g -std=gnu++17 -fPIE -o cmvr-es/controller/CMakeFiles/controller_test.dir/src/controller_test.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/controller/src/controller_test.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/controller/src/controller_test.cpp", - "output": "cmvr-es/controller/CMakeFiles/controller_test.dir/src/controller_test.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dplanner_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/planner/CMakeFiles/planner.dir/joint_space_planner/src/joint_space_planner.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/planner/joint_space_planner/src/joint_space_planner.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/planner/joint_space_planner/src/joint_space_planner.cpp", - "output": "cmvr-es/planner/CMakeFiles/planner.dir/joint_space_planner/src/joint_space_planner.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dplanner_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/planner/CMakeFiles/planner.dir/joint_space_planner/src/joint_space_planner_creator.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/planner/joint_space_planner/src/joint_space_planner_creator.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/planner/joint_space_planner/src/joint_space_planner_creator.cpp", - "output": "cmvr-es/planner/CMakeFiles/planner.dir/joint_space_planner/src/joint_space_planner_creator.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dplanner_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/planner/CMakeFiles/planner.dir/joint_space_planner/src/toppra_bspline.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/planner/joint_space_planner/src/toppra_bspline.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/planner/joint_space_planner/src/toppra_bspline.cpp", - "output": "cmvr-es/planner/CMakeFiles/planner.dir/joint_space_planner/src/toppra_bspline.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dplanner_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/planner/CMakeFiles/planner.dir/s_curve_planner/src/s_curve_position_planner.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/planner/s_curve_planner/src/s_curve_position_planner.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/planner/s_curve_planner/src/s_curve_position_planner.cpp", - "output": "cmvr-es/planner/CMakeFiles/planner.dir/s_curve_planner/src/s_curve_position_planner.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dplanner_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/planner/CMakeFiles/planner.dir/s_curve_planner/src/s_curve_velocity_planner.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/planner/s_curve_planner/src/s_curve_velocity_planner.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/planner/s_curve_planner/src/s_curve_velocity_planner.cpp", - "output": "cmvr-es/planner/CMakeFiles/planner.dir/s_curve_planner/src/s_curve_velocity_planner.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dplanner_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/planner/CMakeFiles/planner.dir/cartesian_space_planner/src/cartesian_twist_limiter.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/planner/cartesian_space_planner/src/cartesian_twist_limiter.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/planner/cartesian_space_planner/src/cartesian_twist_limiter.cpp", - "output": "cmvr-es/planner/CMakeFiles/planner.dir/cartesian_space_planner/src/cartesian_twist_limiter.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/data_center -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIE -o cmvr-es/planner/CMakeFiles/joint_space_planner_test.dir/joint_space_planner/src/joint_space_planner_test.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/planner/joint_space_planner/src/joint_space_planner_test.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/planner/joint_space_planner/src/joint_space_planner_test.cpp", - "output": "cmvr-es/planner/CMakeFiles/joint_space_planner_test.dir/joint_space_planner/src/joint_space_planner_test.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIE -o cmvr-es/planner/CMakeFiles/cartesian_twist_limiter_test.dir/cartesian_space_planner/src/cartesian_twist_limiter_test.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/planner/cartesian_space_planner/src/cartesian_twist_limiter_test.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/planner/cartesian_space_planner/src/cartesian_twist_limiter_test.cpp", - "output": "cmvr-es/planner/CMakeFiles/cartesian_twist_limiter_test.dir/cartesian_space_planner/src/cartesian_twist_limiter_test.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dik_solver_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/ik_solver/CMakeFiles/ik_solver.dir/src/ik_solver.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/ik_solver.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/ik_solver.cpp", - "output": "cmvr-es/ik_solver/CMakeFiles/ik_solver.dir/src/ik_solver.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dik_solver_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/ik_solver/CMakeFiles/ik_solver.dir/src/ik_solver_creator.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/ik_solver_creator.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/ik_solver_creator.cpp", - "output": "cmvr-es/ik_solver/CMakeFiles/ik_solver.dir/src/ik_solver_creator.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dik_solver_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/ik_solver/CMakeFiles/ik_solver.dir/src/urdf_parser.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/urdf_parser.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/urdf_parser.cpp", - "output": "cmvr-es/ik_solver/CMakeFiles/ik_solver.dir/src/urdf_parser.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dik_solver_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/ik_solver/CMakeFiles/ik_solver.dir/src/pinocchio_ik_base.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/pinocchio_ik_base.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/pinocchio_ik_base.cpp", - "output": "cmvr-es/ik_solver/CMakeFiles/ik_solver.dir/src/pinocchio_ik_base.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dik_solver_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/ik_solver/CMakeFiles/ik_solver.dir/src/pinocchio_dls_ik_solver.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/pinocchio_dls_ik_solver.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/pinocchio_dls_ik_solver.cpp", - "output": "cmvr-es/ik_solver/CMakeFiles/ik_solver.dir/src/pinocchio_dls_ik_solver.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dik_solver_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/ik_solver/CMakeFiles/ik_solver.dir/src/pinocchio_qp_ik_solver.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/pinocchio_qp_ik_solver.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/pinocchio_qp_ik_solver.cpp", - "output": "cmvr-es/ik_solver/CMakeFiles/ik_solver.dir/src/pinocchio_qp_ik_solver.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dik_solver_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/ik_solver/CMakeFiles/ik_solver.dir/src/bias_srs_ik_slover.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/bias_srs_ik_slover.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/bias_srs_ik_slover.cpp", - "output": "cmvr-es/ik_solver/CMakeFiles/ik_solver.dir/src/bias_srs_ik_slover.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dik_solver_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/ik_solver/CMakeFiles/ik_solver.dir/src/joints_limit_analyzer.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/joints_limit_analyzer.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/joints_limit_analyzer.cpp", - "output": "cmvr-es/ik_solver/CMakeFiles/ik_solver.dir/src/joints_limit_analyzer.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dik_solver_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/ik_solver/CMakeFiles/ik_solver.dir/src/lawba_ik_solver.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/lawba_ik_solver.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/lawba_ik_solver.cpp", - "output": "cmvr-es/ik_solver/CMakeFiles/ik_solver.dir/src/lawba_ik_solver.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dik_solver_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/ik_solver/CMakeFiles/ik_solver.dir/src/opt_psi_selector.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/opt_psi_selector.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/opt_psi_selector.cpp", - "output": "cmvr-es/ik_solver/CMakeFiles/ik_solver.dir/src/opt_psi_selector.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -I/home/lgv/cmvr/cmvr-es/cmvr-es/simulate/mujoco/mujoco_viewer -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIE -o cmvr-es/ik_solver/CMakeFiles/srs_ik_test.dir/src/srs_ik_test.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/srs_ik_test.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/srs_ik_test.cpp", - "output": "cmvr-es/ik_solver/CMakeFiles/srs_ik_test.dir/src/srs_ik_test.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -I/home/lgv/cmvr/cmvr-es/cmvr-es/simulate/mujoco/mujoco_viewer -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIE -o cmvr-es/ik_solver/CMakeFiles/ik_test.dir/src/ik_test.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/ik_test.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver/src/ik_test.cpp", - "output": "cmvr-es/ik_solver/CMakeFiles/ik_test.dir/src/ik_test.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/data_center -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor -g -std=gnu++17 -fPIC -o cmvr-es/data_center/CMakeFiles/data_center.dir/src/data_center.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/data_center/src/data_center.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/data_center/src/data_center.cpp", - "output": "cmvr-es/data_center/CMakeFiles/data_center.dir/src/data_center.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/data_center -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/canbus -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/motor/ti5_motor -g -std=gnu++17 -fPIC -o cmvr-es/data_center/CMakeFiles/data_center.dir/src/motors_info.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/data_center/src/motors_info.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/data_center/src/motors_info.cpp", - "output": "cmvr-es/data_center/CMakeFiles/data_center.dir/src/motors_info.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/applications -I/home/lgv/cmvr/cmvr-es/cmvr-es/controller -I/home/lgv/cmvr/cmvr-es/cmvr-es/perception -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot -I/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -g -std=gnu++17 -fPIC -o cmvr-es/applications/CMakeFiles/applications.dir/src/touch_screen_app.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/applications/src/touch_screen_app.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/applications/src/touch_screen_app.cpp", - "output": "cmvr-es/applications/CMakeFiles/applications.dir/src/touch_screen_app.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/applications -I/home/lgv/cmvr/cmvr-es/cmvr-es/controller -I/home/lgv/cmvr/cmvr-es/cmvr-es/perception -I/home/lgv/cmvr/cmvr-es/cmvr-es/ik_solver -I/home/lgv/cmvr/cmvr-es/cmvr-es/planner -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices/robot/humanoid_robot -I/home/lgv/cmvr/cmvr-es/cmvr-es/device_manager -I/home/lgv/cmvr/cmvr-es/cmvr-es/service -I/home/lgv/cmvr/cmvr-es/cmvr-es/monitor_manager -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -g -std=gnu++17 -fPIE -o cmvr-es/applications/CMakeFiles/touch_screen_app_test.dir/src/touch_screen_app_test.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/applications/src/touch_screen_app_test.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/applications/src/touch_screen_app_test.cpp", - "output": "cmvr-es/applications/CMakeFiles/touch_screen_app_test.dir/src/touch_screen_app_test.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Dmujoco_viewer_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/simulate/mujoco/mujoco_viewer -g -std=gnu++17 -fPIC -o cmvr-es/simulate/mujoco/mujoco_viewer/CMakeFiles/mujoco_viewer.dir/src/glfw_adapter.cc.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/simulate/mujoco/mujoco_viewer/src/glfw_adapter.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/simulate/mujoco/mujoco_viewer/src/glfw_adapter.cc", - "output": "cmvr-es/simulate/mujoco/mujoco_viewer/CMakeFiles/mujoco_viewer.dir/src/glfw_adapter.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Dmujoco_viewer_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/simulate/mujoco/mujoco_viewer -g -std=gnu++17 -fPIC -o cmvr-es/simulate/mujoco/mujoco_viewer/CMakeFiles/mujoco_viewer.dir/src/glfw_dispatch.cc.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/simulate/mujoco/mujoco_viewer/src/glfw_dispatch.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/simulate/mujoco/mujoco_viewer/src/glfw_dispatch.cc", - "output": "cmvr-es/simulate/mujoco/mujoco_viewer/CMakeFiles/mujoco_viewer.dir/src/glfw_dispatch.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Dmujoco_viewer_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/simulate/mujoco/mujoco_viewer -g -std=gnu++17 -fPIC -o cmvr-es/simulate/mujoco/mujoco_viewer/CMakeFiles/mujoco_viewer.dir/src/mujoco_viewer.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/simulate/mujoco/mujoco_viewer/src/mujoco_viewer.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/simulate/mujoco/mujoco_viewer/src/mujoco_viewer.cpp", - "output": "cmvr-es/simulate/mujoco/mujoco_viewer/CMakeFiles/mujoco_viewer.dir/src/mujoco_viewer.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Dmujoco_viewer_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/simulate/mujoco/mujoco_viewer -g -std=gnu++17 -fPIC -o cmvr-es/simulate/mujoco/mujoco_viewer/CMakeFiles/mujoco_viewer.dir/src/platform_ui_adapter.cc.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/simulate/mujoco/mujoco_viewer/src/platform_ui_adapter.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/simulate/mujoco/mujoco_viewer/src/platform_ui_adapter.cc", - "output": "cmvr-es/simulate/mujoco/mujoco_viewer/CMakeFiles/mujoco_viewer.dir/src/platform_ui_adapter.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -Dmujoco_viewer_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/simulate/mujoco/mujoco_viewer -g -std=gnu++17 -fPIC -o cmvr-es/simulate/mujoco/mujoco_viewer/CMakeFiles/mujoco_viewer.dir/src/simulate.cc.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/simulate/mujoco/mujoco_viewer/src/simulate.cc", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/simulate/mujoco/mujoco_viewer/src/simulate.cc", - "output": "cmvr-es/simulate/mujoco/mujoco_viewer/CMakeFiles/mujoco_viewer.dir/src/simulate.cc.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dcommon_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/common/CMakeFiles/common.dir/curve/src/s_curve.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/common/curve/src/s_curve.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/common/curve/src/s_curve.cpp", - "output": "cmvr-es/common/CMakeFiles/common.dir/curve/src/s_curve.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dcommon_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/common/CMakeFiles/common.dir/utils/config_helper/src/config_setting.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/common/utils/config_helper/src/config_setting.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/common/utils/config_helper/src/config_setting.cpp", - "output": "cmvr-es/common/CMakeFiles/common.dir/utils/config_helper/src/config_setting.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dcommon_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/common/CMakeFiles/common.dir/utils/ffmpeg/src/CameraCapture.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/common/utils/ffmpeg/src/CameraCapture.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/common/utils/ffmpeg/src/CameraCapture.cpp", - "output": "cmvr-es/common/CMakeFiles/common.dir/utils/ffmpeg/src/CameraCapture.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dcommon_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/common/CMakeFiles/common.dir/utils/ffmpeg/src/RealSenseCapture.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/common/utils/ffmpeg/src/RealSenseCapture.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/common/utils/ffmpeg/src/RealSenseCapture.cpp", - "output": "cmvr-es/common/CMakeFiles/common.dir/utils/ffmpeg/src/RealSenseCapture.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dcommon_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/common/CMakeFiles/common.dir/utils/ffmpeg/src/VideoFrameEncoder.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/common/utils/ffmpeg/src/VideoFrameEncoder.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/common/utils/ffmpeg/src/VideoFrameEncoder.cpp", - "output": "cmvr-es/common/CMakeFiles/common.dir/utils/ffmpeg/src/VideoFrameEncoder.cpp.o" -}, -{ - "directory": "/home/lgv/cmvr/cmvr-es/cmake-build-debug", - "command": "/usr/bin/g++-11 -DPROTOBUF_USE_DLLS -Dcommon_EXPORTS -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/coal/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/console_bridge/v1.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/eigenpy/v3.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/Eigen3/v3.4.0 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/example-robot-data/v4.3.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/fcl/v0.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x264/v165/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/x265/v215/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg-jetson/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/ffmpeg/v4.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gflags/v2.2.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/glog/v0.5.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/gtest/v1.17.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jrl-cmakemodules/v1.1.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/jsoncpp/v1.9.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/libccd/v2.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/lodepng/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mujoco/v3.3.7/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp-eigen/v0.10.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/PCAN-Basic/v4.10.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/peak-linux-driver/v8.20.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pinocchio/v3.6.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/pybind11/v3.0.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/realsense/v2.56.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/tinyxml2/v11.0.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/toppra/v0.6.2/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom/v5.0.3/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/urdfdom_headers/v2.0.1/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/opencv/4.13.0/include/opencv4 -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/modbus/3.1.11/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/visp/3.7.0/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/mainif/0.0.5/include -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/matplotplusplus/1.2.0/include -I/home/lgv/cmvr/cmvr-es/cmake-build-debug/_protobuf -I/home/lgv/cmvr/cmvr-es/include -I/home/lgv/cmvr/cmvr-es/cmvr-es/devices -I/home/lgv/cmvr/cmvr-es/cmvr-es/utils -I/home/lgv/cmvr/cmvr-es/cmvr-es -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party -I/home/lgv/cmvr/cmvr-es/dependency/x86/third_party/osqp/v0.6.3/include/osqp -I/home/lgv/cmvr/cmvr-es/cmvr-es/common -I/home/lgv/cmvr/cmvr-es/protos -isystem /home/lgv/cmvr/cmvr-es/dependency/x86/third_party/grpc/v1.76.0/include -g -std=gnu++17 -fPIC -o cmvr-es/common/CMakeFiles/common.dir/utils/ffmpeg/src/VideoWriter.cpp.o -c /home/lgv/cmvr/cmvr-es/cmvr-es/common/utils/ffmpeg/src/VideoWriter.cpp", - "file": "/home/lgv/cmvr/cmvr-es/cmvr-es/common/utils/ffmpeg/src/VideoWriter.cpp", - "output": "cmvr-es/common/CMakeFiles/common.dir/utils/ffmpeg/src/VideoWriter.cpp.o" -} -] \ No newline at end of file diff --git a/data/plot.png b/data/plot.png deleted file mode 100644 index fa1eda91ed71a371c9bf0c15b817a1e678327996..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50981 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ΞIit)lDIR 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 diff --git a/data/s_curve_acceleration.png b/data/s_curve_acceleration.png deleted file mode 100644 index c25c21ead87d4558c87665a98c8d769dfd94916e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 83843 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 Ic>cye0E7Nf4FCWD diff --git a/data/s_curve_acceleration.svg b/data/s_curve_acceleration.svg deleted file mode 100644 index 08f41d97..00000000 --- a/data/s_curve_acceleration.svg +++ /dev/null @@ -1,544 +0,0 @@ - - - -Gnuplot -Produced by GNUPLOT 5.4 patchlevel 2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -6 - - - - - - - - - - - - - -4 - - - - - - - - - - - - - -2 - - - - - - - - - - - - - 0 - - - - - - - - - - - - - 2 - - - - - - - - - - - - - 4 - - - - - - - - - - - - - 6 - - - - - - - - - - - - - 0 - - - - - - - - - - - - - 0.5 - - - - - - - - - - - - - 1 - - - - - - - - - - - - - 1.5 - - - - - - - - - - - - - 2 - - - - - - - - - - - - - 2.5 - - - - - - - - - - - - - 3 - - - - - - - - - acceleration [m/s2] - - - - - time [s] - - - - - - - - - gnuplot_plot_1a - - - - - - gnuplot_plot_2a - - - - gnuplot_plot_3a - - - - ZeroToRest - - - - ZeroToPositiveVf - - - - PositiveV0ToRest - - - - - - - - - - - gnuplot_plot_1a - - - - - - gnuplot_plot_2a - - - - gnuplot_plot_3a - - - - ZeroToRest - - - ZeroToRest - - - - - - ZeroToPositiveVf - - - ZeroToPositiveVf - - - - - - PositiveV0ToRest - - - PositiveV0ToRest - - - - - - - - - - - - - - - - SCurve Acceleration - - - - - - - diff --git a/data/s_curve_jerk.png b/data/s_curve_jerk.png deleted file mode 100644 index 26bdd84092ff376ecbbdf482c30fdf815212dada..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54931 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 - - -Gnuplot -Produced by GNUPLOT 5.4 patchlevel 2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -10 - - - - - - - - - - - - - -5 - - - - - - - - - - - - - 0 - - - - - - - - - - - - - 5 - - - - - - - - - - - - - 10 - - - - - - - - - - - - - 0 - - - - - - - - - - - - - 0.5 - - - - - - - - - - - - - 1 - - - - - - - - - - - - - 1.5 - - - - - - - - - - - - - 2 - - - - - - - - - - - - - 2.5 - - - - - - - - - - - - - 3 - - - - - - - - - jerk [m/s3] - - - - - time [s] - - - - - - - - - gnuplot_plot_1a - - - - - - gnuplot_plot_2a - - - - gnuplot_plot_3a - - - - ZeroToRest - - - - ZeroToPositiveVf - - - - PositiveV0ToRest - - - - - - - - - - - gnuplot_plot_1a - - - - - - gnuplot_plot_2a - - - - gnuplot_plot_3a - - - - ZeroToRest - - - ZeroToRest - - - - - - ZeroToPositiveVf - - - ZeroToPositiveVf - - - - - - PositiveV0ToRest - - - PositiveV0ToRest - - - - - - - - - - - - - - - - SCurve Jerk - - - - - - - diff --git a/data/s_curve_position.png b/data/s_curve_position.png deleted file mode 100644 index b811df44a5d06942acbf57c5c9d05cd327a8cc2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 74164 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 - - -Gnuplot -Produced by GNUPLOT 5.4 patchlevel 2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - - - - - - - - - - - 1 - - - - - - - - - - - - - 2 - - - - - - - - - - - - - 3 - - - - - - - - - - - - - 4 - - - - - - - - - - - - - 5 - - - - - - - - - - - - - 0 - - - - - - - - - - - - - 0.5 - - - - - - - - - - - - - 1 - - - - - - - - - - - - - 1.5 - - - - - - - - - - - - - 2 - - - - - - - - - - - - - 2.5 - - - - - - - - - - - - - 3 - - - - - - - - - position [m] - - - - - time [s] - - - - - - - - - gnuplot_plot_1a - - - - - - gnuplot_plot_2a - - - - gnuplot_plot_3a - - - - ZeroToRest - - - - ZeroToPositiveVf - - - - PositiveV0ToRest - - - - - - - - - - - gnuplot_plot_1a - - - - - - gnuplot_plot_2a - - - - gnuplot_plot_3a - - - - ZeroToRest - - - ZeroToRest - - - - - - ZeroToPositiveVf - - - ZeroToPositiveVf - - - - - - PositiveV0ToRest - - - PositiveV0ToRest - - - - - - - - - - - - - - - - SCurve Position - - - - - - - diff --git a/data/s_curve_velocity.png b/data/s_curve_velocity.png deleted file mode 100644 index 887b07643549fc87f95b35b8f0fc4d47321097db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 101914 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 - - -Gnuplot -Produced by GNUPLOT 5.4 patchlevel 2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - - - - - - - - - - - 0.5 - - - - - - - - - - - - - 1 - - - - - - - - - - - - - 1.5 - - - - - - - - - - - - - 2 - - - - - - - - - - - - - 2.5 - - - - - - - - - - - - - 3 - - - - - - - - - - - - - 0 - - - - - - - - - - - - - 0.5 - - - - - - - - - - - - - 1 - - - - - - - - - - - - - 1.5 - - - - - - - - - - - - - 2 - - - - - - - - - - - - - 2.5 - - - - - - - - - - - - - 3 - - - - - - - - - velocity [m/s] - - - - - time [s] - - - - - - - - - gnuplot_plot_1a - - - - - - gnuplot_plot_2a - - - - gnuplot_plot_3a - - - - ZeroToRest - - - - ZeroToPositiveVf - - - - PositiveV0ToRest - - - - - - - - - - - gnuplot_plot_1a - - - - - - gnuplot_plot_2a - - - - gnuplot_plot_3a - - - - ZeroToRest - - - ZeroToRest - - - - - - ZeroToPositiveVf - - - ZeroToPositiveVf - - - - - - PositiveV0ToRest - - - PositiveV0ToRest - - - - - - - - - - - - - - - - SCurve Velocity - - - - - - - diff --git a/model/ume/README.md b/model/ume/README.md index c7ac5076..794c3fb5 100644 --- a/model/ume/README.md +++ b/model/ume/README.md @@ -17,7 +17,7 @@ The source paths are `ume/robot/ume/v6_imu/models/robot.xml`, respectively. Only the model topology/dynamics parser is used. Pinocchio 3.6 -`mjcf::buildModel` and the adapter tests load these files without resolving +`mjcf::buildModel` and the model adapter load these files without resolving their visual STL assets, so no geometry files are duplicated here. The adapter enforces the model's structural contract. Integrations that require diff --git a/python/hand_eye_calibration/__pycache__/save_poses.cpython-310.pyc b/python/hand_eye_calibration/__pycache__/save_poses.cpython-310.pyc deleted file mode 100644 index b90060edf5c6f7a6e6db822030f943c92ee18384..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2446 zcmbVN-EUMy6rYd#wYS@{Y6As{RzjjH(8`0+hXzR`%2Q*CiJ^gPmc6&zCEI(qb8kO$ zZ=x1OG>ATdTElK11i=74m_Wmaf5*Jq-L_A>^ML+lc3UWtn0T9+bLPyPb7s%)ccx)? zw@dH^`>u{(a|roMEuQ`u7Kbq+HF;!|c+_K6I!d)zDp;+wT2q4}Ms=eXVU< zU;K3Km(My8`&;$1%^N?qetxhSwVg!mZ;jRe=6~de%fD{`uV=2gnW%Yrxw(Ahxn8dO zKb#)k{c7dT<>sy5QL0V%m3!x#S01!$^4wGp@1Aqrb>K&aOI(T0XG3N%-p7dUV~RpQ>=KVJwPRr2MLKcYd&<+; z^kkh}km_7n#pFrb%9K<##50x<7oKKfCPt1VJV#P1vA`~KIM3I?FCw;1dEPcCE^BSW zppPkQ-jFP)NwX+KaZd757)c&gg1jx6n8ldGn3rq>`Uv!qc}YipC87tej}8xxhZFu_ zwLCponwS=PI^aixwYhja3hBSC}ZqqB6S;X`-7s(J+X}sKG+wOvlA~04 zR~o7~lFmvxC+WOUOci*Zh){eL-O7c=k{;C%v?o<1xl8$}5(1O3><4~06?Lk(2m6si zEXT66kGiav?xv{Q%P^JH{WiWV6qQTY?N2BPe)Udrnw(&&b}>!Jf+8+c^h|hS^pY{q zGc{vF?HnN|dvVfAZB)!`*C(+O-b)h8V>>|DUQ|p~XtFOhPg`|cwTgJ#;{o*yRNMg$ zj(SGV^9y}xCeGB|B!l>FVj{Mkb|r4TE9q)bN+v(}1ob!Yx4{h)ktO$yA6&y zw5=3QoWgCq4qlR0q}6T!X-tHkFKuK}k)#Wy(8i*hDujl}WK_D6RVd`NH zeUawa9@@)t)TIv1Qug^6IDSH})zySu^ zw_sp+<{6T(BZ@byOu!-LSuxnNKs|eb1J!M*k?^_^n_!fY7@oZY9NCHU8s+^l_~SVX ztb=D}SW+=>PQ_yf-UW`1ACy9`5|p=GUNx8c0mm?+y_m|l{K+1DY0#oUk=9BX=!|Q8 z&nGjJ>OVAnMEBVrh<5!(yE0k`25i4aF645Rsm(w>wk?A%I`)&{365b<