diff --git a/cmvr-es/common/types/arm/arm_types.h b/cmvr-es/common/types/arm/arm_types.h index 4edf3f0d..b6f8a0ed 100644 --- a/cmvr-es/common/types/arm/arm_types.h +++ b/cmvr-es/common/types/arm/arm_types.h @@ -151,6 +151,18 @@ struct PayloadConfig { double cog_z{0.0}; }; +struct CabinetDigitalInputState { + std::uint32_t count{0}; + bool value{false}; +}; + +struct CabinetDigitalOutputState { + std::uint32_t count{0}; + bool value{false}; + std::string runstate; + int runstate_code{0}; +}; + struct MotionOptions { double velocity{0.0}; double acceleration{0.0}; diff --git a/cmvr-es/devices/arm/aubo_arm/include/aubo_arm.h b/cmvr-es/devices/arm/aubo_arm/include/aubo_arm.h index 6e276870..da392f79 100644 --- a/cmvr-es/devices/arm/aubo_arm/include/aubo_arm.h +++ b/cmvr-es/devices/arm/aubo_arm/include/aubo_arm.h @@ -24,6 +24,16 @@ public: std::string typeName() const override { return "AuboARM"; } bool init() override; bool stop() override; + Result getCabinetDigitalInput( + std::uint32_t index, + CabinetDigitalInputState& state) const override; + Result getCabinetDigitalOutput( + std::uint32_t index, + CabinetDigitalOutputState& state) const override; + Result setCabinetDigitalOutput( + std::uint32_t index, + bool value, + CabinetDigitalOutputState& state) override; RobotModel getRobotModel() const override { return model_; } std::size_t getDof() const override { return model_.dof; } diff --git a/cmvr-es/devices/arm/aubo_arm/src/aubo_arm.cpp b/cmvr-es/devices/arm/aubo_arm/src/aubo_arm.cpp index 092371ef..2473b270 100644 --- a/cmvr-es/devices/arm/aubo_arm/src/aubo_arm.cpp +++ b/cmvr-es/devices/arm/aubo_arm/src/aubo_arm.cpp @@ -356,6 +356,227 @@ bool AuboArm::stop() return stopMotion().ok(); } +Result AuboArm::getCabinetDigitalInput( + const std::uint32_t index, + CabinetDigitalInputState& state) const +{ + state = {}; + std::lock_guard lock(mutex_); + const auto ready = ensureConnected_("getCabinetDigitalInput"); + if (!ready.ok()) { + return ready; + } + +#if defined(CMVR_HAS_AUBO_SDK) + try { + const auto robot_names = sdk_->rpc_client->getRobotNames(); + if (robot_names.empty()) { + return Result::failure( + ArmErrorCode::RobotNotReady, + "[AuboArm] getCabinetDigitalInput failed: robot name list is empty"); + } + auto robot_interface = + sdk_->rpc_client->getRobotInterface(robot_names.front()); + if (!robot_interface || !robot_interface->getIoControl()) { + return Result::failure( + ArmErrorCode::RobotNotReady, + "[AuboArm] getCabinetDigitalInput failed: IO interface is unavailable"); + } + + auto io = robot_interface->getIoControl(); + const int count = io->getStandardDigitalInputNum(); + if (count < 0) { + return Result::failure( + ArmErrorCode::CommandFailed, + "[AuboArm] getCabinetDigitalInput failed: invalid IO count=" + + std::to_string(count)); + } + state.count = static_cast(count); + if (index >= state.count) { + return Result::failure( + ArmErrorCode::InvalidArgument, + "[AuboArm] getCabinetDigitalInput index out of range: index=" + + std::to_string(index) + ", count=" + + std::to_string(state.count)); + } + state.value = io->getStandardDigitalInput(static_cast(index)); + return Result::success(); + } catch (const arcs::common_interface::AuboException& e) { + return Result::failure( + ArmErrorCode::CommandFailed, + "[AuboArm] getCabinetDigitalInput failed: " + + std::string(e.what()) + ", sdk ret=" + + std::to_string(e.code())); + } catch (const std::exception& e) { + return Result::failure( + ArmErrorCode::CommandFailed, + "[AuboArm] getCabinetDigitalInput failed: " + + std::string(e.what())); + } +#else + return Result::failure( + ArmErrorCode::UnsupportedCommand, + "[AuboArm] getCabinetDigitalInput failed: Aubo SDK is unavailable"); +#endif +} + +Result AuboArm::getCabinetDigitalOutput( + const std::uint32_t index, + CabinetDigitalOutputState& state) const +{ + state = {}; + std::lock_guard lock(mutex_); + const auto ready = ensureConnected_("getCabinetDigitalOutput"); + if (!ready.ok()) { + return ready; + } + +#if defined(CMVR_HAS_AUBO_SDK) + try { + const auto robot_names = sdk_->rpc_client->getRobotNames(); + if (robot_names.empty()) { + return Result::failure( + ArmErrorCode::RobotNotReady, + "[AuboArm] getCabinetDigitalOutput failed: robot name list is empty"); + } + auto robot_interface = + sdk_->rpc_client->getRobotInterface(robot_names.front()); + if (!robot_interface || !robot_interface->getIoControl()) { + return Result::failure( + ArmErrorCode::RobotNotReady, + "[AuboArm] getCabinetDigitalOutput failed: IO interface is unavailable"); + } + + auto io = robot_interface->getIoControl(); + const int count = io->getStandardDigitalOutputNum(); + if (count < 0) { + return Result::failure( + ArmErrorCode::CommandFailed, + "[AuboArm] getCabinetDigitalOutput failed: invalid IO count=" + + std::to_string(count)); + } + state.count = static_cast(count); + if (index >= state.count) { + return Result::failure( + ArmErrorCode::InvalidArgument, + "[AuboArm] getCabinetDigitalOutput index out of range: index=" + + std::to_string(index) + ", count=" + + std::to_string(state.count)); + } + + const auto runstate = + io->getStandardDigitalOutputRunstate(static_cast(index)); + state.runstate = arcs::common_interface::toString(runstate); + state.runstate_code = static_cast(runstate); + state.value = + io->getStandardDigitalOutput(static_cast(index)); + return Result::success(); + } catch (const arcs::common_interface::AuboException& e) { + return Result::failure( + ArmErrorCode::CommandFailed, + "[AuboArm] getCabinetDigitalOutput failed: " + + std::string(e.what()) + ", sdk ret=" + + std::to_string(e.code())); + } catch (const std::exception& e) { + return Result::failure( + ArmErrorCode::CommandFailed, + "[AuboArm] getCabinetDigitalOutput failed: " + + std::string(e.what())); + } +#else + return Result::failure( + ArmErrorCode::UnsupportedCommand, + "[AuboArm] getCabinetDigitalOutput failed: Aubo SDK is unavailable"); +#endif +} + +Result AuboArm::setCabinetDigitalOutput( + const std::uint32_t index, + const bool value, + CabinetDigitalOutputState& state) +{ + state = {}; + std::lock_guard lock(mutex_); + const auto ready = ensureConnected_("setCabinetDigitalOutput"); + if (!ready.ok()) { + return ready; + } + +#if defined(CMVR_HAS_AUBO_SDK) + try { + const auto robot_names = sdk_->rpc_client->getRobotNames(); + if (robot_names.empty()) { + return Result::failure( + ArmErrorCode::RobotNotReady, + "[AuboArm] setCabinetDigitalOutput failed: robot name list is empty"); + } + auto robot_interface = + sdk_->rpc_client->getRobotInterface(robot_names.front()); + if (!robot_interface || !robot_interface->getIoControl()) { + return Result::failure( + ArmErrorCode::RobotNotReady, + "[AuboArm] setCabinetDigitalOutput failed: IO interface is unavailable"); + } + + auto io = robot_interface->getIoControl(); + const int count = io->getStandardDigitalOutputNum(); + if (count < 0) { + return Result::failure( + ArmErrorCode::CommandFailed, + "[AuboArm] setCabinetDigitalOutput failed: invalid IO count=" + + std::to_string(count)); + } + state.count = static_cast(count); + if (index >= state.count) { + return Result::failure( + ArmErrorCode::InvalidArgument, + "[AuboArm] setCabinetDigitalOutput index out of range: index=" + + std::to_string(index) + ", count=" + + std::to_string(state.count)); + } + + const auto runstate = + io->getStandardDigitalOutputRunstate(static_cast(index)); + state.runstate = arcs::common_interface::toString(runstate); + state.runstate_code = static_cast(runstate); + using arcs::common_interface::StandardOutputRunState; + if (runstate != StandardOutputRunState::None) { + return Result::failure( + ArmErrorCode::CommandRejected, + "[AuboArm] setCabinetDigitalOutput rejected: output is " + "managed by controller runstate; configure this channel as " + "None before writing"); + } + + const int ret = + io->setStandardDigitalOutput(static_cast(index), value); + if (ret != 0) { + return Result::failure( + ArmErrorCode::CommandFailed, + "[AuboArm] setCabinetDigitalOutput failed: sdk ret=" + + std::to_string(ret)); + } + state.value = value; + return Result::success(); + } catch (const arcs::common_interface::AuboException& e) { + return Result::failure( + ArmErrorCode::CommandFailed, + "[AuboArm] setCabinetDigitalOutput failed: " + + std::string(e.what()) + ", sdk ret=" + + std::to_string(e.code())); + } catch (const std::exception& e) { + return Result::failure( + ArmErrorCode::CommandFailed, + "[AuboArm] setCabinetDigitalOutput failed: " + + std::string(e.what())); + } +#else + return Result::failure( + ArmErrorCode::UnsupportedCommand, + "[AuboArm] setCabinetDigitalOutput failed: Aubo SDK is unavailable"); +#endif +} + ArmState AuboArm::getRobotState() const { ArmState state; diff --git a/cmvr-es/devices/arm/robot_arm.h b/cmvr-es/devices/arm/robot_arm.h index 36d9a8a9..48dab718 100644 --- a/cmvr-es/devices/arm/robot_arm.h +++ b/cmvr-es/devices/arm/robot_arm.h @@ -44,6 +44,34 @@ public: ArmErrorCode::UnsupportedCommand, "ListTCPFrame is not supported by this robot arm"); } + virtual Result getCabinetDigitalInput( + std::uint32_t, + CabinetDigitalInputState& state) const + { + state = {}; + return Result::failure( + ArmErrorCode::UnsupportedCommand, + "cabinet digital input is not supported by this robot arm"); + } + virtual Result getCabinetDigitalOutput( + std::uint32_t, + CabinetDigitalOutputState& state) const + { + state = {}; + return Result::failure( + ArmErrorCode::UnsupportedCommand, + "cabinet digital output is not supported by this robot arm"); + } + virtual Result setCabinetDigitalOutput( + std::uint32_t, + bool, + CabinetDigitalOutputState& state) + { + state = {}; + return Result::failure( + ArmErrorCode::UnsupportedCommand, + "cabinet digital output is not supported by this robot arm"); + } virtual Result torqueOn() = 0; virtual Result torqueOff() = 0; diff --git a/cmvr-es/service/grpc/include/grpc_arm_service.h b/cmvr-es/service/grpc/include/grpc_arm_service.h index d33cfdb2..029c62d5 100644 --- a/cmvr-es/service/grpc/include/grpc_arm_service.h +++ b/cmvr-es/service/grpc/include/grpc_arm_service.h @@ -59,6 +59,18 @@ public: grpc::Status computeForwardKinematics(grpc::ServerContext* context, const api::ComputeForwardKinematics_Request* request, api::ComputeForwardKinematics_Response* response) override; + grpc::Status getCabinetDigitalInput( + grpc::ServerContext* context, + const api::CabinetDigitalInput_Request* request, + api::CabinetDigitalInput_Response* response) override; + grpc::Status getCabinetDigitalOutput( + grpc::ServerContext* context, + const api::CabinetDigitalOutput_Request* request, + api::CabinetDigitalOutput_Response* response) override; + grpc::Status setCabinetDigitalOutput( + grpc::ServerContext* context, + const api::SetCabinetDigitalOutput_Request* request, + api::SetCabinetDigitalOutput_Response* response) override; private: device::DeviceManager& dmgr_; diff --git a/cmvr-es/service/grpc/src/grpc_arm_service.cpp b/cmvr-es/service/grpc/src/grpc_arm_service.cpp index 1cd79f73..4d77f96c 100644 --- a/cmvr-es/service/grpc/src/grpc_arm_service.cpp +++ b/cmvr-es/service/grpc/src/grpc_arm_service.cpp @@ -588,4 +588,107 @@ grpc::Status gRPCArmServiceImpl::computeForwardKinematics(grpc::ServerContext*, return grpc::Status(grpc::StatusCode::UNIMPLEMENTED, "computeForwardKinematics is not implemented"); } +grpc::Status gRPCArmServiceImpl::getCabinetDigitalInput( + grpc::ServerContext*, + const api::CabinetDigitalInput_Request* request, + api::CabinetDigitalInput_Response* response) +{ + auto control_lease = + ControlCommandArbiter::instance().tryAcquireControl(); + if (!control_lease) { + return setControlBusy(response); + } + + try { + const std::string device_id = request->header().device_id(); + auto arm = dmgr_.getDevice(device_id); + if (!arm) { + return setDeviceNotFound(response, device_id); + } + + device::CabinetDigitalInputState state; + const auto result = + arm->getCabinetDigitalInput(request->index(), state); + response->set_count(state.count); + response->set_value(state.value); + if (result.ok()) { + logRpcSuccess("getCabinetDigitalInput", device_id); + } + return setResponseResult(response, result); + } catch (const std::exception& e) { + fillFeedback(response->mutable_header(), false, e.what()); + return grpc::Status(grpc::StatusCode::INTERNAL, e.what()); + } +} + +grpc::Status gRPCArmServiceImpl::getCabinetDigitalOutput( + grpc::ServerContext*, + const api::CabinetDigitalOutput_Request* request, + api::CabinetDigitalOutput_Response* response) +{ + auto control_lease = + ControlCommandArbiter::instance().tryAcquireControl(); + if (!control_lease) { + return setControlBusy(response); + } + + try { + const std::string device_id = request->header().device_id(); + auto arm = dmgr_.getDevice(device_id); + if (!arm) { + return setDeviceNotFound(response, device_id); + } + + device::CabinetDigitalOutputState state; + const auto result = + arm->getCabinetDigitalOutput(request->index(), state); + response->set_count(state.count); + response->set_value(state.value); + response->set_runstate(state.runstate); + response->set_runstate_code(state.runstate_code); + if (result.ok()) { + logRpcSuccess("getCabinetDigitalOutput", device_id); + } + return setResponseResult(response, result); + } catch (const std::exception& e) { + fillFeedback(response->mutable_header(), false, e.what()); + return grpc::Status(grpc::StatusCode::INTERNAL, e.what()); + } +} + +grpc::Status gRPCArmServiceImpl::setCabinetDigitalOutput( + grpc::ServerContext*, + const api::SetCabinetDigitalOutput_Request* request, + api::SetCabinetDigitalOutput_Response* response) +{ + auto control_lease = + ControlCommandArbiter::instance().tryAcquireControl(); + if (!control_lease) { + return setControlBusy(response); + } + + try { + const std::string device_id = request->header().device_id(); + auto arm = dmgr_.getDevice(device_id); + if (!arm) { + return setDeviceNotFound(response, device_id); + } + + device::CabinetDigitalOutputState state; + const auto result = arm->setCabinetDigitalOutput( + request->index(), request->value(), state); + response->set_count(state.count); + response->set_requested_value(request->value()); + response->set_runstate(state.runstate); + response->set_runstate_code(state.runstate_code); + if (result.ok()) { + logRpcSuccess("setCabinetDigitalOutput", device_id); + } + return setResponseResult(response, result); + } catch (const std::exception& e) { + fillFeedback(response->mutable_header(), false, e.what()); + return grpc::Status(grpc::StatusCode::INTERNAL, e.what()); + } +} + } // namespace cmvr::service diff --git a/protos/cmvr/api/arm_command.proto b/protos/cmvr/api/arm_command.proto index 26007b11..bb39d2b7 100644 --- a/protos/cmvr/api/arm_command.proto +++ b/protos/cmvr/api/arm_command.proto @@ -4,197 +4,391 @@ package cmvr.api; import "cmvr/api/common.proto"; +// 机械臂笛卡尔命令使用的参考坐标系。 enum ArmFrameType { + // 机械臂基座坐标系,无单位。 ARM_FRAME_BASE = 0; + // 当前工具/TCP 坐标系,无单位。 ARM_FRAME_TOOL = 1; + // 世界坐标系,无单位。 ARM_FRAME_WORLD = 2; + // 用户自定义坐标系,无单位。 ARM_FRAME_USER = 3; } +// 关节位置命令;数组顺序必须与机械臂关节顺序一致。 message JointPositionCommand { + // 各关节目标角度,单位:rad。 repeated double position = 1; } +// 关节速度命令;数组顺序必须与机械臂关节顺序一致。 message JointVelocityCommand { + // 各关节目标角速度,单位:rad/s。 repeated double velocity = 1; } +// MoveJ 和 MoveL 共用的运动参数。 message MotionOptions { + // 目标速度;MoveJ 单位为 rad/s,MoveL 单位为 m/s。 double velocity = 1; + // 目标加速度;MoveJ 单位为 rad/s^2,MoveL 单位为 m/s^2。 double acceleration = 2; + // 路径交融半径,单位:m;0 表示不交融。 double blend_radius = 3; + // 目标加加速度;MoveJ 单位为 rad/s^3,MoveL 单位为 m/s^3。 double jerk = 4; + // MoveL 规划时各关节的最大角速度限制,单位:rad/s。 repeated double joint_velocity_limits = 5; + // 是否异步执行;true 表示命令提交后立即返回,无单位。 bool asynchronous = 6; } +// TCP 的笛卡尔位姿。 message CartesianPose { + // X 方向位置,单位:m。 double x = 1; + // Y 方向位置,单位:m。 double y = 2; + // Z 方向位置,单位:m。 double z = 3; + // 绕 X 轴的姿态分量,单位:rad。 double rx = 4; + // 绕 Y 轴的姿态分量,单位:rad。 double ry = 5; + // 绕 Z 轴的姿态分量,单位:rad。 double rz = 6; } +// TCP 的笛卡尔速度。 message CartesianVelocity { + // X 方向线速度,单位:m/s。 double vx = 1; + // Y 方向线速度,单位:m/s。 double vy = 2; + // Z 方向线速度,单位:m/s。 double vz = 3; + // 绕 X 轴角速度,单位:rad/s。 double wx = 4; + // 绕 Y 轴角速度,单位:rad/s。 double wy = 5; + // 绕 Z 轴角速度,单位:rad/s。 double wz = 6; } +// 4x4 齐次变换矩阵;前三列为无量纲旋转矩阵,第四列前三项为平移量(m)。 message TransformMatrix4x4 { + // 第一行:m00~m02 无单位,m03 单位为 m。 double m00 = 1; double m01 = 2; double m02 = 3; double m03 = 4; + // 第二行:m10~m12 无单位,m13 单位为 m。 double m10 = 5; double m11 = 6; double m12 = 7; double m13 = 8; + // 第三行:m20~m22 无单位,m23 单位为 m。 double m20 = 9; double m21 = 10; double m22 = 11; double m23 = 12; + // 齐次矩阵最后一行,均无单位,通常为 [0, 0, 0, 1]。 double m30 = 13; double m31 = 14; double m32 = 15; double m33 = 16; } +// 关节空间点到点运动命令。 message MoveJ { + // MoveJ 请求。 message Request { + // 通用请求头,包含目标设备 ID 和请求时间戳。 CommandHeader.Request header = 1; + // 关节目标位置,单位:rad。 JointPositionCommand target = 2; + // 运动参数;速度/加速度/加加速度单位分别为 rad/s、rad/s^2、rad/s^3。 MotionOptions options = 3; } + // MoveJ 执行结果。 message Response { + // 通用响应头,包含成功标志、错误信息和响应时间戳。 CommandHeader.Feedback header = 1; } } +// TCP 笛卡尔直线运动命令。 message MoveL { + // MoveL 请求。 message Request { + // 通用请求头,包含目标设备 ID 和请求时间戳。 CommandHeader.Request header = 1; + // TCP 目标位姿;位置单位为 m,姿态单位为 rad。 CartesianPose target = 2; + // 运动参数;速度/加速度/加加速度单位分别为 m/s、m/s^2、m/s^3。 MotionOptions options = 3; + // 未指定命名坐标系时使用的参考坐标系,无单位。 ArmFrameType frame = 4; - // Optional named frames. When omitted or empty, the arm driver's - // configured default frames are used. + // 可选基准坐标系名称,无单位;不传或为空时使用驱动配置的默认基准坐标系。 optional string base_frame = 5; + // 可选 TCP 坐标系名称,无单位;不传或为空时使用驱动配置的默认 TCP 坐标系。 optional string tcp_frame = 6; } + // MoveL 执行结果。 message Response { + // 通用响应头,包含成功标志、错误信息和响应时间戳。 CommandHeader.Feedback header = 1; } } +// 查询机械臂可用坐标系名称。 message ListFrame { + // 坐标系列表查询请求。 message Request { + // 通用请求头,包含目标设备 ID 和请求时间戳。 CommandHeader.Request header = 1; } + // 坐标系列表查询结果。 message Response { + // 通用响应头,包含成功标志、错误信息和响应时间戳。 CommandHeader.Feedback header = 1; + // 可选坐标系名称列表,无单位。 repeated string frame_names = 2; } } +// 关节速度运动命令。 message SpeedJ { + // SpeedJ 请求。 message Request { + // 通用请求头,包含目标设备 ID 和请求时间戳。 CommandHeader.Request header = 1; + // 各关节目标角速度,单位:rad/s。 JointVelocityCommand velocity = 2; + // 关节角加速度,单位:rad/s^2。 double acceleration = 3; + // 速度命令持续时间,单位:s;具体停止语义由机械臂驱动实现。 double duration = 4; } + // SpeedJ 执行结果。 message Response { + // 通用响应头,包含成功标志、错误信息和响应时间戳。 CommandHeader.Feedback header = 1; } } +// TCP 笛卡尔速度运动命令。 message SpeedL { + // SpeedL 请求。 message Request { + // 通用请求头,包含目标设备 ID 和请求时间戳。 CommandHeader.Request header = 1; + // TCP 目标速度;线速度单位为 m/s,角速度单位为 rad/s。 CartesianVelocity velocity = 2; + // TCP 线加速度,单位:m/s^2。 double acceleration = 3; + // 速度命令持续时间,单位:s;具体停止语义由机械臂驱动实现。 double duration = 4; + // 速度向量所在的参考坐标系,无单位。 ArmFrameType frame = 5; } + // SpeedL 执行结果。 message Response { + // 通用响应头,包含成功标志、错误信息和响应时间戳。 CommandHeader.Feedback header = 1; } } +// 关节位置实时伺服命令。 message ServoJ { + // ServoJ 请求。 message Request { + // 通用请求头,包含目标设备 ID 和请求时间戳。 CommandHeader.Request header = 1; + // 本周期各关节目标角度,单位:rad。 JointPositionCommand target = 2; } + // ServoJ 执行结果。 message Response { + // 通用响应头,包含成功标志、错误信息和响应时间戳。 CommandHeader.Feedback header = 1; } } +// 机械臂关节状态。 message JointState { + // 关节名称列表,无单位;与 position、velocity、effort 按索引对应。 repeated string name = 1; + // 关节实际角度,单位:rad。 repeated double position = 2; + // 关节实际角速度,单位:rad/s。 repeated double velocity = 3; + // 关节实际力矩,单位:N·m。 repeated double effort = 4; + // 状态采样的 Unix 时间戳,单位:s。 double timestamp = 5; } +// 查询关节状态的请求。 message JointRequest { + // 通用请求头,包含目标设备 ID 和请求时间戳。 CommandHeader.Request header = 1; } +// 查询关节状态的响应。 message JointResponse { + // 通用响应头,包含成功标志、错误信息和响应时间戳。 CommandHeader.Feedback header = 1; + // 当前关节状态。 JointState state = 2; } +// 查询 TCP 位姿。 message GetPose { + // 位姿查询请求。 message Request { + // 通用请求头,包含目标设备 ID 和请求时间戳。 CommandHeader.Request header = 1; + // 参考坐标系名称,无单位;为空时使用驱动默认基准坐标系。 string base_link = 2; + // 末端坐标系名称,无单位;为空时使用驱动默认 TCP 坐标系。 string ee_link = 3; } + // 位姿查询结果。 message Response { + // 通用响应头,包含成功标志、错误信息和响应时间戳。 CommandHeader.Feedback header = 1; + // TCP 位姿;位置单位为 m,姿态单位为 rad。 CartesianPose pose = 2; } } +// 指定关节的零位标定命令。 message CalibrateZeroQ { + // 零位标定请求。 message Request { + // 通用请求头,包含目标设备 ID 和请求时间戳。 CommandHeader.Request header = 1; + // 待标定关节名称,无单位。 string joint_name = 2; } + // 零位标定结果。 message Response { + // 通用响应头,包含成功标志、错误信息和响应时间戳。 CommandHeader.Feedback header = 1; } } +// 查询两个坐标系之间的齐次变换矩阵。 message GetPoseMatrix { + // 变换矩阵查询请求。 message Request { + // 通用请求头,包含目标设备 ID 和请求时间戳。 CommandHeader.Request header = 1; + // 参考坐标系名称,无单位。 string base_link = 2; + // 目标末端坐标系名称,无单位。 string ee_link = 3; } + // 变换矩阵查询结果。 message Response { + // 通用响应头,包含成功标志、错误信息和响应时间戳。 CommandHeader.Feedback header = 1; + // 齐次变换矩阵;旋转元素无单位,平移元素单位为 m。 TransformMatrix4x4 matrix = 2; } } +// 根据关节角计算正运动学变换矩阵。 message ComputeForwardKinematics { + // 正运动学计算请求。 message Request { + // 通用请求头,包含目标设备 ID 和请求时间戳。 CommandHeader.Request header = 1; + // 参考坐标系名称,无单位。 string base_link = 2; + // 目标末端坐标系名称,无单位。 string ee_link = 3; + // 用于计算的关节角,单位:rad。 JointPositionCommand joints = 4; } + // 正运动学计算结果。 message Response { + // 通用响应头,包含成功标志、错误信息和响应时间戳。 CommandHeader.Feedback header = 1; + // 齐次变换矩阵;旋转元素无单位,平移元素单位为 m。 TransformMatrix4x4 matrix = 2; } } + +// 读取机械臂控制柜 Standard 数字输入(DI)。 +message CabinetDigitalInput { + // 数字输入读取请求。 + message Request { + // 通用请求头,包含目标设备 ID 和请求时间戳。 + CommandHeader.Request header = 1; + // DI 通道索引,从 0 开始,无单位。 + uint32 index = 2; + } + + // 数字输入读取结果。 + message Response { + // 通用响应头,包含成功标志、错误信息和响应时间戳。 + CommandHeader.Feedback header = 1; + // 控制柜可用 Standard DI 通道总数,无单位。 + uint32 count = 2; + // 输入电平;true 为高电平,false 为低电平,无单位。 + bool value = 3; + } +} + +// 读取机械臂控制柜 Standard 数字输出(DO)。 +message CabinetDigitalOutput { + // 数字输出读取请求。 + message Request { + // 通用请求头,包含目标设备 ID 和请求时间戳。 + CommandHeader.Request header = 1; + // DO 通道索引,从 0 开始,无单位。 + uint32 index = 2; + } + + // 数字输出读取结果。 + message Response { + // 通用响应头,包含成功标志、错误信息和响应时间戳。 + CommandHeader.Feedback header = 1; + // 控制柜可用 Standard DO 通道总数,无单位。 + uint32 count = 2; + // 当前输出电平;true 为高电平,false 为低电平,无单位。 + bool value = 3; + // 控制器对该输出通道配置的运行状态名称,无单位。 + string runstate = 4; + // 控制器输出运行状态枚举值,无单位。 + int32 runstate_code = 5; + } +} + +// 设置机械臂控制柜 Standard 数字输出(DO)。 +message SetCabinetDigitalOutput { + // 数字输出设置请求。 + message Request { + // 通用请求头,包含目标设备 ID 和请求时间戳。 + CommandHeader.Request header = 1; + // DO 通道索引,从 0 开始,无单位。 + uint32 index = 2; + // 目标输出电平;true 为高电平,false 为低电平,无单位。 + bool value = 3; + } + + // 数字输出设置结果。 + message Response { + // 通用响应头,包含成功标志、错误信息和响应时间戳。 + CommandHeader.Feedback header = 1; + // 控制柜可用 Standard DO 通道总数,无单位。 + uint32 count = 2; + // SDK 已接受的目标输出电平,不代表已经回读确认,无单位。 + bool requested_value = 3; + // 写入前该输出通道的控制器运行状态名称,无单位。 + string runstate = 4; + // 写入前该输出通道的控制器运行状态枚举值,无单位。 + int32 runstate_code = 5; + } +} diff --git a/protos/cmvr/api/arm_service.proto b/protos/cmvr/api/arm_service.proto index 459a0bc8..78caa4f9 100644 --- a/protos/cmvr/api/arm_service.proto +++ b/protos/cmvr/api/arm_service.proto @@ -5,21 +5,44 @@ package cmvr.api; import "cmvr/api/common.proto"; import "cmvr/api/arm_command.proto"; +// 机械臂控制服务。除特别说明外,所有接口通过请求头中的 device_id 选择机械臂。 service ArmService { + // 机械臂下电/去使能;不包含数值参数,无单位。 rpc torqueOff(CommandHeader.Request) returns (CommandHeader.Feedback); + // 机械臂上电并使能;不包含数值参数,无单位。 rpc torqueOn(CommandHeader.Request) returns (CommandHeader.Feedback); + // 清除机械臂可恢复故障;不包含数值参数,无单位。 rpc clearFault(CommandHeader.Request) returns (CommandHeader.Feedback); + // 执行关节空间点到点运动;目标角度单位为 rad。 rpc moveJ(MoveJ.Request) returns (MoveJ.Response); + // 执行 TCP 笛卡尔直线运动;位置单位为 m,姿态单位为 rad。 rpc moveL(MoveL.Request) returns (MoveL.Response); + // 查询可用基准坐标系名称;返回名称列表,无单位。 rpc ListBaseFrame(ListFrame.Request) returns (ListFrame.Response); + // 查询可用 TCP 坐标系名称;返回名称列表,无单位。 rpc ListTCPFrame(ListFrame.Request) returns (ListFrame.Response); + // 执行关节速度运动;角速度单位为 rad/s,加速度单位为 rad/s^2。 rpc speedJ(SpeedJ.Request) returns (SpeedJ.Response); + // 执行 TCP 速度运动;线速度单位为 m/s,角速度单位为 rad/s。 rpc speedL(SpeedL.Request) returns (SpeedL.Response); + // 下发单周期关节位置伺服目标;目标角度单位为 rad。 rpc servoJ(ServoJ.Request) returns (ServoJ.Response); + // 停止当前机械臂运动;不包含数值参数,无单位。 rpc stopMotion(CommandHeader.Request) returns (CommandHeader.Feedback); + // 读取关节状态;角度 rad、角速度 rad/s、力矩 N·m。 rpc getJointState(JointRequest) returns (JointResponse); + // 读取 TCP 位姿;位置单位为 m,姿态单位为 rad。 rpc getPose(GetPose.Request) returns (GetPose.Response); + // 对指定关节执行零位标定;关节名称无单位。 rpc calibrateZeroQ(CalibrateZeroQ.Request) returns (CalibrateZeroQ.Response); + // 查询两个坐标系之间的齐次变换矩阵;平移元素单位为 m。 rpc getPoseMatrix(GetPoseMatrix.Request) returns (GetPoseMatrix.Response); + // 根据关节角计算正运动学矩阵;输入角度 rad,输出平移元素 m。 rpc computeForwardKinematics(ComputeForwardKinematics.Request) returns (ComputeForwardKinematics.Response); + // 读取控制柜 Standard DI;通道索引从 0 开始,电平为布尔值。 + rpc getCabinetDigitalInput(CabinetDigitalInput.Request) returns (CabinetDigitalInput.Response); + // 读取控制柜 Standard DO 及其控制器运行状态;通道索引从 0 开始。 + rpc getCabinetDigitalOutput(CabinetDigitalOutput.Request) returns (CabinetDigitalOutput.Response); + // 设置控制柜 Standard DO;仅允许写入未被控制器运行状态管理的通道。 + rpc setCabinetDigitalOutput(SetCabinetDigitalOutput.Request) returns (SetCabinetDigitalOutput.Response); }