Compare commits

..

2 Commits

Author SHA1 Message Date
d15d381b1d add grpc action queue support 2026-09-16 14:33:49 +08:00
9d5a40c4f8 add aubo huayan and seer device support 2026-09-16 14:11:37 +08:00
1010 changed files with 498146 additions and 167 deletions

View File

@ -0,0 +1,450 @@
#ifndef CMVR_ES_AGV_TYPES_H
#define CMVR_ES_AGV_TYPES_H
#include <cstdint>
#include <functional>
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>
#include "common/types/geometry_types.h"
namespace cmvr::device {
/**
* @brief AGV 通用命令/结果错误类别。
*
* 这些枚举描述框架层面的通用结果。厂商或控制器特有错误码应由具体
* AGV 实现转换,或保存在该实现私有的适配参数/细节中。
*/
enum class AgvErrorCode {
OK = 0,
NotConnected,
AlreadyConnected,
ConnectionFailed,
Timeout,
InvalidArgument,
LocalizationLost,
MapNotLoaded,
TaskRejected,
TaskFailed,
TaskCanceled,
CommandFailed,
EmergencyStopped,
Fault,
UnsupportedCommand,
UnknownError
};
/**
* @brief AGV 命令的标准返回值。
*/
struct AgvResult {
AgvErrorCode code{AgvErrorCode::OK};
std::string message{"OK"};
bool ok() const { return code == AgvErrorCode::OK; }
static AgvResult success() { return {AgvErrorCode::OK, "OK"}; }
static AgvResult failure(AgvErrorCode c, const std::string& msg) { return {c, msg}; }
};
/**
* @brief AGV 粗粒度运行模式。
*/
enum class AgvMode {
Unknown = 0,
Disconnected,
Idle,
Manual,
Auto,
Charging,
Paused,
Stopped,
Fault,
EmergencyStop
};
/**
* @brief 当前跟踪的导航任务状态。
*/
enum class AgvTaskState {
None = 0,
Waiting,
Running,
Paused,
Completed,
Failed,
Canceled
};
/**
* @brief 当前跟踪的导航任务类型。
*/
enum class AgvTaskType {
None = 0,
NavigateToPose,
NavigateToStation,
FollowPath,
Dock,
Charge,
Custom
};
/**
* @brief 固定距离平移使用的距离参考模式。
*/
enum class AgvTranslationMode {
Odometry = 0,
Localization
};
/**
* @brief AGV 车体坐标系下的平面速度。
*
* 线速度单位为米/秒,角速度单位为弧度/秒。
*/
struct AgvVelocity {
double vx{0.0};
double vy{0.0};
double wz{0.0};
};
/**
* @brief AGV 车体坐标系下的固定距离平移参数。
*/
struct AgvTranslation {
double distance{0.0};
double vx{0.0};
double vy{0.0};
AgvTranslationMode mode{AgvTranslationMode::Odometry};
};
/**
* @brief 导航通用运动约束和执行选项。
*
* 除非具体实现另有说明,数值限制为 0 表示使用设备或控制器默认值。
*/
struct AgvMotionOptions {
double max_speed{0.0};
double max_angular_speed{0.0};
double max_acceleration{0.0};
double max_angular_acceleration{0.0};
double reach_distance{0.0};
double reach_angle{0.0};
double speed_ratio{1.0};
// 导航默认同步阻塞;调用方只有显式设为 true 才在任务接受后立即返回。
bool asynchronous{false};
int wait_timeout_ms{0};
int poll_interval_ms{0};
int blocked_timeout_ms{0};
// 不带 RPC 框架依赖的取消检查。同步导航等待期间可由
// 上层绑定 deadline/cancel;驱动不得在函数返回后保留该回调。
std::function<bool()> cancellation_requested;
};
/**
* @brief AGV 适配器可选的实现特定参数。
*
* 该结构用于避免抽象接口绑定某一个控制器协议。具体 AGV 驱动可以按需
* 解释操作名、特殊运动模式、设备特定标志等键值。
*/
struct AgvAdapterParams {
std::unordered_map<std::string, std::string> values;
bool empty() const { return values.empty(); }
std::optional<std::string> getString(const std::string& key) const
{
const auto it = values.find(key);
if (it == values.end()) {
return std::nullopt;
}
return it->second;
}
std::optional<double> getDouble(const std::string& key) const
{
const auto value = getString(key);
if (!value) {
return std::nullopt;
}
try {
return std::stod(*value);
} catch (...) {
return std::nullopt;
}
}
std::optional<bool> getBool(const std::string& key) const
{
const auto value = getString(key);
if (!value) {
return std::nullopt;
}
if (*value == "1" || *value == "true" || *value == "yes" || *value == "on") {
return true;
}
if (*value == "0" || *value == "false" || *value == "no" || *value == "off") {
return false;
}
return std::nullopt;
}
};
/**
* @brief 作为 AgvRuntimeState 一部分暴露的电池信息。
*/
struct AgvBatteryState {
double percentage{0.0};
double voltage{0.0};
double current{0.0};
double temperature{0.0};
bool charging{false};
};
/**
* @brief AGV 当前运行状态快照。
*
* 这是 AGV 设备的主要状态查询对象。抽象接口中应避免派生出的便利
* getter;调用方可直接从该快照读取字段。
*/
struct AgvRuntimeState {
double timestamp{0.0};
AgvMode mode{AgvMode::Unknown};
bool connected{false};
bool localized{false};
bool moving{false};
bool fault{false};
bool emergency_stopped{false};
math::Pose2d pose{};
AgvVelocity velocity{};
AgvBatteryState battery{};
std::string current_map;
std::string current_station;
std::string last_error;
};
/**
* @brief AGV 抽象层可见的地图站点/路径点。
*/
struct AgvStation {
std::string id;
std::string type;
math::Pose2d pose{};
std::string description;
};
/**
* @brief 显式导航路径中的一段站点到站点路径。
*/
struct AgvPathSegment {
std::string source_station;
std::string target_station;
};
/**
* @brief AGV 扫图过程中产生的数据文件。
*
* content 可保存控制器返回的二进制内容,例如 SEER Robokit 的 rawmap zip 包。
*/
struct AgvMappingDataFile {
std::string name;
std::string content;
};
/**
* @brief 从控制器增量获取的扫图数据批次。
*/
struct AgvMappingData {
int start_index{0};
int next_index{0};
std::vector<AgvMappingDataFile> files;
};
/**
* @brief 上位机请求的统一地图维度。
*
* 该枚举只表示上位机希望得到 2D、3D 或两者都要;不表示厂商文件格式。
* 厂商原始地图必须由具体 AGV 驱动转换为下面的统一地图结构。
*/
enum class AgvMapDimension {
Unspecified = 0,
Map2D,
Map3D,
Map2DAnd3D
};
/**
* @brief 地图流中的更新类型。
*/
enum class AgvMapUpdateType {
Unspecified = 0,
Snapshot,
Incremental,
Reset
};
/**
* @brief 统一语义地图对象类型。
*/
enum class AgvMapObjectType {
Unspecified = 0,
Station,
Line,
Area,
QrTag,
Reflector,
BinLocation,
ExternalDevice
};
/**
* @brief 地图坐标系下的三维点,单位:米。
*/
struct AgvMapPoint3D {
double x{0.0};
double y{0.0};
double z{0.0};
};
/**
* @brief 统一语义对象。几何点均使用地图坐标系,单位:米。
*/
struct AgvMapObject {
std::string id;
AgvMapObjectType type{AgvMapObjectType::Unspecified};
std::vector<AgvMapPoint3D> points;
double heading{0.0};
std::unordered_map<std::string, std::string> properties;
};
/**
* @brief 统一 2D 地图。
*
* data 采用行优先顺序,取值约定为 -1 未知、0 空闲、100 占据。
* 当厂商地图只提供矢量/语义元素时,data 可以为空,objects 仍然有效。
*/
struct AgvUnifiedMap2D {
std::string frame_id{"map"};
double timestamp{0.0};
double resolution{0.0};
std::uint32_t width{0};
std::uint32_t height{0};
math::Pose2d origin{};
std::vector<std::int32_t> data;
std::vector<AgvMapObject> objects;
};
/**
* @brief 统一 3D 点样本,坐标单位:米。
*/
struct AgvMapPointSample3D {
double x{0.0};
double y{0.0};
double z{0.0};
float intensity{0.0F};
std::uint32_t ring{0};
double time_offset{0.0};
};
/**
* @brief 统一 3D 占据体素。
*/
struct AgvMapVoxel3D {
std::int32_t x{0};
std::int32_t y{0};
std::int32_t z{0};
float probability{-1.0F};
};
/**
* @brief 统一 3D 平面特征。
*/
struct AgvMapPlane3D {
AgvMapPoint3D center;
AgvMapPoint3D normal;
double d{0.0};
double radius{0.0};
};
/**
* @brief 统一 3D 地图。
*/
struct AgvUnifiedMap3D {
std::string frame_id{"map"};
double timestamp{0.0};
double voxel_resolution{0.0};
std::vector<AgvMapPointSample3D> points;
std::vector<AgvMapVoxel3D> voxels;
std::vector<AgvMapPlane3D> planes;
std::vector<AgvMapObject> objects;
};
/**
* @brief 地图流读取参数。
*/
struct AgvMapStreamOptions {
AgvMapDimension dimension{AgvMapDimension::Unspecified};
std::string map_name;
std::string resume_token;
bool snapshot{true};
bool incremental{false};
int max_chunk_bytes{0};
int wait_timeout_ms{1000};
};
/**
* @brief 建图/扫图启动参数。
*/
struct AgvMappingOptions {
AgvMapDimension dimension{AgvMapDimension::Unspecified};
std::string map_name;
bool real_time{false};
};
/**
* @brief 统一地图流中的单条更新。
*/
struct AgvUnifiedMapUpdate {
std::string map_id;
std::string session_id;
std::uint64_t sequence{0};
std::string resume_token;
AgvMapDimension dimension{AgvMapDimension::Unspecified};
AgvMapUpdateType update_type{AgvMapUpdateType::Unspecified};
std::string frame_id{"map"};
double timestamp{0.0};
bool snapshot_begin{false};
bool snapshot_end{false};
std::uint32_t chunk_index{0};
std::uint32_t chunk_count{0};
std::optional<AgvUnifiedMap2D> map_2d;
std::optional<AgvUnifiedMap3D> map_3d;
};
/**
* @brief 当前导航任务状态。
*
* 该状态独立于 AgvRuntimeState,因为导航任务可能处于排队、暂停、
* 完成或失败状态,而车辆本体仍然保持连接并处于正常状态。
*/
struct AgvNavigationStatus {
AgvTaskState state{AgvTaskState::None};
AgvTaskType type{AgvTaskType::None};
double progress{0.0};
std::string message;
};
/**
* @brief 兼容旧 AGV 状态 API 命名的别名。
*/
using AGVState = AgvRuntimeState;
} // namespace cmvr::device
#endif // CMVR_ES_AGV_TYPES_H

View File

@ -2,6 +2,7 @@
#define CMVR_ES_ARM_TYPES_H
#include <cstdint>
#include <functional>
#include <string>
#include <vector>
@ -157,6 +158,9 @@ struct MotionOptions {
double jerk{5.0};
std::vector<double> joint_velocity_limits;
bool asynchronous{false};
// Optional cooperative cancellation used by synchronous ActionQueue
// motion. Drivers must not retain this callback after the command returns.
std::function<bool()> cancellation_requested;
};
struct ServoOptions {

View File

@ -6,4 +6,42 @@ agv {
port: 8080
}
}
agvs {
# 当前部署的控制器型号为 SRC1100;该值是设备实例 ID,不是后端类型名。
id: "src1100"
seer_robokit_agv {
ip: "192.168.192.5"
port_status: 19204
port_control: 19205
port_nav: 19206
port_config: 19207
port_other: 19210
port_push: 19301
recv_timeout_ms: 1000
control_nick_name: "cmvr-es"
enable_state_push: true
state_push_interval_ms: 200
state_push_included_fields: "x"
state_push_included_fields: "y"
state_push_included_fields: "angle"
state_push_included_fields: "vx"
state_push_included_fields: "vy"
state_push_included_fields: "w"
state_push_included_fields: "battery_level"
state_push_included_fields: "battery_temp"
state_push_included_fields: "charging"
state_push_included_fields: "voltage"
state_push_included_fields: "current"
state_push_included_fields: "current_map"
state_push_included_fields: "current_station"
state_push_included_fields: "confidence"
state_push_included_fields: "emergency"
state_push_included_fields: "fatals"
state_push_included_fields: "errors"
enable_map_update: true
map_update_interval_ms: 1000
map_update_history_size: 8
}
}
}

View File

@ -17,6 +17,7 @@ arm {
tool_frame: "tool0"
username: "aubo"
password: "123456"
auto_enable: true
}
}
}

View File

@ -16,6 +16,7 @@ arm {
joint_names: "joint_6"
base_frame: "Base"
tool_frame: "TCP"
auto_enable: true
}
}
}

View File

@ -108,4 +108,12 @@ device_manager {
config_file: "devices/agv/agv.pb.txt"
enable: false
}
devices {
# 仙工控制器实例;与 agv.pb.txt 中的设备 ID 保持一致。
id: "src1100"
type: DEVICE_TYPE_AGV
config_file: "devices/agv/agv.pb.txt"
enable: false
}
}

View File

@ -1,4 +1,5 @@
add_subdirectory(my_agv)
add_subdirectory(seer_robokit)
add_library(agv INTERFACE)
@ -7,6 +8,7 @@ target_include_directories(agv INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(agv
INTERFACE
cmvr_es::device::my_agv
cmvr_es::device::seer_robokit_agv
cmvr_es::proto
)

View File

@ -6,32 +6,271 @@
#define CMVR_ES_ABSTRACT_AGV_H
#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include "common/types/agv/agv_types.h"
#include "devices/abstract_device.h"
namespace cmvr::device{
class AbstractAGV: public AbstractDevice {
public:
namespace cmvr::device {
/**
* @brief AGV/移动底盘设备抽象基类。
*
* 该接口只描述通用 AGV 能力。控制器特有的请求/响应字段应放在具体
* 驱动类中;当公共 API 需要扩展点时,可通过 AgvAdapterParams 传递。
*/
class AbstractAGV : public AbstractDevice {
public:
AbstractAGV() = default;
~AbstractAGV() override=default;
~AbstractAGV() override = default;
DeviceKind kind() const noexcept override { return DeviceKind::AGV; }
virtual bool getState(AGVState &state) { return true; }
// navigation
virtual bool eStop() { return true; }
virtual bool goHome() { return true; }
virtual bool moveto(math::Pose2d &location, double speed_ratio) { return true; }
virtual bool setVelocity(math::Vec3 linear, math::Vec3 angular) { return true; }
/**
* @brief 获取 AGV 运行状态快照。
*/
virtual AgvRuntimeState runtimeState() const { return {}; }
// map
virtual bool initMap(float resolution, int width, int height) { return true; }
virtual bool updateMap() { return true; }
virtual bool saveMap(const std::string& file_path) { return true; }
virtual bool loadMap(const std::string& file_path) { return true; }
/**
* @brief 获取当前导航任务状态。
*/
virtual AgvNavigationStatus navigationStatus() const { return {}; }
protected:
AGVState state_;
};
}
/**
* @brief 触发 AGV 急停行为。
*/
virtual AgvResult emergencyStop()
{
return AgvResult::failure(AgvErrorCode::UnsupportedCommand, "emergencyStop not implemented");
}
#endif //CMVR_ES_ABSTRACT_AGV_H
/**
* @brief 清除可恢复的 AGV 故障或告警。
*/
virtual AgvResult clearFault()
{
return AgvResult::failure(AgvErrorCode::UnsupportedCommand, "clearFault not implemented");
}
virtual AgvResult relocalize(const math::Pose2d& pose)
{
(void)pose;
return AgvResult::failure(AgvErrorCode::UnsupportedCommand,"relocalize not implemented");
}
/**
* @brief 发起到世界/地图位姿的导航任务。
*/
virtual AgvResult navigateToPose(
const math::Pose2d& pose,
const AgvMotionOptions& options = {},
const AgvAdapterParams& adapter_params = AgvAdapterParams{})
{
(void)pose;
(void)options;
(void)adapter_params;
return AgvResult::failure(AgvErrorCode::UnsupportedCommand, "navigateToPose not implemented");
}
/**
* @brief 发起到指定地图站点的导航任务。
*/
virtual AgvResult navigateToStation(
const std::string& station_id,
const AgvMotionOptions& options = {},
const AgvAdapterParams& adapter_params = AgvAdapterParams{})
{
(void)station_id;
(void)options;
(void)adapter_params;
return AgvResult::failure(AgvErrorCode::UnsupportedCommand, "navigateToStation not implemented");
}
/**
* @brief 发起显式站点到站点路径导航任务。
*/
virtual AgvResult followPath(
const std::vector<AgvPathSegment>& path)
{
(void)path;
return AgvResult::failure(AgvErrorCode::UnsupportedCommand, "followPath not implemented");
}
/**
* @brief 按指定速度执行固定距离平移。
*
* 返回成功表示控制器已经接受命令,不表示运动已经完成。
*/
virtual AgvResult translate(const AgvTranslation& translation)
{
(void)translation;
return AgvResult::failure(
AgvErrorCode::UnsupportedCommand,
"translate not implemented");
}
/**
* @brief 发起显式站点到站点路径导航任务,并指定同步/异步选项。
*
* 保留单参数虚函数以兼容已有派生类;旧实现会由本重载转发。
*/
virtual AgvResult followPath(
const std::vector<AgvPathSegment>& path,
const AgvMotionOptions& options)
{
(void)options;
return followPath(path);
}
/**
* @brief 暂停当前导航任务,如果设备支持。
*/
virtual AgvResult pauseNavigation()
{
return AgvResult::failure(AgvErrorCode::UnsupportedCommand, "pauseNavigation not implemented");
}
/**
* @brief 恢复已暂停的导航任务,如果设备支持。
*/
virtual AgvResult resumeNavigation()
{
return AgvResult::failure(AgvErrorCode::UnsupportedCommand, "resumeNavigation not implemented");
}
/**
* @brief 取消当前导航任务,如果设备支持。
*/
virtual AgvResult cancelNavigation()
{
return AgvResult::failure(AgvErrorCode::UnsupportedCommand, "cancelNavigation not implemented");
}
/**
* @brief 向 AGV 下发低层速度控制指令。
*
* 该接口不同于导航命令。具体实现应明确速度控制在导航过程中是中断
* 导航、与导航共存,还是被拒绝执行。
*/
virtual AgvResult setVelocity(const AgvVelocity& velocity)
{
(void)velocity;
return AgvResult::failure(AgvErrorCode::UnsupportedCommand, "setVelocity not implemented");
}
/**
* @brief 通过下发零速度停止低层速度控制。
*
* 该接口不表示取消正在执行的导航任务;取消导航请使用
* cancelNavigation()。
*/
virtual AgvResult stopVelocityControl()
{
return setVelocity(AgvVelocity{});
}
/**
* @brief 查询 AGV 可用地图名称列表。
*/
virtual AgvResult listMaps(std::vector<std::string>& maps) const
{
(void)maps;
return AgvResult::failure(AgvErrorCode::UnsupportedCommand, "listMaps not implemented");
}
/**
* @brief 查询当前活动地图中的站点列表。
*/
virtual AgvResult listStations(std::vector<AgvStation>& stations) const
{
(void)stations;
return AgvResult::failure(AgvErrorCode::UnsupportedCommand, "listStations not implemented");
}
/**
* @brief 切换当前活动地图。
*/
virtual AgvResult switchMap(const std::string& map_name)
{
(void)map_name;
return AgvResult::failure(AgvErrorCode::UnsupportedCommand, "switchMap not implemented");
}
/**
* @brief 按名称上传或替换地图。
*/
virtual AgvResult uploadMap(const std::string& map_name, const std::string& content)
{
(void)map_name;
(void)content;
return AgvResult::failure(AgvErrorCode::UnsupportedCommand, "uploadMap not implemented");
}
/**
* @brief 按名称下载地图内容。
*/
virtual AgvResult downloadMap(const std::string& map_name, std::string& content) const
{
(void)map_name;
(void)content;
return AgvResult::failure(AgvErrorCode::UnsupportedCommand, "downloadMap not implemented");
}
/**
* @brief 开始扫图/建图。
*/
virtual AgvResult startMapping(const AgvMappingOptions& options = {})
{
(void)options;
return AgvResult::failure(AgvErrorCode::UnsupportedCommand, "startMapping not implemented");
}
/**
* @brief 从指定下标开始获取厂商原始扫图数据。
*
* 该接口主要保留给具体驱动内部使用。对外 gRPC 地图流应优先使用
* getUnifiedMapUpdate(),避免把厂商文件格式暴露给上位机。
*/
virtual AgvResult getMappingData(int start_index, AgvMappingData& data) const
{
(void)start_index;
(void)data;
return AgvResult::failure(AgvErrorCode::UnsupportedCommand, "getMappingData not implemented");
}
/**
* @brief 获取统一地图更新。
*
* after_sequence 为 0 时通常返回最近可用的全量快照;大于 0 时返回
* 指定序号之后的下一条更新。如果当前没有新地图,具体实现可在
* options.wait_timeout_ms 内等待后台更新线程写入缓存。
*/
virtual AgvResult getUnifiedMapUpdate(
std::uint64_t after_sequence,
const AgvMapStreamOptions& options,
AgvUnifiedMapUpdate& update) const
{
(void)after_sequence;
(void)options;
(void)update;
return AgvResult::failure(AgvErrorCode::UnsupportedCommand, "getUnifiedMapUpdate not implemented");
}
/**
* @brief 停止扫图/建图。
*/
virtual AgvResult stopMapping()
{
return AgvResult::failure(AgvErrorCode::UnsupportedCommand, "stopMapping not implemented");
}
};
} // namespace cmvr::device
#endif // CMVR_ES_ABSTRACT_AGV_H

View File

@ -7,6 +7,7 @@
#include "common/base/logging/logger.h"
#include "devices/agv/abstract_agv.h"
#include "devices/agv/my_agv/include/my_agv.h"
#include "seer_robokit_agv.h"
namespace cmvr::device {
@ -30,6 +31,16 @@ public:
backend.set_id(cfg.id());
return std::make_shared<MyAgv>(backend);
}
case config::AGVDeviceConfig::kSeerRobokitAgv:
{
if (!cfg.seer_robokit_agv().id().empty() && cfg.seer_robokit_agv().id() != cfg.id()) {
CMVR_LOG(ERROR) << "[AGVFactory]: AGV id does not match backend id: " << cfg.id();
return nullptr;
}
auto backend = cfg.seer_robokit_agv();
backend.set_id(cfg.id());
return std::make_shared<SeerRobokitAgv>(backend);
}
case config::AGVDeviceConfig::BACKEND_NOT_SET:
default:

View File

@ -20,15 +20,13 @@ public:
bool stop() override;
bool update() override;
bool getState(AGVState& state) override;
bool eStop() override;
bool goHome() override;
bool moveto(math::Pose2d& location, double speed_ratio) override;
bool setVelocity(math::Vec3 linear, math::Vec3 angular) override;
bool initMap(float resolution, int width, int height) override;
bool updateMap() override;
bool saveMap(const std::string& file_path) override;
bool loadMap(const std::string& file_path) override;
AgvRuntimeState runtimeState() const override;
AgvResult emergencyStop() override;
AgvResult navigateToPose(
const math::Pose2d& pose,
const AgvMotionOptions& options = {},
const AgvAdapterParams& adapter_params = AgvAdapterParams{}) override;
AgvResult setVelocity(const AgvVelocity& velocity) override;
private:
config::MyAgvConfig config_;

View File

@ -27,49 +27,27 @@ bool MyAgv::update()
return true;
}
bool MyAgv::getState(AGVState&)
AgvRuntimeState MyAgv::runtimeState() const
{
return true;
return {};
}
bool MyAgv::eStop()
AgvResult MyAgv::emergencyStop()
{
return true;
return AgvResult::success();
}
bool MyAgv::goHome()
AgvResult MyAgv::navigateToPose(
const math::Pose2d&,
const AgvMotionOptions&,
const AgvAdapterParams&)
{
return true;
return AgvResult::success();
}
bool MyAgv::moveto(math::Pose2d&, double)
AgvResult MyAgv::setVelocity(const AgvVelocity&)
{
return true;
}
bool MyAgv::setVelocity(math::Vec3, math::Vec3)
{
return true;
}
bool MyAgv::initMap(float, int, int)
{
return true;
}
bool MyAgv::updateMap()
{
return true;
}
bool MyAgv::saveMap(const std::string&)
{
return true;
}
bool MyAgv::loadMap(const std::string&)
{
return true;
return AgvResult::success();
}
} // namespace cmvr::device

View File

@ -0,0 +1,29 @@
add_library(seer_robokit_agv SHARED
src/seer_robokit_agv.cpp
src/seer_robokit_transport.cpp
src/seer_robokit_control.cpp
src/seer_robokit_status.cpp
src/seer_robokit_navigation.cpp
src/seer_robokit_navigation_wait.cpp
src/seer_robokit_map.cpp
include/seer_robokit_agv.h
include/seer_robokit_protocol.h
include/seer_robokit_utils.h
include/seer_robokit_navigation_utils.h
include/seer_robokit_pgv_utils.h
)
target_include_directories(seer_robokit_agv
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
${PROJECT_SOURCE_DIR}/cmvr-es
)
target_link_libraries(seer_robokit_agv
PUBLIC
cmvr_es::proto
jsoncpp
)
add_library(cmvr_es::device::seer_robokit_agv ALIAS seer_robokit_agv)
install(TARGETS seer_robokit_agv LIBRARY DESTINATION lib)

View File

@ -0,0 +1,375 @@
# 仙工 SEER Robokit AGV 适配器
`SeerRobokitAgv` 将仙工 SEER Robokit TCP/IP API 适配为 CMVR 的通用
`AbstractAGV`/`cmvr.api.AgvService`。厂商命令号、端口、抢占控制权、状态轮询、
地图格式转换和错误码解析都封装在本目录内。
本项目现场使用的控制器型号仍是 SRC1100,所以设备实例 ID 保持为
`src1100`;它只用于配置关联和 gRPC 路由,不再作为驱动实现名称。后端配置字段
使用 `seer_robokit_agv`,目录、类、库和测试统一使用 `seer_robokit` /
`SeerRobokitAgv` 命名。
从旧版本升级时,外部部署配置必须同步使用 `seer_robokit_agv { ... }`,并把
配置路径更新为 `devices/agv/seer_robokit.pb.txt`;设备实例 ID 保持不变。程序、
外部配置和部署脚本需要原子升级,不能把旧字段或旧路径与新二进制混用。
返回 [Devices 模块指南](../../README.md) 或 [项目总览](../../../../README.md)。
## 代码与配置
所有驱动头文件统一放在 `include/`,实现文件统一放在 `src/`;测试源码独立放在
`tests/`。除 `seer_robokit_agv.h` 外,其余头文件均为驱动内部实现细节。
- 公共类声明:[`include/seer_robokit_agv.h`](include/seer_robokit_agv.h)
- 导航轮询工具:
[`include/seer_robokit_navigation_utils.h`](include/seer_robokit_navigation_utils.h)
- PGV 参数转换:
[`include/seer_robokit_pgv_utils.h`](include/seer_robokit_pgv_utils.h)
- 协议常量:[`include/seer_robokit_protocol.h`](include/seer_robokit_protocol.h)
- 通用解析工具:[`include/seer_robokit_utils.h`](include/seer_robokit_utils.h)
- 生命周期和连接:[`src/seer_robokit_agv.cpp`](src/seer_robokit_agv.cpp)
- TCP 帧与收发:[`src/seer_robokit_transport.cpp`](src/seer_robokit_transport.cpp)
- 控制权与受控命令:[`src/seer_robokit_control.cpp`](src/seer_robokit_control.cpp)
- 状态与推送缓存:[`src/seer_robokit_status.cpp`](src/seer_robokit_status.cpp)
- 导航命令:[`src/seer_robokit_navigation.cpp`](src/seer_robokit_navigation.cpp)
- 阻塞等待与停车确认:
[`src/seer_robokit_navigation_wait.cpp`](src/seer_robokit_navigation_wait.cpp)
- 地图和建图:[`src/seer_robokit_map.cpp`](src/seer_robokit_map.cpp)
- 设备配置:
[`../../../config/devices/agv/agv.pb.txt`](../../../config/devices/agv/agv.pb.txt)
- DeviceManager 配置:
[`../../../config/manager/device_manager.pb.txt`](../../../config/manager/device_manager.pb.txt)
- gRPC API:
[`../../../../protos/cmvr/api/agv_service.proto`](../../../../protos/cmvr/api/agv_service.proto)、
[`../../../../protos/cmvr/api/agv_command.proto`](../../../../protos/cmvr/api/agv_command.proto)、
[`../../../../protos/cmvr/msgs/agv.proto`](../../../../protos/cmvr/msgs/agv.proto)
## 配置和启动
现场配置至少需要修改控制器 IP;端口通常保持仙工默认值:
```textproto
agv {
agvs {
id: "src1100"
seer_robokit_agv {
ip: "192.168.192.5"
port_status: 19204
port_control: 19205
port_nav: 19206
port_config: 19207
port_other: 19210
port_push: 19301
recv_timeout_ms: 1000
control_nick_name: "cmvr-es"
enable_state_push: true
state_push_interval_ms: 200
enable_map_update: true
map_update_interval_ms: 1000
map_update_history_size: 8
}
}
}
```
还要在 `device_manager.pb.txt` 中确认同一个设备 id,并在完成现场安全检查后把
`enable` 改为 `true`。源码默认配置故意保持关闭。
```textproto
devices {
id: "src1100"
type: DEVICE_TYPE_AGV
config_file: "devices/agv/seer_robokit.pb.txt"
enable: true
}
```
构建、安装并启动:
```bash
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j2
cmake --install build
./output/bin/cmvr_es
```
`output/bin/cmvr_es` 默认读取 `output/bin/config/`。修改源码配置后需要重新安装,
或通过程序支持的外部配置入口启动,不能只修改源码文件后继续使用旧的
`output/` 配置。
## 控制器端口和命令
| 端口 | 主要用途 | 当前使用的命令 |
| --- | --- | --- |
| `19204` | 状态、站点、地图和建图文件 | `1004`、`1007`、`1020`、`1101`、`1110`、`1300`、`1301`、`1780`、`1800` |
| `19205` | 底盘控制 | `2000`、`2010`、`2022` |
| `19206` | 导航任务 | `3001`、`3002`、`3003`、`3051`、`3066`、`3067` |
| `19207` | 控制权、清错、地图上传下载 | `4005`、`4009`、`4010`、`4011` |
| `19210` | 开始/停止建图 | `6100`、`6101` |
| `19301` | 机器人状态推送 | `9300`/`19300` 配置,`19301` 推送 |
所有会改变机器人或控制器状态的调用都在 SEER Robokit 子类内部先通过 `4005`
抢权,负载为稳定的 `nick_name`,成功后才发送实际命令。普通命令集中走
`sendControlledCommand_`;`emergencyStop` 为保证 `2000` 和导航取消之间不被
插入其他命令,会在同一个控制序列锁内只抢一次权。只读查询不抢权。不要在
gRPC 客户端另做一套租约逻辑。
## gRPC 接口概览
默认示例端点为 `127.0.0.1:50052`;远程部署时替换为 CMVR 服务所在主机,
不是 SEER Robokit 原生 TCP 端口。
| gRPC 方法 | SEER Robokit 行为 | 说明 |
| --- | --- | --- |
| `getRuntimeState` | 推送缓存,缺失时查询 `1004/1007/1300` | 只读 |
| `getNavigationStatus` | 跟踪任务查询 `1110`,无精确上下文时回退 `1020` | 只读;同步等待另用 `1101` 确认停车 |
| `emergencyStop` | `2000`,再执行 `3003` 或 `3067` | 软件停止,不替代硬件急停 |
| `clearFault` | `4009` | 抢权后发送无请求体命令,清除可恢复故障 |
| `navigateToPose` | `3051` + `freeGo` | 地图绝对位姿,仅双轮差速底盘 |
| `navigateToStation` | `3051` | 站点路径导航;PGV 二次定位也使用此方法 |
| `followPath` | `3066` | 仙工“指定路径导航”,与 `3051` 不同 |
| `pauseNavigation` / `resumeNavigation` | `3001` / `3002` | 导航控制 |
| `cancelNavigation` | `3003`,路径队列使用 `3067` | 取消当前跟踪任务 |
| `setVelocity` / `stopVelocityControl` | `2010` | 车体速度;停止时发送全零速度 |
| `listMaps` / `listStations` | `1300` / `1301` | 只读 |
| `switchMap` | `2022` | 会改变定位所用地图 |
| `uploadMap` / `downloadMap` | `4010` / `4011` | 上传会抢权,下载只读 |
| `startMapping` / `stopMapping` | `6100` / `6101` | 建图控制 |
| `streamMap` | `1780/1800` 加内部解析和缓存 | 对外发送统一 2D/3D 地图,不暴露 `.smap` 原始格式 |
查询运行状态:
```bash
grpcurl -plaintext \
-d '{"header":{"deviceId":"src1100"}}' \
127.0.0.1:50052 \
cmvr.api.AgvService/getRuntimeState
```
查询导航状态:
```bash
grpcurl -plaintext \
-d '{"header":{"deviceId":"src1100"}}' \
127.0.0.1:50052 \
cmvr.api.AgvService/getNavigationStatus
```
列出地图和当前地图站点:
```bash
grpcurl -plaintext \
-d '{"header":{"deviceId":"src1100"}}' \
127.0.0.1:50052 \
cmvr.api.AgvService/listMaps
grpcurl -plaintext \
-d '{"header":{"deviceId":"src1100"}}' \
127.0.0.1:50052 \
cmvr.api.AgvService/listStations
```
## 导航的同步语义
`navigateToPose`、`navigateToStation` 和 `followPath` 默认同步阻塞。控制器接受
命令后,适配器继续轮询精确任务状态,并结合 `1101` 状态确认底盘已经停车;
到达、失败、取消、遇障停止或超时后才返回。`waitTimeoutMs` 为 `0` 时使用
适配器默认值,当前为 10 分钟;`pollIntervalMs` 为 `0` 时当前使用 200 ms。
连续观察到障碍阻挡且底盘已经停止后,适配器会主动取消该导航;清理结果不明确
时还可能发送软件停止。任务不会在障碍消失后由本次调用自动恢复。等待超时、
RPC cancel 和 deadline 到期也会进入安全取消及停车确认,因此函数返回时间可能
晚于最初发现障碍或取消请求的时刻。
调用方的 gRPC deadline 必须大于预计行程时间和 `waitTimeoutMs`。RPC 被取消或
deadline 到期时,适配器会进入安全取消/停车确认流程。显式设置
`"asynchronous":true` 后不会等待任务终态:站点导航和指定路径导航在控制器
接受后返回;自由导航仍会做最长约 1.5 秒的启动确认。异步成功不代表已经到点。
`AgvMotionOptions` 中,SEER Robokit 的 `3051` 导航当前支持:
| gRPC 字段 | 控制器字段 | 单位 |
| --- | --- | --- |
| `maxSpeed` | `max_speed` | m/s |
| `maxAngularSpeed` | `max_wspeed` | rad/s |
| `maxAcceleration` | `max_acc` | m/s² |
| `maxAngularAcceleration` | `max_wacc` | rad/s² |
| `reachDistance` | `reach_dist` | m |
| `reachAngle` | `reach_angle` | rad |
`asynchronous`、`waitTimeoutMs` 和 `pollIntervalMs` 由适配器本地执行。
`speedRatio` 当前没有对应的 SEER Robokit 序列化字段。`followPath` 的运动选项当前只
控制同步/异步等待、超时和轮询;在没有确认 `3066` 的速度字段前,不会猜测性地
写入每个路径段。
## 固定路径导航的 PGV 二次定位
仙工文档 [“路径导航 / 2. 固定路径导航 PGV 二次定位调整”](https://seer-group.feishu.cn/wiki/Q26SwaNoGisuLWk2vCxcPfVWn2e)
说明 PGV 参数是 `3051 / robot_task_gotarget_req` 的顶层可选字段。因此在 CMVR
中应调用 `navigateToStation`,不是 `followPath`。后者对应另一条
`3066 / 指定路径导航` 协议,现有仙工资料和仓库历史都没有证明 `3066` 支持
PGV 字段。
PGV 参数通过 `adapterParams.values` 传入。protobuf map 的值是字符串,
SEER Robokit 适配器会在任何状态查询、抢权和运动命令之前完成校验,再转换为控制器
要求的 JSON `bool`/`number`:
| `adapterParams.values` 键 | 输出 JSON 类型 | 含义 |
| --- | --- | --- |
| `use_pgv` | `bool` | 使用上视 PGV |
| `use_down_pgv` | `bool` | 使用下视 PGV |
| `pgv_adjust_dist` | `number` | 最大调整半径,必须为有限非负数;用于仙工第 3/4 种调整方式 |
| `pgv_adjust_cx` | `number` | 调整范围圆心在二维码坐标系下的 X 偏移;用于第 4 种方式 |
| `pgv_adjust_cy` | `number` | 调整范围圆心在二维码坐标系下的 Y 偏移;用于第 4 种方式 |
| `pgv_x_adjust` | `number` | 仅调整小车 X 方向误差;用于第 2 种方式 |
所有数字都必须是完整、有限的数字字符串;偏移量允许正负。适配器不臆造
调整半径上限,也不假定上视和下视一定互斥,这些约束应由实际 PGV 安装、标定和
当前控制器版本确定。显式的 `"false"` 和 `"0"` 仍会作为原生布尔值和数值
发给控制器;没有给出的字段不会发送。第 2/3/4 种方式由控制器和站点配置决定,
本接口只传递与所选方式匹配的调整参数。
一旦请求中出现任意 PGV 键,适配器只允许同时出现 `source_id`、`task_id` 和
上述 PGV 字段;`operation`、`jack_height`、脚本名或未知扩展字段都会在状态
查询和抢权前被拒绝,避免一次 PGV 导航意外夹带顶升、货叉、IO 或脚本动作。
没有 PGV 键的既有站点导航扩展语义保持不变。
上视 PGV 示例。该命令会让机器人导航到 `AP1`,只能在确认地图、站点、PGV
标定、行驶区域和急停人员后执行:
```bash
grpcurl -plaintext \
-d '{
"header":{"deviceId":"src1100"},
"stationId":"AP1",
"options":{
"maxSpeed":0.15,
"maxAcceleration":0.15,
"asynchronous":false,
"waitTimeoutMs":300000,
"pollIntervalMs":200
},
"adapterParams":{"values":{
"use_pgv":"true",
"pgv_adjust_dist":"0.3",
"pgv_adjust_cx":"-0.3",
"pgv_adjust_cy":"0"
}}
}' \
127.0.0.1:50052 \
cmvr.api.AgvService/navigateToStation
```
下视 PGV 使用同一接口,把 `use_down_pgv` 设为字符串 `"true"`;其他调整
字段是否需要传入取决于现场定位方案。如果控制器版本要求明确起点,可在同一个
map 中增加 `"source_id":"实际起点站点"`;默认起点为 `SELF_POSITION`。
仙工在线文档当前有两处拼写不一致:
- 代码块出现了损坏字段 `pgv_adjustuse_pgv_dist`;适配器会拒绝它,正确字段是
`pgv_adjust_dist`;
- 表格写成 `pgv_ajdust_cy`,而示例和仓库旧版序列化代码使用
`pgv_adjust_cy`。适配器兼容接收前者,但只向控制器输出规范字段
`pgv_adjust_cy`;两个拼写同时出现会因歧义被拒绝。
C++ 调用同样复用通用扩展参数:
```cpp
cmvr::device::AgvMotionOptions options;
options.max_speed = 0.15;
options.max_acceleration = 0.15;
cmvr::device::AgvAdapterParams adapter;
adapter.values["use_pgv"] = "true";
adapter.values["pgv_adjust_dist"] = "0.3";
adapter.values["pgv_adjust_cx"] = "-0.3";
adapter.values["pgv_adjust_cy"] = "0";
const auto result = agv.navigateToStation("AP1", options, adapter);
```
## 其他导航和控制示例
自由导航使用地图绝对坐标,不是“相对当前位置移动多少米”。示例只展示请求
结构,发送前必须读取当前位姿并确认目标在同一地图的安全区域:
```bash
grpcurl -plaintext \
-d '{
"header":{"deviceId":"src1100"},
"pose":{"x":1.0,"y":0.0,"theta":0.0},
"options":{"maxSpeed":0.15,"maxAcceleration":0.15}
}' \
127.0.0.1:50052 \
cmvr.api.AgvService/navigateToPose
```
显式站点路径使用 `3066`:
```bash
grpcurl -plaintext \
-d '{
"header":{"deviceId":"src1100"},
"path":[
{"sourceStation":"LM1","targetStation":"LM2"},
{"sourceStation":"LM2","targetStation":"AP1"}
]
}' \
127.0.0.1:50052 \
cmvr.api.AgvService/followPath
```
暂停、继续和取消的请求体直接是 `CommandHeader.Request`,没有外层 `header`:
```bash
grpcurl -plaintext -d '{"deviceId":"src1100"}' \
127.0.0.1:50052 cmvr.api.AgvService/pauseNavigation
grpcurl -plaintext -d '{"deviceId":"src1100"}' \
127.0.0.1:50052 cmvr.api.AgvService/resumeNavigation
grpcurl -plaintext -d '{"deviceId":"src1100"}' \
127.0.0.1:50052 cmvr.api.AgvService/cancelNavigation
```
差速底盘的 `vy` 应保持 `0`。低层速度控制不等价于导航,并可能与已有任务
冲突;只应在专门的速度控制测试流程中使用:
```bash
grpcurl -plaintext \
-d '{"header":{"deviceId":"src1100"},"velocity":{"vx":0.05,"vy":0,"wz":0}}' \
127.0.0.1:50052 \
cmvr.api.AgvService/setVelocity
grpcurl -plaintext -d '{"deviceId":"src1100"}' \
127.0.0.1:50052 cmvr.api.AgvService/stopVelocityControl
```
## 错误返回
控制器响应中的非零 `ret_code` 和 `err_msg` 会保留在 `AgvResult.message`,并由
gRPC 同时写入 transport status message 和反馈头的 `errorMessage`。非 OK RPC
下,标准客户端通常不会交付响应体,因此跨客户端应以 transport status message
为准,不要依赖反馈头仍然可见。例如:
```text
SEER Robokit command failed: ret_code=43051, err_msg=planner_rejected_pose
```
控制器仅返回“已接收”不等于导航完成;同步接口仍要等待精确任务终态和停车
确认。若发送后连接中断且控制器是否执行已无法确定,错误会明确提示 outcome
unknown,调用方不能自动重发运动命令,应先查询状态并取消或停止。
## 安全边界
- 仙工文档明确把 `3051` 定位为任务链或验证测试等单车场景接口;不要把它当作
多车调度接口,否则可能出现路径/速度不连续等危险行为。
- `emergencyStop` 是控制器软件停止,不是功能安全急停;真实系统必须保留可达的
硬件急停、安全激光、碰撞条和独立安全链。
- 首次 PGV 测试应在低速、空载、隔离区域进行,并先核对二维码坐标系、传感器
上/下视方向、调整半径和中心偏移的标定值。
- PGV 同步成功目前能证明精确 `3051` 任务进入终态,并连续确认两次零速度;
仙工文档没有明确 `Completed` 是否一定覆盖 PGV 二次调整的全部阶段,仍需实机
验证后才能据此联动机械臂。异步成功更不代表 PGV 调整完成。
- 地图切换、地图上传和开始建图会改变控制器状态,也会先抢占控制权;不要和
现场调度系统并行操作。

View File

@ -0,0 +1,346 @@
#ifndef CMVR_ES_SEER_ROBOKIT_AGV_H
#define CMVR_ES_SEER_ROBOKIT_AGV_H
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <cstdint>
#include <deque>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
#include <json/json.h>
#include "cmvr/config/agv_config/agv_config.pb.h"
#include "devices/agv/abstract_agv.h"
namespace cmvr::device {
class SeerRobokitAgvTestPeer;
class SeerRobokitAgv final : public AbstractAGV {
public:
explicit SeerRobokitAgv(const config::SeerRobokitAgvConfig& cfg);
~SeerRobokitAgv() override;
std::string typeName() const override { return "SeerRobokitAgv"; }
bool init() override;
bool start() override;
bool stop() override;
bool update() override;
AgvRuntimeState runtimeState() const override;
AgvNavigationStatus navigationStatus() const override;
AgvResult emergencyStop() override;
AgvResult clearFault() override;
AgvResult relocalize(const math::Pose2d& pose) override;
AgvResult navigateToPose(
const math::Pose2d& pose,
const AgvMotionOptions& options = {},
const AgvAdapterParams& adapter_params = AgvAdapterParams{}) override;
AgvResult navigateToStation(
const std::string& station_id,
const AgvMotionOptions& options = {},
const AgvAdapterParams& adapter_params = AgvAdapterParams{}) override;
AgvResult followPath(
const std::vector<AgvPathSegment>& path) override;
AgvResult followPath(
const std::vector<AgvPathSegment>& path,
const AgvMotionOptions& options) override;
AgvResult translate(const AgvTranslation& translation) override;
AgvResult pauseNavigation() override;
AgvResult resumeNavigation() override;
AgvResult cancelNavigation() override;
AgvResult setVelocity(const AgvVelocity& velocity) override;
AgvResult listMaps(std::vector<std::string>& maps) const override;
AgvResult listStations(std::vector<AgvStation>& stations) const override;
AgvResult switchMap(const std::string& map_name) override;
AgvResult uploadMap(const std::string& map_name, const std::string& content) override;
AgvResult downloadMap(const std::string& map_name, std::string& content) const override;
AgvResult startMapping(const AgvMappingOptions& options = {}) override;
AgvResult getMappingData(int start_index, AgvMappingData& data) const override;
AgvResult getUnifiedMapUpdate(
std::uint64_t after_sequence,
const AgvMapStreamOptions& options,
AgvUnifiedMapUpdate& update) const override;
AgvResult stopMapping() override;
private:
friend class SeerRobokitAgvTestPeer;
struct Ports {
int status{19204};
int control{19205};
int navigation{19206};
int config{19207};
int other{19210};
int push{19301};
};
struct PoseTaskStatus {
bool found{false};
int state{0};
int type{0};
bool type_present{false};
double progress{0.0};
std::string detail;
};
struct NavigationSnapshot {
int task_status{0};
int task_type{0};
bool task_status_present{false};
bool task_type_present{false};
bool blocked{false};
bool blocked_present{false};
int block_reason{-1};
std::string block_reason_raw;
bool velocity_present{false};
double vx{0.0};
double vy{0.0};
double w{0.0};
bool emergency{false};
std::string target_id;
std::string active_faults;
bool only_recoverable_blocking_faults{false};
std::string detail;
};
enum class CommandTransmissionState {
NotSent,
PossiblySent,
};
struct TrackedNavigationContext {
std::string token;
std::vector<std::string> task_ids;
AgvTaskType type{AgvTaskType::None};
std::string target_id;
std::vector<std::string> target_ids;
std::uint64_t navigation_generation{0};
std::chrono::steady_clock::time_point accepted_at{};
bool synchronous_wait{false};
};
struct PoseTaskContext {
std::string task_id;
math::Pose2d target{};
double reach_distance{0.0};
double reach_angle{0.0};
std::uint64_t navigation_generation{0};
std::uint64_t controller_fault_sequence_at_start{0};
std::uint64_t control_attempt_sequence_at_start{0};
std::uint64_t controller_fault_channel_epoch_at_start{0};
};
AgvResult connect_();
AgvResult disconnect_();
AgvResult emergencyStopTrackedNavigation_(
const TrackedNavigationContext* expected_navigation);
AgvResult connectSocket_(int& sock, int port);
AgvResult ensureOtherSocket_();
void closeSocket_(int& sock) const;
bool connected_() const;
AgvResult acquireControl_() const;
AgvResult confirmPoseNavigationStarted_(
const PoseTaskContext& context,
bool accept_paused,
const AgvMotionOptions& options) const;
AgvResult waitForPoseNavigationTerminal_(
const PoseTaskContext& pose_context,
const TrackedNavigationContext& navigation_context,
const AgvMotionOptions& options);
AgvResult waitForTrackedNavigationTerminal_(
const TrackedNavigationContext& context,
const AgvMotionOptions& options);
AgvResult queryNavigationSnapshot_(NavigationSnapshot& snapshot) const;
AgvResult cancelTrackedNavigation_(
const TrackedNavigationContext& context,
std::uint64_t& accepted_generation);
AgvResult waitForCanceledTaskToStop_(
const TrackedNavigationContext& context,
const AgvMotionOptions& options,
const std::string& reason,
bool require_global_stopped = false);
AgvResult failAndCancelTrackedNavigation_(
const TrackedNavigationContext& context,
const AgvMotionOptions& options,
AgvErrorCode error_code,
const std::string& reason);
AgvResult queryPoseTaskStatus_(
const std::string& task_id,
PoseTaskStatus& status) const;
AgvResult queryTaskStatuses_(
const std::vector<std::string>& task_ids,
std::vector<PoseTaskStatus>& statuses) const;
bool poseTargetReached_(
const PoseTaskContext& context,
std::string& detail) const;
std::string cachedControllerFaultDetail_(
std::uint64_t after_sequence = 0,
int wait_ms = 0,
std::uint64_t* associated_control_attempt = nullptr) const;
int controllerFaultCaptureGraceMs_() const;
int controllerFaultStateMaxAgeMs_() const;
std::string freeNavigationFaultStateUnavailableDetail_() const;
void rememberPoseTask_(const PoseTaskContext& context) const;
void advancePoseTaskGeneration_(
std::uint64_t navigation_generation,
std::uint64_t control_attempt_sequence) const;
void advancePoseTaskControlAttempt_(
std::uint64_t control_attempt_sequence) const;
void clearPoseTask_(std::uint64_t navigation_generation) const;
void clearPoseTaskIfTaskId_(const std::string& task_id) const;
bool currentPoseTask_(PoseTaskContext& context) const;
void rememberTrackedNavigation_(
const TrackedNavigationContext& context) const;
void advanceTrackedNavigationGeneration_(
std::uint64_t navigation_generation) const;
void clearTrackedNavigation_(std::uint64_t navigation_generation) const;
void clearTrackedNavigationIfToken_(const std::string& token) const;
bool currentTrackedNavigation_(
TrackedNavigationContext& context) const;
AgvResult sendControlledCommand_(int sock,
std::uint16_t command,
const Json::Value& payload,
Json::Value* response,
std::uint64_t* accepted_navigation_generation = nullptr,
std::uint64_t* controller_fault_sequence_at_attempt = nullptr,
std::uint64_t* control_attempt_sequence = nullptr,
PoseTaskContext* pose_context_to_publish = nullptr,
bool reject_if_active_controller_fault = false,
TrackedNavigationContext* navigation_context_to_publish = nullptr,
bool preserve_tracked_navigation = false,
const std::string* expected_navigation_token = nullptr,
const std::function<bool()>* cancellation_requested = nullptr,
const TrackedNavigationContext* expected_active_navigation = nullptr) const;
AgvResult sendCommand_(int sock,
std::uint16_t command,
const Json::Value& payload,
Json::Value* response,
CommandTransmissionState* transmission_state = nullptr) const;
AgvResult sendCommandRaw_(int sock,
std::uint16_t command,
const Json::Value& payload,
std::string* response_payload,
CommandTransmissionState* transmission_state = nullptr) const;
AgvResult sendCommandNoResponse_(int sock, std::uint16_t command, const Json::Value& payload) const;
AgvResult configurePush_();
void startPushThread_();
void stopPushThread_();
void pushLoop_();
void invalidateControllerFaultState_();
AgvRuntimeState queryRuntimeState_() const;
void updateCachedRuntimeState_(const Json::Value& payload);
void startMapUpdateThread_();
void stopMapUpdateThread_();
void mapUpdateLoop_();
AgvResult refreshMapCacheOnce_(const AgvMapStreamOptions& options) const;
AgvResult parseMapFileToUpdates_(
const std::string& file_name,
const std::string& content,
const AgvMapStreamOptions& options,
std::vector<AgvUnifiedMapUpdate>& updates) const;
AgvResult parseSeerRobokitMapArchive_(
const std::string& file_name,
const std::string& content,
const AgvMapStreamOptions& options,
std::vector<AgvUnifiedMapUpdate>& updates) const;
AgvResult parseSeerRobokitMap2D_(
const std::string& file_name,
const std::string& content,
const AgvMapStreamOptions& options,
AgvUnifiedMapUpdate& update) const;
AgvResult parseSeerRobokitMap3D_(
const std::string& file_name,
const std::string& content,
const AgvMapStreamOptions& options,
AgvUnifiedMapUpdate& update) const;
void cacheMapUpdates_(std::vector<AgvUnifiedMapUpdate> updates) const;
bool findCachedMapUpdate_(
std::uint64_t after_sequence,
const AgvMapStreamOptions& options,
AgvUnifiedMapUpdate& update) const;
bool mapUpdateMatches_(
const AgvUnifiedMapUpdate& update,
const AgvMapStreamOptions& options) const;
static std::vector<std::uint8_t> buildFrame_(std::uint16_t command, const std::string& payload);
static std::string toJsonString_(const Json::Value& value);
static bool parseJson_(const std::string& input, Json::Value& output, std::string& error);
static std::string extractJson_(const std::string& raw);
static AgvResult receiveFrame_(int sock, std::uint16_t& command, std::string& payload);
static void applyMotionOptions_(
Json::Value& payload,
const AgvMotionOptions& options,
bool include_reach_options = true);
static void applyAdapterParams_(Json::Value& payload, const AgvAdapterParams& params);
static AgvResult resultFromResponse_(const Json::Value& response);
config::SeerRobokitAgvConfig config_;
std::string ip_;
std::string control_nick_name_;
int recv_timeout_ms_{1000};
Ports ports_;
bool state_push_enabled_{false};
bool map_update_enabled_{false};
int map_update_interval_ms_{1000};
std::size_t map_update_history_size_{8};
mutable std::mutex mutex_;
mutable std::mutex status_io_mutex_;
mutable std::mutex control_sequence_mutex_;
mutable std::atomic<std::uint64_t> navigation_generation_{0};
mutable std::atomic<std::uint64_t> pose_task_sequence_{0};
mutable std::atomic<std::uint64_t> control_attempt_sequence_{0};
mutable std::atomic<std::uint64_t> controller_fault_channel_epoch_{0};
mutable std::mutex pose_task_mutex_;
mutable PoseTaskContext pose_task_context_;
mutable std::mutex tracked_navigation_mutex_;
mutable TrackedNavigationContext tracked_navigation_context_;
mutable int sock_status_{-1};
mutable int sock_control_{-1};
mutable int sock_navigation_{-1};
mutable int sock_config_{-1};
mutable int sock_other_{-1};
mutable int sock_push_{-1};
std::string last_error_;
std::atomic<bool> push_running_{false};
std::thread push_thread_;
mutable std::mutex runtime_state_mutex_;
mutable std::condition_variable runtime_state_cv_;
AgvRuntimeState cached_runtime_state_;
bool cached_runtime_state_valid_{false};
std::uint64_t controller_fault_sequence_{0};
bool controller_fault_state_observed_{false};
std::chrono::steady_clock::time_point controller_fault_state_observed_at_{};
std::string active_controller_fault_detail_;
double last_controller_fault_timestamp_{0.0};
std::string last_controller_fault_detail_;
std::uint64_t last_controller_fault_control_attempt_{0};
mutable std::atomic<bool> map_update_running_{false};
mutable std::thread map_update_thread_;
mutable std::mutex map_update_mutex_;
mutable std::condition_variable map_update_cv_;
mutable std::deque<AgvUnifiedMapUpdate> cached_map_updates_;
mutable std::uint64_t map_sequence_{0};
mutable int next_mapping_index_{0};
mutable std::size_t last_map_content_hash_{0};
mutable std::string map_session_id_;
};
} // namespace cmvr::device
#endif // CMVR_ES_SEER_ROBOKIT_AGV_H

View File

@ -0,0 +1,303 @@
#ifndef CMVR_ES_SEER_ROBOKIT_NAVIGATION_UTILS_H
#define CMVR_ES_SEER_ROBOKIT_NAVIGATION_UTILS_H
#include <algorithm>
#include <chrono>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <string>
#include <thread>
#include "devices/agv/abstract_agv.h"
namespace cmvr::device::seer_robokit::navigation {
constexpr auto kPoseNavigationStartTimeout = std::chrono::milliseconds(1500);
constexpr auto kPoseNavigationPollInterval = std::chrono::milliseconds(50);
constexpr int kPoseNavigationRequiredRunningSamples = 2;
constexpr auto kDefaultNavigationWaitTimeout =
std::chrono::milliseconds(600000);
constexpr auto kDefaultNavigationBlockedTimeout =
std::chrono::milliseconds(60000);
constexpr auto kDefaultNavigationPollInterval =
std::chrono::milliseconds(200);
constexpr auto kMaximumNavigationPollInterval =
std::chrono::milliseconds(5000);
constexpr auto kNavigationCancellationCheckInterval =
std::chrono::milliseconds(50);
constexpr auto kNavigationCancelPollInterval =
std::chrono::milliseconds(100);
constexpr auto kNavigationCancelConfirmationTimeout =
std::chrono::milliseconds(3000);
constexpr int kRequiredCompletedStopSamples = 2;
constexpr double kNavigationStopVelocityTolerance = 0.005;
constexpr int kRobotBlockedFaultCode = 52200;
constexpr int kMinimumControllerFaultCaptureGraceMs = 250;
constexpr int kMaximumControllerFaultCaptureGraceMs = 5000;
constexpr int kDefaultControllerFaultPushIntervalMs = 1000;
constexpr int kControllerFaultPushJitterMs = 100;
constexpr int kMinimumControllerFaultStateMaxAgeMs = 2000;
constexpr int kControllerFaultStateMaxAgeIntervals = 5;
constexpr double kDefaultPoseReachDistance = 0.05;
constexpr double kDefaultPoseReachAngle = 0.10;
constexpr double kTwoPi = 6.28318530717958647692;
static inline bool exactTaskStateIsActive(const int state)
{
return state >= 1 && state <= 3;
}
static inline bool exactTaskStateIsKnownTerminal(const int state)
{
return state >= 4 && state <= 7;
}
static inline bool globalTaskStateIsKnownTerminal(const int state)
{
return state == 0 || exactTaskStateIsKnownTerminal(state);
}
// Some SRC firmware versions report station navigation as task type 3.
// Exact task ids and target ids remain the primary ownership evidence.
static inline bool exactTrackedNavigationTaskTypeMatches(
const AgvTaskType expected_type,
const int actual_type)
{
switch (expected_type) {
case AgvTaskType::NavigateToPose:
return actual_type == 1;
case AgvTaskType::NavigateToStation:
case AgvTaskType::FollowPath:
return actual_type == 2 || actual_type == 3;
default:
return false;
}
}
static inline bool globalNavigationTaskTypeMatches(
const AgvTaskType expected_type,
const int actual_type)
{
switch (expected_type) {
case AgvTaskType::NavigateToPose:
return actual_type == 1;
case AgvTaskType::NavigateToStation:
return actual_type == 2 || actual_type == 3;
case AgvTaskType::FollowPath:
return actual_type == 3;
default:
return false;
}
}
static inline double angleDistance(const double lhs, const double rhs)
{
return std::abs(std::remainder(lhs - rhs, kTwoPi));
}
static inline AgvResult withUnknownControllerOutcome(AgvResult result)
{
const auto code = result.ok() ? AgvErrorCode::CommandFailed : result.code;
std::string detail = result.message.empty() ? "unknown transport or protocol error" : result.message;
detail +=
"; SEER Robokit controller outcome is unknown after the command attempt; "
"the command may already have taken effect; do not issue another motion "
"command automatically; query status and cancel or stop first";
return AgvResult::failure(code, detail);
}
static inline std::string makePoseTaskId(
const std::string& device_id,
const std::uint64_t task_sequence)
{
const auto timestamp = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::system_clock::now().time_since_epoch()).count();
const std::string prefix = device_id.empty() ? "cmvr-es" : device_id;
return prefix + "_pose_" + std::to_string(timestamp)
+ "_" + std::to_string(task_sequence);
}
static inline std::string makeNavigationTaskId(
const std::string& device_id,
const char* kind,
const std::uint64_t task_sequence)
{
const auto timestamp = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::system_clock::now().time_since_epoch()).count();
const std::string prefix = device_id.empty() ? "cmvr-es" : device_id;
return prefix + "_" + kind + "_" + std::to_string(timestamp)
+ "_" + std::to_string(task_sequence);
}
static inline const char* blockReasonName(const int reason)
{
switch (reason) {
case 0:
return "ultrasonic";
case 1:
return "laser";
case 2:
return "fallingdown";
case 3:
return "collision";
case 4:
return "infrared";
case 5:
return "locked";
default:
return "unknown";
}
}
static inline std::string invalidMotionOption(const AgvMotionOptions& options)
{
const auto non_negative_error = [](const double value, const char* field) {
if (!std::isfinite(value)) {
return std::string(field) + " must be finite";
}
if (value < 0.0) {
return std::string(field) + " must be non-negative";
}
return std::string{};
};
if (auto error = non_negative_error(options.max_speed, "max_speed");
!error.empty()) return error;
if (auto error = non_negative_error(
options.max_angular_speed,
"max_angular_speed");
!error.empty()) return error;
if (auto error = non_negative_error(
options.max_acceleration,
"max_acceleration");
!error.empty()) return error;
if (auto error = non_negative_error(
options.max_angular_acceleration,
"max_angular_acceleration");
!error.empty()) return error;
if (auto error = non_negative_error(
options.reach_distance,
"reach_distance");
!error.empty()) return error;
if (auto error = non_negative_error(options.reach_angle, "reach_angle");
!error.empty()) return error;
if (auto error = non_negative_error(options.speed_ratio, "speed_ratio");
!error.empty()) return error;
if (options.wait_timeout_ms < 0) {
return "wait_timeout_ms must be non-negative";
}
if (options.blocked_timeout_ms < 0) {
return "blocked_timeout_ms must be non-negative";
}
if (options.poll_interval_ms < 0) {
return "poll_interval_ms must be non-negative";
}
if (options.poll_interval_ms
> kMaximumNavigationPollInterval.count()) {
return "poll_interval_ms must not exceed "
+ std::to_string(kMaximumNavigationPollInterval.count());
}
if (options.wait_timeout_ms > 0
&& options.poll_interval_ms > options.wait_timeout_ms) {
return "poll_interval_ms must not exceed wait_timeout_ms";
}
return {};
}
static inline std::chrono::milliseconds navigationWaitTimeout(
const AgvMotionOptions& options)
{
return options.wait_timeout_ms > 0
? std::chrono::milliseconds(options.wait_timeout_ms)
: kDefaultNavigationWaitTimeout;
}
static inline std::chrono::milliseconds navigationBlockedTimeout(
const AgvMotionOptions& options)
{
return options.blocked_timeout_ms > 0
? std::chrono::milliseconds(options.blocked_timeout_ms)
: kDefaultNavigationBlockedTimeout;
}
static inline std::chrono::milliseconds navigationPollInterval(
const AgvMotionOptions& options)
{
if (options.poll_interval_ms <= 0) {
return kDefaultNavigationPollInterval;
}
return std::chrono::milliseconds(
std::max(options.poll_interval_ms, 20));
}
static inline bool navigationCancellationRequested(const AgvMotionOptions& options)
{
return options.cancellation_requested
&& options.cancellation_requested();
}
static inline void sleepForNavigationPoll(
const std::chrono::milliseconds poll_interval,
const std::chrono::steady_clock::time_point overall_deadline,
const AgvMotionOptions& options)
{
const auto poll_deadline = std::min(
overall_deadline,
std::chrono::steady_clock::now() + poll_interval);
while (std::chrono::steady_clock::now() < poll_deadline
&& !navigationCancellationRequested(options)) {
const auto remaining = std::chrono::duration_cast<std::chrono::milliseconds>(
poll_deadline - std::chrono::steady_clock::now());
if (remaining <= std::chrono::milliseconds::zero()) {
break;
}
std::this_thread::sleep_for(std::min(
kNavigationCancellationCheckInterval,
remaining));
}
}
template <typename Snapshot>
static inline bool navigationStopped(const Snapshot& snapshot)
{
return snapshot.velocity_present
&& std::abs(snapshot.vx) <= kNavigationStopVelocityTolerance
&& std::abs(snapshot.vy) <= kNavigationStopVelocityTolerance
&& std::abs(snapshot.w) <= kNavigationStopVelocityTolerance;
}
static inline AgvResult reconciledNavigationResult(
const AgvResult& command_result,
AgvResult terminal_result)
{
if (command_result.ok()) {
return terminal_result;
}
if (terminal_result.ok()) {
terminal_result.message =
"SEER Robokit navigation completed after an indeterminate command "
"acknowledgment; initial_detail=" + command_result.message;
return terminal_result;
}
terminal_result.message =
"SEER Robokit navigation command acknowledgment was indeterminate: "
+ command_result.message + "; status reconciliation: "
+ terminal_result.message;
return terminal_result;
}
static inline bool parseFiniteDouble(const std::string& value, double& parsed)
{
std::size_t consumed = 0;
try {
parsed = std::stod(value, &consumed);
} catch (...) {
return false;
}
return consumed == value.size() && std::isfinite(parsed);
}
} // namespace cmvr::device::seer_robokit::navigation
#endif // CMVR_ES_SEER_ROBOKIT_NAVIGATION_UTILS_H

View File

@ -0,0 +1,141 @@
#ifndef CMVR_ES_SEER_ROBOKIT_PGV_UTILS_H
#define CMVR_ES_SEER_ROBOKIT_PGV_UTILS_H
#include <string>
#include <json/json.h>
#include "devices/agv/abstract_agv.h"
#include "seer_robokit_navigation_utils.h"
#include "seer_robokit_utils.h"
namespace cmvr::device::seer_robokit::pgv {
constexpr char kUsePgv[] = "use_pgv";
constexpr char kPgvAdjustDist[] = "pgv_adjust_dist";
constexpr char kPgvAdjustCx[] = "pgv_adjust_cx";
constexpr char kPgvAdjustCy[] = "pgv_adjust_cy";
constexpr char kPgvXAdjust[] = "pgv_x_adjust";
constexpr char kUseDownPgv[] = "use_down_pgv";
// These spellings currently appear in the vendor document, but conflict with
// its own field table/example and the repository's older working serializer.
constexpr char kMalformedAdjustDist[] = "pgv_adjustuse_pgv_dist";
constexpr char kAdjustCyDocumentAlias[] = "pgv_ajdust_cy";
static inline bool isPgvAdjustmentKey(const std::string& key)
{
return key == kUsePgv
|| key == kPgvAdjustDist
|| key == kPgvAdjustCx
|| key == kPgvAdjustCy
|| key == kPgvXAdjust
|| key == kUseDownPgv
|| key == kMalformedAdjustDist
|| key == kAdjustCyDocumentAlias;
}
static inline bool hasPgvAdjustmentParams(const AgvAdapterParams& params)
{
for (const auto& [key, value] : params.values) {
(void)value;
if (isPgvAdjustmentKey(key)) {
return true;
}
}
return false;
}
/**
* Parse the string-valued generic adapter parameters into the native JSON
* types required by SEER Robokit API 3051. Returns an error string without
* modifying controller state; an empty string means success.
*/
static inline std::string applyPgvAdjustmentParams(
Json::Value& payload,
const AgvAdapterParams& params)
{
if (params.getString(kMalformedAdjustDist)) {
return std::string(kMalformedAdjustDist)
+ " is a vendor-document typo; use " + kPgvAdjustDist;
}
if (hasPgvAdjustmentParams(params)) {
for (const auto& [key, value] : params.values) {
(void)value;
if (!isPgvAdjustmentKey(key)
&& key != "source_id"
&& key != "task_id") {
return "PGV adjustment must not be combined with adapter "
"field " + key;
}
}
}
const auto adjust_cy = params.getString(kPgvAdjustCy);
const auto adjust_cy_alias = params.getString(kAdjustCyDocumentAlias);
if (adjust_cy && adjust_cy_alias) {
return std::string(kPgvAdjustCy) + " and its vendor-document alias "
+ kAdjustCyDocumentAlias + " must not both be set";
}
const auto apply_bool = [&payload, &params](const char* key) {
if (!params.getString(key)) {
return std::string{};
}
const auto parsed = params.getBool(key);
if (!parsed) {
return std::string(key)
+ " must be a boolean string such as true or false";
}
detail::jsonMember(payload, key) = *parsed;
return std::string{};
};
if (auto error = apply_bool(kUsePgv); !error.empty()) {
return error;
}
if (auto error = apply_bool(kUseDownPgv); !error.empty()) {
return error;
}
const auto apply_number = [&payload, &params](
const char* key,
const bool non_negative) {
const auto raw = params.getString(key);
if (!raw) {
return std::string{};
}
double parsed = 0.0;
if (!navigation::parseFiniteDouble(*raw, parsed)) {
return std::string(key) + " must be a complete finite number";
}
if (non_negative && parsed < 0.0) {
return std::string(key) + " must be non-negative";
}
detail::jsonMember(payload, key) = parsed;
return std::string{};
};
if (auto error = apply_number(kPgvAdjustDist, true); !error.empty()) {
return error;
}
if (auto error = apply_number(kPgvAdjustCx, false); !error.empty()) {
return error;
}
if (adjust_cy_alias) {
double parsed = 0.0;
if (!navigation::parseFiniteDouble(*adjust_cy_alias, parsed)) {
return std::string(kAdjustCyDocumentAlias)
+ " must be a complete finite number";
}
detail::jsonMember(payload, kPgvAdjustCy) = parsed;
} else if (auto error = apply_number(kPgvAdjustCy, false);
!error.empty()) {
return error;
}
if (auto error = apply_number(kPgvXAdjust, false); !error.empty()) {
return error;
}
return {};
}
} // namespace cmvr::device::seer_robokit::pgv
#endif // CMVR_ES_SEER_ROBOKIT_PGV_UTILS_H

View File

@ -0,0 +1,41 @@
#ifndef CMVR_ES_SEER_ROBOKIT_PROTOCOL_H
#define CMVR_ES_SEER_ROBOKIT_PROTOCOL_H
#include <cstdint>
namespace cmvr::device::seer_robokit::protocol {
constexpr std::uint16_t kRobotStatusLoc = 1004;
constexpr std::uint16_t kRobotStatusBattery = 1007;
constexpr std::uint16_t kRobotStatusAll2 = 1101;
constexpr std::uint16_t kRobotStatusTask = 1020;
constexpr std::uint16_t kRobotStatusTaskPackage = 1110;
constexpr std::uint16_t kRobotStatusMap = 1300;
constexpr std::uint16_t kRobotStatusStation = 1301;
constexpr std::uint16_t kRobotStatusMappingFileList = 1780;
constexpr std::uint16_t kRobotStatusDownloadFile = 1800;
constexpr std::uint16_t kRobotControlStop = 2000;
constexpr std::uint16_t kRobotControlReloc = 2002;
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 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;
constexpr std::uint16_t kRobotOtherStopMapping = 6101;
constexpr std::uint16_t kRobotPushConfigReq = 9300;
constexpr std::uint16_t kRobotPushConfigRes = 19300;
constexpr std::uint16_t kRobotPush = 19301;
constexpr std::uint32_t kMaxFramePayloadBytes = 512U * 1024U * 1024U;
} // namespace cmvr::device::seer_robokit::protocol
#endif // CMVR_ES_SEER_ROBOKIT_PROTOCOL_H

View File

@ -0,0 +1,92 @@
#ifndef CMVR_ES_SEER_ROBOKIT_UTILS_H
#define CMVR_ES_SEER_ROBOKIT_UTILS_H
#include <cerrno>
#include <chrono>
#include <cstring>
#include <string>
#include <json/json.h>
namespace cmvr::device::seer_robokit::detail {
static inline std::string systemError()
{
return std::strerror(errno);
}
static inline Json::Value& jsonMember(
Json::Value& value,
const char* key)
{
return *value.demand(key, key + std::strlen(key));
}
static inline Json::Value& jsonMember(
Json::Value& value,
const std::string& key)
{
return *value.demand(key.data(), key.data() + key.size());
}
static inline const Json::Value* jsonFind(
const Json::Value& value,
const char* key)
{
return value.find(key, key + std::strlen(key));
}
static inline Json::Value jsonGet(
const Json::Value& value,
const char* key,
const Json::Value& fallback)
{
const auto* found = jsonFind(value, key);
return found ? *found : fallback;
}
static inline double nowSeconds()
{
const auto now = std::chrono::system_clock::now().time_since_epoch();
return std::chrono::duration<double>(now).count();
}
static inline bool jsonHas(
const Json::Value& value,
const char* key)
{
return jsonFind(value, key) != nullptr;
}
static inline bool hasNumericControllerRetCode(
const Json::Value& response)
{
const auto* ret_code = jsonFind(response, "ret_code");
return ret_code
&& (ret_code->isInt()
|| ret_code->isUInt()
|| ret_code->isInt64()
|| ret_code->isUInt64());
}
static inline std::string jsonValueToString(const Json::Value& value)
{
if (value.isString()) return value.asString();
if (value.isBool()) return value.asBool() ? "true" : "false";
if (value.isInt64() || value.isInt()) {
return std::to_string(value.asInt64());
}
if (value.isUInt64() || value.isUInt()) {
return std::to_string(value.asUInt64());
}
if (value.isDouble()) return std::to_string(value.asDouble());
if (value.isNull()) return {};
Json::StreamWriterBuilder builder;
builder["indentation"] = "";
return Json::writeString(builder, value);
}
} // namespace cmvr::device::seer_robokit::detail
#endif // CMVR_ES_SEER_ROBOKIT_UTILS_H

View File

@ -0,0 +1,175 @@
#include "seer_robokit_agv.h"
#include <atomic>
#include <cstddef>
#include <mutex>
#include "common/base/logging/logger.h"
namespace cmvr::device {
namespace {
constexpr int kDefaultMapUpdateIntervalMs = 1000;
constexpr std::size_t kDefaultMapUpdateHistorySize = 8;
} // namespace
SeerRobokitAgv::SeerRobokitAgv(const config::SeerRobokitAgvConfig& cfg)
: config_(cfg),
ip_(cfg.ip()),
control_nick_name_(
cfg.control_nick_name().empty()
? (cfg.id().empty() ? "cmvr-es" : "cmvr-es:" + cfg.id())
: cfg.control_nick_name()),
recv_timeout_ms_(cfg.recv_timeout_ms() > 0 ? cfg.recv_timeout_ms() : 1000),
state_push_enabled_(cfg.enable_state_push()),
map_update_enabled_(cfg.enable_map_update()),
map_update_interval_ms_(cfg.map_update_interval_ms() > 0 ? cfg.map_update_interval_ms() : kDefaultMapUpdateIntervalMs),
map_update_history_size_(cfg.map_update_history_size() > 0 ? cfg.map_update_history_size() : kDefaultMapUpdateHistorySize)
{
id_ = cfg.id();
if (cfg.port_status() > 0) ports_.status = cfg.port_status();
if (cfg.port_control() > 0) ports_.control = cfg.port_control();
if (cfg.port_nav() > 0) ports_.navigation = cfg.port_nav();
if (cfg.port_config() > 0) ports_.config = cfg.port_config();
if (cfg.port_other() > 0) ports_.other = cfg.port_other();
if (cfg.port_push() > 0) ports_.push = cfg.port_push();
const auto result = connect_();
if (!result.ok()) {
CMVR_LOG(ERROR) << "[SeerRobokitAgv] Auto connect failed"
<< ", id=" << id_
<< ", ip=" << ip_
<< ", error=" << result.message;
}
}
SeerRobokitAgv::~SeerRobokitAgv()
{
(void)disconnect_();
}
bool SeerRobokitAgv::init()
{
return !id_.empty() && !ip_.empty();
}
bool SeerRobokitAgv::start()
{
return true;
}
bool SeerRobokitAgv::stop()
{
return true;
}
bool SeerRobokitAgv::update()
{
return true;
}
AgvResult SeerRobokitAgv::connect_()
{
const auto lifecycle_generation =
navigation_generation_.fetch_add(1, std::memory_order_relaxed) + 1;
clearPoseTask_(lifecycle_generation);
clearTrackedNavigation_(lifecycle_generation);
stopPushThread_();
stopMapUpdateThread_();
{
// Status requests may wait for a controller receive timeout without
// holding mutex_. Serialize lifecycle changes with that channel before
// replacing or closing its descriptor.
std::lock_guard<std::mutex> status_io_lock(status_io_mutex_);
std::lock_guard<std::mutex> lock(mutex_);
closeSocket_(sock_status_);
closeSocket_(sock_control_);
closeSocket_(sock_navigation_);
closeSocket_(sock_config_);
closeSocket_(sock_other_);
closeSocket_(sock_push_);
if (ip_.empty()) {
return AgvResult::failure(AgvErrorCode::InvalidArgument, "SEER Robokit AGV ip is empty");
}
const auto close_all = [this]() {
closeSocket_(sock_status_);
closeSocket_(sock_control_);
closeSocket_(sock_navigation_);
closeSocket_(sock_config_);
closeSocket_(sock_other_);
closeSocket_(sock_push_);
};
if (auto result = connectSocket_(sock_status_, ports_.status); !result.ok()) {
close_all();
return result;
}
if (auto result = connectSocket_(sock_control_, ports_.control); !result.ok()) {
close_all();
return result;
}
if (auto result = connectSocket_(sock_navigation_, ports_.navigation); !result.ok()) {
close_all();
return result;
}
if (auto result = connectSocket_(sock_config_, ports_.config); !result.ok()) {
close_all();
return result;
}
if (state_push_enabled_) {
const auto result = connectSocket_(sock_push_, ports_.push);
if (!result.ok()) {
CMVR_LOG(ERROR) << "[SeerRobokitAgv] Connect push port failed"
<< ", id=" << id_
<< ", port=" << ports_.push
<< ", error=" << result.message;
closeSocket_(sock_push_);
}
}
last_error_.clear();
}
if (state_push_enabled_ && sock_push_ >= 0) {
const auto result = configurePush_();
if (result.ok()) {
startPushThread_();
} else {
CMVR_LOG(ERROR) << "[SeerRobokitAgv] Configure push failed"
<< ", id=" << id_
<< ", error=" << result.message;
std::lock_guard<std::mutex> lock(mutex_);
closeSocket_(sock_push_);
}
}
if (map_update_enabled_) {
startMapUpdateThread_();
}
return AgvResult::success();
}
AgvResult SeerRobokitAgv::disconnect_()
{
const auto lifecycle_generation =
navigation_generation_.fetch_add(1, std::memory_order_relaxed) + 1;
clearPoseTask_(lifecycle_generation);
clearTrackedNavigation_(lifecycle_generation);
stopMapUpdateThread_();
stopPushThread_();
std::lock_guard<std::mutex> status_io_lock(status_io_mutex_);
std::lock_guard<std::mutex> lock(mutex_);
closeSocket_(sock_status_);
closeSocket_(sock_control_);
closeSocket_(sock_navigation_);
closeSocket_(sock_config_);
closeSocket_(sock_other_);
closeSocket_(sock_push_);
return AgvResult::success();
}
} // namespace cmvr::device

View File

@ -0,0 +1,375 @@
#include "seer_robokit_agv.h"
#include "seer_robokit_navigation_utils.h"
#include "seer_robokit_protocol.h"
#include "seer_robokit_utils.h"
#include <algorithm>
#include <chrono>
#include <cstdint>
#include <functional>
#include <mutex>
#include <string>
#include <utility>
#include <vector>
namespace cmvr::device {
using namespace seer_robokit::navigation;
using namespace seer_robokit::protocol;
using namespace seer_robokit::detail;
AgvResult SeerRobokitAgv::acquireControl_() const
{
Json::Value payload(Json::objectValue);
jsonMember(payload, "nick_name") = control_nick_name_;
Json::Value response;
auto result = sendCommand_(sock_config_, kRobotConfigLock, payload, &response);
return result.ok() ? resultFromResponse_(response) : result;
}
AgvResult SeerRobokitAgv::sendControlledCommand_(
const int sock,
const std::uint16_t command,
const Json::Value& payload,
Json::Value* response,
std::uint64_t* accepted_navigation_generation,
std::uint64_t* controller_fault_sequence_at_attempt,
std::uint64_t* control_attempt_sequence,
PoseTaskContext* pose_context_to_publish,
const bool reject_if_active_controller_fault,
TrackedNavigationContext* navigation_context_to_publish,
const bool preserve_tracked_navigation,
const std::string* expected_navigation_token,
const std::function<bool()>* cancellation_requested,
const TrackedNavigationContext* expected_active_navigation) const
{
const auto canceled_before_send = [cancellation_requested]() {
return cancellation_requested
&& *cancellation_requested
&& (*cancellation_requested)();
};
if (canceled_before_send()) {
return AgvResult::failure(
AgvErrorCode::TaskCanceled,
"SEER Robokit command was not sent because the caller canceled the "
"operation before control authority was acquired");
}
const auto expected_context_is_current =
[this, expected_active_navigation]() {
if (!expected_active_navigation) {
return true;
}
TrackedNavigationContext active_context;
return currentTrackedNavigation_(active_context)
&& active_context.token
== expected_active_navigation->token
&& active_context.navigation_generation
== expected_active_navigation->navigation_generation
&& active_context.type
== expected_active_navigation->type
&& navigation_generation_.load(std::memory_order_relaxed)
== expected_active_navigation->navigation_generation;
};
// Conditional cancel ownership checks are deliberately performed without
// the control sequencing mutex. A slow 1110/1101 response must never
// prevent emergencyStop() from acquiring authority and sending 2000.
// The exact local token/generation/type is revalidated under the control
// lock both before and after authority acquisition below.
if (expected_active_navigation) {
if (!expected_context_is_current()) {
return AgvResult::failure(
AgvErrorCode::TaskCanceled,
"SEER Robokit did not start conditional navigation cancel "
"preflight because the tracked task was already replaced or "
"ended");
}
std::vector<PoseTaskStatus> statuses;
const auto exact_result = queryTaskStatuses_(
expected_active_navigation->task_ids,
statuses);
if (!exact_result.ok()) {
return AgvResult::failure(
exact_result.code,
"SEER Robokit did not send the conditional navigation cancel "
"because exact task ownership preflight failed: "
+ exact_result.message);
}
const bool all_exact_tasks_terminal = !statuses.empty()
&& std::all_of(
statuses.begin(),
statuses.end(),
[](const PoseTaskStatus& status) {
return status.found
&& exactTaskStateIsKnownTerminal(status.state);
});
if (all_exact_tasks_terminal) {
return AgvResult::success();
}
const bool exact_task_still_active = std::any_of(
statuses.begin(),
statuses.end(),
[](const PoseTaskStatus& status) {
return status.found
&& exactTaskStateIsActive(status.state);
});
NavigationSnapshot snapshot;
const auto snapshot_result = queryNavigationSnapshot_(snapshot);
if (!snapshot_result.ok()) {
return AgvResult::failure(
snapshot_result.code,
"SEER Robokit did not send the conditional navigation cancel "
"because 1101 ownership preflight was unavailable: "
+ snapshot_result.message);
}
const bool global_active =
exactTaskStateIsActive(snapshot.task_status);
const bool global_type_matches =
globalNavigationTaskTypeMatches(
expected_active_navigation->type,
snapshot.task_type);
const bool target_conflicts = global_active
&& !snapshot.target_id.empty()
&& !expected_active_navigation->target_ids.empty()
&& std::find(
expected_active_navigation->target_ids.begin(),
expected_active_navigation->target_ids.end(),
snapshot.target_id)
== expected_active_navigation->target_ids.end();
if (global_active
&& (!global_type_matches
|| target_conflicts)) {
return AgvResult::failure(
AgvErrorCode::TaskCanceled,
"SEER Robokit did not send the conditional navigation cancel "
"because 1101 reports another active task: "
+ snapshot.detail);
}
if (!exact_task_still_active) {
const bool clearing_path_queue =
expected_active_navigation->type
== AgvTaskType::FollowPath;
const bool terminal_target_matches =
expected_active_navigation->type
!= AgvTaskType::NavigateToStation
|| (!snapshot.target_id.empty()
&& snapshot.target_id
== expected_active_navigation->target_id);
if (globalTaskStateIsKnownTerminal(snapshot.task_status)
&& snapshot.task_status != 0
&& !clearing_path_queue
&& global_type_matches
&& terminal_target_matches) {
return AgvResult::success();
}
}
}
// Keep the permission acquisition and the following write ordered with
// respect to other control RPCs in this process. Channel I/O serialization
// is separate, so this must remain a distinct lock.
std::lock_guard<std::mutex> sequence_lock(control_sequence_mutex_);
if (expected_navigation_token) {
TrackedNavigationContext active_context;
const bool has_active_context =
currentTrackedNavigation_(active_context);
const bool expected_context_matches = expected_active_navigation
? (has_active_context
&& active_context.token
== expected_active_navigation->token
&& active_context.navigation_generation
== expected_active_navigation->navigation_generation
&& active_context.type
== expected_active_navigation->type
&& navigation_generation_.load(std::memory_order_relaxed)
== expected_active_navigation->navigation_generation)
: (has_active_context
&& active_context.token == *expected_navigation_token);
if (!expected_context_matches) {
return AgvResult::failure(
AgvErrorCode::TaskCanceled,
"SEER Robokit did not send the conditional navigation cancel "
"because the tracked task was already replaced or ended; "
"expected_token=" + *expected_navigation_token
+ (active_context.token.empty()
? std::string(", active_token=<none>")
: ", active_token=" + active_context.token));
}
}
const auto attempt_sequence =
control_attempt_sequence_.fetch_add(
1,
std::memory_order_relaxed) + 1;
if (control_attempt_sequence) {
*control_attempt_sequence = attempt_sequence;
}
if (pose_context_to_publish) {
pose_context_to_publish->control_attempt_sequence_at_start =
attempt_sequence;
}
const auto authority = acquireControl_();
if (!authority.ok()) {
const std::string detail = authority.message.empty() ? "unknown error" : authority.message;
return AgvResult::failure(
authority.code,
"SEER Robokit acquire control authority failed: " + detail);
}
if (expected_active_navigation && !expected_context_is_current()) {
return AgvResult::failure(
AgvErrorCode::TaskCanceled,
"SEER Robokit did not send the conditional navigation cancel because "
"the tracked token, generation, or type changed while control "
"authority was being acquired");
}
if (canceled_before_send()) {
return AgvResult::failure(
AgvErrorCode::TaskCanceled,
"SEER Robokit command was not sent because the caller canceled the "
"operation while control authority was being acquired");
}
std::string controller_fault_gate_error;
if (controller_fault_sequence_at_attempt
|| pose_context_to_publish
|| reject_if_active_controller_fault) {
std::lock_guard<std::mutex> lock(runtime_state_mutex_);
if (controller_fault_sequence_at_attempt) {
*controller_fault_sequence_at_attempt =
controller_fault_sequence_;
}
if (pose_context_to_publish) {
pose_context_to_publish->controller_fault_sequence_at_start =
controller_fault_sequence_;
pose_context_to_publish
->controller_fault_channel_epoch_at_start =
controller_fault_channel_epoch_.load(
std::memory_order_relaxed);
}
if (reject_if_active_controller_fault) {
if (!state_push_enabled_) {
controller_fault_gate_error =
"controller fault state is unavailable because state push "
"is disabled";
} else if (!active_controller_fault_detail_.empty()) {
controller_fault_gate_error =
"the controller reported a fault or invalid fault state: "
+ active_controller_fault_detail_;
} else if (!controller_fault_state_observed_) {
controller_fault_gate_error =
"no state push containing fatals/errors has been observed";
} else {
const auto fault_state_age =
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now()
- controller_fault_state_observed_at_)
.count();
if (fault_state_age > controllerFaultStateMaxAgeMs_()) {
controller_fault_gate_error =
"the most recent fatals/errors state push is stale "
"(age_ms=" + std::to_string(fault_state_age)
+ ", max_age_ms="
+ std::to_string(controllerFaultStateMaxAgeMs_())
+ ")";
}
}
}
}
if (!controller_fault_gate_error.empty()) {
return AgvResult::failure(
AgvErrorCode::Fault,
"SEER Robokit free-navigation command was not sent because "
+ controller_fault_gate_error);
}
if (canceled_before_send()) {
return AgvResult::failure(
AgvErrorCode::TaskCanceled,
"SEER Robokit command was not sent because the caller canceled the "
"operation before the controller command write");
}
if (canceled_before_send()) {
return AgvResult::failure(
AgvErrorCode::TaskCanceled,
"SEER Robokit command was not sent because the caller canceled the "
"operation immediately before the controller command write");
}
const auto publish_navigation_generation =
[this,
accepted_navigation_generation,
pose_context_to_publish,
navigation_context_to_publish,
preserve_tracked_navigation]() {
const auto generation =
navigation_generation_.fetch_add(
1,
std::memory_order_relaxed) + 1;
*accepted_navigation_generation = generation;
if (pose_context_to_publish) {
pose_context_to_publish->navigation_generation = generation;
rememberPoseTask_(*pose_context_to_publish);
}
if (navigation_context_to_publish) {
navigation_context_to_publish->navigation_generation =
generation;
navigation_context_to_publish->accepted_at =
std::chrono::steady_clock::now();
rememberTrackedNavigation_(
*navigation_context_to_publish);
} else if (preserve_tracked_navigation) {
advanceTrackedNavigationGeneration_(generation);
} else {
clearTrackedNavigation_(generation);
}
};
CommandTransmissionState transmission_state =
CommandTransmissionState::NotSent;
auto result = sendCommand_(
sock,
command,
payload,
response,
&transmission_state);
if (!result.ok()) {
if (accepted_navigation_generation
&& transmission_state
== CommandTransmissionState::PossiblySent) {
// Once the control write has been attempted, a timeout, disconnect,
// wrong response opcode, or malformed JSON cannot prove rejection:
// the controller may already have executed the command.
publish_navigation_generation();
return withUnknownControllerOutcome(std::move(result));
}
return result;
}
if (!accepted_navigation_generation) {
return result;
}
if (!response) {
publish_navigation_generation();
return withUnknownControllerOutcome(AgvResult::failure(
AgvErrorCode::CommandFailed,
"SEER Robokit cannot confirm navigation command without a response"));
}
if (!hasNumericControllerRetCode(*response)) {
publish_navigation_generation();
return withUnknownControllerOutcome(resultFromResponse_(*response));
}
result = resultFromResponse_(*response);
if (!result.ok()) {
return result;
}
// Advance only after the controller accepted the command, and do it before
// releasing control_sequence_mutex_. This prevents a failed cancel/pause or
// failed authority acquisition from falsely reporting a pose task canceled,
// while preserving the controller's actual command order under concurrency.
publish_navigation_generation();
return result;
}
} // namespace cmvr::device

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,725 @@
#include "seer_robokit_agv.h"
#include "seer_robokit_protocol.h"
#include "seer_robokit_utils.h"
#include <chrono>
#include <cmath>
#include <cstdint>
#include <mutex>
#include <sstream>
#include <string>
#include <sys/socket.h>
#include <thread>
#include <google/protobuf/repeated_ptr_field.h>
namespace cmvr::device {
using namespace seer_robokit::protocol;
using namespace seer_robokit::detail;
namespace {
bool hasFaultArray(const Json::Value& value, const char* key)
{
const auto* found = jsonFind(value, key);
return found && found->isArray() && !found->empty();
}
void appendStringArray(Json::Value& value, const char* key, const google::protobuf::RepeatedPtrField<std::string>& strings)
{
if (strings.empty()) {
return;
}
Json::Value array(Json::arrayValue);
for (const auto& item : strings) {
array.append(item);
}
jsonMember(value, key) = array;
}
AgvMode modeFromTaskState(const int state)
{
switch (state) {
case 2:
return AgvMode::Auto;
case 3:
return AgvMode::Paused;
case 5:
return AgvMode::Fault;
case 6:
return AgvMode::Stopped;
default:
return AgvMode::Idle;
}
}
AgvTaskState toTaskState(const int value)
{
switch (value) {
case 1:
return AgvTaskState::Waiting;
case 2:
return AgvTaskState::Running;
case 3:
return AgvTaskState::Paused;
case 4:
return AgvTaskState::Completed;
case 5:
case 7:
return AgvTaskState::Failed;
case 6:
return AgvTaskState::Canceled;
case 0:
default:
return AgvTaskState::None;
}
}
AgvTaskType toTaskType(const int value)
{
switch (value) {
case 1:
return AgvTaskType::NavigateToPose;
case 2:
return AgvTaskType::NavigateToStation;
case 3:
return AgvTaskType::FollowPath;
case 100:
return AgvTaskType::Custom;
default:
return AgvTaskType::None;
}
}
} // namespace
AgvRuntimeState SeerRobokitAgv::runtimeState() const
{
AgvRuntimeState cached_state;
bool has_cached_state = false;
if (state_push_enabled_) {
std::lock_guard<std::mutex> lock(runtime_state_mutex_);
if (cached_runtime_state_valid_) {
cached_state = cached_runtime_state_;
has_cached_state = true;
}
}
if (has_cached_state) {
std::string adapter_error;
{
std::lock_guard<std::mutex> lock(mutex_);
cached_state.connected = connected_();
adapter_error = last_error_;
}
if (!adapter_error.empty()) {
if (cached_state.last_error.empty()) {
cached_state.last_error = adapter_error;
} else if (cached_state.last_error != adapter_error) {
cached_state.last_error += "; adapter_error=" + adapter_error;
}
}
if (!cached_state.connected) {
cached_state.mode = AgvMode::Disconnected;
}
return cached_state;
}
return queryRuntimeState_();
}
AgvRuntimeState SeerRobokitAgv::queryRuntimeState_() const
{
AgvRuntimeState state;
{
std::lock_guard<std::mutex> lock(mutex_);
state.connected = connected_();
state.last_error = last_error_;
}
state.mode = state.connected ? AgvMode::Idle : AgvMode::Disconnected;
Json::Value loc;
if (sendCommand_(sock_status_, kRobotStatusLoc, Json::Value(Json::objectValue), &loc).ok()) {
state.pose.x = jsonGet(loc, "x", 0.0).asDouble();
state.pose.y = jsonGet(loc, "y", 0.0).asDouble();
state.pose.theta = jsonGet(loc, "angle", 0.0).asDouble();
state.localized = jsonGet(loc, "confidence", 0.0).asDouble() > 0.0;
state.current_station = jsonGet(loc, "current_station", "").asString();
}
Json::Value battery;
if (sendCommand_(sock_status_, kRobotStatusBattery, Json::Value(Json::objectValue), &battery).ok()) {
state.battery.percentage = jsonGet(battery, "battery_level", 0.0).asDouble();
state.battery.temperature = jsonGet(battery, "battery_temp", 0.0).asDouble();
state.battery.charging = jsonGet(battery, "charging", false).asBool();
state.battery.voltage = jsonGet(battery, "voltage", 0.0).asDouble();
state.battery.current = jsonGet(battery, "current", 0.0).asDouble();
}
Json::Value map;
if (sendCommand_(sock_status_, kRobotStatusMap, Json::Value(Json::objectValue), &map).ok()) {
state.current_map = jsonGet(map, "current_map", "").asString();
}
const auto nav = navigationStatus();
state.moving = nav.state == AgvTaskState::Running;
state.fault = nav.state == AgvTaskState::Failed;
state.mode = state.fault ? AgvMode::Fault : modeFromTaskState(static_cast<int>(nav.state));
return state;
}
AgvNavigationStatus SeerRobokitAgv::navigationStatus() const
{
AgvNavigationStatus status;
std::string missing_pose_task_detail;
for (int attempt = 0; attempt < 2; ++attempt) {
PoseTaskContext pose_context;
if (!currentPoseTask_(pose_context)) {
break;
}
const auto observed_navigation_generation =
navigation_generation_.load(std::memory_order_relaxed);
if (pose_context.navigation_generation
!= observed_navigation_generation) {
continue;
}
PoseTaskStatus task_status;
const auto result = queryPoseTaskStatus_(pose_context.task_id, task_status);
PoseTaskContext latest_context;
if (navigation_generation_.load(std::memory_order_relaxed)
!= observed_navigation_generation
|| !currentPoseTask_(latest_context)
|| latest_context.navigation_generation
!= pose_context.navigation_generation
|| latest_context.task_id != pose_context.task_id) {
continue;
}
status.type = AgvTaskType::NavigateToPose;
const auto fault_monitoring_unavailable =
[this, &pose_context]() {
if (controller_fault_channel_epoch_.load(
std::memory_order_relaxed)
!= pose_context
.controller_fault_channel_epoch_at_start) {
return std::string(
"the controller fault push channel changed or was "
"invalidated after the free-navigation command was "
"accepted");
}
return freeNavigationFaultStateUnavailableDetail_();
};
if (!result.ok()) {
status.state = AgvTaskState::Failed;
status.message = result.message;
return status;
}
if (!task_status.found || task_status.state == 404) {
std::uint64_t missing_task_fault_control_attempt = 0;
const std::string missing_task_fault =
cachedControllerFaultDetail_(
pose_context.controller_fault_sequence_at_start,
controllerFaultCaptureGraceMs_(),
&missing_task_fault_control_attempt);
PoseTaskContext post_missing_context;
if (navigation_generation_.load(std::memory_order_relaxed)
!= observed_navigation_generation
|| !currentPoseTask_(post_missing_context)
|| post_missing_context.navigation_generation
!= pose_context.navigation_generation
|| post_missing_context.task_id != pose_context.task_id) {
continue;
}
if (!missing_task_fault.empty()) {
std::string attribution;
if (missing_task_fault_control_attempt != 0
&& missing_task_fault_control_attempt
!= pose_context.control_attempt_sequence_at_start) {
attribution =
"controller_fault_attribution=ambiguous because the "
"fault was observed after another control command "
"attempt had begun, ";
}
status.state = AgvTaskState::Failed;
status.message =
"SEER Robokit tracked free-navigation task disappeared from "
"1110 task_status_package while a new controller fault "
"was observed: " + task_status.detail + ", "
+ attribution + missing_task_fault;
clearPoseTask_(pose_context.navigation_generation);
return status;
}
if (const std::string unavailable =
fault_monitoring_unavailable();
!unavailable.empty()) {
status.state = AgvTaskState::Failed;
status.message =
"SEER Robokit tracked free-navigation status is unsafe to "
"accept because controller fault monitoring is "
"unavailable: " + unavailable
+ "; query the controller and cancel or stop before "
"another motion command";
return status;
}
missing_pose_task_detail = task_status.detail;
clearPoseTask_(pose_context.navigation_generation);
break;
}
if (task_status.type_present && task_status.type != 1) {
status.state = AgvTaskState::Failed;
status.type = toTaskType(task_status.type);
status.message =
"SEER Robokit returned an unexpected task type for the tracked "
"free-navigation task: " + task_status.detail;
clearPoseTask_(pose_context.navigation_generation);
return status;
}
status.state = toTaskState(task_status.state);
status.progress = task_status.progress;
status.message = task_status.detail;
const auto controller_reported_state = status.state;
const bool controller_state_terminal =
controller_reported_state == AgvTaskState::Completed
|| controller_reported_state == AgvTaskState::Failed
|| controller_reported_state == AgvTaskState::Canceled;
std::uint64_t fault_control_attempt = 0;
const std::string fault = cachedControllerFaultDetail_(
pose_context.controller_fault_sequence_at_start,
controller_reported_state == AgvTaskState::Completed
|| controller_reported_state == AgvTaskState::Failed
? controllerFaultCaptureGraceMs_()
: 0,
&fault_control_attempt);
PoseTaskContext post_fault_context;
if (navigation_generation_.load(std::memory_order_relaxed)
!= observed_navigation_generation
|| !currentPoseTask_(post_fault_context)
|| post_fault_context.navigation_generation
!= pose_context.navigation_generation
|| post_fault_context.task_id != pose_context.task_id) {
continue;
}
const std::string unavailable =
fault_monitoring_unavailable();
if (!fault.empty()) {
std::string attribution;
if (fault_control_attempt != 0
&& fault_control_attempt
!= pose_context.control_attempt_sequence_at_start) {
attribution =
"controller_fault_attribution=ambiguous because the "
"fault was observed after another control command "
"attempt had begun, ";
}
status.state = AgvTaskState::Failed;
status.message =
"SEER Robokit reported a new controller fault while the tracked "
"free-navigation task had controller_task_state="
+ std::to_string(task_status.state) + ": "
+ task_status.detail + ", " + attribution + fault;
if (!unavailable.empty()) {
status.message +=
", controller_fault_monitoring_unavailable="
+ unavailable;
}
} else if (!unavailable.empty()) {
if (controller_reported_state == AgvTaskState::Failed
|| controller_reported_state == AgvTaskState::Canceled) {
status.message +=
", controller_fault_monitoring_unavailable="
+ unavailable;
} else {
status.state = AgvTaskState::Failed;
status.message =
"SEER Robokit tracked free-navigation state is unsafe to accept "
"because controller fault monitoring became unavailable: "
+ unavailable
+ "; query the controller and cancel or stop before "
"another motion command";
return status;
}
}
if (status.state == AgvTaskState::Completed) {
std::string pose_detail;
const bool target_reached =
poseTargetReached_(pose_context, pose_detail);
PoseTaskContext post_pose_context;
if (navigation_generation_.load(std::memory_order_relaxed)
!= observed_navigation_generation
|| !currentPoseTask_(post_pose_context)
|| post_pose_context.navigation_generation
!= pose_context.navigation_generation
|| post_pose_context.task_id != pose_context.task_id) {
continue;
}
std::uint64_t post_pose_fault_control_attempt = 0;
const std::string post_pose_fault =
cachedControllerFaultDetail_(
pose_context.controller_fault_sequence_at_start,
0,
&post_pose_fault_control_attempt);
if (!post_pose_fault.empty()) {
status.state = AgvTaskState::Failed;
std::string attribution;
if (post_pose_fault_control_attempt != 0
&& post_pose_fault_control_attempt
!= pose_context
.control_attempt_sequence_at_start) {
attribution =
"controller_fault_attribution=ambiguous because the "
"fault was observed after another control command "
"attempt had begun, ";
}
status.message =
"SEER Robokit reported the tracked free-navigation task "
"Completed, but a new controller fault was observed during "
"target verification: " + task_status.detail + ", "
+ attribution + post_pose_fault;
} else if (const std::string post_pose_unavailable =
fault_monitoring_unavailable();
!post_pose_unavailable.empty()) {
status.state = AgvTaskState::Failed;
status.message =
"SEER Robokit tracked free-navigation completion is unsafe to "
"accept because controller fault monitoring became "
"unavailable: " + post_pose_unavailable
+ "; query the controller and cancel or stop before "
"another motion command";
return status;
} else if (!target_reached) {
status.state = AgvTaskState::Failed;
status.message =
"SEER Robokit reported the tracked free-navigation task "
"Completed, but the requested target was not reached: "
+ task_status.detail + ", " + pose_detail;
} else {
status.message += ", target_verified: " + pose_detail;
}
}
if (controller_state_terminal) {
clearPoseTask_(pose_context.navigation_generation);
}
return status;
}
PoseTaskContext changed_context;
if (currentPoseTask_(changed_context)) {
status.state = AgvTaskState::Waiting;
status.type = AgvTaskType::NavigateToPose;
status.message =
"SEER Robokit free-navigation task changed while its status was being "
"queried; query navigation status again";
return status;
}
Json::Value payload(Json::objectValue);
jsonMember(payload, "simple") = false;
Json::Value response;
const auto result = sendCommand_(sock_status_, kRobotStatusTask, payload, &response);
if (!result.ok()) {
status.state = AgvTaskState::Failed;
status.message = missing_pose_task_detail.empty()
? result.message
: missing_pose_task_detail + "; 1020 status query failed: "
+ result.message;
return status;
}
const auto controller_result = resultFromResponse_(response);
if (!controller_result.ok()) {
status.state = AgvTaskState::Failed;
status.message = missing_pose_task_detail.empty()
? controller_result.message
: missing_pose_task_detail + "; 1020 status query failed: "
+ controller_result.message;
return status;
}
status.state = toTaskState(jsonGet(response, "task_status", 0).asInt());
status.type = toTaskType(jsonGet(response, "task_type", 0).asInt());
status.message = jsonGet(response, "move_status_info", jsonGet(response, "err_msg", "")).asString();
if (!missing_pose_task_detail.empty()) {
status.message = missing_pose_task_detail
+ "; fallback_1020_status=" + std::to_string(
jsonGet(response, "task_status", 0).asInt())
+ ", fallback_1020_type=" + std::to_string(
jsonGet(response, "task_type", 0).asInt())
+ (status.message.empty() ? std::string{} : ", " + status.message);
}
if (const auto* task_status_package = jsonFind(response, "task_status_package")) {
status.progress = jsonGet(*task_status_package, "percentage", 0.0).asDouble();
}
return status;
}
AgvResult SeerRobokitAgv::configurePush_()
{
if (config_.state_push_included_fields_size() > 0 && config_.state_push_excluded_fields_size() > 0) {
return AgvResult::failure(
AgvErrorCode::InvalidArgument,
"SEER Robokit push included_fields and excluded_fields cannot both be set");
}
Json::Value payload(Json::objectValue);
if (config_.state_push_interval_ms() > 0) {
jsonMember(payload, "interval") = config_.state_push_interval_ms();
}
appendStringArray(payload, "included_fields", config_.state_push_included_fields());
appendStringArray(payload, "excluded_fields", config_.state_push_excluded_fields());
if (payload.empty()) {
return AgvResult::success();
}
const std::string payload_text = toJsonString_(payload);
const auto frame = buildFrame_(kRobotPushConfigReq, payload_text);
std::lock_guard<std::mutex> lock(mutex_);
if (sock_push_ < 0) {
return AgvResult::failure(AgvErrorCode::NotConnected, "SEER Robokit push socket not connected");
}
if (::send(sock_push_, frame.data(), frame.size(), MSG_NOSIGNAL) != static_cast<ssize_t>(frame.size())) {
return AgvResult::failure(AgvErrorCode::CommandFailed, "SEER Robokit send push config failed: " + systemError());
}
while (true) {
std::uint16_t command = 0;
std::string response_payload;
const auto result = receiveFrame_(sock_push_, command, response_payload);
if (!result.ok()) {
return result;
}
Json::Value response;
std::string error;
if (!response_payload.empty() && !parseJson_(response_payload, response, error)) {
return AgvResult::failure(AgvErrorCode::CommandFailed, error);
}
if (command == kRobotPushConfigRes) {
return resultFromResponse_(response);
}
if (command == kRobotPush && response.isObject()) {
updateCachedRuntimeState_(response);
}
}
}
void SeerRobokitAgv::startPushThread_()
{
if (!state_push_enabled_) {
return;
}
if (push_running_.exchange(true)) {
return;
}
if (sock_push_ < 0) {
push_running_ = false;
return;
}
push_thread_ = std::thread(&SeerRobokitAgv::pushLoop_, this);
}
void SeerRobokitAgv::stopPushThread_()
{
const bool was_running = push_running_.exchange(false);
if (was_running) {
int sock = -1;
{
std::lock_guard<std::mutex> lock(mutex_);
sock = sock_push_;
}
if (sock >= 0) {
::shutdown(sock, SHUT_RDWR);
}
}
if (push_thread_.joinable()) {
push_thread_.join();
}
invalidateControllerFaultState_();
}
void SeerRobokitAgv::pushLoop_()
{
while (push_running_) {
int sock = -1;
{
std::lock_guard<std::mutex> lock(mutex_);
sock = sock_push_;
}
if (sock < 0) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
continue;
}
std::uint16_t command = 0;
std::string payload;
const auto result = receiveFrame_(sock, command, payload);
if (!push_running_) {
break;
}
if (!result.ok()) {
if (result.code != AgvErrorCode::Timeout) {
invalidateControllerFaultState_();
std::lock_guard<std::mutex> lock(mutex_);
last_error_ = result.message;
closeSocket_(sock_push_);
}
continue;
}
if (command != kRobotPush || payload.empty()) {
continue;
}
Json::Value parsed;
std::string error;
if (!parseJson_(payload, parsed, error)) {
invalidateControllerFaultState_();
std::lock_guard<std::mutex> lock(mutex_);
last_error_ = error;
continue;
}
updateCachedRuntimeState_(parsed);
}
}
void SeerRobokitAgv::invalidateControllerFaultState_()
{
std::lock_guard<std::mutex> lock(runtime_state_mutex_);
controller_fault_channel_epoch_.fetch_add(
1,
std::memory_order_relaxed);
controller_fault_state_observed_ = false;
controller_fault_state_observed_at_ = {};
active_controller_fault_detail_.clear();
runtime_state_cv_.notify_all();
}
void SeerRobokitAgv::updateCachedRuntimeState_(const Json::Value& payload)
{
std::lock_guard<std::mutex> lock(runtime_state_mutex_);
auto state = cached_runtime_state_valid_ ? cached_runtime_state_ : AgvRuntimeState{};
state.timestamp = nowSeconds();
state.connected = true;
if (jsonHas(payload, "x")) state.pose.x = jsonGet(payload, "x", state.pose.x).asDouble();
if (jsonHas(payload, "y")) state.pose.y = jsonGet(payload, "y", state.pose.y).asDouble();
if (jsonHas(payload, "angle")) state.pose.theta = jsonGet(payload, "angle", state.pose.theta).asDouble();
if (jsonHas(payload, "vx")) state.velocity.vx = jsonGet(payload, "vx", state.velocity.vx).asDouble();
if (jsonHas(payload, "vy")) state.velocity.vy = jsonGet(payload, "vy", state.velocity.vy).asDouble();
if (jsonHas(payload, "w")) state.velocity.wz = jsonGet(payload, "w", state.velocity.wz).asDouble();
if (jsonHas(payload, "battery_level")) {
state.battery.percentage = jsonGet(payload, "battery_level", state.battery.percentage).asDouble();
}
if (jsonHas(payload, "battery_temp")) {
state.battery.temperature = jsonGet(payload, "battery_temp", state.battery.temperature).asDouble();
}
if (jsonHas(payload, "charging")) {
state.battery.charging = jsonGet(payload, "charging", state.battery.charging).asBool();
}
if (jsonHas(payload, "voltage")) {
state.battery.voltage = jsonGet(payload, "voltage", state.battery.voltage).asDouble();
}
if (jsonHas(payload, "current")) {
state.battery.current = jsonGet(payload, "current", state.battery.current).asDouble();
}
if (jsonHas(payload, "current_map")) {
state.current_map = jsonGet(payload, "current_map", state.current_map).asString();
}
if (jsonHas(payload, "current_station")) {
state.current_station = jsonGet(payload, "current_station", state.current_station).asString();
}
if (jsonHas(payload, "confidence")) {
state.localized = jsonGet(payload, "confidence", 0.0).asDouble() > 0.0;
}
if (jsonHas(payload, "emergency")) {
state.emergency_stopped = jsonGet(payload, "emergency", state.emergency_stopped).asBool();
}
state.moving = std::hypot(state.velocity.vx, state.velocity.vy) > 1e-4 || std::abs(state.velocity.wz) > 1e-4;
const bool has_fatals = jsonHas(payload, "fatals");
const bool has_errors = jsonHas(payload, "errors");
const bool has_fault_fields = has_fatals || has_errors;
if (has_fault_fields) {
const auto* fatals = jsonFind(payload, "fatals");
const auto* errors = jsonFind(payload, "errors");
const bool valid_fatals = !has_fatals
|| (fatals && fatals->isArray());
const bool valid_errors = !has_errors
|| (errors && errors->isArray());
const bool complete_fault_state =
has_fatals && has_errors && valid_fatals && valid_errors;
if (complete_fault_state) {
controller_fault_state_observed_ = true;
controller_fault_state_observed_at_ =
std::chrono::steady_clock::now();
} else {
controller_fault_state_observed_ = false;
controller_fault_state_observed_at_ = {};
}
const bool reported_fault =
hasFaultArray(payload, "fatals")
|| hasFaultArray(payload, "errors");
const bool invalid_or_incomplete_fault_state =
!complete_fault_state && !reported_fault;
state.fault = reported_fault
|| invalid_or_incomplete_fault_state;
if (state.fault) {
std::ostringstream detail;
detail << (reported_fault
? "SEER Robokit controller fault"
: "SEER Robokit controller fault state is incomplete or malformed");
if (fatals
&& (!fatals->isArray()
|| !fatals->empty()
|| !complete_fault_state)) {
detail << ": fatals="
<< (fatals->isNull()
? std::string("null")
: jsonValueToString(*fatals));
}
if (errors
&& (!errors->isArray()
|| !errors->empty()
|| !complete_fault_state)) {
detail << ": errors="
<< (errors->isNull()
? std::string("null")
: jsonValueToString(*errors));
}
state.last_error = detail.str();
if (state.last_error != active_controller_fault_detail_) {
active_controller_fault_detail_ = state.last_error;
++controller_fault_sequence_;
last_controller_fault_timestamp_ = state.timestamp;
last_controller_fault_detail_ = state.last_error;
last_controller_fault_control_attempt_ =
control_attempt_sequence_.load(
std::memory_order_acquire);
}
} else {
state.last_error.clear();
active_controller_fault_detail_.clear();
}
}
if (state.emergency_stopped) {
state.mode = AgvMode::EmergencyStop;
} else if (state.fault) {
state.mode = AgvMode::Fault;
} else if (state.battery.charging) {
state.mode = AgvMode::Charging;
} else if (state.moving) {
state.mode = AgvMode::Auto;
} else {
state.mode = AgvMode::Idle;
}
cached_runtime_state_ = state;
cached_runtime_state_valid_ = true;
runtime_state_cv_.notify_all();
}
} // namespace cmvr::device

View File

@ -0,0 +1,362 @@
#include "seer_robokit_agv.h"
#include "seer_robokit_protocol.h"
#include "seer_robokit_utils.h"
#include <algorithm>
#include <arpa/inet.h>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <mutex>
#include <string>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
#include <utility>
#include <vector>
namespace cmvr::device {
using namespace seer_robokit::protocol;
using namespace seer_robokit::detail;
AgvResult SeerRobokitAgv::connectSocket_(int& sock, const int port)
{
sock = ::socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
last_error_ = "create socket failed: " + systemError();
return AgvResult::failure(AgvErrorCode::ConnectionFailed, last_error_);
}
sockaddr_in address{};
address.sin_family = AF_INET;
address.sin_port = htons(static_cast<std::uint16_t>(port));
if (::inet_pton(AF_INET, ip_.c_str(), &address.sin_addr) <= 0) {
closeSocket_(sock);
last_error_ = "invalid SEER Robokit ip: " + ip_;
return AgvResult::failure(AgvErrorCode::InvalidArgument, last_error_);
}
if (::connect(sock, reinterpret_cast<sockaddr*>(&address), sizeof(address)) < 0) {
closeSocket_(sock);
last_error_ = "connect SEER Robokit port " + std::to_string(port) + " failed: " + systemError();
return AgvResult::failure(AgvErrorCode::ConnectionFailed, last_error_);
}
timeval timeout{};
timeout.tv_sec = recv_timeout_ms_ / 1000;
timeout.tv_usec = (recv_timeout_ms_ % 1000) * 1000;
::setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
return AgvResult::success();
}
AgvResult SeerRobokitAgv::ensureOtherSocket_()
{
std::lock_guard<std::mutex> lock(mutex_);
if (sock_other_ >= 0) {
return AgvResult::success();
}
return connectSocket_(sock_other_, ports_.other);
}
void SeerRobokitAgv::closeSocket_(int& sock) const
{
if (sock >= 0) {
::close(sock);
sock = -1;
}
}
bool SeerRobokitAgv::connected_() const
{
return sock_status_ >= 0 && sock_control_ >= 0 && sock_navigation_ >= 0 && sock_config_ >= 0;
}
AgvResult SeerRobokitAgv::sendCommand_(
const int sock,
const std::uint16_t command,
const Json::Value& payload,
Json::Value* response,
CommandTransmissionState* transmission_state) const
{
std::string response_payload;
auto result = sendCommandRaw_(
sock,
command,
payload,
&response_payload,
transmission_state);
if (!result.ok()) {
return result;
}
if (!response) {
return AgvResult::success();
}
Json::Value parsed;
std::string error;
if (!parseJson_(response_payload, parsed, error)) {
const std::string json_text = extractJson_(response_payload);
if (json_text.empty() || !parseJson_(json_text, parsed, error)) {
return AgvResult::failure(AgvErrorCode::CommandFailed, error);
}
}
*response = std::move(parsed);
return AgvResult::success();
}
AgvResult SeerRobokitAgv::sendCommandRaw_(
const int sock,
const std::uint16_t command,
const Json::Value& payload,
std::string* response_payload,
CommandTransmissionState* transmission_state) const
{
if (transmission_state) {
*transmission_state = CommandTransmissionState::NotSent;
}
const auto exchange = [&]() {
const std::string payload_text = payload.empty() ? std::string{} : toJsonString_(payload);
const auto frame = buildFrame_(command, payload_text);
const auto sent = ::send(
sock,
frame.data(),
frame.size(),
MSG_NOSIGNAL);
if (sent > 0 && transmission_state) {
*transmission_state = CommandTransmissionState::PossiblySent;
}
if (sent != static_cast<ssize_t>(frame.size())) {
return AgvResult::failure(
AgvErrorCode::CommandFailed,
"SEER Robokit send command failed: " + systemError());
}
std::uint16_t response_command = 0;
std::string payload_text_response;
const auto result = receiveFrame_(sock, response_command, payload_text_response);
if (!result.ok()) {
return result;
}
const auto expected_response_command = static_cast<std::uint16_t>(
command + 10000U);
if (response_command != expected_response_command) {
return AgvResult::failure(
AgvErrorCode::CommandFailed,
"SEER Robokit response command mismatch: expected="
+ std::to_string(expected_response_command)
+ ", actual=" + std::to_string(response_command));
}
if (response_payload) {
*response_payload = std::move(payload_text_response);
}
return AgvResult::success();
};
const auto close_matching_socket_locked = [this, sock]() {
if (sock == sock_status_) {
closeSocket_(sock_status_);
} else if (sock == sock_control_) {
closeSocket_(sock_control_);
} else if (sock == sock_navigation_) {
closeSocket_(sock_navigation_);
} else if (sock == sock_config_) {
closeSocket_(sock_config_);
} else if (sock == sock_other_) {
closeSocket_(sock_other_);
}
};
const auto mark_channel_desynchronized = [](AgvResult result) {
std::string detail = result.message.empty()
? "unknown transport or frame error"
: result.message;
detail +=
"; SEER Robokit channel closed because the response stream may be "
"desynchronized; reconnect before sending another command";
return AgvResult::failure(result.code, detail);
};
bool is_status_socket = false;
{
std::lock_guard<std::mutex> lock(mutex_);
if (sock < 0) {
return AgvResult::failure(
AgvErrorCode::NotConnected,
"SEER Robokit socket not connected");
}
is_status_socket = sock == sock_status_;
}
if (is_status_socket) {
// A slow 1110 status response must never hold the lifecycle/global I/O
// mutex needed by cancelNavigation() or emergencyStop(). The dedicated
// status lock still serializes requests on port 19204. connect_() and
// disconnect_() take this lock before changing the descriptor.
std::lock_guard<std::mutex> status_lock(status_io_mutex_);
{
std::lock_guard<std::mutex> lock(mutex_);
if (sock < 0 || sock != sock_status_) {
return AgvResult::failure(
AgvErrorCode::NotConnected,
"SEER Robokit status socket is no longer connected");
}
}
auto result = exchange();
if (!result.ok()) {
std::lock_guard<std::mutex> lock(mutex_);
close_matching_socket_locked();
return mark_channel_desynchronized(std::move(result));
}
return result;
}
std::lock_guard<std::mutex> lock(mutex_);
if (sock < 0
|| (sock != sock_control_
&& sock != sock_navigation_
&& sock != sock_config_
&& sock != sock_other_)) {
return AgvResult::failure(
AgvErrorCode::NotConnected,
"SEER Robokit socket is no longer connected");
}
auto result = exchange();
if (!result.ok()) {
close_matching_socket_locked();
return mark_channel_desynchronized(std::move(result));
}
return result;
}
AgvResult SeerRobokitAgv::sendCommandNoResponse_(
const int sock,
const std::uint16_t command,
const Json::Value& payload) const
{
return sendCommand_(sock, command, payload, nullptr);
}
std::vector<std::uint8_t> SeerRobokitAgv::buildFrame_(
const std::uint16_t command,
const std::string& payload)
{
std::vector<std::uint8_t> frame(16 + payload.size(), 0);
frame[0] = 0x5A;
frame[1] = 0x01;
frame[2] = 0x00;
frame[3] = 0x01;
const auto length = static_cast<std::uint32_t>(payload.size());
frame[4] = static_cast<std::uint8_t>((length >> 24U) & 0xFFU);
frame[5] = static_cast<std::uint8_t>((length >> 16U) & 0xFFU);
frame[6] = static_cast<std::uint8_t>((length >> 8U) & 0xFFU);
frame[7] = static_cast<std::uint8_t>(length & 0xFFU);
frame[8] = static_cast<std::uint8_t>((command >> 8U) & 0xFFU);
frame[9] = static_cast<std::uint8_t>(command & 0xFFU);
std::copy(payload.begin(), payload.end(), frame.begin() + 16);
return frame;
}
std::string SeerRobokitAgv::toJsonString_(const Json::Value& value)
{
Json::StreamWriterBuilder builder;
builder["indentation"] = "";
return Json::writeString(builder, value);
}
bool SeerRobokitAgv::parseJson_(const std::string& input, Json::Value& output, std::string& error)
{
Json::CharReaderBuilder builder;
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
return reader->parse(input.data(), input.data() + input.size(), &output, &error);
}
std::string SeerRobokitAgv::extractJson_(const std::string& raw)
{
const auto begin = raw.find('{');
const auto end = raw.rfind('}');
if (begin == std::string::npos || end == std::string::npos || end < begin) {
return {};
}
return raw.substr(begin, end - begin + 1);
}
AgvResult SeerRobokitAgv::receiveFrame_(const int sock, std::uint16_t& command, std::string& payload)
{
const auto recv_exact = [](const int fd, std::uint8_t* data, const std::size_t size) -> AgvResult {
std::size_t offset = 0;
while (offset < size) {
const ssize_t count = ::recv(fd, data + offset, size - offset, 0);
if (count > 0) {
offset += static_cast<std::size_t>(count);
continue;
}
if (count == 0) {
return AgvResult::failure(AgvErrorCode::NotConnected, "SEER Robokit socket closed");
}
if (errno == EINTR) {
continue;
}
if (errno == EAGAIN || errno == EWOULDBLOCK) {
return AgvResult::failure(AgvErrorCode::Timeout, "SEER Robokit receive timeout");
}
return AgvResult::failure(AgvErrorCode::CommandFailed, "SEER Robokit receive failed: " + systemError());
}
return AgvResult::success();
};
std::uint8_t header[16]{};
auto result = recv_exact(sock, header, sizeof(header));
if (!result.ok()) {
return result;
}
if (header[0] != 0x5A) {
return AgvResult::failure(AgvErrorCode::CommandFailed, "SEER Robokit frame header is invalid");
}
const auto length = (static_cast<std::uint32_t>(header[4]) << 24U)
| (static_cast<std::uint32_t>(header[5]) << 16U)
| (static_cast<std::uint32_t>(header[6]) << 8U)
| static_cast<std::uint32_t>(header[7]);
command = static_cast<std::uint16_t>((static_cast<std::uint16_t>(header[8]) << 8U) | header[9]);
payload.clear();
if (length == 0) {
return AgvResult::success();
}
if (length > kMaxFramePayloadBytes) {
return AgvResult::failure(AgvErrorCode::CommandFailed, "SEER Robokit frame payload is too large");
}
std::vector<std::uint8_t> buffer(length);
result = recv_exact(sock, buffer.data(), buffer.size());
if (!result.ok()) {
return result;
}
payload.assign(reinterpret_cast<const char*>(buffer.data()), buffer.size());
return AgvResult::success();
}
AgvResult SeerRobokitAgv::resultFromResponse_(const Json::Value& response)
{
if (!hasNumericControllerRetCode(response)) {
return AgvResult::failure(
AgvErrorCode::CommandFailed,
"SEER Robokit controller response is missing a numeric ret_code");
}
const auto* ret_code_value = jsonFind(response, "ret_code");
const bool success = ret_code_value->isUInt() || ret_code_value->isUInt64()
? ret_code_value->asUInt64() == 0
: ret_code_value->asInt64() == 0;
const std::string ret_code = jsonValueToString(*ret_code_value);
const std::string message = jsonGet(response, "err_msg", "").asString();
if (success) {
return AgvResult::success();
}
std::string detail = "SEER Robokit command failed: ret_code=" + ret_code;
if (!message.empty()) {
detail += ", err_msg=" + message;
}
return AgvResult::failure(AgvErrorCode::CommandFailed, detail);
}
} // namespace cmvr::device

View File

@ -2,10 +2,18 @@ add_library(aubo_arm SHARED
src/aubo_arm.cpp
)
find_package(Threads REQUIRED)
target_include_directories(aubo_arm PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
set(AUBO_SDK_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/third_party/AuboSdk/linux/include)
set(AUBO_SDK_LIB_DIR ${CMAKE_SOURCE_DIR}/third_party/AuboSdk/linux/lib)
if(NOT DEFINED AUBO_SDK_ROOT)
set(AUBO_SDK_ROOT ${CMAKE_SOURCE_DIR}/dependency/${ARCH}/third_party/aubo_sdk/v0.27.1)
endif()
if(NOT EXISTS "${AUBO_SDK_ROOT}/include/aubo_sdk/rpc.h")
set(AUBO_SDK_ROOT ${CMAKE_SOURCE_DIR}/third_party/AuboSdk/linux)
endif()
set(AUBO_SDK_INCLUDE_DIR ${AUBO_SDK_ROOT}/include)
set(AUBO_SDK_LIB_DIR ${AUBO_SDK_ROOT}/lib)
if (EXISTS "${AUBO_SDK_INCLUDE_DIR}/aubo_sdk/rpc.h")
target_compile_definitions(aubo_arm PRIVATE CMVR_HAS_AUBO_SDK)
@ -23,7 +31,17 @@ target_link_libraries(aubo_arm
cmvr_es::proto
PRIVATE
glog
Threads::Threads
)
add_library(cmvr_es::device::aubo_arm ALIAS aubo_arm)
install(TARGETS aubo_arm LIBRARY DESTINATION lib)
if(BUILD_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)
endif()

View File

@ -2,10 +2,12 @@
#define CMVR_ES_AUBO_ARM_H
#include <atomic>
#include <condition_variable>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <thread>
#include <vector>
#include "cmvr/config/arm_config/arm_config.pb.h"
@ -28,8 +30,11 @@ public:
JointGroupState getJointState() const override;
CartesianPose getTcpPose(FrameType frame = FrameType::Base) const override;
RobotMode getRobotMode() const override;
SafetyMode getSafetyMode() const override { return SafetyMode::Normal; }
SafetyMode getSafetyMode() const override;
ControlMode getControlMode() const override { return ControlMode::Position; }
bool supportsActionQueueMotion() const noexcept override { return true; }
Result listBaseFrame(std::vector<std::string>& frame_names) const override;
Result listTCPFrame(std::vector<std::string>& frame_names) const override;
Result torqueOn() override;
Result torqueOff() override;
@ -39,13 +44,19 @@ public:
Result setSpeedScaling(double scaling) override;
double getSpeedScaling() const override { return speed_scaling_; }
bool isProtectiveStopped() const override { return false; }
bool isEmergencyStopped() const override { return emergency_stopped_; }
bool isFault() const override { return false; }
bool isEmergencyStopped() const override;
bool isFault() const override;
Result moveJ(const JointPositionCommand& target, const MotionOptions& options) override;
Result speedJ(const JointVelocityCommand& velocity, double acceleration, double duration) override;
Result stopJ(double acceleration) override;
Result moveL(const CartesianPose& target, const MotionOptions& options, FrameType frame = FrameType::Base) override;
Result moveL(const CartesianPose& target,
const MotionOptions& options,
FrameType frame = FrameType::Base) override;
Result moveL(const CartesianPose& target,
const MotionOptions& options,
const std::string& base_frame,
const std::string& tcp_frame) override;
Result speedL(const CartesianVelocity& velocity, double acceleration, double duration, FrameType frame = FrameType::Base) override;
Result stopL(std::optional<double> acceleration = std::nullopt) override;
Result stopMotion() override;
@ -84,9 +95,11 @@ private:
Result unsupported_(const std::string& name) const;
bool validDof_(std::size_t size, std::string& error) const;
Result ensureConnected_(const std::string& context) const;
Result ensureMotionReady_(const std::string& context) const;
#if defined(CMVR_HAS_AUBO_SDK)
struct SdkState;
void autoEnableMonitorLoop_();
#endif
private:
@ -97,10 +110,15 @@ private:
int port_{30004};
std::string username_;
std::string password_;
bool auto_enable_{false};
double speed_scaling_{1.0};
std::atomic<bool> connected_{false};
std::atomic<bool> busy_{false};
bool emergency_stopped_{false};
std::atomic<bool> emergency_stopped_{false};
std::atomic<bool> hardware_emergency_stopped_{false};
std::atomic<int> hardware_safety_mode_{0};
std::atomic<bool> hardware_estop_latched_{false};
std::atomic<bool> auto_recovery_suppressed_{false};
mutable std::mutex mutex_;
#if defined(CMVR_HAS_AUBO_SDK)

View File

@ -0,0 +1,34 @@
#ifndef CMVR_ES_AUBO_MOTION_RESULT_H
#define CMVR_ES_AUBO_MOTION_RESULT_H
namespace cmvr::device::aubo_internal {
enum class MotionCommandOutcome {
CompletedWithoutMotion,
CompletedAfterMotion,
SubmitFailed,
CompletionFailed,
};
template <typename WaitForCompletion>
MotionCommandOutcome resolveMotionCommand(
const int return_code,
const int success_code,
const int request_ignore_code,
WaitForCompletion&& wait_for_completion)
{
if (return_code == request_ignore_code) {
return MotionCommandOutcome::CompletedWithoutMotion;
}
if (return_code != success_code) {
return MotionCommandOutcome::SubmitFailed;
}
if (wait_for_completion() != 0) {
return MotionCommandOutcome::CompletionFailed;
}
return MotionCommandOutcome::CompletedAfterMotion;
}
} // namespace cmvr::device::aubo_internal
#endif // CMVR_ES_AUBO_MOTION_RESULT_H

View File

@ -1,8 +1,11 @@
#include "devices/arm/aubo_arm/include/aubo_arm.h"
#include "devices/arm/aubo_arm/include/aubo_motion_result.h"
#include <algorithm>
#include <chrono>
#include <exception>
#include <set>
#include <stdexcept>
#include <thread>
#include "common/base/logging/logger.h"
@ -40,11 +43,179 @@ std::string vendorBrandName(const config::VendorRobotArmBrand brand)
}
}
#if defined(CMVR_HAS_AUBO_SDK)
constexpr auto kAutoEnablePollInterval = std::chrono::milliseconds(100);
constexpr auto kAutoEnableReconnectInterval = std::chrono::milliseconds(500);
constexpr auto kAutoEnableRetryInterval = std::chrono::seconds(1);
constexpr auto kAutoEnableModeTimeout = std::chrono::seconds(10);
int waitArrival(
const arcs::aubo_sdk::RobotInterfacePtr& robot_interface,
const std::function<bool()>& cancellation_requested = {})
{
const auto deadline =
std::chrono::steady_clock::now() + std::chrono::seconds(60);
const auto canceled = [&]() {
return cancellation_requested && cancellation_requested();
};
const auto hardwareEmergencyStopActive = [&]() {
const auto mode = robot_interface->getRobotState()->getSafetyModeType();
const int source = robot_interface->getRobotConfig()
->getRobotEmergencyStopSource();
using arcs::common_interface::SafetyModeType;
return mode == SafetyModeType::RobotEmergencyStop ||
mode == SafetyModeType::SystemEmergencyStop || source != 0;
};
const auto stopMotion = [&]() {
try {
(void)robot_interface->getMotionControl()->stopMove(true, true);
} catch (...) {
}
};
int retry_count = 0;
int exec_id = robot_interface->getMotionControl()->getExecId();
while (exec_id == -1 && retry_count++ < 5) {
if (canceled()) {
stopMotion();
return -2;
}
if (hardwareEmergencyStopActive()) {
return -3;
}
std::this_thread::sleep_for(std::chrono::milliseconds(50));
exec_id = robot_interface->getMotionControl()->getExecId();
}
if (exec_id == -1) {
return -1;
}
while (robot_interface->getMotionControl()->getExecId() != -1) {
if (canceled()) {
stopMotion();
return -2;
}
if (hardwareEmergencyStopActive()) {
return -3;
}
if (std::chrono::steady_clock::now() >= deadline) {
stopMotion();
return -4;
}
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
return 0;
}
bool isHardwareEmergencyStop(
const arcs::common_interface::SafetyModeType mode,
const int robot_emergency_stop_source)
{
using arcs::common_interface::SafetyModeType;
return mode == SafetyModeType::RobotEmergencyStop ||
mode == SafetyModeType::SystemEmergencyStop ||
robot_emergency_stop_source != 0;
}
bool isHardwareEmergencyStopReleased(
const arcs::common_interface::SafetyModeType mode,
const int robot_emergency_stop_source)
{
using arcs::common_interface::SafetyModeType;
return robot_emergency_stop_source == 0 &&
(mode == SafetyModeType::Normal ||
mode == SafetyModeType::ReducedMode);
}
SafetyMode toPublicSafetyMode(
const arcs::common_interface::SafetyModeType mode,
const int robot_emergency_stop_source)
{
using arcs::common_interface::SafetyModeType;
if (mode == SafetyModeType::SystemEmergencyStop) {
return SafetyMode::SystemEmergencyStop;
}
if (mode == SafetyModeType::RobotEmergencyStop ||
robot_emergency_stop_source != 0) {
return SafetyMode::EmergencyStop;
}
switch (mode) {
case SafetyModeType::Normal:
return SafetyMode::Normal;
case SafetyModeType::ReducedMode:
return SafetyMode::Reduced;
case SafetyModeType::ProtectiveStop:
return SafetyMode::ProtectiveStop;
case SafetyModeType::SafeguardStop:
return SafetyMode::SafeguardStop;
case SafetyModeType::Violation:
case SafetyModeType::Fault:
return SafetyMode::Fault;
case SafetyModeType::Recovery:
case SafetyModeType::Undefined:
case SafetyModeType::SystemEmergencyStop:
case SafetyModeType::RobotEmergencyStop:
break;
}
return SafetyMode::Unknown;
}
std::vector<std::string> listAuboWorldFrames(
const arcs::common_interface::SyncMovePtr& sync_move)
{
if (!sync_move) {
return {};
}
std::set<std::string> frame_names{"world", "base", "flange", "tcp"};
std::vector<std::string> pending(frame_names.begin(), frame_names.end());
for (std::size_t index = 0; index < pending.size(); ++index) {
for (const auto& child : sync_move->frameGetChildren(pending[index])) {
if (!child.empty() && sync_move->frameExist(child) &&
frame_names.insert(child).second) {
pending.push_back(child);
}
}
}
return {frame_names.begin(), frame_names.end()};
}
bool isAuboTcpFrame(const arcs::common_interface::SyncMovePtr& sync_move,
const std::string& frame_name)
{
if (frame_name == "tool0" || frame_name == "flange" ||
frame_name == "tcp") {
return true;
}
if (!sync_move || !sync_move->frameExist(frame_name)) {
return false;
}
std::set<std::string> visited;
std::string current = frame_name;
while (visited.insert(current).second) {
const std::string parent = sync_move->frameGetParent(current);
if (parent == "flange" || parent == "tcp") {
return true;
}
if (parent.empty() || parent == "world" || parent == "base" ||
parent == current) {
return false;
}
current = parent;
}
return false;
}
#endif
} // namespace
#if defined(CMVR_HAS_AUBO_SDK)
struct AuboArm::SdkState {
std::shared_ptr<arcs::aubo_sdk::RpcClient> rpc_client;
std::atomic<bool> monitor_running{false};
std::mutex monitor_wait_mutex;
std::condition_variable monitor_cv;
std::thread monitor_thread;
};
#endif
@ -60,6 +231,7 @@ AuboArm::AuboArm(const config::RobotArmConfig& cfg)
port_ = vendor_cfg_.port() > 0 ? vendor_cfg_.port() : 30004;
username_ = vendor_cfg_.username().empty() ? "aubo" : vendor_cfg_.username();
password_ = vendor_cfg_.password().empty() ? "123456" : vendor_cfg_.password();
auto_enable_ = vendor_cfg_.auto_enable();
const auto dof = vendor_cfg_.dof() > 0 ? static_cast<std::size_t>(vendor_cfg_.dof()) : 6U;
model_.name = vendor_cfg_.model().empty() ? "AuboARM" : vendor_cfg_.model();
@ -109,7 +281,8 @@ ArmState AuboArm::getRobotState() const
state.robot_mode = getRobotMode();
state.safety_mode = getSafetyMode();
state.control_mode = getControlMode();
state.emergency_stopped = emergency_stopped_;
state.emergency_stopped = isEmergencyStopped();
state.fault = isFault();
state.speed_scaling = speed_scaling_;
state.actual_joint_state = getJointState();
state.target_joint_state = state.actual_joint_state;
@ -167,12 +340,107 @@ RobotMode AuboArm::getRobotMode() const
if (!connected_.load()) {
return RobotMode::Disconnected;
}
if (emergency_stopped_) {
if (isEmergencyStopped()) {
return RobotMode::Stopped;
}
return busy_.load() ? RobotMode::Running : RobotMode::Idle;
}
SafetyMode AuboArm::getSafetyMode() const
{
if (emergency_stopped_.load()) {
return SafetyMode::EmergencyStop;
}
return static_cast<SafetyMode>(hardware_safety_mode_.load());
}
bool AuboArm::isEmergencyStopped() const
{
return emergency_stopped_.load() || hardware_emergency_stopped_.load();
}
bool AuboArm::isFault() const
{
return getSafetyMode() == SafetyMode::Fault;
}
Result AuboArm::listBaseFrame(std::vector<std::string>& frame_names) const
{
frame_names.clear();
const auto ready = ensureConnected_("ListBaseFrame");
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] robot name list is empty");
}
const auto robot_interface =
sdk_->rpc_client->getRobotInterface(robot_names.front());
if (!robot_interface || !robot_interface->getSyncMove()) {
return Result::failure(
ArmErrorCode::RobotNotReady,
"[AuboArm] world-frame interface is unavailable");
}
frame_names = listAuboWorldFrames(robot_interface->getSyncMove());
return Result::success();
} catch (const std::exception& e) {
return Result::failure(
ArmErrorCode::CommandFailed,
std::string("[AuboArm] ListBaseFrame failed: ") + e.what());
}
#else
return unsupported_("ListBaseFrame");
#endif
}
Result AuboArm::listTCPFrame(std::vector<std::string>& frame_names) const
{
frame_names.clear();
const auto ready = ensureConnected_("ListTCPFrame");
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] robot name list is empty");
}
const auto robot_interface =
sdk_->rpc_client->getRobotInterface(robot_names.front());
if (!robot_interface || !robot_interface->getSyncMove()) {
return Result::failure(
ArmErrorCode::RobotNotReady,
"[AuboArm] world-frame interface is unavailable");
}
const auto sync_move = robot_interface->getSyncMove();
frame_names = {"tool0", "flange", "tcp"};
for (const auto& frame_name : listAuboWorldFrames(sync_move)) {
if (frame_name != "flange" && frame_name != "tcp" &&
isAuboTcpFrame(sync_move, frame_name)) {
frame_names.push_back(frame_name);
}
}
return Result::success();
} catch (const std::exception& e) {
return Result::failure(
ArmErrorCode::CommandFailed,
std::string("[AuboArm] ListTCPFrame failed: ") + e.what());
}
#else
return unsupported_("ListTCPFrame");
#endif
}
Result AuboArm::torqueOn()
{
const auto ready = ensureConnected_("torqueOn");
@ -182,6 +450,7 @@ Result AuboArm::torqueOn()
#if defined(CMVR_HAS_AUBO_SDK)
try {
auto_recovery_suppressed_.store(false);
const auto robot_names = sdk_->rpc_client->getRobotNames();
if (robot_names.empty()) {
return Result::failure(ArmErrorCode::RobotNotReady, "[AuboArm] robot name list is empty");
@ -199,11 +468,30 @@ Result AuboArm::torqueOn()
if (robot_interface->getRobotState()->getRobotModeType() !=
arcs::common_interface::RobotModeType::Running) {
robot_interface->getRobotManage()->poweron();
std::this_thread::sleep_for(std::chrono::milliseconds(200));
robot_interface->getRobotManage()->startup();
const int power_on_ret = robot_interface->getRobotManage()->poweron();
if (power_on_ret != arcs::common_interface::AUBO_OK) {
return Result::failure(
ArmErrorCode::CommandFailed,
"[AuboArm] poweron failed: sdk ret=" +
std::to_string(power_on_ret));
}
std::this_thread::sleep_for(std::chrono::milliseconds(200));
const int startup_ret = robot_interface->getRobotManage()->startup();
if (startup_ret != arcs::common_interface::AUBO_OK) {
return Result::failure(
ArmErrorCode::CommandFailed,
"[AuboArm] startup failed: sdk ret=" +
std::to_string(startup_ret));
}
}
emergency_stopped_.store(false);
// A hardware emergency-stop latch is owned by the monitor. Do not
// clear it merely because poweron/startup accepted a request: motion
// must remain blocked until the monitor has confirmed that the safety
// input is released and the controller is stably idle.
if (!hardware_estop_latched_.load()) {
hardware_emergency_stopped_.store(false);
}
emergency_stopped_ = false;
return Result::success();
} catch (const std::exception& e) {
return Result::failure(ArmErrorCode::CommandFailed, std::string("[AuboArm] torqueOn failed: ") + e.what());
@ -215,6 +503,7 @@ Result AuboArm::torqueOn()
Result AuboArm::torqueOff()
{
auto_recovery_suppressed_.store(true);
const auto ready = ensureConnected_("torqueOff");
if (!ready.ok()) {
return ready;
@ -248,7 +537,8 @@ Result AuboArm::calibrateZeroQ(const std::string& joint_name)
Result AuboArm::emergencyStop()
{
emergency_stopped_ = true;
emergency_stopped_.store(true);
auto_recovery_suppressed_.store(true);
return stopMotion();
}
@ -263,11 +553,15 @@ Result AuboArm::setSpeedScaling(const double scaling)
Result AuboArm::moveJ(const JointPositionCommand& target, const MotionOptions& options)
{
if (options.cancellation_requested && options.cancellation_requested()) {
return Result::failure(ArmErrorCode::CommandRejected,
"[AuboArm] moveJ canceled before dispatch");
}
std::string error;
if (!validDof_(target.position.size(), error)) {
return Result::failure(ArmErrorCode::InvalidDof, error);
}
const auto ready = ensureConnected_("moveJ");
const auto ready = ensureMotionReady_("moveJ");
if (!ready.ok()) {
return ready;
}
@ -286,14 +580,34 @@ Result AuboArm::moveJ(const JointPositionCommand& target, const MotionOptions& o
if (!robot_interface) {
return Result::failure(ArmErrorCode::RobotNotReady, "[AuboArm] robot interface is null");
}
robot_interface->getMotionControl()->setSpeedFraction(speed_scaling_);
robot_interface->getMotionControl()->moveJoint(
auto motion_control = robot_interface->getMotionControl();
motion_control->setSpeedFraction(speed_scaling_);
const int ret = motion_control->moveJoint(
target.position,
options.acceleration > 0.0 ? options.acceleration : 0.5,
options.velocity > 0.0 ? options.velocity : 0.5,
options.blend_radius,
0);
const auto outcome = aubo_internal::resolveMotionCommand(
ret,
arcs::common_interface::AUBO_OK,
arcs::common_interface::AUBO_REQUEST_IGNORE,
[&robot_interface, &options]() {
return waitArrival(
robot_interface, options.cancellation_requested);
});
if (outcome == aubo_internal::MotionCommandOutcome::CompletedWithoutMotion
|| outcome == aubo_internal::MotionCommandOutcome::CompletedAfterMotion) {
return Result::success();
}
if (outcome == aubo_internal::MotionCommandOutcome::SubmitFailed) {
return Result::failure(
ArmErrorCode::CommandFailed,
"[AuboArm] moveJ failed: sdk ret=" + std::to_string(ret));
}
return Result::failure(
ArmErrorCode::CommandFailed,
"[AuboArm] moveJ did not complete");
} catch (const std::exception& e) {
return Result::failure(ArmErrorCode::CommandFailed, std::string("[AuboArm] moveJ failed: ") + e.what());
}
@ -316,10 +630,24 @@ Result AuboArm::stopJ(double acceleration)
return stopMotion();
}
Result AuboArm::moveL(const CartesianPose& target, const MotionOptions& options, FrameType frame)
Result AuboArm::moveL(const CartesianPose& target,
const MotionOptions& options,
const FrameType frame)
{
(void)frame;
const auto ready = ensureConnected_("moveL");
return moveL(target, options, {}, {});
}
Result AuboArm::moveL(const CartesianPose& target,
const MotionOptions& options,
const std::string& base_frame,
const std::string& tcp_frame)
{
if (options.cancellation_requested && options.cancellation_requested()) {
return Result::failure(ArmErrorCode::CommandRejected,
"[AuboArm] moveL canceled before dispatch");
}
const auto ready = ensureMotionReady_("moveL");
if (!ready.ok()) {
return ready;
}
@ -338,17 +666,98 @@ Result AuboArm::moveL(const CartesianPose& target, const MotionOptions& options,
if (!robot_interface) {
return Result::failure(ArmErrorCode::RobotNotReady, "[AuboArm] robot interface is null");
}
robot_interface->getMotionControl()->setSpeedFraction(speed_scaling_);
std::vector<double> tcp_offset(6, 0.0);
robot_interface->getRobotConfig()->setTcpOffset(tcp_offset);
auto motion_control = robot_interface->getMotionControl();
motion_control->setSpeedFraction(speed_scaling_);
const std::string selected_base_frame = base_frame.empty()
? (vendor_cfg_.base_frame().empty()
? std::string{"base"}
: vendor_cfg_.base_frame())
: base_frame;
const std::string selected_tcp_frame = tcp_frame.empty()
? (vendor_cfg_.tool_frame().empty()
? std::string{"tool0"}
: vendor_cfg_.tool_frame())
: tcp_frame;
auto robot_config = robot_interface->getRobotConfig();
auto sync_move = robot_interface->getSyncMove();
if (selected_base_frame != "base" &&
(!sync_move || !sync_move->frameExist(selected_base_frame))) {
return Result::failure(
ArmErrorCode::InvalidArgument,
"[AuboArm] moveL failed: base_frame does not exist: " +
selected_base_frame);
}
std::vector<double> tcp_offset;
if (selected_tcp_frame == "tool0" ||
selected_tcp_frame == "flange") {
tcp_offset.assign(6, 0.0);
} else if (selected_tcp_frame == "tcp") {
tcp_offset = robot_config->getTcpOffset();
} else {
if (!isAuboTcpFrame(sync_move, selected_tcp_frame)) {
return Result::failure(
ArmErrorCode::InvalidArgument,
"[AuboArm] moveL failed: tcp_frame is not attached to "
"flange/tcp or does not exist: " +
selected_tcp_frame);
}
tcp_offset = sync_move->frameGetPose(
selected_tcp_frame, "flange", "flange");
}
if (tcp_offset.size() != 6) {
return Result::failure(
ArmErrorCode::InvalidArgument,
"[AuboArm] moveL failed: invalid tcp_frame pose: " +
selected_tcp_frame);
}
const int tcp_ret = robot_config->setTcpOffset(tcp_offset);
if (tcp_ret != arcs::common_interface::AUBO_OK) {
return Result::failure(
ArmErrorCode::CommandFailed,
"[AuboArm] moveL failed to select tcp_frame " +
selected_tcp_frame + ": sdk ret=" +
std::to_string(tcp_ret));
}
std::vector<double> pose{target.x, target.y, target.z, target.rx, target.ry, target.rz};
robot_interface->getMotionControl()->moveLine(
if (selected_base_frame != "base") {
pose = sync_move->frameConvertPose(
pose, selected_base_frame, "base");
if (pose.size() != 6) {
return Result::failure(
ArmErrorCode::InvalidArgument,
"[AuboArm] moveL failed: invalid converted pose for "
"base_frame: " + selected_base_frame);
}
}
const int ret = motion_control->moveLine(
pose,
options.acceleration > 0.0 ? options.acceleration : 0.5,
options.velocity > 0.0 ? options.velocity : 0.25,
options.blend_radius,
0);
const auto outcome = aubo_internal::resolveMotionCommand(
ret,
arcs::common_interface::AUBO_OK,
arcs::common_interface::AUBO_REQUEST_IGNORE,
[&robot_interface, &options]() {
return waitArrival(
robot_interface, options.cancellation_requested);
});
if (outcome == aubo_internal::MotionCommandOutcome::CompletedWithoutMotion
|| outcome == aubo_internal::MotionCommandOutcome::CompletedAfterMotion) {
return Result::success();
}
if (outcome == aubo_internal::MotionCommandOutcome::SubmitFailed) {
return Result::failure(
ArmErrorCode::CommandFailed,
"[AuboArm] moveL failed: sdk ret=" + std::to_string(ret));
}
return Result::failure(
ArmErrorCode::CommandFailed,
"[AuboArm] moveL did not complete");
} catch (const std::exception& e) {
return Result::failure(ArmErrorCode::CommandFailed, std::string("[AuboArm] moveL failed: ") + e.what());
}
@ -374,6 +783,9 @@ Result AuboArm::stopL(std::optional<double> acceleration)
Result AuboArm::stopMotion()
{
if (hardware_estop_latched_.load()) {
auto_recovery_suppressed_.store(true);
}
#if defined(CMVR_HAS_AUBO_SDK)
if (!connected_.load() || !sdk_ || !sdk_->rpc_client) {
return Result::success();
@ -385,7 +797,7 @@ Result AuboArm::stopMotion()
}
auto robot_interface = sdk_->rpc_client->getRobotInterface(robot_names.front());
if (robot_interface) {
robot_interface->getMotionControl()->stopMove();
robot_interface->getMotionControl()->stopMove(true, true);
}
busy_.store(false);
return Result::success();
@ -454,6 +866,15 @@ Result AuboArm::connect(const std::string& ip, const int port)
ip_ = ip;
port_ = port > 0 ? port : 30004;
connected_.store(true);
hardware_safety_mode_.store(static_cast<int>(SafetyMode::Unknown));
hardware_emergency_stopped_.store(false);
hardware_estop_latched_.store(false);
auto_recovery_suppressed_.store(false);
if (auto_enable_) {
sdk_->monitor_running.store(true);
sdk_->monitor_thread =
std::thread(&AuboArm::autoEnableMonitorLoop_, this);
}
return Result::success();
} catch (const std::exception& e) {
sdk_.reset();
@ -471,6 +892,14 @@ Result AuboArm::connect(const std::string& ip, const int port)
Result AuboArm::disconnect()
{
#if defined(CMVR_HAS_AUBO_SDK)
if (sdk_) {
sdk_->monitor_running.store(false);
sdk_->monitor_cv.notify_all();
if (sdk_->monitor_thread.joinable()) {
sdk_->monitor_thread.join();
}
}
auto_recovery_suppressed_.store(true);
try {
if (sdk_ && sdk_->rpc_client) {
sdk_->rpc_client->logout();
@ -483,9 +912,285 @@ Result AuboArm::disconnect()
#endif
connected_.store(false);
busy_.store(false);
hardware_emergency_stopped_.store(false);
hardware_estop_latched_.store(false);
hardware_safety_mode_.store(static_cast<int>(SafetyMode::Unknown));
return Result::success();
}
#if defined(CMVR_HAS_AUBO_SDK)
void AuboArm::autoEnableMonitorLoop_()
{
using arcs::common_interface::RobotModeType;
using arcs::common_interface::RuntimeState;
using arcs::common_interface::SafetyModeType;
auto monitorWait = [this](const std::chrono::milliseconds duration) {
std::unique_lock<std::mutex> lock(sdk_->monitor_wait_mutex);
return sdk_->monitor_cv.wait_for(
lock,
duration,
[this]() { return !sdk_->monitor_running.load(); });
};
auto sdkResultOk = [](const int result) {
return result == arcs::common_interface::AUBO_OK ||
result == arcs::common_interface::AUBO_REQUEST_IGNORE;
};
auto next_attempt = std::chrono::steady_clock::time_point::min();
SafetyModeType latched_kind = SafetyModeType::Undefined;
while (sdk_->monitor_running.load()) {
std::shared_ptr<arcs::aubo_sdk::RpcClient> monitor_client;
try {
monitor_client = std::make_shared<arcs::aubo_sdk::RpcClient>();
monitor_client->setRequestTimeout(1000);
monitor_client->connect(ip_, port_ > 0 ? port_ : 30004);
monitor_client->login(username_, password_);
const auto robot_names = monitor_client->getRobotNames();
if (robot_names.empty()) {
throw std::runtime_error("robot name list is empty");
}
const auto robot_interface =
monitor_client->getRobotInterface(robot_names.front());
if (!robot_interface) {
throw std::runtime_error("robot interface is null");
}
while (sdk_->monitor_running.load()) {
const auto robot_state = robot_interface->getRobotState();
const auto safety_mode = robot_state->getSafetyModeType();
const int emergency_source = robot_interface->getRobotConfig()
->getRobotEmergencyStopSource();
const bool hardware_estop_active =
isHardwareEmergencyStop(safety_mode, emergency_source);
hardware_safety_mode_.store(static_cast<int>(
toPublicSafetyMode(safety_mode, emergency_source)));
if (hardware_estop_active) {
if (!hardware_estop_latched_.exchange(true)) {
latched_kind = safety_mode ==
SafetyModeType::SystemEmergencyStop
? SafetyModeType::SystemEmergencyStop
: SafetyModeType::RobotEmergencyStop;
if (!emergency_stopped_.load()) {
auto_recovery_suppressed_.store(false);
}
CMVR_LOG(WARNING)
<< "[AuboArm] hardware emergency stop detected, id="
<< id_ << ", type="
<< (latched_kind == SafetyModeType::SystemEmergencyStop
? "SystemEmergencyStop"
: "RobotEmergencyStop")
<< ", source=" << emergency_source;
}
busy_.store(false);
} else if (hardware_estop_latched_.load() &&
isHardwareEmergencyStopReleased(
safety_mode, emergency_source) &&
!emergency_stopped_.load() &&
!auto_recovery_suppressed_.load() &&
std::chrono::steady_clock::now() >= next_attempt) {
const auto safetyStillReleased = [&]() {
const auto current_state =
robot_interface->getRobotState();
const auto current_safety =
current_state->getSafetyModeType();
const int current_source =
robot_interface->getRobotConfig()
->getRobotEmergencyStopSource();
hardware_safety_mode_.store(static_cast<int>(
toPublicSafetyMode(current_safety, current_source)));
const bool released =
isHardwareEmergencyStopReleased(
current_safety, current_source);
hardware_emergency_stopped_.store(
!released || hardware_estop_latched_.load());
return released &&
!emergency_stopped_.load() &&
!auto_recovery_suppressed_.load() &&
sdk_->monitor_running.load();
};
bool recovered = safetyStillReleased();
auto mode = robot_state->getRobotModeType();
if (recovered && mode != RobotModeType::Idle &&
mode != RobotModeType::Running) {
recovered = sdkResultOk(
robot_interface->getRobotManage()->poweron());
const auto deadline =
std::chrono::steady_clock::now() +
kAutoEnableModeTimeout;
while (recovered &&
std::chrono::steady_clock::now() < deadline) {
if (!safetyStillReleased()) {
recovered = false;
break;
}
mode = robot_interface->getRobotState()
->getRobotModeType();
if (mode == RobotModeType::Idle ||
mode == RobotModeType::Running) {
break;
}
if (monitorWait(kAutoEnablePollInterval)) {
recovered = false;
break;
}
}
recovered = recovered &&
(mode == RobotModeType::Idle ||
mode == RobotModeType::Running);
}
const auto clearControllerWork = [&]() {
const auto runtime =
monitor_client->getRuntimeMachine();
const auto motion =
robot_interface->getMotionControl();
int stop_ret = arcs::common_interface::AUBO_OK;
int abort_ret = arcs::common_interface::AUBO_OK;
int servo_ret = arcs::common_interface::AUBO_OK;
int clear_ret = arcs::common_interface::AUBO_OK;
if (motion->getExecId() != -1 ||
!robot_interface->getRobotState()->isSteady()) {
stop_ret = motion->stopMove(true, true);
}
if (runtime->getRuntimeState() != RuntimeState::Stopped) {
abort_ret = runtime->abort();
}
if (motion->getServoModeSelect() != 0) {
servo_ret = motion->setServoModeSelect(0);
}
if (motion->getQueueSize() != 0 ||
motion->getTrajectoryQueueSize() != 0) {
clear_ret = motion->clearPath();
}
return sdkResultOk(stop_ret) &&
sdkResultOk(abort_ret) &&
sdkResultOk(servo_ret) &&
sdkResultOk(clear_ret);
};
if (recovered) {
recovered = clearControllerWork() &&
safetyStillReleased();
}
if (recovered && mode != RobotModeType::Running) {
recovered = sdkResultOk(
robot_interface->getRobotManage()->startup());
const auto deadline =
std::chrono::steady_clock::now() +
kAutoEnableModeTimeout;
while (recovered &&
std::chrono::steady_clock::now() < deadline) {
if (!safetyStillReleased()) {
recovered = false;
break;
}
mode = robot_interface->getRobotState()
->getRobotModeType();
if (mode == RobotModeType::Running) {
break;
}
if (monitorWait(kAutoEnablePollInterval)) {
recovered = false;
break;
}
}
recovered = recovered &&
mode == RobotModeType::Running;
}
if (recovered) {
recovered = clearControllerWork() &&
safetyStillReleased();
}
int stable_samples = 0;
const auto confirm_deadline =
std::chrono::steady_clock::now() +
kAutoEnableModeTimeout;
while (recovered && stable_samples < 3 &&
std::chrono::steady_clock::now() <
confirm_deadline) {
if (!safetyStillReleased()) {
recovered = false;
break;
}
const auto motion =
robot_interface->getMotionControl();
const bool idle =
robot_interface->getRobotState()
->getRobotModeType() ==
RobotModeType::Running &&
robot_interface->getRobotState()->isSteady() &&
motion->getExecId() == -1 &&
motion->getQueueSize() == 0 &&
motion->getTrajectoryQueueSize() == 0 &&
motion->getServoModeSelect() == 0 &&
monitor_client->getRuntimeMachine()
->getRuntimeState() ==
RuntimeState::Stopped;
stable_samples = idle ? stable_samples + 1 : 0;
if (stable_samples < 3 &&
monitorWait(kAutoEnablePollInterval)) {
recovered = false;
break;
}
}
recovered = recovered && stable_samples >= 3;
if (recovered) {
hardware_estop_latched_.store(false);
hardware_emergency_stopped_.store(false);
auto_recovery_suppressed_.store(false);
CMVR_LOG(INFO)
<< "[AuboArm] hardware emergency-stop release "
"automatically powered on and enabled, id="
<< id_ << ", type="
<< (latched_kind ==
SafetyModeType::SystemEmergencyStop
? "SystemEmergencyStop"
: "RobotEmergencyStop");
} else {
next_attempt = std::chrono::steady_clock::now() +
kAutoEnableRetryInterval;
CMVR_LOG(WARNING)
<< "[AuboArm] automatic enable after hardware "
"emergency-stop release failed, id=" << id_;
}
}
hardware_emergency_stopped_.store(
hardware_estop_active || hardware_estop_latched_.load());
if (monitorWait(kAutoEnablePollInterval)) {
break;
}
}
} catch (const std::exception& e) {
hardware_safety_mode_.store(
static_cast<int>(SafetyMode::Unknown));
CMVR_LOG(WARNING)
<< "[AuboArm] auto-enable monitor unavailable, id=" << id_
<< ", error=" << e.what();
}
if (monitor_client) {
try {
monitor_client->logout();
monitor_client->disconnect();
} catch (...) {
}
}
if (sdk_->monitor_running.load()) {
(void)monitorWait(kAutoEnableReconnectInterval);
}
}
}
#endif
Result AuboArm::shutdown()
{
(void)stopMotion();
@ -572,4 +1277,37 @@ Result AuboArm::ensureConnected_(const std::string& context) const
return Result::success();
}
Result AuboArm::ensureMotionReady_(const std::string& context) const
{
const auto connected = ensureConnected_(context);
if (!connected.ok()) {
return connected;
}
if (isEmergencyStopped() || hardware_estop_latched_.load()) {
return Result::failure(
ArmErrorCode::RobotInEmergencyStop,
"[AuboArm] " + context +
" rejected: emergency stop is active or recovery is incomplete");
}
const auto safety = getSafetyMode();
if (safety == SafetyMode::Fault) {
return Result::failure(
ArmErrorCode::RobotInFault,
"[AuboArm] " + context + " rejected: robot safety fault");
}
if (safety == SafetyMode::ProtectiveStop ||
safety == SafetyMode::SafeguardStop) {
return Result::failure(
ArmErrorCode::RobotInProtectiveStop,
"[AuboArm] " + context + " rejected: protective stop is active");
}
if (auto_enable_ && safety == SafetyMode::Unknown) {
return Result::failure(
ArmErrorCode::RobotNotReady,
"[AuboArm] " + context +
" rejected: hardware safety state is unavailable");
}
return Result::success();
}
} // namespace cmvr::device

View File

@ -0,0 +1,58 @@
#include "devices/arm/aubo_arm/include/aubo_motion_result.h"
#include <iostream>
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::resolveMotionCommand;
constexpr int success_code = 0;
constexpr int request_ignore_code = 13;
int wait_calls = 0;
const auto wait_succeeded = [&wait_calls]() {
++wait_calls;
return 0;
};
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);
wait_calls = 0;
CHECK_TRUE(resolveMotionCommand(7, success_code, request_ignore_code,
wait_succeeded)
== MotionCommandOutcome::SubmitFailed);
CHECK_TRUE(wait_calls == 0);
const auto wait_failed = [&wait_calls]() {
++wait_calls;
return -1;
};
wait_calls = 0;
CHECK_TRUE(resolveMotionCommand(success_code, success_code, request_ignore_code,
wait_failed)
== MotionCommandOutcome::CompletionFailed);
CHECK_TRUE(wait_calls == 1);
return 0;
}

View File

@ -1,5 +1,7 @@
add_library(huayan_arm SHARED huayan_arm.cpp)
find_package(Threads REQUIRED)
set(HUAYAN_ARM_SDK_DIR ${CMAKE_SOURCE_DIR}/dependency/${ARCH}/third_party/huayan_arm/v1.0)
target_include_directories(huayan_arm
@ -20,6 +22,7 @@ target_link_libraries(huayan_arm
PRIVATE
HR_Pro
glog
Threads::Threads
)
add_library(cmvr_es::device::huayan_arm ALIAS huayan_arm)

View File

@ -2,8 +2,10 @@
#include <algorithm>
#include <array>
#include <chrono>
#include <cmath>
#include <sstream>
#include <thread>
#include "huayan_arm/v1.0/include/HR_Pro.h"
#include "common/base/logging/logger.h"
@ -16,6 +18,9 @@ constexpr double kDefaultMoveJVelocityDeg = 30.0;
constexpr double kDefaultMoveJAccelerationDeg = 60.0;
constexpr double kDefaultMoveLVelocityMm = 100.0;
constexpr double kDefaultMoveLAccelerationMm = 200.0;
constexpr auto kAutoEnablePollInterval = std::chrono::milliseconds(100);
constexpr auto kAutoEnableRetryInterval = std::chrono::seconds(1);
constexpr auto kAutoEnableTimeout = std::chrono::seconds(5);
double radToDeg(const double value)
{
@ -86,6 +91,7 @@ HuayanRobot::HuayanRobot(const config::RobotArmConfig& cfg)
port_ = vendor_cfg_.port() > 0 ? vendor_cfg_.port() : 10003;
tcp_name_ = vendor_cfg_.tool_frame().empty() ? "TCP" : vendor_cfg_.tool_frame();
ucs_name_ = vendor_cfg_.base_frame().empty() ? "Base" : vendor_cfg_.base_frame();
auto_enable_ = vendor_cfg_.auto_enable();
const auto dof = vendor_cfg_.dof() > 0 ? static_cast<std::size_t>(vendor_cfg_.dof()) : 6U;
model_.name = vendor_cfg_.model().empty() ? "HuayanRobot" : vendor_cfg_.model();
@ -117,6 +123,7 @@ bool HuayanRobot::init()
CMVR_LOG(ERROR) << "[HuayanRobot] init failed: " << result.message;
return false;
}
setSpeedScaling(1.0);
return true;
}
@ -135,9 +142,16 @@ ArmState HuayanRobot::getRobotState() const
state.brake_released = hr_state.valid ? hr_state.brake != 0 : state.connected;
state.moving = hr_state.valid ? hr_state.moving != 0 : busy_.load();
state.program_running = state.moving;
state.protective_stopped = hr_state.valid ? hr_state.safeguard != 0 : false;
state.emergency_stopped = hr_state.valid ? hr_state.emergency_stop != 0 : false;
state.fault = hr_state.valid ? hr_state.error != 0 : false;
state.protective_stopped = hr_state.valid
? (hr_state.safeguard != 0 || hr_state.safeguard_input != 0)
: false;
state.emergency_stopped = hr_state.valid
? (hr_state.emergency_stop != 0 || hr_state.emergency_input != 0)
: false;
state.fault = hr_state.valid
? (hr_state.error != 0 || hr_state.emergency_signal_fault != 0 ||
hr_state.safeguard_signal_fault != 0)
: false;
state.robot_mode = getRobotMode();
state.safety_mode = getSafetyMode();
state.control_mode = getControlMode();
@ -174,10 +188,11 @@ RobotMode HuayanRobot::getRobotMode() const
if (!state.valid) {
return busy_.load() ? RobotMode::Running : RobotMode::Idle;
}
if (state.error != 0) {
if (state.error != 0 || state.emergency_signal_fault != 0 ||
state.safeguard_signal_fault != 0) {
return RobotMode::Fault;
}
if (state.emergency_stop != 0) {
if (state.emergency_stop != 0 || state.emergency_input != 0) {
return RobotMode::Stopped;
}
if (state.paused != 0) {
@ -195,13 +210,14 @@ SafetyMode HuayanRobot::getSafetyMode() const
if (!state.valid) {
return SafetyMode::Unknown;
}
if (state.error != 0) {
if (state.error != 0 || state.emergency_signal_fault != 0 ||
state.safeguard_signal_fault != 0) {
return SafetyMode::Fault;
}
if (state.emergency_stop != 0) {
if (state.emergency_stop != 0 || state.emergency_input != 0) {
return SafetyMode::EmergencyStop;
}
if (state.safeguard != 0) {
if (state.safeguard != 0 || state.safeguard_input != 0) {
return SafetyMode::SafeguardStop;
}
return SafetyMode::Normal;
@ -213,13 +229,24 @@ Result HuayanRobot::torqueOn()
if (!ready.ok()) {
return ready;
}
auto_recovery_suppressed_.store(false);
if (hardware_estop_latched_.load()) {
if (!recoverAfterHardwareEstop_()) {
return Result::failure(
ArmErrorCode::RobotNotReady,
"[HuayanRobot] torqueOn failed: hardware emergency-stop "
"recovery was not confirmed");
}
hardware_estop_latched_.store(false);
return Result::success();
}
std::lock_guard<std::mutex> lock(mutex_);
return hrResult_(HRIF_GrpEnable(box_id_, robot_id_), "GrpEnable");
}
Result HuayanRobot::torqueOff()
{
auto_recovery_suppressed_.store(true);
const auto ready = ensureConnected_("torqueOff");
if (!ready.ok()) {
return ready;
@ -237,6 +264,7 @@ Result HuayanRobot::calibrateZeroQ(const std::string& joint_name)
Result HuayanRobot::emergencyStop()
{
auto_recovery_suppressed_.store(true);
return stopMotion();
}
@ -255,28 +283,70 @@ Result HuayanRobot::setSpeedScaling(const double scaling)
bool HuayanRobot::isProtectiveStopped() const
{
const auto state = readHrState_();
return state.valid && state.safeguard != 0;
return state.valid &&
(state.safeguard != 0 || state.safeguard_input != 0);
}
bool HuayanRobot::isEmergencyStopped() const
{
const auto state = readHrState_();
return state.valid && state.emergency_stop != 0;
return state.valid &&
(state.emergency_stop != 0 || state.emergency_input != 0);
}
bool HuayanRobot::isFault() const
{
const auto state = readHrState_();
return state.valid && state.error != 0;
return state.valid &&
(state.error != 0 || state.emergency_signal_fault != 0 ||
state.safeguard_signal_fault != 0);
}
Result HuayanRobot::listBaseFrame(
std::vector<std::string>& frame_names) const
{
frame_names.clear();
const auto ready = ensureConnected_("ListBaseFrame");
if (!ready.ok()) {
return ready;
}
int ret = 0;
{
std::lock_guard<std::mutex> lock(mutex_);
ret = HRIF_ReadUCSList(box_id_, robot_id_, frame_names);
}
return hrResult_(ret, "ReadUCSList");
}
Result HuayanRobot::listTCPFrame(
std::vector<std::string>& frame_names) const
{
frame_names.clear();
const auto ready = ensureConnected_("ListTCPFrame");
if (!ready.ok()) {
return ready;
}
int ret = 0;
{
std::lock_guard<std::mutex> lock(mutex_);
ret = HRIF_ReadTCPList(box_id_, robot_id_, frame_names);
}
return hrResult_(ret, "ReadTCPList");
}
Result HuayanRobot::moveJ(const JointPositionCommand& target, const MotionOptions& options)
{
if (options.cancellation_requested && options.cancellation_requested()) {
return Result::failure(ArmErrorCode::CommandRejected,
"[HuayanRobot] moveJ canceled before dispatch");
}
std::string error;
if (!validDof_(target.position.size(), error)) {
return Result::failure(ArmErrorCode::InvalidDof, error);
}
const auto ready = ensureConnected_("moveJ");
const auto ready = ensureMotionReady_("moveJ");
if (!ready.ok()) {
return ready;
}
@ -303,7 +373,8 @@ Result HuayanRobot::moveJ(const JointPositionCommand& target, const MotionOption
busy_.store(false);
return hrResult_(ret, "moveJ");
}
const auto wait_result = waitMotionDone_("moveJ", 60000);
const auto wait_result = waitMotionDone_(
"moveJ", 60000, options.cancellation_requested);
busy_.store(false);
return wait_result;
}
@ -314,7 +385,7 @@ Result HuayanRobot::speedJ(const JointVelocityCommand& velocity, const double ac
if (!validDof_(velocity.velocity.size(), error)) {
return Result::failure(ArmErrorCode::InvalidDof, error);
}
const auto ready = ensureConnected_("speedJ");
const auto ready = ensureMotionReady_("speedJ");
if (!ready.ok()) {
return ready;
}
@ -344,10 +415,23 @@ Result HuayanRobot::stopJ(const double acceleration)
return stopMotion();
}
Result HuayanRobot::moveL(const CartesianPose& target, const MotionOptions& options, const FrameType frame)
Result HuayanRobot::moveL(const CartesianPose& target,
const MotionOptions& options,
const FrameType frame)
{
(void)frame;
const auto ready = ensureConnected_("moveL");
return moveL(target, options, {}, {});
}
Result HuayanRobot::moveL(const CartesianPose& target,
const MotionOptions& options,
const std::string& base_frame,
const std::string& tcp_frame)
{
if (options.cancellation_requested && options.cancellation_requested()) {
return Result::failure(ArmErrorCode::CommandRejected,
"[HuayanRobot] moveL canceled before dispatch");
}
const auto ready = ensureMotionReady_("moveL");
if (!ready.ok()) {
return ready;
}
@ -361,17 +445,23 @@ Result HuayanRobot::moveL(const CartesianPose& target, const MotionOptions& opti
const double acceleration = options.acceleration > 0.0 ? metersToMm(options.acceleration) : kDefaultMoveLAccelerationMm;
const double blend = metersToMm(options.blend_radius);
const std::string command_id = nextCommandId_();
const std::string& selected_base_frame =
base_frame.empty() ? ucs_name_ : base_frame;
const std::string& selected_tcp_frame =
tcp_frame.empty() ? tcp_name_ : tcp_frame;
const int ret = HRIF_MoveL(box_id_, robot_id_,
pose[0], pose[1], pose[2], pose[3], pose[4], pose[5],
q_deg[0], q_deg[1], q_deg[2], q_deg[3], q_deg[4], q_deg[5],
tcp_name_, ucs_name_, velocity * speed_scaling_, acceleration, blend,
selected_tcp_frame, selected_base_frame,
velocity * speed_scaling_, acceleration, blend,
0, 0, 0, command_id);
if (ret != 0) {
busy_.store(false);
return hrResult_(ret, "moveL");
}
const auto wait_result = waitMotionDone_("moveL", 60000);
const auto wait_result = waitMotionDone_(
"moveL", 60000, options.cancellation_requested);
busy_.store(false);
return wait_result;
}
@ -381,7 +471,7 @@ Result HuayanRobot::speedL(const CartesianVelocity& velocity,
const double duration,
const FrameType frame)
{
const auto ready = ensureConnected_("speedL");
const auto ready = ensureMotionReady_("speedL");
if (!ready.ok()) {
return ready;
}
@ -421,6 +511,9 @@ Result HuayanRobot::stopL(std::optional<double> acceleration = std::nullopt)
Result HuayanRobot::stopMotion()
{
if (hardware_estop_latched_.load()) {
auto_recovery_suppressed_.store(true);
}
if (!isConnected()) {
busy_.store(false);
servo_mode_.store(false);
@ -435,7 +528,7 @@ Result HuayanRobot::stopMotion()
Result HuayanRobot::startServoMode(const ServoOptions& options)
{
const auto ready = ensureConnected_("startServoMode");
const auto ready = ensureMotionReady_("startServoMode");
if (!ready.ok()) {
return ready;
}
@ -454,7 +547,7 @@ Result HuayanRobot::servoJ(const JointPositionCommand& target)
if (!validDof_(target.position.size(), error)) {
return Result::failure(ArmErrorCode::InvalidDof, error);
}
const auto ready = ensureConnected_("servoJ");
const auto ready = ensureMotionReady_("servoJ");
if (!ready.ok()) {
return ready;
}
@ -471,7 +564,7 @@ Result HuayanRobot::servoJ(const JointPositionCommand& target)
Result HuayanRobot::servoL(const CartesianPose& target, const FrameType frame)
{
(void)frame;
const auto ready = ensureConnected_("servoL");
const auto ready = ensureMotionReady_("servoL");
if (!ready.ok()) {
return ready;
}
@ -510,9 +603,11 @@ Result HuayanRobot::connect(const std::string& ip, const int port)
return Result::failure(ArmErrorCode::InvalidArgument, "[HuayanRobot] ip is empty");
}
std::lock_guard<std::mutex> lock(mutex_);
const int use_port = port > 0 ? port : 10003;
const auto result = hrResult_(HRIF_Connect(box_id_, ip.c_str(), static_cast<unsigned short>(use_port)),
{
std::lock_guard<std::mutex> lock(mutex_);
const auto result = hrResult_(
HRIF_Connect(box_id_, ip.c_str(), static_cast<unsigned short>(use_port)),
"Connect");
if (!result.ok()) {
connected_.store(false);
@ -521,11 +616,17 @@ Result HuayanRobot::connect(const std::string& ip, const int port)
ip_ = ip;
port_ = use_port;
connected_.store(true);
}
hardware_estop_latched_.store(false);
auto_recovery_suppressed_.store(false);
startAutoEnableMonitor_();
return Result::success();
}
Result HuayanRobot::disconnect()
{
stopAutoEnableMonitor_();
auto_recovery_suppressed_.store(true);
if (connected_.load() || HRIF_IsConnected(box_id_)) {
const auto result = hrResult_(HRIF_DisConnect(box_id_), "DisConnect");
connected_.store(false);
@ -574,7 +675,7 @@ Result HuayanRobot::loadProgram(const std::string& program_name)
Result HuayanRobot::playProgram()
{
const auto ready = ensureConnected_("playProgram");
const auto ready = ensureMotionReady_("playProgram");
if (!ready.ok()) {
return ready;
}
@ -637,6 +738,46 @@ Result HuayanRobot::ensureConnected_(const std::string& context) const
return Result::success();
}
Result HuayanRobot::ensureMotionReady_(const std::string& context) const
{
const auto connected = ensureConnected_(context);
if (!connected.ok()) {
return connected;
}
const auto state = readHrState_();
if (!state.valid) {
return Result::failure(
ArmErrorCode::RobotNotReady,
"[HuayanRobot] " + context +
" rejected: hardware state is unavailable");
}
if (hardware_estop_latched_.load() || state.emergency_stop != 0 ||
state.emergency_input != 0) {
return Result::failure(
ArmErrorCode::RobotInEmergencyStop,
"[HuayanRobot] " + context +
" rejected: emergency stop is active or recovery is incomplete");
}
if (state.error != 0 || state.emergency_signal_fault != 0 ||
state.safeguard_signal_fault != 0) {
return Result::failure(
ArmErrorCode::RobotInFault,
"[HuayanRobot] " + context + " rejected: robot safety fault");
}
if (state.safeguard != 0 || state.safeguard_input != 0) {
return Result::failure(
ArmErrorCode::RobotInProtectiveStop,
"[HuayanRobot] " + context +
" rejected: safeguard stop is active");
}
if (state.enabled == 0 || state.electrified == 0) {
return Result::failure(
ArmErrorCode::RobotNotPowered,
"[HuayanRobot] " + context + " rejected: robot is not enabled");
}
return Result::success();
}
Result HuayanRobot::unsupported_(const std::string& name) const
{
const std::string message = "[HuayanRobot] " + name + " is not implemented";
@ -685,7 +826,7 @@ HuayanRobot::HrState HuayanRobot::readHrState_() const
return state;
}
const int ret = HRIF_ReadRobotState(box_id_, robot_id_,
const int state_ret = HRIF_ReadRobotState(box_id_, robot_id_,
state.moving,
state.enabled,
state.error,
@ -699,13 +840,148 @@ HuayanRobot::HrState HuayanRobot::readHrState_() const
state.connected_to_box,
state.blending_done,
state.in_pos);
state.valid = ret == 0;
if (ret != 0) {
CMVR_LOG(ERROR) << "[HuayanRobot] read robot state failed, code=" << ret;
const int safety_ret = HRIF_ReadEmergencyInfo(box_id_, robot_id_,
state.emergency_signal_fault,
state.emergency_input,
state.safeguard_signal_fault,
state.safeguard_input);
state.valid = state_ret == 0 && safety_ret == 0;
if (state_ret != 0 || safety_ret != 0) {
CMVR_LOG(ERROR) << "[HuayanRobot] read robot state failed, state_code="
<< state_ret << ", safety_code=" << safety_ret;
}
return state;
}
void HuayanRobot::startAutoEnableMonitor_()
{
if (!auto_enable_ || auto_enable_monitor_running_.exchange(true)) {
return;
}
auto_enable_thread_ = std::thread(&HuayanRobot::autoEnableMonitorLoop_, this);
}
void HuayanRobot::stopAutoEnableMonitor_()
{
auto_enable_monitor_running_.store(false);
auto_enable_cv_.notify_all();
if (auto_enable_thread_.joinable()) {
auto_enable_thread_.join();
}
}
void HuayanRobot::autoEnableMonitorLoop_()
{
auto next_attempt = std::chrono::steady_clock::time_point::min();
while (auto_enable_monitor_running_.load()) {
const auto state = readHrState_();
const bool hardware_estop_active = state.valid &&
(state.emergency_stop != 0 || state.emergency_input != 0);
if (hardware_estop_active) {
if (!hardware_estop_latched_.exchange(true)) {
auto_recovery_suppressed_.store(false);
CMVR_LOG(WARNING)
<< "[HuayanRobot] hardware emergency stop detected, id=" << id_;
}
busy_.store(false);
servo_mode_.store(false);
} else if (hardware_estop_latched_.load() && state.valid &&
state.emergency_input == 0 &&
state.emergency_signal_fault == 0 &&
state.safeguard_signal_fault == 0 &&
state.safeguard_input == 0 && state.safeguard == 0 &&
!auto_recovery_suppressed_.load() &&
std::chrono::steady_clock::now() >= next_attempt) {
if (recoverAfterHardwareEstop_()) {
hardware_estop_latched_.store(false);
CMVR_LOG(INFO)
<< "[HuayanRobot] hardware emergency-stop release automatically "
"powered on and enabled, id=" << id_;
} else {
next_attempt = std::chrono::steady_clock::now() +
kAutoEnableRetryInterval;
}
}
std::unique_lock<std::mutex> wait_lock(auto_enable_wait_mutex_);
auto_enable_cv_.wait_for(
wait_lock,
kAutoEnablePollInterval,
[this]() { return !auto_enable_monitor_running_.load(); });
}
}
bool HuayanRobot::recoverAfterHardwareEstop_()
{
if (auto_recovery_in_progress_.exchange(true)) {
return false;
}
struct RecoveryGuard {
std::atomic<bool>& active;
~RecoveryGuard() { active.store(false); }
} recovery_guard{auto_recovery_in_progress_};
const auto before = readHrState_();
if (!before.valid || before.emergency_stop != 0 ||
before.emergency_input != 0 || before.emergency_signal_fault != 0 ||
before.safeguard != 0 || before.safeguard_input != 0 ||
before.safeguard_signal_fault != 0 ||
auto_recovery_suppressed_.load()) {
return false;
}
int stop_ret = 0;
int reset_ret = 0;
int enable_ret = 0;
{
std::lock_guard<std::mutex> lock(mutex_);
stop_ret = HRIF_GrpStop(box_id_, robot_id_);
if (stop_ret == 0) {
reset_ret = HRIF_GrpReset(box_id_, robot_id_);
}
if (stop_ret == 0 && reset_ret == 0 &&
!auto_recovery_suppressed_.load()) {
enable_ret = HRIF_GrpEnable(box_id_, robot_id_);
}
}
if (stop_ret != 0 || reset_ret != 0 || enable_ret != 0) {
CMVR_LOG(WARNING)
<< "[HuayanRobot] automatic enable failed, id=" << id_
<< ", stop_ret=" << stop_ret
<< ", reset_ret=" << reset_ret
<< ", enable_ret=" << enable_ret;
return false;
}
const auto deadline = std::chrono::steady_clock::now() + kAutoEnableTimeout;
int stable_samples = 0;
while (auto_enable_monitor_running_.load() &&
std::chrono::steady_clock::now() < deadline) {
if (auto_recovery_suppressed_.load()) {
return false;
}
const auto state = readHrState_();
const bool ready = state.valid && state.error == 0 &&
state.emergency_stop == 0 && state.emergency_input == 0 &&
state.emergency_signal_fault == 0 && state.safeguard == 0 &&
state.safeguard_input == 0 && state.safeguard_signal_fault == 0 &&
state.enabled != 0 && state.electrified != 0 && state.moving == 0;
if (ready) {
if (++stable_samples >= 2) {
return true;
}
} else {
stable_samples = 0;
}
std::unique_lock<std::mutex> wait_lock(auto_enable_wait_mutex_);
auto_enable_cv_.wait_for(wait_lock, kAutoEnablePollInterval);
}
CMVR_LOG(WARNING)
<< "[HuayanRobot] automatic enable timed out, id=" << id_;
return false;
}
std::vector<double> HuayanRobot::readJointPositionRad_() const
{
std::vector<double> q(model_.dof, 0.0);
@ -829,10 +1105,19 @@ std::string HuayanRobot::nextCommandId_() const
return id_ + "_" + std::to_string(++command_seq_);
}
Result HuayanRobot::waitMotionDone_(const std::string& context, const int timeout_ms) const
Result HuayanRobot::waitMotionDone_(
const std::string& context,
const int timeout_ms,
const std::function<bool()>& cancellation_requested) const
{
const auto start = std::chrono::steady_clock::now();
while (true) {
if (cancellation_requested && cancellation_requested()) {
(void)HRIF_GrpStop(box_id_, robot_id_);
return Result::failure(
ArmErrorCode::CommandRejected,
"[HuayanRobot] " + context + " canceled");
}
bool done = false;
const int ret = HRIF_IsMotionDone(box_id_, robot_id_, done);
if (ret != 0) {
@ -840,20 +1125,22 @@ Result HuayanRobot::waitMotionDone_(const std::string& context, const int timeou
}
const auto state = readHrState_();
if (state.valid) {
if (state.error != 0) {
if (state.error != 0 || state.emergency_signal_fault != 0 ||
state.safeguard_signal_fault != 0) {
return Result::failure(
ArmErrorCode::CommandFailed,
"[HuayanRobot] " + context + " failed: robot error, code=" +
"[HuayanRobot] " + context +
" failed: robot or safety-signal error, code=" +
std::to_string(state.error_code));
}
if (state.emergency_stop != 0) {
if (state.emergency_stop != 0 || state.emergency_input != 0) {
return Result::failure(
ArmErrorCode::CommandFailed,
"[HuayanRobot] " + context + " failed: emergency stop");
}
if (state.safeguard != 0) {
if (state.safeguard != 0 || state.safeguard_input != 0) {
return Result::failure(
ArmErrorCode::CommandFailed,
"[HuayanRobot] " + context + " failed: safeguard stop");
@ -878,7 +1165,7 @@ Result HuayanRobot::waitMotionDone_(const std::string& context, const int timeou
"[HuayanRobot] " + context + " timeout");
}
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}

View File

@ -9,9 +9,12 @@
#define CMVR_ES_HUAYAN_ROBOT_H
#include <atomic>
#include <condition_variable>
#include <functional>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
#include "cmvr/config/arm_config/arm_config.pb.h"
@ -36,6 +39,9 @@ public:
RobotMode getRobotMode() const override;
SafetyMode getSafetyMode() const override;
ControlMode getControlMode() const override { return servo_mode_.load() ? ControlMode::Servo : ControlMode::Position; }
bool supportsActionQueueMotion() const noexcept override { return true; }
Result listBaseFrame(std::vector<std::string>& frame_names) const override;
Result listTCPFrame(std::vector<std::string>& frame_names) const override;
Result torqueOn() override;
Result torqueOff() override;
@ -51,7 +57,13 @@ public:
Result moveJ(const JointPositionCommand& target, const MotionOptions& options) override;
Result speedJ(const JointVelocityCommand& velocity, double acceleration, double duration) override;
Result stopJ(double acceleration) override;
Result moveL(const CartesianPose& target, const MotionOptions& options, FrameType frame = FrameType::Base) override;
Result moveL(const CartesianPose& target,
const MotionOptions& options,
FrameType frame = FrameType::Base) override;
Result moveL(const CartesianPose& target,
const MotionOptions& options,
const std::string& base_frame,
const std::string& tcp_frame) override;
Result speedL(const CartesianVelocity& velocity, double acceleration, double duration, FrameType frame = FrameType::Base) override;
Result stopL(const std::optional<double> acceleration) override;
Result stopMotion() override;
@ -97,6 +109,10 @@ private:
int paused{0};
int emergency_stop{0};
int safeguard{0};
int emergency_signal_fault{0};
int emergency_input{0};
int safeguard_signal_fault{0};
int safeguard_input{0};
int electrified{0};
int connected_to_box{0};
int blending_done{0};
@ -105,6 +121,7 @@ private:
};
Result ensureConnected_(const std::string& context) const;
Result ensureMotionReady_(const std::string& context) const;
Result unsupported_(const std::string& name) const;
Result hrResult_(int code, const std::string& context) const;
bool validDof_(std::size_t size, std::string& error) const;
@ -115,7 +132,13 @@ private:
CartesianVelocity readTcpVelocity_() const;
std::vector<double> currentJointPositionDeg_() const;
std::string nextCommandId_() const;
Result waitMotionDone_(const std::string& context, int timeout_ms) const;
Result waitMotionDone_(const std::string& context,
int timeout_ms,
const std::function<bool()>& cancellation_requested = {}) const;
void startAutoEnableMonitor_();
void stopAutoEnableMonitor_();
void autoEnableMonitorLoop_();
bool recoverAfterHardwareEstop_();
private:
config::RobotArmConfig cfg_;
@ -127,11 +150,19 @@ private:
unsigned int robot_id_{0};
std::string tcp_name_{"TCP"};
std::string ucs_name_{"Base"};
bool auto_enable_{false};
double speed_scaling_{1.0};
std::atomic<bool> connected_{false};
std::atomic<bool> busy_{false};
std::atomic<bool> servo_mode_{false};
std::atomic<bool> auto_enable_monitor_running_{false};
std::atomic<bool> hardware_estop_latched_{false};
std::atomic<bool> auto_recovery_in_progress_{false};
std::atomic<bool> auto_recovery_suppressed_{false};
mutable std::mutex mutex_;
std::mutex auto_enable_wait_mutex_;
std::condition_variable auto_enable_cv_;
std::thread auto_enable_thread_;
mutable std::atomic<unsigned long long> command_seq_{0};
};

View File

@ -27,6 +27,23 @@ public:
virtual RobotMode getRobotMode() const = 0;
virtual SafetyMode getSafetyMode() const = 0;
virtual ControlMode getControlMode() const = 0;
// ActionQueue requires synchronous motion and cooperative cancellation.
// Backends opt in only after both semantics are implemented.
virtual bool supportsActionQueueMotion() const noexcept { return false; }
virtual Result listBaseFrame(std::vector<std::string>& frame_names) const
{
frame_names.clear();
return Result::failure(
ArmErrorCode::UnsupportedCommand,
"ListBaseFrame is not supported by this robot arm");
}
virtual Result listTCPFrame(std::vector<std::string>& frame_names) const
{
frame_names.clear();
return Result::failure(
ArmErrorCode::UnsupportedCommand,
"ListTCPFrame is not supported by this robot arm");
}
virtual Result torqueOn() = 0;
virtual Result torqueOff() = 0;
@ -50,6 +67,19 @@ public:
virtual Result moveL(const CartesianPose& target,
const MotionOptions& options,
FrameType frame = FrameType::Base) = 0;
// Named-frame overload. Empty names select the driver's configured defaults.
virtual Result moveL(const CartesianPose& target,
const MotionOptions& options,
const std::string& base_frame,
const std::string& tcp_frame)
{
if (base_frame.empty() && tcp_frame.empty()) {
return moveL(target, options, FrameType::Base);
}
return Result::failure(
ArmErrorCode::UnsupportedCommand,
"named base_frame/tcp_frame are not supported by this robot arm");
}
virtual Result speedL(const CartesianVelocity& velocity,
double acceleration,
double duration,

View File

@ -8,10 +8,12 @@
#include <atomic>
#include <cmath>
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <set>
#include "common/types/agv/agv_types.h"
#include "common/types/geometry_types.h"
@ -34,11 +36,6 @@ namespace cmvr::device{
UNKNOWN
};
// ------------------------------------- AGV -------------------------------------
typedef struct{
} AGVState;
// ------------------------------------- robot -------------------------------------
typedef enum {
FORWARD, BACKWARD,

View File

@ -1,5 +1,7 @@
add_library(service
grpc/action/src/action_queue.cpp
grpc/action/src/control_command_arbiter.cpp
grpc/src/grpc_camera_service.cpp
grpc/src/grpc_system_service.cpp
grpc/src/grpc_speaker_service.cpp
@ -7,6 +9,7 @@ add_library(service
grpc/src/grpc_head_service.cpp
grpc/src/grpc_dexhand_service.cpp
grpc/src/grpc_arm_service.cpp
grpc/src/grpc_agv_service.cpp
grpc/src/grpc_hlc_service.cpp
../task/grpc_server_task/src/grpc_server_task.cpp
)
@ -26,6 +29,25 @@ target_link_libraries(service PRIVATE
add_library(cmvr_es::service ALIAS service)
install(TARGETS service LIBRARY DESTINATION lib)
if(BUILD_TESTING)
enable_testing()
add_executable(action_queue_test
grpc/action/tests/action_queue_test.cpp
grpc/action/src/action_queue.cpp
grpc/action/src/control_command_arbiter.cpp)
target_link_libraries(action_queue_test PRIVATE
cmvr_es::proto
cmvr_es::logging
gtest
gtest_main
pthread)
set_target_properties(action_queue_test PROPERTIES
BUILD_RPATH "${CMAKE_BINARY_DIR};${CMAKE_SOURCE_DIR}/output/lib;${CMAKE_SOURCE_DIR}/dependency/${ARCH}/third_party/grpc/v1.76.0/lib")
add_test(NAME action_queue_test COMMAND action_queue_test)
set_tests_properties(action_queue_test PROPERTIES
ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}:${CMAKE_SOURCE_DIR}/output/lib:${CMAKE_SOURCE_DIR}/dependency/${ARCH}/third_party/grpc/v1.76.0/lib")
endif()
# --------------------------------------------------------
# Unit test
# --------------------------------------------------------

View File

@ -0,0 +1,60 @@
#ifndef CMVR_ES_ACTION_QUEUE_H
#define CMVR_ES_ACTION_QUEUE_H
#include <functional>
#include <memory>
#include <string>
#include "cmvr/api/system_command.pb.h"
namespace cmvr::device {
class RobotArm;
}
namespace cmvr::service {
// Executes one submitted sequence at a time. The RPC waits synchronously for
// the terminal result, while StopAll may cancel the active sequence from a
// different gRPC handler.
class ActionQueue final {
public:
using ArmResolver = std::function<std::shared_ptr<device::RobotArm>(
const std::string&)>;
enum class State {
Idle,
Validating,
Running,
Stopping,
Completed,
Failed,
Canceled,
TimedOut,
Rejected,
ShuttingDown,
};
explicit ActionQueue(ArmResolver arm_resolver);
~ActionQueue();
ActionQueue(const ActionQueue&) = delete;
ActionQueue& operator=(const ActionQueue&) = delete;
void execute(const api::ActionQueueCommand_Request& request,
api::ActionQueueCommand_Feedback& feedback);
// Immediately removes every not-yet-dispatched step and requests a typed
// stop for the active arm. No ActionQueue mutex is held across that call.
void cancelAndClear();
void shutdown();
State state() const;
private:
struct Impl;
std::unique_ptr<Impl> impl_;
};
} // namespace cmvr::service
#endif // CMVR_ES_ACTION_QUEUE_H

View File

@ -0,0 +1,66 @@
#ifndef CMVR_ES_CONTROL_COMMAND_ARBITER_H
#define CMVR_ES_CONTROL_COMMAND_ARBITER_H
#include <cstddef>
#include <mutex>
namespace cmvr::service {
// Process-local admission gate for gRPC control commands. Ordinary controls
// may overlap each other, but ActionQueue owns the control domain exclusively.
// Stop leases are preemptive: they never wait for the current owner and block
// all new admission until the stop operation returns.
class ControlCommandArbiter final {
public:
enum class LeaseKind {
None,
Control,
ActionQueue,
Stop,
};
class Lease final {
public:
Lease() = default;
~Lease();
Lease(const Lease&) = delete;
Lease& operator=(const Lease&) = delete;
Lease(Lease&& other) noexcept;
Lease& operator=(Lease&& other) noexcept;
explicit operator bool() const noexcept { return owner_ != nullptr; }
void reset() noexcept;
private:
friend class ControlCommandArbiter;
Lease(ControlCommandArbiter* owner, LeaseKind kind)
: owner_(owner), kind_(kind)
{
}
ControlCommandArbiter* owner_{nullptr};
LeaseKind kind_{LeaseKind::None};
};
static ControlCommandArbiter& instance();
Lease tryAcquireControl();
Lease tryAcquireActionQueue();
Lease beginStop();
bool actionQueueActive() const;
std::size_t activeControlCount() const;
private:
void release(LeaseKind kind) noexcept;
mutable std::mutex mutex_;
std::size_t active_controls_{0};
std::size_t active_stops_{0};
bool action_queue_active_{false};
};
} // namespace cmvr::service
#endif // CMVR_ES_CONTROL_COMMAND_ARBITER_H

View File

@ -0,0 +1,45 @@
#ifndef CMVR_ES_CONTROL_COMMAND_GUARD_H
#define CMVR_ES_CONTROL_COMMAND_GUARD_H
#include <string>
#include <grpcpp/grpcpp.h>
#include "cmvr/api/common.pb.h"
#include "common/base/grpc_utils.h"
namespace cmvr::service {
inline const std::string& controlCommandBusyMessage()
{
static const std::string message =
"control command rejected while ActionQueue or StopAll is active";
return message;
}
inline grpc::Status rejectControlCommand(api::CommandHeader_Feedback* response)
{
response->set_success(false);
response->set_error_message(controlCommandBusyMessage());
setCurrentTimestamp(response->mutable_timestamp());
return grpc::Status(
grpc::StatusCode::FAILED_PRECONDITION,
controlCommandBusyMessage());
}
template <typename Response>
grpc::Status rejectControlCommand(Response* response)
{
return rejectControlCommand(response->mutable_header());
}
inline grpc::Status rejectControlCommand()
{
return grpc::Status(
grpc::StatusCode::FAILED_PRECONDITION,
controlCommandBusyMessage());
}
} // namespace cmvr::service
#endif // CMVR_ES_CONTROL_COMMAND_GUARD_H

View File

@ -0,0 +1,575 @@
#include "service/grpc/action/include/action_queue.h"
#include <algorithm>
#include <atomic>
#include <chrono>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <deque>
#include <functional>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <google/protobuf/util/time_util.h>
#include "common/base/logging/logger.h"
#include "devices/arm/robot_arm.h"
#include "service/grpc/action/include/control_command_arbiter.h"
namespace cmvr::service {
namespace {
constexpr std::size_t kMaximumStepCount = 100;
constexpr auto kDefaultTotalTimeout = std::chrono::minutes(5);
constexpr auto kMaximumTimeout = std::chrono::minutes(30);
constexpr auto kMaximumTimeoutMs =
std::chrono::duration_cast<std::chrono::milliseconds>(kMaximumTimeout)
.count();
bool finiteNonNegative(const double value)
{
return std::isfinite(value) && value >= 0.0;
}
device::JointPositionCommand toJointPosition(
const api::JointPositionCommand& source)
{
device::JointPositionCommand target;
target.position.assign(source.position().begin(), source.position().end());
return target;
}
device::MotionOptions toMotionOptions(const api::MotionOptions& source)
{
device::MotionOptions options;
options.velocity = source.velocity();
options.acceleration = source.acceleration();
options.blend_radius = source.blend_radius();
options.jerk = source.jerk() > 0.0 ? source.jerk() : 5.0;
options.joint_velocity_limits.assign(
source.joint_velocity_limits().begin(),
source.joint_velocity_limits().end());
options.asynchronous = source.asynchronous();
return options;
}
device::CartesianPose toCartesianPose(const api::CartesianPose& source)
{
return {source.x(), source.y(), source.z(),
source.rx(), source.ry(), source.rz()};
}
device::FrameType toFrameType(const api::ArmFrameType frame)
{
switch (frame) {
case api::ARM_FRAME_TOOL:
return device::FrameType::Tool;
case api::ARM_FRAME_WORLD:
return device::FrameType::World;
case api::ARM_FRAME_USER:
return device::FrameType::User;
case api::ARM_FRAME_BASE:
default:
return device::FrameType::Base;
}
}
bool validMotionOptions(const api::MotionOptions& options, std::string& error)
{
if (options.asynchronous()) {
error = "ActionQueue requires synchronous RobotArm motion";
return false;
}
if (!finiteNonNegative(options.velocity()) ||
!finiteNonNegative(options.acceleration()) ||
!finiteNonNegative(options.blend_radius()) ||
!finiteNonNegative(options.jerk())) {
error = "motion options must be finite and non-negative";
return false;
}
for (const double limit : options.joint_velocity_limits()) {
if (!finiteNonNegative(limit)) {
error = "joint velocity limits must be finite and non-negative";
return false;
}
}
return true;
}
void finishFeedback(api::ActionQueueCommand_Feedback& feedback,
const api::ActionResultCode result,
const std::uint32_t completed_steps,
const std::string& error,
const int failed_step_index = -1)
{
feedback.Clear();
feedback.set_result(result);
feedback.set_completed_steps(completed_steps);
if (failed_step_index >= 0) {
feedback.set_failed_step_index(
static_cast<std::uint32_t>(failed_step_index));
}
auto* header = feedback.mutable_header();
header->set_success(result == api::ACTION_RESULT_CODE_COMPLETED);
header->set_error_message(error);
*header->mutable_timestamp() =
google::protobuf::util::TimeUtil::GetCurrentTime();
}
} // namespace
struct ActionQueue::Impl {
struct PreparedStep {
api::ActionStep source;
std::shared_ptr<device::RobotArm> arm;
std::size_t source_index{0};
};
struct CommandHandler {
std::function<bool(const api::ActionStep&,
std::size_t,
PreparedStep&,
std::string&)> prepare;
std::function<device::Result(
const PreparedStep&,
const std::function<bool()>&)> execute;
};
explicit Impl(ActionQueue::ArmResolver resolver)
: arm_resolver(std::move(resolver))
{
registerCommands();
}
void registerCommands()
{
handlers.emplace(
api::ActionStep::kArmMoveJ,
CommandHandler{
[this](const api::ActionStep& step,
const std::size_t index,
PreparedStep& prepared,
std::string& error) {
const auto& command = step.arm_move_j();
return prepareArmStep(
step, command.header().device_id(), index,
command.options(), prepared, error,
[&command, &error](const device::RobotArm& arm) {
if (command.target().position_size() !=
static_cast<int>(arm.getDof())) {
error = "MoveJ target size does not match arm DOF";
return false;
}
for (const double value : command.target().position()) {
if (!std::isfinite(value)) {
error = "MoveJ target must contain finite values";
return false;
}
}
return true;
});
},
[](const PreparedStep& prepared,
const std::function<bool()>& canceled) {
const auto& command = prepared.source.arm_move_j();
auto options = toMotionOptions(command.options());
options.cancellation_requested = canceled;
return prepared.arm->moveJ(
toJointPosition(command.target()), options);
}});
handlers.emplace(
api::ActionStep::kArmMoveL,
CommandHandler{
[this](const api::ActionStep& step,
const std::size_t index,
PreparedStep& prepared,
std::string& error) {
const auto& command = step.arm_move_l();
return prepareArmStep(
step, command.header().device_id(), index,
command.options(), prepared, error,
[&command, &error](const device::RobotArm&) {
const auto& pose = command.target();
if (!std::isfinite(pose.x()) ||
!std::isfinite(pose.y()) ||
!std::isfinite(pose.z()) ||
!std::isfinite(pose.rx()) ||
!std::isfinite(pose.ry()) ||
!std::isfinite(pose.rz())) {
error = "MoveL target must contain finite values";
return false;
}
return true;
});
},
[](const PreparedStep& prepared,
const std::function<bool()>& canceled) {
const auto& command = prepared.source.arm_move_l();
auto options = toMotionOptions(command.options());
options.cancellation_requested = canceled;
const auto target = toCartesianPose(command.target());
const bool named_frame =
(command.has_base_frame() &&
!command.base_frame().empty()) ||
(command.has_tcp_frame() &&
!command.tcp_frame().empty());
if (named_frame) {
return prepared.arm->moveL(
target,
options,
command.has_base_frame()
? command.base_frame()
: std::string{},
command.has_tcp_frame()
? command.tcp_frame()
: std::string{});
}
return prepared.arm->moveL(
target, options, toFrameType(command.frame()));
}});
}
template <typename ExtraValidator>
bool prepareArmStep(const api::ActionStep& step,
const std::string& device_id,
const std::size_t index,
const api::MotionOptions& options,
PreparedStep& prepared,
std::string& error,
ExtraValidator&& validate)
{
if (device_id.empty()) {
error = "RobotArm device_id is required";
return false;
}
auto arm = arm_resolver(device_id);
if (!arm) {
error = "RobotArm device not found: " + device_id;
return false;
}
if (!arm->supportsActionQueueMotion()) {
error = "RobotArm backend does not support ActionQueue motion: " +
device_id;
return false;
}
if (!validMotionOptions(options, error) || !validate(*arm)) {
return false;
}
prepared.source = step;
prepared.arm = std::move(arm);
prepared.source_index = index;
return true;
}
bool prepare(const api::ActionQueueCommand_Request& request,
std::vector<PreparedStep>& prepared,
std::string& error,
int& failed_index)
{
if (request.steps_size() == 0) {
error = "ActionQueue requires at least one step";
return false;
}
if (request.steps_size() > static_cast<int>(kMaximumStepCount)) {
error = "ActionQueue step count exceeds the server limit";
return false;
}
if (request.total_timeout_ms() >
static_cast<std::uint64_t>(kMaximumTimeoutMs)) {
error = "ActionQueue total timeout exceeds the server limit";
return false;
}
prepared.reserve(static_cast<std::size_t>(request.steps_size()));
for (int index = 0; index < request.steps_size(); ++index) {
const auto& step = request.steps(index);
if (step.timeout_ms() >
static_cast<std::uint64_t>(kMaximumTimeoutMs)) {
error = "step timeout exceeds the server limit";
failed_index = index;
return false;
}
const auto handler = handlers.find(step.command_case());
if (handler == handlers.end()) {
error = "ActionQueue command type is not supported";
failed_index = index;
return false;
}
PreparedStep item;
if (!handler->second.prepare(
step, static_cast<std::size_t>(index), item, error)) {
failed_index = index;
return false;
}
prepared.push_back(std::move(item));
}
return true;
}
void setState(const State next)
{
std::lock_guard lock(mutex);
state = next;
}
ActionQueue::ArmResolver arm_resolver;
std::unordered_map<int, CommandHandler> handlers;
mutable std::mutex mutex;
State state{State::Idle};
std::deque<PreparedStep> pending;
std::shared_ptr<device::RobotArm> active_arm;
std::atomic<bool> stop_requested{false};
std::atomic<bool> shutting_down{false};
};
ActionQueue::ActionQueue(ArmResolver arm_resolver)
: impl_(std::make_unique<Impl>(std::move(arm_resolver)))
{
}
ActionQueue::~ActionQueue()
{
shutdown();
}
void ActionQueue::execute(
const api::ActionQueueCommand_Request& request,
api::ActionQueueCommand_Feedback& feedback)
{
if (impl_->shutting_down.load()) {
finishFeedback(feedback, api::ACTION_RESULT_CODE_REJECTED, 0,
"ActionQueue is shutting down");
return;
}
auto action_lease =
ControlCommandArbiter::instance().tryAcquireActionQueue();
if (!action_lease) {
finishFeedback(
feedback, api::ACTION_RESULT_CODE_REJECTED, 0,
"ActionQueue cannot start while another control command is active");
return;
}
{
std::lock_guard lock(impl_->mutex);
impl_->stop_requested.store(false);
impl_->state = State::Validating;
}
std::vector<Impl::PreparedStep> prepared;
std::string error;
int failed_index = -1;
if (!impl_->prepare(request, prepared, error, failed_index)) {
if (impl_->stop_requested.load() || impl_->shutting_down.load()) {
impl_->setState(State::Canceled);
finishFeedback(feedback, api::ACTION_RESULT_CODE_CANCELED, 0,
"ActionQueue was stopped");
impl_->setState(impl_->shutting_down.load()
? State::ShuttingDown
: State::Idle);
return;
}
impl_->setState(State::Rejected);
finishFeedback(feedback, api::ACTION_RESULT_CODE_REJECTED, 0,
error, failed_index);
impl_->setState(State::Idle);
return;
}
{
std::lock_guard lock(impl_->mutex);
if (impl_->stop_requested.load() || impl_->shutting_down.load()) {
impl_->state = impl_->shutting_down.load()
? State::ShuttingDown
: State::Idle;
finishFeedback(feedback, api::ACTION_RESULT_CODE_CANCELED, 0,
"ActionQueue was stopped");
return;
}
impl_->pending.assign(
std::make_move_iterator(prepared.begin()),
std::make_move_iterator(prepared.end()));
impl_->active_arm.reset();
impl_->state = State::Running;
}
const auto total_timeout = request.total_timeout_ms() == 0
? kDefaultTotalTimeout
: std::chrono::milliseconds(request.total_timeout_ms());
const auto total_deadline = std::chrono::steady_clock::now() +
total_timeout;
std::uint32_t completed_steps = 0;
while (true) {
Impl::PreparedStep step;
{
std::lock_guard lock(impl_->mutex);
if (impl_->stop_requested.load() || impl_->shutting_down.load()) {
impl_->state = State::Canceled;
finishFeedback(feedback, api::ACTION_RESULT_CODE_CANCELED,
completed_steps, "ActionQueue was stopped");
impl_->active_arm.reset();
impl_->state = impl_->shutting_down.load()
? State::ShuttingDown
: State::Idle;
return;
}
if (impl_->pending.empty()) {
impl_->state = State::Completed;
finishFeedback(feedback, api::ACTION_RESULT_CODE_COMPLETED,
completed_steps, {});
impl_->active_arm.reset();
impl_->state = State::Idle;
return;
}
if (std::chrono::steady_clock::now() >= total_deadline) {
impl_->pending.clear();
impl_->state = State::TimedOut;
finishFeedback(feedback, api::ACTION_RESULT_CODE_TIMED_OUT,
completed_steps,
"ActionQueue total timeout expired");
impl_->state = State::Idle;
return;
}
step = std::move(impl_->pending.front());
impl_->pending.pop_front();
impl_->active_arm = step.arm;
}
auto step_deadline = total_deadline;
if (step.source.timeout_ms() != 0) {
step_deadline = std::min(
step_deadline,
std::chrono::steady_clock::now() +
std::chrono::milliseconds(step.source.timeout_ms()));
}
const auto canceled = [this, step_deadline]() {
return impl_->stop_requested.load() ||
impl_->shutting_down.load() ||
std::chrono::steady_clock::now() >= step_deadline;
};
device::Result result;
try {
const auto handler = impl_->handlers.find(
step.source.command_case());
result = handler->second.execute(step, canceled);
} catch (const std::exception& exception) {
result = device::Result::failure(
device::ArmErrorCode::CommandFailed, exception.what());
} catch (...) {
result = device::Result::failure(
device::ArmErrorCode::CommandFailed,
"ActionQueue command threw an unknown exception");
}
{
std::lock_guard lock(impl_->mutex);
impl_->active_arm.reset();
if (impl_->stop_requested.load() || impl_->shutting_down.load()) {
impl_->pending.clear();
impl_->state = State::Canceled;
finishFeedback(
feedback, api::ACTION_RESULT_CODE_CANCELED,
completed_steps, "ActionQueue was stopped",
static_cast<int>(step.source_index));
impl_->state = impl_->shutting_down.load()
? State::ShuttingDown
: State::Idle;
return;
}
if (std::chrono::steady_clock::now() >= step_deadline) {
impl_->pending.clear();
impl_->state = State::TimedOut;
finishFeedback(
feedback, api::ACTION_RESULT_CODE_TIMED_OUT,
completed_steps, "ActionQueue step timeout expired",
static_cast<int>(step.source_index));
impl_->state = State::Idle;
return;
}
if (!result.ok()) {
impl_->pending.clear();
impl_->state = State::Failed;
finishFeedback(
feedback, api::ACTION_RESULT_CODE_FAILED,
completed_steps, result.message,
static_cast<int>(step.source_index));
impl_->state = State::Idle;
return;
}
++completed_steps;
}
}
}
void ActionQueue::cancelAndClear()
{
std::shared_ptr<device::RobotArm> active_arm;
{
std::lock_guard lock(impl_->mutex);
if (impl_->state == State::Idle ||
impl_->state == State::Rejected ||
impl_->state == State::Completed ||
impl_->state == State::Failed ||
impl_->state == State::Canceled ||
impl_->state == State::TimedOut) {
return;
}
impl_->stop_requested.store(true);
impl_->pending.clear();
impl_->state = impl_->shutting_down.load()
? State::ShuttingDown
: State::Stopping;
active_arm = impl_->active_arm;
}
// Never call a device SDK while holding the ActionQueue mutex. This keeps
// hardware emergency-stop and auto-enable monitor callbacks from forming a
// lock cycle with StopAll.
if (active_arm) {
try {
const auto result = active_arm->stopMotion();
if (!result.ok()) {
CMVR_LOG(WARNING)
<< "[ActionQueue] active arm stop was not confirmed: "
<< result.message;
}
} catch (const std::exception& error) {
CMVR_LOG(WARNING)
<< "[ActionQueue] active arm stop threw: " << error.what();
} catch (...) {
CMVR_LOG(WARNING)
<< "[ActionQueue] active arm stop threw an unknown exception";
}
}
}
void ActionQueue::shutdown()
{
if (!impl_) {
return;
}
impl_->shutting_down.store(true);
cancelAndClear();
std::lock_guard lock(impl_->mutex);
if (!impl_->active_arm) {
impl_->state = State::ShuttingDown;
}
}
ActionQueue::State ActionQueue::state() const
{
std::lock_guard lock(impl_->mutex);
return impl_->state;
}
} // namespace cmvr::service

View File

@ -0,0 +1,105 @@
#include "service/grpc/action/include/control_command_arbiter.h"
#include <utility>
namespace cmvr::service {
ControlCommandArbiter::Lease::~Lease()
{
reset();
}
ControlCommandArbiter::Lease::Lease(Lease&& other) noexcept
: owner_(std::exchange(other.owner_, nullptr)),
kind_(std::exchange(other.kind_, LeaseKind::None))
{
}
ControlCommandArbiter::Lease& ControlCommandArbiter::Lease::operator=(
Lease&& other) noexcept
{
if (this != &other) {
reset();
owner_ = std::exchange(other.owner_, nullptr);
kind_ = std::exchange(other.kind_, LeaseKind::None);
}
return *this;
}
void ControlCommandArbiter::Lease::reset() noexcept
{
if (owner_) {
owner_->release(kind_);
owner_ = nullptr;
kind_ = LeaseKind::None;
}
}
ControlCommandArbiter& ControlCommandArbiter::instance()
{
static ControlCommandArbiter arbiter;
return arbiter;
}
ControlCommandArbiter::Lease ControlCommandArbiter::tryAcquireControl()
{
std::lock_guard lock(mutex_);
if (action_queue_active_ || active_stops_ != 0) {
return {};
}
++active_controls_;
return {this, LeaseKind::Control};
}
ControlCommandArbiter::Lease ControlCommandArbiter::tryAcquireActionQueue()
{
std::lock_guard lock(mutex_);
if (action_queue_active_ || active_controls_ != 0 || active_stops_ != 0) {
return {};
}
action_queue_active_ = true;
return {this, LeaseKind::ActionQueue};
}
ControlCommandArbiter::Lease ControlCommandArbiter::beginStop()
{
std::lock_guard lock(mutex_);
++active_stops_;
return {this, LeaseKind::Stop};
}
bool ControlCommandArbiter::actionQueueActive() const
{
std::lock_guard lock(mutex_);
return action_queue_active_;
}
std::size_t ControlCommandArbiter::activeControlCount() const
{
std::lock_guard lock(mutex_);
return active_controls_;
}
void ControlCommandArbiter::release(const LeaseKind kind) noexcept
{
std::lock_guard lock(mutex_);
switch (kind) {
case LeaseKind::Control:
if (active_controls_ != 0) {
--active_controls_;
}
break;
case LeaseKind::ActionQueue:
action_queue_active_ = false;
break;
case LeaseKind::Stop:
if (active_stops_ != 0) {
--active_stops_;
}
break;
case LeaseKind::None:
break;
}
}
} // namespace cmvr::service

View File

@ -0,0 +1,330 @@
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <future>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
#include <gtest/gtest.h>
#include "devices/arm/robot_arm.h"
#include "service/grpc/action/include/action_queue.h"
#include "service/grpc/action/include/control_command_arbiter.h"
namespace cmvr::service {
namespace {
using namespace std::chrono_literals;
class FakeActionQueueArm final : public device::RobotArm {
public:
explicit FakeActionQueueArm(std::string device_id)
{
id_ = std::move(device_id);
model_.dof = 6;
model_.joint_names = {"j1", "j2", "j3", "j4", "j5", "j6"};
}
std::string typeName() const override { return "FakeActionQueueArm"; }
bool stop() override { return stopMotion().ok(); }
device::RobotModel getRobotModel() const override { return model_; }
std::size_t getDof() const override { return model_.dof; }
device::ArmState getRobotState() const override { return {}; }
device::JointGroupState getJointState() const override { return {}; }
device::CartesianPose getTcpPose(device::FrameType) const override { return {}; }
device::RobotMode getRobotMode() const override { return device::RobotMode::Idle; }
device::SafetyMode getSafetyMode() const override {
return emergency_.load()
? device::SafetyMode::EmergencyStop
: device::SafetyMode::Normal;
}
device::ControlMode getControlMode() const override {
return device::ControlMode::Position;
}
bool supportsActionQueueMotion() const noexcept override { return true; }
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 {
emergency_.store(true);
return stopMotion();
}
device::Result protectiveStop() override { return emergencyStop(); }
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 emergency_.load(); }
bool isFault() const override { return false; }
device::Result moveJ(const device::JointPositionCommand&,
const device::MotionOptions& options) override
{
return runMotion("MoveJ", 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&,
const device::MotionOptions& options,
device::FrameType) override
{
return runMotion("MoveL", options);
}
device::Result moveL(const device::CartesianPose&,
const device::MotionOptions& options,
const std::string& base_frame,
const std::string& tcp_frame) override
{
{
std::lock_guard lock(mutex_);
base_frame_ = base_frame;
tcp_frame_ = tcp_frame;
}
return runMotion("MoveL", options);
}
device::Result speedL(const device::CartesianVelocity&, double, double,
device::FrameType) override {
return device::Result::success();
}
device::Result stopL(std::optional<double>) override { return stopMotion(); }
device::Result stopMotion() override
{
++stop_count_;
cv_.notify_all();
return 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) override { return device::Result::success(); }
device::Result servoSpeedJ(const device::JointVelocityCommand&) override { return device::Result::success(); }
device::Result servoSpeedL(const device::CartesianVelocity&, device::FrameType) 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<double> ik(const std::string&, const std::string&,
const device::CartesianPose&) override { return {}; }
std::shared_ptr<cmvr::IKSolver> kinematicsSolver() const override { return nullptr; }
device::CartesianPose fk(const std::string&, const std::string&) override { return {}; }
device::CartesianPose fk(bool) override { return {}; }
device::CartesianVelocity getSpeedLCommandTwistBase() const override { return {}; }
bool busy() const override { return busy_.load(); }
void blockMotion(bool value)
{
block_.store(value);
cv_.notify_all();
}
bool waitUntilStarted()
{
std::unique_lock lock(mutex_);
return cv_.wait_for(lock, 2s, [this] { return started_; });
}
std::vector<std::string> calls() const
{
std::lock_guard lock(mutex_);
return calls_;
}
std::string baseFrame() const
{
std::lock_guard lock(mutex_);
return base_frame_;
}
std::string tcpFrame() const
{
std::lock_guard lock(mutex_);
return tcp_frame_;
}
int stopCount() const { return stop_count_.load(); }
void triggerHardwareEstop()
{
emergency_.store(true);
cv_.notify_all();
}
private:
device::Result runMotion(const std::string& name,
const device::MotionOptions& options)
{
busy_.store(true);
{
std::lock_guard lock(mutex_);
calls_.push_back(name);
started_ = true;
}
cv_.notify_all();
while (block_.load()) {
if (emergency_.load()) {
busy_.store(false);
return device::Result::failure(
device::ArmErrorCode::RobotInEmergencyStop,
"hardware emergency stop");
}
if (options.cancellation_requested &&
options.cancellation_requested()) {
busy_.store(false);
return device::Result::failure(
device::ArmErrorCode::CommandRejected, "canceled");
}
std::unique_lock lock(mutex_);
cv_.wait_for(lock, 10ms);
}
busy_.store(false);
return emergency_.load()
? device::Result::failure(
device::ArmErrorCode::RobotInEmergencyStop,
"hardware emergency stop")
: device::Result::success();
}
device::RobotModel model_;
mutable std::mutex mutex_;
std::condition_variable cv_;
std::vector<std::string> calls_;
std::string base_frame_;
std::string tcp_frame_;
bool started_{false};
std::atomic<bool> block_{false};
std::atomic<bool> busy_{false};
std::atomic<bool> emergency_{false};
std::atomic<int> stop_count_{0};
};
ActionQueue makeQueue(const std::shared_ptr<FakeActionQueueArm>& arm)
{
return ActionQueue([arm](const std::string& device_id) {
return device_id == arm->id()
? std::static_pointer_cast<device::RobotArm>(arm)
: std::shared_ptr<device::RobotArm>{};
});
}
api::ActionQueueCommand_Request twoStepRequest(const std::string& device_id)
{
api::ActionQueueCommand_Request request;
auto* move_j = request.add_steps()->mutable_arm_move_j();
move_j->mutable_header()->set_device_id(device_id);
for (int index = 0; index < 6; ++index) {
move_j->mutable_target()->add_position(0.1 * index);
}
auto* move_l = request.add_steps()->mutable_arm_move_l();
move_l->mutable_header()->set_device_id(device_id);
move_l->set_base_frame("workpiece");
move_l->set_tcp_frame("gripper");
return request;
}
TEST(ActionQueueTest, ExecutesMoveJAndNamedFrameMoveLInOrder)
{
auto arm = std::make_shared<FakeActionQueueArm>("action_arm_order");
auto queue = makeQueue(arm);
api::ActionQueueCommand_Feedback feedback;
queue.execute(twoStepRequest(arm->id()), feedback);
EXPECT_TRUE(feedback.header().success())
<< feedback.header().error_message();
EXPECT_EQ(feedback.result(), api::ACTION_RESULT_CODE_COMPLETED);
EXPECT_EQ(feedback.completed_steps(), 2U);
EXPECT_EQ(arm->calls(), (std::vector<std::string>{"MoveJ", "MoveL"}));
EXPECT_EQ(arm->baseFrame(), "workpiece");
EXPECT_EQ(arm->tcpFrame(), "gripper");
}
TEST(ActionQueueTest, StopClearsRemainingStepsAndReleasesControlDomain)
{
auto arm = std::make_shared<FakeActionQueueArm>("action_arm_stop");
arm->blockMotion(true);
auto queue = makeQueue(arm);
api::ActionQueueCommand_Feedback feedback;
std::thread executor([&] {
queue.execute(twoStepRequest(arm->id()), feedback);
});
ASSERT_TRUE(arm->waitUntilStarted());
EXPECT_FALSE(ControlCommandArbiter::instance().tryAcquireControl());
queue.cancelAndClear();
executor.join();
EXPECT_EQ(feedback.result(), api::ACTION_RESULT_CODE_CANCELED);
EXPECT_EQ(feedback.completed_steps(), 0U);
EXPECT_EQ(arm->calls(), (std::vector<std::string>{"MoveJ"}));
EXPECT_GE(arm->stopCount(), 1);
EXPECT_TRUE(ControlCommandArbiter::instance().tryAcquireControl());
}
TEST(ActionQueueTest, RejectsSubmissionWhileOrdinaryControlIsActive)
{
auto arm = std::make_shared<FakeActionQueueArm>("action_arm_gate");
auto queue = makeQueue(arm);
api::ActionQueueCommand_Feedback feedback;
auto control_lease =
ControlCommandArbiter::instance().tryAcquireControl();
ASSERT_TRUE(control_lease);
queue.execute(twoStepRequest(arm->id()), feedback);
EXPECT_EQ(feedback.result(), api::ACTION_RESULT_CODE_REJECTED);
EXPECT_TRUE(arm->calls().empty());
}
TEST(ActionQueueTest, HardwareEmergencyStopTerminatesWithoutHoldingTheGate)
{
auto arm = std::make_shared<FakeActionQueueArm>("action_arm_estop");
arm->blockMotion(true);
auto queue = makeQueue(arm);
api::ActionQueueCommand_Feedback feedback;
auto execution = std::async(std::launch::async, [&] {
queue.execute(twoStepRequest(arm->id()), feedback);
});
ASSERT_TRUE(arm->waitUntilStarted());
arm->triggerHardwareEstop();
ASSERT_EQ(execution.wait_for(2s), std::future_status::ready);
execution.get();
EXPECT_EQ(feedback.result(), api::ACTION_RESULT_CODE_FAILED);
EXPECT_EQ(arm->calls(), (std::vector<std::string>{"MoveJ"}));
EXPECT_TRUE(ControlCommandArbiter::instance().tryAcquireControl());
}
TEST(ActionQueueTest, StepTimeoutStopsBlockedMotion)
{
auto arm = std::make_shared<FakeActionQueueArm>("action_arm_timeout");
arm->blockMotion(true);
auto queue = makeQueue(arm);
auto request = twoStepRequest(arm->id());
request.mutable_steps(0)->set_timeout_ms(30);
api::ActionQueueCommand_Feedback feedback;
queue.execute(request, feedback);
EXPECT_EQ(feedback.result(), api::ACTION_RESULT_CODE_TIMED_OUT);
EXPECT_EQ(feedback.completed_steps(), 0U);
EXPECT_EQ(arm->calls(), (std::vector<std::string>{"MoveJ"}));
}
} // namespace
} // namespace cmvr::service

View File

@ -0,0 +1,88 @@
#ifndef CMVR_ES_GRPC_AGV_SERVICE_H
#define CMVR_ES_GRPC_AGV_SERVICE_H
#include "cmvr/api/agv_service.grpc.pb.h"
#include "devices/agv/abstract_agv.h"
#include "manager/device_manager/include/device_manager.h"
namespace cmvr::service {
class gRPCAgvServiceImpl final : public api::AgvService::Service {
public:
gRPCAgvServiceImpl();
~gRPCAgvServiceImpl() override = default;
grpc::Status getRuntimeState(grpc::ServerContext* context,
const api::AgvRuntimeStateCommand_Request* request,
api::AgvRuntimeStateCommand_Feedback* response) override;
grpc::Status getNavigationStatus(grpc::ServerContext* context,
const api::AgvNavigationStatusCommand_Request* request,
api::AgvNavigationStatusCommand_Feedback* response) override;
grpc::Status emergencyStop(grpc::ServerContext* context,
const api::CommandHeader_Request* request,
api::CommandHeader_Feedback* response) override;
grpc::Status clearFault(grpc::ServerContext* context,
const api::CommandHeader_Request* request,
api::CommandHeader_Feedback* response) override;
grpc::Status relocalize(grpc::ServerContext* context,
const api::AgvRelocalizeCommand_Request* request,
api::AgvRelocalizeCommand_Feedback* response) override;
grpc::Status navigateToPose(grpc::ServerContext* context,
const api::AgvNavigateToPoseCommand_Request* request,
api::AgvNavigateToPoseCommand_Feedback* response) override;
grpc::Status navigateToStation(grpc::ServerContext* context,
const api::AgvNavigateToStationCommand_Request* request,
api::AgvNavigateToStationCommand_Feedback* response) override;
grpc::Status followPath(grpc::ServerContext* context,
const api::AgvFollowPathCommand_Request* request,
api::AgvFollowPathCommand_Feedback* response) override;
grpc::Status pauseNavigation(grpc::ServerContext* context,
const api::CommandHeader_Request* request,
api::CommandHeader_Feedback* response) override;
grpc::Status resumeNavigation(grpc::ServerContext* context,
const api::CommandHeader_Request* request,
api::CommandHeader_Feedback* response) override;
grpc::Status cancelNavigation(grpc::ServerContext* context,
const api::CommandHeader_Request* request,
api::CommandHeader_Feedback* response) override;
grpc::Status setVelocity(grpc::ServerContext* context,
const api::AgvSetVelocityCommand_Request* request,
api::AgvSetVelocityCommand_Feedback* response) override;
grpc::Status translate(grpc::ServerContext* context,
const api::AgvTranslateCommand_Request* request,
api::AgvTranslateCommand_Feedback* response) override;
grpc::Status stopVelocityControl(grpc::ServerContext* context,
const api::CommandHeader_Request* request,
api::CommandHeader_Feedback* response) override;
grpc::Status listMaps(grpc::ServerContext* context,
const api::AgvListMapsCommand_Request* request,
api::AgvListMapsCommand_Feedback* response) override;
grpc::Status listStations(grpc::ServerContext* context,
const api::AgvListStationsCommand_Request* request,
api::AgvListStationsCommand_Feedback* response) override;
grpc::Status switchMap(grpc::ServerContext* context,
const api::AgvMapCommand_Request* request,
api::AgvMapCommand_Feedback* response) override;
grpc::Status uploadMap(grpc::ServerContext* context,
const api::AgvMapCommand_Request* request,
api::AgvMapCommand_Feedback* response) override;
grpc::Status downloadMap(grpc::ServerContext* context,
const api::AgvMapCommand_Request* request,
api::AgvMapCommand_Feedback* response) override;
grpc::Status startMapping(grpc::ServerContext* context,
const api::AgvStartMappingCommand_Request* request,
api::AgvStartMappingCommand_Feedback* response) override;
grpc::Status streamMap(grpc::ServerContext* context,
const api::AgvMapStreamCommand_Request* request,
grpc::ServerWriter<api::AgvMapStreamCommand_Feedback>* writer) override;
grpc::Status stopMapping(grpc::ServerContext* context,
const api::CommandHeader_Request* request,
api::CommandHeader_Feedback* response) override;
private:
device::DeviceManager& dmgr_;
};
} // namespace cmvr::service
#endif // CMVR_ES_GRPC_AGV_SERVICE_H

View File

@ -17,12 +17,21 @@ public:
grpc::Status torqueOn(grpc::ServerContext* context,
const api::CommandHeader_Request* request,
api::CommandHeader_Feedback* response) override;
grpc::Status clearFault(grpc::ServerContext* context,
const api::CommandHeader_Request* request,
api::CommandHeader_Feedback* response) override;
grpc::Status moveJ(grpc::ServerContext* context,
const api::MoveJ_Request* request,
api::MoveJ_Response* response) override;
grpc::Status moveL(grpc::ServerContext* context,
const api::MoveL_Request* request,
api::MoveL_Response* response) override;
grpc::Status ListBaseFrame(grpc::ServerContext* context,
const api::ListFrame_Request* request,
api::ListFrame_Response* response) override;
grpc::Status ListTCPFrame(grpc::ServerContext* context,
const api::ListFrame_Request* request,
api::ListFrame_Response* response) override;
grpc::Status speedJ(grpc::ServerContext* context,
const api::SpeedJ_Request* request,
api::SpeedJ_Response* response) override;

View File

@ -5,22 +5,31 @@
#ifndef GRPC_SYSTEM_SERVICE_H
#define GRPC_SYSTEM_SERVICE_H
#include <memory>
#include <mutex>
#include "cmvr/api/system_service.grpc.pb.h"
#include "common/base/grpc_utils.h"
#include "manager/device_manager/include/device_manager.h"
namespace cmvr::service
{
class ActionQueue;
class gRPCSystemServiceImpl: public api::SystemService::Service {
public:
gRPCSystemServiceImpl();
~gRPCSystemServiceImpl() override = default;
~gRPCSystemServiceImpl() override;
void prepareForShutdown();
grpc::Status GetSystemInfo(grpc::ServerContext* context, const api::GetSystemInfoCommand_Request* request, api::GetSystemInfoCommand_Feedback* response) override;
grpc::Status GetSystemStatus(grpc::ServerContext* context, const api::GetSystemStatusCommand_Request* request, api::GetSystemStatusCommand_Feedback* response) override;
grpc::Status UpdateParams(grpc::ServerContext* context, const cmvr::api::UpdateParamsCommand_Request* request, cmvr::api::UpdateParamsCommand_Feedback* response) override;
grpc::Status StopAll(grpc::ServerContext* context, const cmvr::api::StopAllCommand_Request* request, cmvr::api::StopAllCommand_Feedback* response) override;
grpc::Status ExecuteActionQueue(grpc::ServerContext* context, const cmvr::api::ActionQueueCommand_Request* request, cmvr::api::ActionQueueCommand_Feedback* response) override;
private:
device::DeviceManager& dmgr_;
std::unique_ptr<ActionQueue> action_queue_;
std::mutex stop_all_mutex_;
};
}

View File

@ -0,0 +1,876 @@
#include "service/grpc/include/grpc_agv_service.h"
#include <cstdint>
#include <exception>
#include <string>
#include <vector>
#include <google/protobuf/util/time_util.h>
#include "service/grpc/action/include/control_command_arbiter.h"
#include "service/grpc/action/include/control_command_guard.h"
using google::protobuf::util::TimeUtil;
namespace cmvr::service {
namespace {
void fillFeedback(api::CommandHeader_Feedback* feedback,
const bool success,
const std::string& message = {})
{
feedback->set_success(success);
feedback->set_error_message(message);
*feedback->mutable_timestamp() = TimeUtil::GetCurrentTime();
}
grpc::Status resultToStatus(const device::AgvResult& result)
{
if (result.ok()) {
return grpc::Status::OK;
}
switch (result.code) {
case device::AgvErrorCode::InvalidArgument:
return grpc::Status(
grpc::StatusCode::INVALID_ARGUMENT,
result.message);
case device::AgvErrorCode::TaskCanceled:
return grpc::Status(
grpc::StatusCode::CANCELLED,
result.message);
case device::AgvErrorCode::Timeout:
return grpc::Status(
grpc::StatusCode::DEADLINE_EXCEEDED,
result.message);
default:
return grpc::Status(
grpc::StatusCode::INTERNAL,
result.message);
}
}
template <typename Response>
grpc::Status setResponseResult(Response* response, const device::AgvResult& result)
{
fillFeedback(response->mutable_header(), result.ok(), result.ok() ? "" : result.message);
return resultToStatus(result);
}
grpc::Status setResponseResult(api::CommandHeader_Feedback* response, const device::AgvResult& result)
{
fillFeedback(response, result.ok(), result.ok() ? "" : result.message);
return resultToStatus(result);
}
template <typename Response>
grpc::Status setDeviceNotFound(Response* response, const std::string& device_id)
{
const std::string message = "AGV device not found: " + device_id;
fillFeedback(response->mutable_header(), false, message);
return grpc::Status(grpc::StatusCode::NOT_FOUND, message);
}
grpc::Status setDeviceNotFound(api::CommandHeader_Feedback* response, const std::string& device_id)
{
const std::string message = "AGV device not found: " + device_id;
fillFeedback(response, false, message);
return grpc::Status(grpc::StatusCode::NOT_FOUND, message);
}
template <typename Response>
grpc::Status setNavigationRequestCanceled(Response* response)
{
constexpr char message[] =
"AGV navigation request was canceled before command dispatch";
fillFeedback(response->mutable_header(), false, message);
return grpc::Status(grpc::StatusCode::CANCELLED, message);
}
device::AgvAdapterParams toAdapterParams(const msgs::AgvAdapterParams& src)
{
device::AgvAdapterParams dst;
for (const auto& [key, value] : src.values()) {
dst.values.emplace(key, value);
}
return dst;
}
device::AgvMotionOptions toMotionOptions(
const msgs::AgvMotionOptions& src,
grpc::ServerContext* context = nullptr)
{
device::AgvMotionOptions dst;
dst.max_speed = src.max_speed();
dst.max_angular_speed = src.max_angular_speed();
dst.max_acceleration = src.max_acceleration();
dst.max_angular_acceleration = src.max_angular_acceleration();
dst.reach_distance = src.reach_distance();
dst.reach_angle = src.reach_angle();
dst.speed_ratio = src.speed_ratio() > 0.0 ? src.speed_ratio() : 1.0;
dst.asynchronous = src.asynchronous();
dst.wait_timeout_ms = src.wait_timeout_ms();
dst.poll_interval_ms = src.poll_interval_ms();
dst.blocked_timeout_ms = src.blocked_timeout_ms();
if (context) {
dst.cancellation_requested = [context]() {
return context->IsCancelled();
};
}
return dst;
}
device::AgvVelocity toVelocity(const msgs::AgvVelocity& src)
{
return {src.vx(), src.vy(), src.wz()};
}
device::AgvTranslation toTranslation(const msgs::AgvTranslation& src)
{
device::AgvTranslation dst;
dst.distance = src.distance();
dst.vx = src.vx();
dst.vy = src.vy();
dst.mode = src.mode() == msgs::AGV_TRANSLATION_MODE_LOCALIZATION
? device::AgvTranslationMode::Localization
: device::AgvTranslationMode::Odometry;
return dst;
}
device::AgvPathSegment toPathSegment(const msgs::AgvPathSegment& src)
{
device::AgvPathSegment dst;
dst.source_station = src.source_station();
dst.target_station = src.target_station();
return dst;
}
math::Pose2d toPose2d(const msgs::AgvPose2d& src)
{
return {src.x(), src.y(), src.theta()};
}
device::AgvMapDimension toMapDimension(const msgs::AgvMapDimension src)
{
switch (src) {
case msgs::AGV_MAP_2D:
return device::AgvMapDimension::Map2D;
case msgs::AGV_MAP_3D:
return device::AgvMapDimension::Map3D;
case msgs::AGV_MAP_2D_AND_3D:
return device::AgvMapDimension::Map2DAnd3D;
case msgs::AGV_MAP_DIMENSION_UNSPECIFIED:
default:
return device::AgvMapDimension::Unspecified;
}
}
msgs::AgvMapDimension toProtoMapDimension(const device::AgvMapDimension src)
{
switch (src) {
case device::AgvMapDimension::Map2D:
return msgs::AGV_MAP_2D;
case device::AgvMapDimension::Map3D:
return msgs::AGV_MAP_3D;
case device::AgvMapDimension::Map2DAnd3D:
return msgs::AGV_MAP_2D_AND_3D;
case device::AgvMapDimension::Unspecified:
default:
return msgs::AGV_MAP_DIMENSION_UNSPECIFIED;
}
}
msgs::AgvMapUpdateType toProtoMapUpdateType(const device::AgvMapUpdateType src)
{
switch (src) {
case device::AgvMapUpdateType::Snapshot:
return msgs::AGV_MAP_UPDATE_SNAPSHOT;
case device::AgvMapUpdateType::Incremental:
return msgs::AGV_MAP_UPDATE_INCREMENTAL;
case device::AgvMapUpdateType::Reset:
return msgs::AGV_MAP_UPDATE_RESET;
case device::AgvMapUpdateType::Unspecified:
default:
return msgs::AGV_MAP_UPDATE_UNSPECIFIED;
}
}
msgs::AgvMapObjectType toProtoMapObjectType(const device::AgvMapObjectType src)
{
switch (src) {
case device::AgvMapObjectType::Station:
return msgs::AGV_MAP_OBJECT_STATION;
case device::AgvMapObjectType::Line:
return msgs::AGV_MAP_OBJECT_LINE;
case device::AgvMapObjectType::Area:
return msgs::AGV_MAP_OBJECT_AREA;
case device::AgvMapObjectType::QrTag:
return msgs::AGV_MAP_OBJECT_QR_TAG;
case device::AgvMapObjectType::Reflector:
return msgs::AGV_MAP_OBJECT_REFLECTOR;
case device::AgvMapObjectType::BinLocation:
return msgs::AGV_MAP_OBJECT_BIN_LOCATION;
case device::AgvMapObjectType::ExternalDevice:
return msgs::AGV_MAP_OBJECT_EXTERNAL_DEVICE;
case device::AgvMapObjectType::Unspecified:
default:
return msgs::AGV_MAP_OBJECT_UNSPECIFIED;
}
}
void fillPose2d(msgs::AgvPose2d* dst, const math::Pose2d& src)
{
dst->set_x(src.x);
dst->set_y(src.y);
dst->set_theta(src.theta);
}
void fillVelocity(msgs::AgvVelocity* dst, const device::AgvVelocity& src)
{
dst->set_vx(src.vx);
dst->set_vy(src.vy);
dst->set_wz(src.wz);
}
void fillBattery(msgs::AgvBatteryState* dst, const device::AgvBatteryState& src)
{
dst->set_percentage(src.percentage);
dst->set_voltage(src.voltage);
dst->set_current(src.current);
dst->set_temperature(src.temperature);
dst->set_charging(src.charging);
}
void fillRuntimeState(msgs::AgvRuntimeState* dst, const device::AgvRuntimeState& src)
{
dst->set_timestamp(src.timestamp);
dst->set_mode(static_cast<int>(src.mode));
dst->set_connected(src.connected);
dst->set_localized(src.localized);
dst->set_moving(src.moving);
dst->set_fault(src.fault);
dst->set_emergency_stopped(src.emergency_stopped);
fillPose2d(dst->mutable_pose(), src.pose);
fillVelocity(dst->mutable_velocity(), src.velocity);
fillBattery(dst->mutable_battery(), src.battery);
dst->set_current_map(src.current_map);
dst->set_current_station(src.current_station);
dst->set_last_error(src.last_error);
}
void fillNavigationStatus(msgs::AgvNavigationStatus* dst, const device::AgvNavigationStatus& src)
{
dst->set_state(static_cast<int>(src.state));
dst->set_type(static_cast<int>(src.type));
dst->set_progress(src.progress);
dst->set_message(src.message);
}
void fillStation(msgs::AgvStation* dst, const device::AgvStation& src)
{
dst->set_id(src.id);
dst->set_type(src.type);
fillPose2d(dst->mutable_pose(), src.pose);
dst->set_description(src.description);
}
void fillMapPoint3D(msgs::AgvMapPoint3D* dst, const device::AgvMapPoint3D& src)
{
dst->set_x(src.x);
dst->set_y(src.y);
dst->set_z(src.z);
}
void fillMapObject(msgs::AgvMapObject* dst, const device::AgvMapObject& src)
{
dst->set_id(src.id);
dst->set_type(toProtoMapObjectType(src.type));
for (const auto& point : src.points) {
fillMapPoint3D(dst->add_points(), point);
}
dst->set_heading(src.heading);
auto* properties = dst->mutable_properties();
for (const auto& [key, value] : src.properties) {
(*properties)[key] = value;
}
}
void fillUnifiedMap2D(msgs::AgvUnifiedMap2D* dst, const device::AgvUnifiedMap2D& src)
{
dst->set_frame_id(src.frame_id);
dst->set_timestamp(src.timestamp);
dst->set_resolution(src.resolution);
dst->set_width(src.width);
dst->set_height(src.height);
fillPose2d(dst->mutable_origin(), src.origin);
for (const auto value : src.data) {
dst->add_data(value);
}
for (const auto& object : src.objects) {
fillMapObject(dst->add_objects(), object);
}
}
void fillUnifiedMap3D(msgs::AgvUnifiedMap3D* dst, const device::AgvUnifiedMap3D& src)
{
dst->set_frame_id(src.frame_id);
dst->set_timestamp(src.timestamp);
dst->set_voxel_resolution(src.voxel_resolution);
for (const auto& point : src.points) {
auto* dst_point = dst->add_points();
dst_point->set_x(point.x);
dst_point->set_y(point.y);
dst_point->set_z(point.z);
dst_point->set_intensity(point.intensity);
dst_point->set_ring(point.ring);
dst_point->set_time_offset(point.time_offset);
}
for (const auto& voxel : src.voxels) {
auto* dst_voxel = dst->add_voxels();
dst_voxel->set_x(voxel.x);
dst_voxel->set_y(voxel.y);
dst_voxel->set_z(voxel.z);
dst_voxel->set_probability(voxel.probability);
}
for (const auto& plane : src.planes) {
auto* dst_plane = dst->add_planes();
fillMapPoint3D(dst_plane->mutable_center(), plane.center);
fillMapPoint3D(dst_plane->mutable_normal(), plane.normal);
dst_plane->set_d(plane.d);
dst_plane->set_radius(plane.radius);
}
for (const auto& object : src.objects) {
fillMapObject(dst->add_objects(), object);
}
}
void fillUnifiedMapUpdate(msgs::AgvUnifiedMapUpdate* dst, const device::AgvUnifiedMapUpdate& src)
{
dst->set_map_id(src.map_id);
dst->set_session_id(src.session_id);
dst->set_sequence(src.sequence);
dst->set_resume_token(src.resume_token);
dst->set_dimension(toProtoMapDimension(src.dimension));
dst->set_update_type(toProtoMapUpdateType(src.update_type));
dst->set_frame_id(src.frame_id);
dst->set_timestamp(src.timestamp);
dst->set_snapshot_begin(src.snapshot_begin);
dst->set_snapshot_end(src.snapshot_end);
dst->set_chunk_index(src.chunk_index);
dst->set_chunk_count(src.chunk_count);
if (src.map_2d) {
fillUnifiedMap2D(dst->mutable_map_2d(), *src.map_2d);
} else if (src.map_3d) {
fillUnifiedMap3D(dst->mutable_map_3d(), *src.map_3d);
}
}
} // namespace
gRPCAgvServiceImpl::gRPCAgvServiceImpl()
: dmgr_(device::DeviceManager::getInstance())
{
}
grpc::Status gRPCAgvServiceImpl::getRuntimeState(grpc::ServerContext*,
const api::AgvRuntimeStateCommand_Request* request,
api::AgvRuntimeStateCommand_Feedback* response)
{
try {
const std::string device_id = request->header().device_id();
auto agv = dmgr_.getDevice<device::AbstractAGV>(device_id);
if (!agv) {
return setDeviceNotFound(response, device_id);
}
fillRuntimeState(response->mutable_state(), agv->runtimeState());
fillFeedback(response->mutable_header(), true);
return grpc::Status::OK;
} catch (const std::exception& e) {
fillFeedback(response->mutable_header(), false, e.what());
return grpc::Status(grpc::StatusCode::INTERNAL, e.what());
}
}
grpc::Status gRPCAgvServiceImpl::getNavigationStatus(grpc::ServerContext*,
const api::AgvNavigationStatusCommand_Request* request,
api::AgvNavigationStatusCommand_Feedback* response)
{
try {
const std::string device_id = request->header().device_id();
auto agv = dmgr_.getDevice<device::AbstractAGV>(device_id);
if (!agv) {
return setDeviceNotFound(response, device_id);
}
fillNavigationStatus(response->mutable_status(), agv->navigationStatus());
fillFeedback(response->mutable_header(), true);
return grpc::Status::OK;
} catch (const std::exception& e) {
fillFeedback(response->mutable_header(), false, e.what());
return grpc::Status(grpc::StatusCode::INTERNAL, e.what());
}
}
grpc::Status gRPCAgvServiceImpl::emergencyStop(grpc::ServerContext*,
const api::CommandHeader_Request* request,
api::CommandHeader_Feedback* response)
{
try {
auto agv = dmgr_.getDevice<device::AbstractAGV>(request->device_id());
if (!agv) {
return setDeviceNotFound(response, request->device_id());
}
return setResponseResult(response, agv->emergencyStop());
} catch (const std::exception& e) {
fillFeedback(response, false, e.what());
return grpc::Status(grpc::StatusCode::INTERNAL, e.what());
}
}
grpc::Status gRPCAgvServiceImpl::clearFault(grpc::ServerContext*,
const api::CommandHeader_Request* request,
api::CommandHeader_Feedback* response)
{
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
auto agv = dmgr_.getDevice<device::AbstractAGV>(request->device_id());
if (!agv) {
return setDeviceNotFound(response, request->device_id());
}
return setResponseResult(response, agv->clearFault());
} catch (const std::exception& e) {
fillFeedback(response, false, e.what());
return grpc::Status(grpc::StatusCode::INTERNAL, e.what());
}
}
grpc::Status gRPCAgvServiceImpl::relocalize(
grpc::ServerContext*,
const api::AgvRelocalizeCommand_Request* request,
api::AgvRelocalizeCommand_Feedback* response)
{
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
const std::string device_id = request->header().device_id();
auto agv = dmgr_.getDevice<device::AbstractAGV>(device_id);
if (!agv) {
return setDeviceNotFound(response, device_id);
}
return setResponseResult(response, agv->relocalize(toPose2d(request->pose())));
} catch (const std::exception& e) {
fillFeedback(response->mutable_header(), false, e.what());
return grpc::Status(grpc::StatusCode::INTERNAL, e.what());
}
}
grpc::Status gRPCAgvServiceImpl::navigateToPose(grpc::ServerContext* context,
const api::AgvNavigateToPoseCommand_Request* request,
api::AgvNavigateToPoseCommand_Feedback* response)
{
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
if (context && context->IsCancelled()) {
return setNavigationRequestCanceled(response);
}
const std::string device_id = request->header().device_id();
auto agv = dmgr_.getDevice<device::AbstractAGV>(device_id);
if (!agv) {
return setDeviceNotFound(response, device_id);
}
return setResponseResult(response, agv->navigateToPose(
toPose2d(request->pose()),
toMotionOptions(request->options(), context),
toAdapterParams(request->adapter_params())));
} catch (const std::exception& e) {
fillFeedback(response->mutable_header(), false, e.what());
return grpc::Status(grpc::StatusCode::INTERNAL, e.what());
}
}
grpc::Status gRPCAgvServiceImpl::navigateToStation(grpc::ServerContext* context,
const api::AgvNavigateToStationCommand_Request* request,
api::AgvNavigateToStationCommand_Feedback* response)
{
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
if (context && context->IsCancelled()) {
return setNavigationRequestCanceled(response);
}
const std::string device_id = request->header().device_id();
auto agv = dmgr_.getDevice<device::AbstractAGV>(device_id);
if (!agv) {
return setDeviceNotFound(response, device_id);
}
return setResponseResult(response, agv->navigateToStation(
request->station_id(),
toMotionOptions(request->options(), context),
toAdapterParams(request->adapter_params())));
} catch (const std::exception& e) {
fillFeedback(response->mutable_header(), false, e.what());
return grpc::Status(grpc::StatusCode::INTERNAL, e.what());
}
}
grpc::Status gRPCAgvServiceImpl::followPath(grpc::ServerContext* context,
const api::AgvFollowPathCommand_Request* request,
api::AgvFollowPathCommand_Feedback* response)
{
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
if (context && context->IsCancelled()) {
return setNavigationRequestCanceled(response);
}
const std::string device_id = request->header().device_id();
auto agv = dmgr_.getDevice<device::AbstractAGV>(device_id);
if (!agv) {
return setDeviceNotFound(response, device_id);
}
std::vector<device::AgvPathSegment> path;
path.reserve(static_cast<std::size_t>(request->path_size()));
for (const auto& segment : request->path()) {
path.push_back(toPathSegment(segment));
}
return setResponseResult(
response,
agv->followPath(
path,
toMotionOptions(request->options(), context)));
} catch (const std::exception& e) {
fillFeedback(response->mutable_header(), false, e.what());
return grpc::Status(grpc::StatusCode::INTERNAL, e.what());
}
}
grpc::Status gRPCAgvServiceImpl::pauseNavigation(grpc::ServerContext*,
const api::CommandHeader_Request* request,
api::CommandHeader_Feedback* response)
{
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
auto agv = dmgr_.getDevice<device::AbstractAGV>(request->device_id());
if (!agv) {
return setDeviceNotFound(response, request->device_id());
}
return setResponseResult(response, agv->pauseNavigation());
} catch (const std::exception& e) {
fillFeedback(response, false, e.what());
return grpc::Status(grpc::StatusCode::INTERNAL, e.what());
}
}
grpc::Status gRPCAgvServiceImpl::resumeNavigation(grpc::ServerContext*,
const api::CommandHeader_Request* request,
api::CommandHeader_Feedback* response)
{
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
auto agv = dmgr_.getDevice<device::AbstractAGV>(request->device_id());
if (!agv) {
return setDeviceNotFound(response, request->device_id());
}
return setResponseResult(response, agv->resumeNavigation());
} catch (const std::exception& e) {
fillFeedback(response, false, e.what());
return grpc::Status(grpc::StatusCode::INTERNAL, e.what());
}
}
grpc::Status gRPCAgvServiceImpl::cancelNavigation(grpc::ServerContext*,
const api::CommandHeader_Request* request,
api::CommandHeader_Feedback* response)
{
try {
auto agv = dmgr_.getDevice<device::AbstractAGV>(request->device_id());
if (!agv) {
return setDeviceNotFound(response, request->device_id());
}
return setResponseResult(response, agv->cancelNavigation());
} catch (const std::exception& e) {
fillFeedback(response, false, e.what());
return grpc::Status(grpc::StatusCode::INTERNAL, e.what());
}
}
grpc::Status gRPCAgvServiceImpl::setVelocity(grpc::ServerContext*,
const api::AgvSetVelocityCommand_Request* request,
api::AgvSetVelocityCommand_Feedback* response)
{
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
const std::string device_id = request->header().device_id();
auto agv = dmgr_.getDevice<device::AbstractAGV>(device_id);
if (!agv) {
return setDeviceNotFound(response, device_id);
}
return setResponseResult(response, agv->setVelocity(toVelocity(request->velocity())));
} catch (const std::exception& e) {
fillFeedback(response->mutable_header(), false, e.what());
return grpc::Status(grpc::StatusCode::INTERNAL, e.what());
}
}
grpc::Status gRPCAgvServiceImpl::translate(
grpc::ServerContext*,
const api::AgvTranslateCommand_Request* request,
api::AgvTranslateCommand_Feedback* response)
{
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
const std::string device_id = request->header().device_id();
auto agv = dmgr_.getDevice<device::AbstractAGV>(device_id);
if (!agv) {
return setDeviceNotFound(response, device_id);
}
return setResponseResult(response, agv->translate(toTranslation(request->translation())));
} catch (const std::exception& e) {
fillFeedback(response->mutable_header(), false, e.what());
return grpc::Status(grpc::StatusCode::INTERNAL, e.what());
}
}
grpc::Status gRPCAgvServiceImpl::stopVelocityControl(grpc::ServerContext*,
const api::CommandHeader_Request* request,
api::CommandHeader_Feedback* response)
{
try {
auto agv = dmgr_.getDevice<device::AbstractAGV>(request->device_id());
if (!agv) {
return setDeviceNotFound(response, request->device_id());
}
return setResponseResult(response, agv->stopVelocityControl());
} catch (const std::exception& e) {
fillFeedback(response, false, e.what());
return grpc::Status(grpc::StatusCode::INTERNAL, e.what());
}
}
grpc::Status gRPCAgvServiceImpl::listMaps(grpc::ServerContext*,
const api::AgvListMapsCommand_Request* request,
api::AgvListMapsCommand_Feedback* response)
{
try {
const std::string device_id = request->header().device_id();
auto agv = dmgr_.getDevice<device::AbstractAGV>(device_id);
if (!agv) {
return setDeviceNotFound(response, device_id);
}
std::vector<std::string> maps;
const auto result = agv->listMaps(maps);
if (result.ok()) {
for (const auto& map : maps) {
response->add_maps(map);
}
}
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 gRPCAgvServiceImpl::listStations(grpc::ServerContext*,
const api::AgvListStationsCommand_Request* request,
api::AgvListStationsCommand_Feedback* response)
{
try {
const std::string device_id = request->header().device_id();
auto agv = dmgr_.getDevice<device::AbstractAGV>(device_id);
if (!agv) {
return setDeviceNotFound(response, device_id);
}
std::vector<device::AgvStation> stations;
const auto result = agv->listStations(stations);
if (result.ok()) {
for (const auto& station : stations) {
fillStation(response->add_stations(), station);
}
}
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 gRPCAgvServiceImpl::switchMap(grpc::ServerContext*,
const api::AgvMapCommand_Request* request,
api::AgvMapCommand_Feedback* response)
{
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
const std::string device_id = request->header().device_id();
auto agv = dmgr_.getDevice<device::AbstractAGV>(device_id);
if (!agv) {
return setDeviceNotFound(response, device_id);
}
return setResponseResult(response, agv->switchMap(request->map_name()));
} catch (const std::exception& e) {
fillFeedback(response->mutable_header(), false, e.what());
return grpc::Status(grpc::StatusCode::INTERNAL, e.what());
}
}
grpc::Status gRPCAgvServiceImpl::uploadMap(grpc::ServerContext*,
const api::AgvMapCommand_Request* request,
api::AgvMapCommand_Feedback* response)
{
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
const std::string device_id = request->header().device_id();
auto agv = dmgr_.getDevice<device::AbstractAGV>(device_id);
if (!agv) {
return setDeviceNotFound(response, device_id);
}
return setResponseResult(response, agv->uploadMap(request->map_name(), request->content()));
} catch (const std::exception& e) {
fillFeedback(response->mutable_header(), false, e.what());
return grpc::Status(grpc::StatusCode::INTERNAL, e.what());
}
}
grpc::Status gRPCAgvServiceImpl::downloadMap(grpc::ServerContext*,
const api::AgvMapCommand_Request* request,
api::AgvMapCommand_Feedback* response)
{
try {
const std::string device_id = request->header().device_id();
auto agv = dmgr_.getDevice<device::AbstractAGV>(device_id);
if (!agv) {
return setDeviceNotFound(response, device_id);
}
std::string content;
const auto result = agv->downloadMap(request->map_name(), content);
if (result.ok()) {
response->set_content(content);
}
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 gRPCAgvServiceImpl::startMapping(grpc::ServerContext*,
const api::AgvStartMappingCommand_Request* request,
api::AgvStartMappingCommand_Feedback* response)
{
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
const std::string device_id = request->header().device_id();
auto agv = dmgr_.getDevice<device::AbstractAGV>(device_id);
if (!agv) {
return setDeviceNotFound(response, device_id);
}
device::AgvMappingOptions options;
options.dimension = toMapDimension(request->dimension());
options.map_name = request->map_name();
options.real_time = request->real_time();
const auto result = agv->startMapping(options);
if (result.ok()) {
response->set_session_id(device_id + "_mapping");
}
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 gRPCAgvServiceImpl::streamMap(grpc::ServerContext* context,
const api::AgvMapStreamCommand_Request* request,
grpc::ServerWriter<api::AgvMapStreamCommand_Feedback>* writer)
{
try {
const std::string device_id = request->header().device_id();
auto agv = dmgr_.getDevice<device::AbstractAGV>(device_id);
api::AgvMapStreamCommand_Feedback feedback;
if (!agv) {
const std::string message = "AGV device not found: " + device_id;
fillFeedback(feedback.mutable_header(), false, message);
writer->Write(feedback);
return grpc::Status(grpc::StatusCode::NOT_FOUND, message);
}
device::AgvMapStreamOptions options;
options.dimension = toMapDimension(request->dimension());
options.map_name = request->map_name();
options.resume_token = request->resume_token();
options.snapshot = request->snapshot();
options.incremental = request->incremental();
options.max_chunk_bytes = request->max_chunk_bytes();
std::uint64_t after_sequence = 0;
if (!request->resume_token().empty()) {
try {
after_sequence = static_cast<std::uint64_t>(std::stoull(request->resume_token()));
} catch (...) {
after_sequence = 0;
}
}
bool wrote_any = false;
while (!context->IsCancelled()) {
options.wait_timeout_ms = (!options.incremental && wrote_any) ? 20 : 1000;
device::AgvUnifiedMapUpdate update;
const auto result = agv->getUnifiedMapUpdate(after_sequence, options, update);
if (!result.ok()) {
if (result.code == device::AgvErrorCode::Timeout && wrote_any && !options.incremental) {
return grpc::Status::OK;
}
if (result.code == device::AgvErrorCode::Timeout && wrote_any && options.incremental) {
continue;
}
fillFeedback(feedback.mutable_header(), false, result.message);
writer->Write(feedback);
return resultToStatus(result);
}
api::AgvMapStreamCommand_Feedback update_feedback;
fillFeedback(update_feedback.mutable_header(), true);
fillUnifiedMapUpdate(update_feedback.mutable_update(), update);
if (!writer->Write(update_feedback)) {
return grpc::Status(grpc::StatusCode::CANCELLED, "AGV map stream writer closed");
}
wrote_any = true;
after_sequence = update.sequence;
options.resume_token.clear();
}
return grpc::Status(grpc::StatusCode::CANCELLED, "AGV map stream cancelled");
} catch (const std::exception& e) {
api::AgvMapStreamCommand_Feedback feedback;
fillFeedback(feedback.mutable_header(), false, e.what());
writer->Write(feedback);
return grpc::Status(grpc::StatusCode::INTERNAL, e.what());
}
}
grpc::Status gRPCAgvServiceImpl::stopMapping(grpc::ServerContext*,
const api::CommandHeader_Request* request,
api::CommandHeader_Feedback* response)
{
try {
auto agv = dmgr_.getDevice<device::AbstractAGV>(request->device_id());
if (!agv) {
return setDeviceNotFound(response, request->device_id());
}
return setResponseResult(response, agv->stopMapping());
} catch (const std::exception& e) {
fillFeedback(response, false, e.what());
return grpc::Status(grpc::StatusCode::INTERNAL, e.what());
}
}
} // namespace cmvr::service

View File

@ -3,6 +3,7 @@
#include <google/protobuf/util/time_util.h>
#include "common/base/logging/logger.h"
#include "service/grpc/action/include/control_command_arbiter.h"
using google::protobuf::util::TimeUtil;
@ -119,6 +120,23 @@ grpc::Status setDeviceNotFound(Response* response, const std::string& device_id)
return grpc::Status(grpc::StatusCode::NOT_FOUND, message);
}
grpc::Status setControlBusy(api::CommandHeader_Feedback* response)
{
const std::string message =
"control command rejected while ActionQueue or StopAll is active";
fillFeedback(response, false, message);
return grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, message);
}
template <typename Response>
grpc::Status setControlBusy(Response* response)
{
const std::string message =
"control command rejected while ActionQueue or StopAll is active";
fillFeedback(response->mutable_header(), false, message);
return grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, message);
}
} // namespace
gRPCArmServiceImpl::gRPCArmServiceImpl()
@ -152,6 +170,11 @@ grpc::Status gRPCArmServiceImpl::torqueOn(grpc::ServerContext*,
const api::CommandHeader_Request* request,
api::CommandHeader_Feedback* response)
{
auto control_lease =
ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) {
return setControlBusy(response);
}
try {
const std::string device_id = request->device_id();
auto arm = dmgr_.getDevice<device::RobotArm>(device_id);
@ -170,10 +193,43 @@ grpc::Status gRPCArmServiceImpl::torqueOn(grpc::ServerContext*,
}
}
grpc::Status gRPCArmServiceImpl::clearFault(
grpc::ServerContext*,
const api::CommandHeader_Request* request,
api::CommandHeader_Feedback* response)
{
auto control_lease =
ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) {
return setControlBusy(response);
}
try {
const std::string device_id = request->device_id();
auto arm = dmgr_.getDevice<device::RobotArm>(device_id);
if (!arm) {
return setDeviceNotFound(response, device_id);
}
const auto result = arm->clearFault();
fillFeedback(response, result.ok(), result.ok() ? "" : result.message);
if (result.ok()) {
logRpcSuccess("clearFault", device_id);
}
return resultToStatus(result);
} catch (const std::exception& e) {
fillFeedback(response, false, e.what());
return grpc::Status(grpc::StatusCode::INTERNAL, e.what());
}
}
grpc::Status gRPCArmServiceImpl::moveJ(grpc::ServerContext*,
const api::MoveJ_Request* request,
api::MoveJ_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::RobotArm>(device_id);
@ -197,18 +253,99 @@ grpc::Status gRPCArmServiceImpl::moveL(grpc::ServerContext*,
const api::MoveL_Request* request,
api::MoveL_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::RobotArm>(device_id);
if (!arm) {
return setDeviceNotFound(response, device_id);
}
const auto result = arm->moveL(toCartesianPose(request->target()),
const bool has_named_frame =
(request->has_base_frame() && !request->base_frame().empty()) ||
(request->has_tcp_frame() && !request->tcp_frame().empty());
const auto result = has_named_frame
? arm->moveL(toCartesianPose(request->target()),
toMotionOptions(request->options()),
request->has_base_frame()
? request->base_frame()
: std::string{},
request->has_tcp_frame()
? request->tcp_frame()
: std::string{})
: arm->moveL(toCartesianPose(request->target()),
toMotionOptions(request->options()),
toFrameType(request->frame()));
if (result.ok()) {
CMVR_LOG(DEBUG) << "[gRPCArmServiceImpl] (moveL): success, id=" << device_id
<< ", frame=" << request->frame();
<< ", frame=" << request->frame()
<< ", base_frame="
<< (request->has_base_frame()
? request->base_frame()
: "<default>")
<< ", tcp_frame="
<< (request->has_tcp_frame()
? request->tcp_frame()
: "<default>");
}
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::ListBaseFrame(
grpc::ServerContext*,
const api::ListFrame_Request* request,
api::ListFrame_Response* response)
{
try {
const std::string device_id = request->header().device_id();
auto arm = dmgr_.getDevice<device::RobotArm>(device_id);
if (!arm) {
return setDeviceNotFound(response, device_id);
}
std::vector<std::string> frame_names;
const auto result = arm->listBaseFrame(frame_names);
if (result.ok()) {
for (const auto& frame_name : frame_names) {
response->add_frame_names(frame_name);
}
CMVR_LOG(DEBUG)
<< "[gRPCArmServiceImpl] (ListBaseFrame): success, id="
<< device_id << ", count=" << frame_names.size();
}
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::ListTCPFrame(
grpc::ServerContext*,
const api::ListFrame_Request* request,
api::ListFrame_Response* response)
{
try {
const std::string device_id = request->header().device_id();
auto arm = dmgr_.getDevice<device::RobotArm>(device_id);
if (!arm) {
return setDeviceNotFound(response, device_id);
}
std::vector<std::string> frame_names;
const auto result = arm->listTCPFrame(frame_names);
if (result.ok()) {
for (const auto& frame_name : frame_names) {
response->add_frame_names(frame_name);
}
CMVR_LOG(DEBUG)
<< "[gRPCArmServiceImpl] (ListTCPFrame): success, id="
<< device_id << ", count=" << frame_names.size();
}
return setResponseResult(response, result);
} catch (const std::exception& e) {
@ -221,6 +358,11 @@ grpc::Status gRPCArmServiceImpl::speedJ(grpc::ServerContext*,
const api::SpeedJ_Request* request,
api::SpeedJ_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::RobotArm>(device_id);
@ -247,6 +389,11 @@ grpc::Status gRPCArmServiceImpl::speedL(grpc::ServerContext*,
const api::SpeedL_Request* request,
api::SpeedL_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::RobotArm>(device_id);
@ -274,6 +421,11 @@ grpc::Status gRPCArmServiceImpl::servoJ(grpc::ServerContext*,
const api::ServoJ_Request* request,
api::ServoJ_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::RobotArm>(device_id);
@ -373,6 +525,11 @@ grpc::Status gRPCArmServiceImpl::calibrateZeroQ(grpc::ServerContext*,
const api::CalibrateZeroQ_Request* request,
api::CalibrateZeroQ_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::RobotArm>(device_id);

View File

@ -12,6 +12,8 @@
#include <vector>
#include "devices/dexhand/rh56dftp_dexhand/include/rh56dftp_dexhand.h"
#include "service/grpc/action/include/control_command_arbiter.h"
#include "service/grpc/action/include/control_command_guard.h"
using namespace std;
using namespace cmvr::service;
@ -227,6 +229,8 @@ grpc::Status gRPCDexHandServiceImpl::GetStatus(grpc::ServerContext* context,
grpc::Status gRPCDexHandServiceImpl::SetDexHandPos(grpc::ServerContext* context
, const cmvr::api::SetDexHandPositionsCommand_Request* request
, cmvr::api::SetDexHandPositionsCommand_Feedback* response) {
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
string dev_id = request->header().device_id();
CMVR_LOG(INFO) << "[gRPCDexHandServiceImpl] (SetDexHandPos): id=" << dev_id;
@ -264,6 +268,8 @@ grpc::Status gRPCDexHandServiceImpl::SetDexHandPos(grpc::ServerContext* context
grpc::Status gRPCDexHandServiceImpl::SetDexHandAngle(grpc::ServerContext* context
, const cmvr::api::SetDexHandAnglesCommand_Request* request
, cmvr::api::SetDexHandAnglesCommand_Feedback* response) {
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
string dev_id = request->header().device_id();
CMVR_LOG(INFO) << "[gRPCDexHandServiceImpl] (SetDexHandAngle): id=" << dev_id;
@ -305,6 +311,8 @@ grpc::Status gRPCDexHandServiceImpl::SetDexHandAngle(grpc::ServerContext* contex
grpc::Status gRPCDexHandServiceImpl::SetDexHandForce(grpc::ServerContext* context
, const cmvr::api::SetDexHandForceCommand_Request* request
, cmvr::api::SetDexHandForceCommand_Feedback* response) {
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
string dev_id = request->header().device_id();
CMVR_LOG(INFO) << "[gRPCDexHandServiceImpl] (SetDexHandForce): id=" << dev_id;
@ -342,6 +350,8 @@ grpc::Status gRPCDexHandServiceImpl::SetDexHandForce(grpc::ServerContext* contex
grpc::Status gRPCDexHandServiceImpl::SetDexHandSpeed(grpc::ServerContext* context
, const cmvr::api::SetDexHandSpeedCommand_Request* request
, cmvr::api::SetDexHandSpeedCommand_Feedback* response) {
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
string dev_id = request->header().device_id();
CMVR_LOG(INFO) << "[gRPCDexHandServiceImpl] (SetDexHandSpeed): id=" << dev_id;
@ -379,6 +389,8 @@ grpc::Status gRPCDexHandServiceImpl::SetDexHandSpeed(grpc::ServerContext* contex
grpc::Status gRPCDexHandServiceImpl::SetDexHandPresetAct(grpc::ServerContext* context
, const cmvr::api::SetDexHandPresetActCommand_Request* request
, cmvr::api::SetDexHandPresetActCommand_Feedback* response) {
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
string dev_id = request->header().device_id();
CMVR_LOG(INFO) << "[gRPCDexHandServiceImpl] (SetDexHandPresetAct): id=" << dev_id;

View File

@ -5,6 +5,8 @@
#include "manager/device_manager/include/device_manager.h"
#include "common/base/grpc_utils.h"
#include "biohead/biohead_esp32/include/biohead_esp32.h"
#include "service/grpc/action/include/control_command_arbiter.h"
#include "service/grpc/action/include/control_command_guard.h"
#include <chrono>
#include <algorithm>
#include <iostream>
@ -40,6 +42,9 @@ grpc::Status gRPCMBioHeadServiceImpl::SetExpression(
const SetFacialExpression_Request* request,
SetFacialExpression_Feedback* response) {
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
std::string dev_id = request->header().device_id();
auto robot = dmgr_.getDevice<AbstractBiohead>(dev_id);
@ -90,6 +95,8 @@ grpc::Status gRPCMBioHeadServiceImpl::StreamExpression(
grpc::ServerContext* context,
grpc::ServerReaderWriter<StreamFacialExpression_Feedback, StreamFacialExpression_Request>* stream)
{
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand();
StreamFacialExpression_Feedback feedback_msg;
std::string dev_id;
std::shared_ptr<AbstractBiohead> robot;
@ -268,6 +275,9 @@ grpc::Status gRPCMBioHeadServiceImpl::EmergencyStop(
grpc::Status gRPCMBioHeadServiceImpl::SpeakStart(grpc::ServerContext* context, const cmvr::api::SpeakStart_Request* request, cmvr::api::SpeakStart_Feedback* response)
{
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
{
try {
@ -326,6 +336,8 @@ grpc::Status gRPCMBioHeadServiceImpl::SpeakStop(grpc::ServerContext* context, co
grpc::Status gRPCMBioHeadServiceImpl::Happy(grpc::ServerContext* context, const cmvr::api::Happy_Request* request, cmvr::api::Happy_Feedback* response)
{
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
string dev_id = request->header().device_id();
auto robot = dmgr_.getDevice<AbstractBiohead>(dev_id);
@ -350,6 +362,8 @@ grpc::Status gRPCMBioHeadServiceImpl::Happy(grpc::ServerContext* context, const
grpc::Status gRPCMBioHeadServiceImpl::Surprise(grpc::ServerContext* context, const cmvr::api::Surprise_Request* request, cmvr::api::Surprise_Feedback* response)
{
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
string dev_id = request->header().device_id();
auto robot = dmgr_.getDevice<AbstractBiohead>(dev_id);
@ -375,6 +389,8 @@ grpc::Status gRPCMBioHeadServiceImpl::Surprise(grpc::ServerContext* context, con
grpc::Status gRPCMBioHeadServiceImpl::ExpressionTired(grpc::ServerContext* context, const cmvr::api::ExpressionTired_Request* request, cmvr::api::ExpressionTired_Feedback* response)
{
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
string dev_id = request->header().device_id();
auto robot = dmgr_.getDevice<AbstractBiohead>(dev_id);
@ -401,6 +417,8 @@ grpc::Status gRPCMBioHeadServiceImpl::ExpressionTired(grpc::ServerContext* conte
grpc::Status gRPCMBioHeadServiceImpl::ExpressionAngry(grpc::ServerContext* context, const cmvr::api::ExpressionAngry_Request* request, cmvr::api::ExpressionAngry_Feedback* response)
{
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
string dev_id = request->header().device_id();
auto robot = dmgr_.getDevice<AbstractBiohead>(dev_id);
@ -427,6 +445,8 @@ grpc::Status gRPCMBioHeadServiceImpl::ExpressionAngry(grpc::ServerContext* conte
grpc::Status gRPCMBioHeadServiceImpl::ExpressionSadness(grpc::ServerContext* context, const cmvr::api::ExpressionSadness_Request* request, cmvr::api::ExpressionSadness_Feedback* response)
{
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
string dev_id = request->header().device_id();
auto robot = dmgr_.getDevice<AbstractBiohead>(dev_id);
@ -452,6 +472,8 @@ grpc::Status gRPCMBioHeadServiceImpl::ExpressionSadness(grpc::ServerContext* con
grpc::Status gRPCMBioHeadServiceImpl::ExpressionYawn(grpc::ServerContext* context, const cmvr::api::ExpressionYawn_Request* request, cmvr::api::ExpressionYawn_Feedback* response)
{
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
string dev_id = request->header().device_id();
auto robot = dmgr_.getDevice<AbstractBiohead>(dev_id);

View File

@ -14,6 +14,8 @@
#include "common/base/logging/logger.h"
#include "manager/task_manager/include/task_manager.h"
#include "task/touch_screen_task/include/touch_screen_task.h"
#include "service/grpc/action/include/control_command_arbiter.h"
#include "service/grpc/action/include/control_command_guard.h"
using namespace cmvr::service;
@ -43,6 +45,8 @@ void fillTouchResponse(Touch_Response* response,
gRPCHlcServiceImpl::gRPCHlcServiceImpl() = default;
grpc::Status gRPCHlcServiceImpl::touch(grpc::ServerContext *context, const cmvr::api::Touch_Request *request, cmvr::api::Touch_Response *response) {
auto control_lease = ControlCommandArbiter::instance().tryAcquireControl();
if (!control_lease) return rejectControlCommand(response);
try {
auto touch_task = task::TaskManager::getInstance().getTouchScreenTask();
if (!touch_task) {

View File

@ -5,12 +5,32 @@
#include "../include/grpc_system_service.h"
#include "common/base/logging/logger.h"
#include "service/grpc/action/include/action_queue.h"
#include "service/grpc/action/include/control_command_arbiter.h"
using namespace cmvr::device;
using namespace cmvr::device;
using namespace cmvr::service;
gRPCSystemServiceImpl::gRPCSystemServiceImpl(): dmgr_(DeviceManager::getInstance()) {}
gRPCSystemServiceImpl::gRPCSystemServiceImpl()
: dmgr_(DeviceManager::getInstance()),
action_queue_(std::make_unique<ActionQueue>(
[this](const std::string& device_id) {
return dmgr_.getDevice<device::RobotArm>(device_id);
}))
{
}
gRPCSystemServiceImpl::~gRPCSystemServiceImpl()
{
prepareForShutdown();
}
void gRPCSystemServiceImpl::prepareForShutdown()
{
if (action_queue_) {
action_queue_->shutdown();
}
}
grpc::Status gRPCSystemServiceImpl::GetSystemInfo(grpc::ServerContext* context,
const api::GetSystemInfoCommand_Request* request, api::GetSystemInfoCommand_Feedback* response)
@ -95,6 +115,17 @@ grpc::Status gRPCSystemServiceImpl::StopAll(grpc::ServerContext* context,
const cmvr::api::StopAllCommand_Request* request, cmvr::api::StopAllCommand_Feedback* response)
{
try {
std::unique_lock stop_all_lock(stop_all_mutex_, std::try_to_lock);
if (!stop_all_lock.owns_lock()) {
response->mutable_header()->set_success(false);
response->mutable_header()->set_error_message(
"another StopAll request is already running");
setCurrentTimestamp(
response->mutable_header()->mutable_timestamp());
return grpc::Status::OK;
}
auto stop_lease = ControlCommandArbiter::instance().beginStop();
action_queue_->cancelAndClear();
dmgr_.stop();
response->mutable_header()->set_success(true);
setCurrentTimestamp(response->mutable_header()->mutable_timestamp());
@ -108,3 +139,34 @@ grpc::Status gRPCSystemServiceImpl::StopAll(grpc::ServerContext* context,
return grpc::Status::OK;
}
}
grpc::Status gRPCSystemServiceImpl::ExecuteActionQueue(
grpc::ServerContext*,
const cmvr::api::ActionQueueCommand_Request* request,
cmvr::api::ActionQueueCommand_Feedback* response)
{
if (!request || !response) {
return grpc::Status(
grpc::StatusCode::INVALID_ARGUMENT,
"ActionQueue request and response are required");
}
try {
action_queue_->execute(*request, *response);
return grpc::Status::OK;
} catch (const std::exception& error) {
response->Clear();
response->set_result(api::ACTION_RESULT_CODE_FAILED);
response->mutable_header()->set_success(false);
response->mutable_header()->set_error_message(error.what());
setCurrentTimestamp(response->mutable_header()->mutable_timestamp());
return grpc::Status::OK;
} catch (...) {
response->Clear();
response->set_result(api::ACTION_RESULT_CODE_FAILED);
response->mutable_header()->set_success(false);
response->mutable_header()->set_error_message(
"ActionQueue failed with an unknown exception");
setCurrentTimestamp(response->mutable_header()->mutable_timestamp());
return grpc::Status::OK;
}
}

View File

@ -11,6 +11,10 @@
#include "cmvr/config/grpc_server_config/grpc_server_config.pb.h"
#include "task/task.h"
namespace cmvr::service {
class gRPCSystemServiceImpl;
}
namespace cmvr::task {
class GrpcServerTask final : public Task {
@ -49,12 +53,13 @@ private:
std::thread wait_thread_;
std::unique_ptr<grpc::Service> camera_service_;
std::unique_ptr<grpc::Service> system_service_;
std::unique_ptr<service::gRPCSystemServiceImpl> system_service_;
std::unique_ptr<grpc::Service> speaker_service_;
std::unique_ptr<grpc::Service> microphone_service_;
std::unique_ptr<grpc::Service> dexhand_service_;
std::unique_ptr<grpc::Service> biohand_service_;
std::unique_ptr<grpc::Service> arm_service_;
std::unique_ptr<grpc::Service> agv_service_;
std::unique_ptr<grpc::Service> hlc_service_;
};

View File

@ -8,6 +8,7 @@
#include "cmvr/config/task_manager_config/task_manager_config.pb.h"
#include "common/base/logging/logger.h"
#include "common/config/config_files.h"
#include "service/grpc/include/grpc_agv_service.h"
#include "service/grpc/include/grpc_arm_service.h"
#include "service/grpc/include/grpc_camera_service.h"
#include "service/grpc/include/grpc_dexhand_service.h"
@ -101,6 +102,7 @@ bool GrpcServerTask::start()
dexhand_service_ = std::make_unique<service::gRPCDexHandServiceImpl>();
biohand_service_ = std::make_unique<service::gRPCMBioHeadServiceImpl>();
arm_service_ = std::make_unique<service::gRPCArmServiceImpl>();
agv_service_ = std::make_unique<service::gRPCAgvServiceImpl>();
hlc_service_ = std::make_unique<service::gRPCHlcServiceImpl>();
grpc::ServerBuilder builder;
@ -112,6 +114,7 @@ bool GrpcServerTask::start()
builder.RegisterService(dexhand_service_.get());
builder.RegisterService(biohand_service_.get());
builder.RegisterService(arm_service_.get());
builder.RegisterService(agv_service_.get());
builder.RegisterService(hlc_service_.get());
server_ = builder.BuildAndStart();
@ -158,6 +161,9 @@ void GrpcServerTask::stop()
{
{
std::lock_guard lock(mutex_);
if (system_service_) {
system_service_->prepareForShutdown();
}
if (server_) {
server_->Shutdown();
}
@ -247,6 +253,7 @@ void GrpcServerTask::waitLoop()
void GrpcServerTask::clearServices()
{
hlc_service_.reset();
agv_service_.reset();
arm_service_.reset();
biohand_service_.reset();
dexhand_service_.reset();

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,403 @@
/** @file aubo_api.h
* @brief \~chinese 机器人及外部轴等控制API接口,如获取机器人列表、获取系统信息等等
* @brief \~english API for controlling the robot and external axis
*/
#ifndef AUBO_SDK_AUBO_API_INTERFACE_H
#define AUBO_SDK_AUBO_API_INTERFACE_H
#include <aubo/system_info.h>
#include <aubo/runtime_machine.h>
#include <aubo/register_control.h>
#include <aubo/robot_interface.h>
#include <aubo/global_config.h>
#include <aubo/math.h>
#include <aubo/socket.h>
#include <aubo/serial.h>
#include <aubo/axis_interface.h>
#include <aubo/gripper_interface.h>
namespace arcs {
namespace common_interface {
/**
* \chinese
* @defgroup AuboApi AuboApi (主入口)
* @ingroup AuboApi
* AuboApi
* \endchinese
*
* \english
* @defgroup AuboApi Main Entrance
* @ingroup AuboApi
* AuboApi
* \endenglish
*/
class ARCS_ABI_EXPORT AuboApi
{
public:
AuboApi();
virtual ~AuboApi();
/**
* @ingroup AuboApi
* @ref Math
* \chinese
* 获取纯数学相关接口
*
* @return MathPtr对象的指针
*
* @par Python函数原型
* getMath(self: pyaubo_sdk.AuboApi) -> pyaubo_sdk.Math
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* MathPtr ptr = rpc_cli->getMath();
* @endcode
* \endchinese
*
*\english
* Get pure mathematic related API
*
* @return Shared pointer to a Math object
*
* @par Python function prototype
* getMath(self: pyaubo_sdk.AuboApi) -> pyaubo_sdk.Math
*
* @par C++ example
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* MathPtr ptr = rpc_cli->getMath();
* @endcode
*\endenglish
*/
MathPtr getMath();
/**
* @ingroup AuboApi
* @ref SystemInfo
* \chinese
* 获取系统信息
*
* @return SystemInfoPtr对象的指针
*
* @par Python函数原型
* getSystemInfo(self: pyaubo_sdk.AuboApi) -> pyaubo_sdk.SystemInfo
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* SystemInfoPtr ptr = rpc_cli->getSystemInfo();
* @endcode
* \endchinese
*
* \english
* Get system info
*
* @return Shared pointer to SystemInfo object
*
* @par Python function prototype
* getSystemInfo(self: pyaubo_sdk.AuboApi) -> pyaubo_sdk.SystemInfo
*
* @par C++ example
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* SystemInfoPtr ptr = rpc_cli->getSystemInfo();
* @endcode
* \endenglish
*/
SystemInfoPtr getSystemInfo();
/**
* @ingroup AuboApi
* @ref RuntimeMachine
* \chinese
* 获取运行时接口
*
* @return RuntimeMachinePtr对象的指针
*
* @par Python函数原型
* getRuntimeMachine(self: pyaubo_sdk.AuboApi) -> pyaubo_sdk.RuntimeMachine
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* RuntimeMachinePtr ptr = rpc_cli->getRuntimeMachine();
* @endcode
* \endchinese
*
* \english
* Get runtime api
*
* @return Shared pointer to RuntimeMachine object
* Python function prototype
* getRuntimeMachine(self: pyaubo_sdk.AuboApi) -> pyaubo_sdk.RuntimeMachine
*
* @par C++ example
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* RuntimeMachinePtr ptr = rpc_cli->getRuntimeMachine();
* @endcode
* \endenglish
*/
RuntimeMachinePtr getRuntimeMachine();
/**
* @ingroup AuboApi
* @ref RegisterControl
* \chinese
* 对外寄存器接口
*
* @return RegisterControlPtr对象的指针
*
* @par Python函数原型
* getRegisterControl(self: pyaubo_sdk.AuboApi) ->
* pyaubo_sdk.RegisterControl
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* RegisterControlPtr ptr = rpc_cli->getRegisterControl();
* @endcode
* \endchinese
*
* \english
* External registers api
*
* @return Shared pointer to RegisterControl object
*
* @par Python function prototype
* getRegisterControl(self: pyaubo_sdk.AuboApi) ->
* pyaubo_sdk.RegisterControl
*
* @par C++ example
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* RegisterControlPtr ptr = rpc_cli->getRegisterControl();
* @endcode
* \endenglish
*/
RegisterControlPtr getRegisterControl();
/**
* @ingroup AuboApi
* \chinese
* 获取机器人列表
*
* @return 机器人列表
*
* @par Python函数原型
* getRobotNames(self: pyaubo_sdk.AuboApi) -> List[str]
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* @endcode
*
* @par JSON-RPC请求示例
* {"jsonrpc":"2.0","method":"getRobotNames","params":[],"id":1}
*
* @par JSON-RPC响应示例
* {"id":1,"jsonrpc":"2.0","result":["rob1"]}
* \endchinese
*
* \english
* Get robot list
*
* @return robot list
*
* @par Python function prototype
* getRobotNames(self: pyaubo_sdk.AuboApi) -> List[str]
*
* @par C++ example
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* @endcode
*
* @par JSON-RPC request example
* {"jsonrpc":"2.0","method":"getRobotNames","params":[],"id":1}
*
* @par JSON-RPC response example
* {"id":1,"jsonrpc":"2.0","result":["rob1"]}
* \endenglish
*/
std::vector<std::string> getRobotNames();
/**
* @ingroup AuboApi
* @ref RobotInterface
* \chinese
* 根据名字获取 RobotInterfacePtr 接口
*
* @param name 机器人名字
* @return RobotInterfacePtr对象的指针
*
* @par Python函数原型
* getRobotInterface(self: pyaubo_sdk.AuboApi, arg0: str) ->
* pyaubo_sdk.RobotInterface
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* RobotInterfacePtr ptr = rpc_cli->getRobotInterface(robot_name);
* @endcode
* \endchinese
*
* \english
* Get RobotInterfacePtr based on name
*
* @param name Robot name
* @return Shared pointer to a RobotInterface object
*
* @par Python function prototype
* getRobotInterface(self: pyaubo_sdk.AuboApi, arg0: str) ->
* pyaubo_sdk.RobotInterface
*
* @par C++ example
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* RobotInterfacePtr ptr = rpc_cli->getRobotInterface(robot_name);
* @endcode
* \endenglish
*/
RobotInterfacePtr getRobotInterface(const std::string &name);
/**
* @ingroup AuboApi
* \~chinese 获取外部轴列表 \~english Get external axis list
*
* @return
*/
std::vector<std::string> getAxisNames();
/**
* @ingroup AuboApi
* @ref AxisInterface
* \chinese
* 获取外部轴接口
*
* @param name
* @return
* \endchinese
*
* \english
* Get external axis interface
*
* @param name
* @return
* \endenglish
*/
AxisInterfacePtr getAxisInterface(const std::string &name);
/**
* @ingroup AuboApi
* @ref Socket
* \chinese
* 获取 socket
* @return SocketPtr对象的指针
*
* @par Python函数原型
* getSocket(self: pyaubo_sdk.AuboApi) -> arcs::common_interface::Socket
* @endcode
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* SocketPtr ptr = rpc_cli->getSocket();
* @endcode
* \endchinese
*
* \english
* Get socket
* @return Shared pointer to a socket object
*
* @par Python function prototype
* getSocket(self: pyaubo_sdk.AuboApi) -> arcs::common_interface::Socket
* @endcode
*
* @par C++ example
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* SocketPtr ptr = rpc_cli->getSocket();
* @endcode
* \endenglish
*/
SocketPtr getSocket();
/**
* @ingroup AuboApi
* @ref Serial
* \chinese
* 获取Serial串口
* @return SerialPtr对象的指针
*
* @par Python函数原型
* getSerial(self: pyaubo_sdk.AuboApi) -> arcs::common_interface::Serial
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* SerialPtr ptr = rpc_cli->getSerial();
* @endcode
* \endchinese
*
* \english
* @return Shared pointer to Serial object
*
* @par Python function prototype
* getSerial(self: pyaubo_sdk.AuboApi) -> arcs::common_interface::Serial
*
* @par C++ example
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* SerialPtr ptr = rpc_cli->getSerial();
* @endcode
* \endenglish
*/
SerialPtr getSerial();
/**
* @ingroup AuboApi
* @ref SyncMove
* \~chinese 获取同步运动接口 \~english Get syncronous move interface
*
* \~chinese @return SyncMovePtr对象的指针
* \~english @return Shared pointer to SyncMove object
*/
SyncMovePtr getSyncMove(const std::string &name);
/**
* @ingroup AuboApi
* @ref Trace
* \~chinese 获取告警信息接口
* \~english Get alert interface
*
* \~chinese @return TracePtr对象的指针
* \~english @return Shared pointer of trace object
*/
TracePtr getTrace(const std::string &name);
/**
* @ingroup AuboApi
* @ref GripperInterface
* \~chinese 获取通用夹爪接口
* \~english Get gripper interface
*
* \~chinese @return GripperInterfacePtr对象的指针
* \~english @return Shared pointer of gripper object
*/
GripperInterfacePtr getGripperInterface();
protected:
void *d_{ nullptr };
};
using AuboApiPtr = std::shared_ptr<AuboApi>;
} // namespace common_interface
} // namespace arcs
#endif // AUBO_SDK_AUBO_API_H

View File

@ -0,0 +1,650 @@
/** @file axes.h
* @brief 外部轴接口
*/
#ifndef AUBO_SDK_AXIS_INTERFACE_H
#define AUBO_SDK_AXIS_INTERFACE_H
#include <aubo/sync_move.h>
#include <aubo/trace.h>
namespace arcs {
namespace common_interface {
/**
* \chinese
* @defgroup AxisInterface AxisInterface (外部轴)
* 外部轴API接口
* \endchinese
*
* \english
* @defgroup AxisInterface External Axis
* External axis API interface
* \endenglish
*/
class ARCS_ABI_EXPORT AxisInterface
{
public:
AxisInterface();
virtual ~AxisInterface();
/**
* @ingroup AxisInterface
* \~chinese 通电
* \~english Power on
* @return
*/
int poweronExtAxis();
/**
* @ingroup AxisInterface
* \~chinese 断电
* \~english Power off
* @return
*/
int poweroffExtAxis();
/**
* @ingroup AxisInterface
* \~chinese 使能
* \~english Enable
* @return
*/
int enableExtAxis();
/**
* @ingroup AxisInterface
* \~chinese 设置外部轴的安装位姿(相对于世界坐标系)
* \~chinese @param pose
* \~english Set mounting pose of external axis (wrt world frame)
* \~english @param pose
* @return
*/
int setExtAxisMountingPose(const std::vector<double> &pose);
/**
* @ingroup AxisInterface
* \chinese 运动到指定点, 旋转或者平移
*
* @param pos
* @param v
* @param a
* @param duration
* @return
* \endchinese
*
* \english move to pos, rotation or linear
*
* @param pos
* @param v
* @param a
* @param duration
* @return
* \endenglish
*/
int moveExtJoint(double pos, double v, double a, double duration);
/**
* @ingroup AxisInterface
* \chinese
* 制定目标运动速度
*
* @param v
* @param a
* @param duration
* @return
* \endchinese
*
* \english
* Set target speed, acceleration and duration
* @param v
* @param a
* @param duration
* @return
* \endenglish
*/
int speedExtJoint(double v, double a, double duration);
/**
* @ingroup AxisInterface
* \chinese
* 停止外部轴运动
*
* @param a
* @return
* \endchinese
*
* \english
* stop ext joint
* @param a
* @return
* \endenglish
*/
int stopExtJoint(double a);
/**
* @ingroup AxisInterface
* \~chinese 获取外部轴的类型 0代表是旋转 1代表平移
* \~english Get external axis type: 0 for rotation, 1 for linear
* @return
*/
int getExtAxisType();
/**
* @ingroup AxisInterface
* \~chinese 设置外部轴的类型
* @param type 0代表是旋转 1代表平移
*
* \~english Set external axis type
* @param type: 0 for rotation, 1 for linear
* @return
*/
int setExtAxisType(int type);
/**
* @ingroup AxisInterface
* \chinese
* 获取当前外部轴的状态
*
* @return 当前外部轴的状态
* \endchinese
*
* \english
* Get external axis status
*
* @return Current exteral axis status
* \endenglish
*/
AxisModeType getAxisModeType();
/**
* @ingroup AxisInterface
* \chinese
* 获取外部轴安装位姿
*
* @return 外部轴安装位姿
* \endchinese
*
* \english
* Get external axis mounting pose
*
* @return External axis pose
* \endenglish
*/
std::vector<double> getExtAxisMountingPose();
/**
* @ingroup AxisInterface
* \chinese
* 获取相对于安装坐标系的位姿,外部轴可能为变位机或者导轨
*
* @return 相对于安装坐标系的位姿
* \endchinese
*
* \english
* Get pose wrt mounting coordinate system, axis can be positioner or linear
* rail
*
* @return Pose wrt mounting coordinate system
* \endenglish
*/
std::vector<double> getExtAxisPose();
/**
* @ingroup AxisInterface
* \chinese
* 获取外部轴位置
*
* @return 外部轴位置
* \endchinese
*
* \english
* Get external axis position
*
* @return External axis position
* \endenglish
*/
double getExtAxisPosition();
/**
* @ingroup AxisInterface
* \chinese
* 获取外部轴运行速度
*
* @return 外部轴运行速度
* \endchinese
*
* \english
* Get external axis speed
*
* @return External axis speed
* \endenglish
*/
double getExtAxisVelocity();
/**
* @ingroup AxisInterface
* \chinese
* 设置外部轴运行速度
*
* @return
* \endchinese
*
* \english
* Set external axis speed
*
* @return
* \endenglish
*/
int setExtAxisVelocity(double velocity);
/**
* @ingroup AxisInterface
* \chinese
* 获取外部轴运行加速度
*
* @return 外部轴运行加速度
* \endchinese
*
* \english
* Get external axis acceleration
*
* @return External axis acceleration
* \endenglish
*/
double getExtAxisAcceleration();
/**
* @ingroup AxisInterface
* \chinese
* 设置外部轴运行加速度
*
* @param acc
* @return
* \endchinese
*
* \english
* Set external axis acceleration
*
* @param acc
* @return
* \endenglish
*/
int setExtAxisAcceleration(double acc);
/**
* @ingroup AxisInterface
* \chinese
* 获取外部轴电流
*
* @return 外部轴电流
* \endchinese
*
* \english
* Get external axis current
*
* @return External axis current
* \endenglish
*/
double getExtAxisCurrent();
/**
* @ingroup AxisInterface
* \chinese
* 获取外部轴温度
*
* @return 外部轴温度
* \endchinese
*
* \english
* Get external axis temperature
*
* @return External axis temperature
* \endenglish
*/
double getExtAxisTemperature();
/**
* @ingroup AxisInterface
* \chinese
* 获取外部轴电压
*
* @return 外部轴电压
* \endchinese
*
* \english
* Get external axis voltage
*
* @return External axis voltage
* \endenglish
*/
double getExtAxisBusVoltage();
/**
* @ingroup AxisInterface
* \chinese
* 获取外部轴电流
*
* @return 外部轴电流
* \endchinese
*
* \english
* Get external axis current
*
* @return external axis current
* \endenglish
*/
double getExtAxisBusCurrent();
/**
* @ingroup AxisInterface
* \chinese
* 获取外部轴最大位置(物理极限)
*
* @return 外部轴最大位置
* \endchinese
*
* \english
* Get external axis max position
*
* @return External axis max position
* \endenglish
*/
double getExtAxisMaxPosition();
/**
* @ingroup AxisInterface
* \chinese
* 设置外部轴最大位置(软件/算法限制)
*
* @param q
* @return
* \endchinese
*
* \english
* Set external axis max position
*
* @param q
* @return
* \endenglish
*/
int setExtAxisMaxPositionLimit(double q);
/**
* @ingroup AxisInterface
* \chinese
* 获取外部轴最大位置(软件/算法限制)
*
* @return 外部轴最大位置
* \endchinese
*
* \english
* Get external axis max position
*
* @return External axis max position
* \endenglish
*/
double getExtAxisMaxPositionLimit();
/**
* @ingroup AxisInterface
* \chinese
* 获取外部轴最小位置(物理极限)
*
* @return 外部轴最小位置
* \endchinese
*
* \english
* Get external axis min position
*
* @return External axis min position
* \endenglish
*/
double getExtMinPosition();
/**
* @ingroup AxisInterface
* \chinese
* 设置外部轴最小位置(软件/算法限制)
*
* @param q
* @return
* \endchinese
*
* \english
* Set external axis min position
*
* @param q
* @return
* \endenglish
*/
int setExtMinPositionLimit(double q);
/**
* @ingroup AxisInterface
* \chinese
* 获取外部轴最小位置(软件/算法限制)
*
* @return 外部轴最小位置
* \endchinese
*
* \english
* Get external axis min position
*
* @return External axis min position
* \endenglish
*/
double getExtMinPositionLimit();
/**
* @ingroup AxisInterface
* \chinese
* 获取外部轴最大速度(物理极限)
*
* @return 外部轴最大速度
* \endchinese
*
* \english
* Get external axis max speed
*
* @return External axis max speed
* \endenglish
*/
double getExtAxisMaxVelocity();
/**
* @ingroup AxisInterface
* \chinese
* 设置外部轴最大速度(软件/算法限制)
*
* @param v
* @return
* \endchinese
*
* \english
* Set external axis max speed
*
* @param v
* @return
* \endenglish
*/
int setExtAxisMaxVelocityLimit(double v);
/**
* @ingroup AxisInterface
* \chinese
* 获取外部轴最大速度(软件/算法限制)
*
* @return 外部轴最大速度
* \endchinese
*
* \english
* Get external axis max speed
*
* @return External axis max speed
* \endenglish
*/
double getExtAxisMaxVelocityLimit();
/**
* @ingroup AxisInterface
* \chinese
* 获取外部轴最大加速度(物理极限)
*
* @return 外部轴最大加速度
* \endchinese
*
* \english
* Get external axis max acceleration
*
* @return External axis max acceleration
* \endenglish
*/
double getExtAxisMaxAcceleration();
/**
* @ingroup AxisInterface
* \chinese
* 设置外部轴最大加速度(软件/算法限制)
*
* @param acc
* @return
* \endchinese
*
* \english
* Set external axis max acceleration
*
* @param acc
* @return
* \endenglish
*/
int setExtAxisMaxAccelerationLimit(double acc);
/**
* @ingroup AxisInterface
* \chinese
* 获取外部轴最大加速度(软件/算法限制)
*
* @return 外部轴最大加速度
* \endchinese
*
* \english
* Get external axis max acceleration
*
* @return External axis max acceleration
* \endenglish
*/
double getExtAxisMaxAccelerationLimit();
/**
* @ingroup AxisInterface
* \chinese
* 跟踪另一个外部轴的运动(禁止运动过程中使用)
*
* @param target_name 目标的外部轴名字
* @param phase 相位差
* @param err 跟踪运行的最大误差
* @return
* \endchinese
*
* \english
* Follow motion of another external axis (not to be used during motion)
*
* @param target_name name of target axis
* @param phase phase difference
* @param err max error when following motion
* @return
* \endenglish
*/
int followAnotherAxis(const std::string &target_name, double phase,
double err);
/**
* @ingroup AxisInterface
* \~chinese @brief stopFollowAnotherAxis(禁止运动过程中使用)
* \~english @brief stopFollowAnotherAxis(not to be used during motion)
* @return
*/
int stopFollowAnotherAxis();
/**
* @ingroup AxisInterface
* \~chinese @brief getErrorCode(获取外部轴错误码)
* \~english @brief getErrorCode(Get raw external axis error code)
* @return
*/
int getErrorCode();
/**
* @ingroup AxisInterface
* \chinese
* 重置外部轴错误
*
* @return
* \endchinese
*
* \english
* Reset axis error
*
* @return
* \endenglish
*/
int clearAxisError();
/**
* @ingroup AxisInterface
* \chinese
* 将当前外部轴位置设置为零位
*
* @return
* \endchinese
*
* \english
* Set current external axis position as zero.
*
* @return
* \endenglish
*/
int setExtAxisZero();
/**
* @ingroup AxisInterface
* \chinese
* 设置外部轴减速比
*
* @return
* \endchinese
*
* \english
* Set axis reduction ratio
*
* @return
* \endenglish
*/
int setReductionRatio(double ratio);
/**
* @ingroup AxisInterface
* \chinese
* 获取外部轴减速比
*
* @return
* \endchinese
*
* \english
* Get axis reduction ratio
*
* @return
* \endenglish
*/
double getReductionRatio();
protected:
void *d_;
};
using AxisInterfacePtr = std::shared_ptr<AxisInterface>;
} // namespace common_interface
} // namespace arcs
#endif // AUBO_SDK_AXIS_INTERFACE_H

View File

@ -0,0 +1,118 @@
/** @file error_stack.h
* @brief 汇总错误码
*/
#ifndef AUBO_SDK_ERROR_STACK_H
#define AUBO_SDK_ERROR_STACK_H
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <string>
#include <sstream>
#include <iomanip>
#include <aubo/global_config.h>
// 格式化占位符,默认是 fmt 的格式
#ifndef _PH1_
#define _PH1_ "{}"
#define _PH2_ "{}"
#define _PH3_ "{}"
#define _PH4_ "{}"
#endif
namespace arcs {
namespace error_stack {
constexpr int ARCS_ABI_EXPORT codeCompose(int aa, int bb, int cccc)
{
return (int)((aa * 1000000) + (bb * 10000) + cccc);
}
constexpr int ARCS_ABI_EXPORT mod(int x)
{
return (x % 1000000);
}
#include <aubo/error_stack/hal_error.h>
#include <aubo/error_stack/rtm_error.h>
#include <aubo/error_stack/system_error.h>
#define ARCS_ERROR_CODES \
SYSTEM_ERRORS \
JOINT_ERRORS \
JOINT_EX_ERRORS \
EXT_AXIS_ERRORS \
SAFETY_INTERFACE_BOARD_ERRORS \
RTM_ERRORS \
TOOL_ERRORS \
EX_TOOL_ERRORS \
PEDSTRAL_ERRORS \
EX_PEDSTRAL_ERRORS \
HARDWARE_INTERFACE_ERRORS \
_D(ARCS_MAX_ERROR_CODE, -1, "Max error code", "suggest...")
// 错误代码枚举
enum ErrorCodes
{
#define _D(n, v, s, r, ...) n = (int)v,
ARCS_ERROR_CODES
#undef _D
};
inline int str2ErrorCode(const char *err_code_name)
{
#define _D(n, v, s, r, ...) \
if (strcmp(#n, err_code_name) == 0) \
return v;
ARCS_ERROR_CODES
#undef _D
return ARCS_MAX_ERROR_CODE;
}
inline const char *errorCode2Str(int err_code)
{
static const char *errcode_str[] = {
#define _D(n, v, s, r, ...) s,
ARCS_ERROR_CODES
#undef _D
};
enum arcs_index
{
#define _D(n, v, s, r, ...) n##_INDEX,
ARCS_ERROR_CODES
#undef _D
};
int index = -1;
#define _D(n, v, s, r, ...) \
if (err_code == v) \
index = n##_INDEX;
ARCS_ERROR_CODES
#undef _D
if (index == -1) {
index = ARCS_MAX_ERROR_CODE_INDEX;
}
return errcode_str[(unsigned)index];
}
inline std::ostream &dump(std::ostream &os)
{
#define _D(n, v, s, r, ...) \
os << std::setw(20) << #n << "\t" << v << "\t" << s << "\t" << r \
<< std::endl;
ARCS_ERROR_CODES
#undef _D
return os;
}
} // namespace error_stack
} // namespace arcs
#endif // AUBO_SDK_ERROR_STACK_H

View File

@ -0,0 +1,350 @@
/** @file hal_error.h
* @brief 定义硬件抽象层的错误码
*/
#ifndef AUBO_SDK_HAL_ERROR_H
#define AUBO_SDK_HAL_ERROR_H
// 缩写说明
// JNT: joint
// PDL: pedstral
// TP: teach pendant
// COMM: communication
// ENC: encoder
// CURR: current
// POS: position
// PKG: package
// PROG: program
// clang-format off
#define JOINT_ERRORS \
_D(JOINT_ERR_OVER_CURRENET, 10001, "joint" _PH1_ " error: over current", "(a) Check for short circuit. (b) Do a Complete rebooting sequence. (c) If this happens more than two times in a row, replace joint") \
_D(JOINT_ERR_OVER_VOLTAGE, 10002, "joint" _PH1_ " error: over voltage", "(a) Do a Complete rebooting sequence. (b) Check 48 V Power supply, current distributer, energy eater and Control Board for issues") \
_D(JOINT_ERR_LOW_VOLTAGE, 10003, "joint" _PH1_ " error: low voltage", "(a) Do a Complete rebooting sequence. (b) Check for short circuit in robot arm. (c) Check 48 V Power supply, current distributer, energy eater and Control Board for issues") \
_D(JOINT_ERR_OVER_TEMP, 10004, "joint" _PH1_ " error: over temperature", "(a) Check robot’s environment and make sure the robot is operating within recommended limits. (b) Do a Complete rebooting sequence") \
_D(JOINT_ERR_HALL, 10005, "joint" _PH1_ " error: hall", "suggest...") \
_D(JOINT_ERR_ENCODER, 10006, "joint" _PH1_ " error: encoder", "Check encoder connections") \
_D(JOINT_ERR_ABS_ENCODER, 10007, "joint" _PH1_ " error: abs encoder", "suggest...") \
_D(JOINT_ERR_Q_CURRENT, 10008, "joint" _PH1_ " error: detect current", "suggest...") \
_D(JOINT_ERR_ENC_POLL, 10009, "joint" _PH1_ " error: encoder pollustion", "suggest...") \
_D(JOINT_ERR_ENC_Z_SIGNAL, 10010, "joint" _PH1_ " error: enocder z signal", "suggest...") \
_D(JOINT_ERR_ENC_CAL, 10011, "joint" _PH1_ " error: encoder calibrate", "suggest...") \
_D(JOINT_ERR_IMU_SENS, 10012, "joint" _PH1_ " error: IMU sensor", "suggest...") \
_D(JOINT_ERR_TEMP_SENS, 10013, "joint" _PH1_ " error: TEMP sensor", "suggest...") \
_D(JOINT_ERR_CAN_BUS, 10014, "joint" _PH1_ " error: CAN bus error", "suggest...") \
_D(JOINT_ERR_SYS_CUR, 10015, "joint" _PH1_ " error: system current error", "suggest...") \
_D(JOINT_ERR_SYS_POS, 10016, "joint" _PH1_ " error: system position error","suggest...") \
_D(JOINT_ERR_OVER_SP, 10017, "joint" _PH1_ " error: over speed","suggest...") \
_D(JOINT_ERR_OVER_ACC, 10018, "joint" _PH1_ " error: over accelerate", "suggest...") \
_D(JOINT_ERR_TRACE, 10019, "joint" _PH1_ " error: trace accuracy", "suggest...") \
_D(JOINT_ERR_TAG_POS_OVER, 10020, "joint" _PH1_ " error: target position out of range", "suggest...") \
_D(JOINT_ERR_TAG_SP_OVER, 10021, "joint" _PH1_ " error: target speed out of range", "suggest...") \
_D(JOINT_ERR_COLLISION, 10022, "joint" _PH1_ " error: collision", "suggest...") \
_D(JOINT_ERR_COMMON, 10023, "joint" _PH1_ " error: unkown error. Check communication with joint.", "suggest...") \
_D(JOINT_ERR_SWITCH_SERVO_MODE, 10024, "joint" _PH1_ " error: switch servo mode timeout.", "suggest...") \
_D(JOINT_ERR_MOTOR_STUCK, 10025, "joint" _PH1_ " error: motor stucked.", "suggest...") \
_D(JOINT_ERR_REDUCER_OVER_TEMP, 10026, "joint" _PH1_ " error: reducer over temperature", "(a) Check robot’s environment and make sure the robot is operating within recommended limits. (b) Do a Complete rebooting sequence") \
_D(JOINT_ERR_REDUCER_NTC, 10027, "joint" _PH1_ " error: reducer TEMP sensor failure", "(a) Check robot’s environment and make sure the robot is operating within recommended limits. (b) Do a Complete rebooting sequence") \
_D(JOINT_ERR_ABS_MULTITURN, 10028, "joint" _PH1_ " error: absolute encoder multiturn error", "(a) Check robot’s environment and make sure the robot is operating within recommended limits. (b) Do a Complete rebooting sequence") \
_D(JOINT_ERR_ADC_ZERO_OFFSET, 10029, "joint" _PH1_ " error: ADC zero offset failure", "(a) Check robot’s environment and make sure the robot is operating within recommended limits. (b) Do a Complete rebooting sequence") \
_D(JOINT_ERR_SHORT_CIRCUIT, 10030, "joint" _PH1_ " error: short circuit", "(a) Check robot’s environment and make sure the robot is operating within recommended limits. (b) Do a Complete rebooting sequence") \
_D(JOINT_ERR_PHASE_LOST, 10031, "joint" _PH1_ " error: motor phase lost", "(a) Check robot’s environment and make sure the robot is operating within recommended limits. (b) Do a Complete rebooting sequence") \
_D(JOINT_ERR_BRAKE, 10032, "joint" _PH1_ " error: brake failure", "(a) Check robot’s environment and make sure the robot is operating within recommended limits. (b) Do a Complete rebooting sequence") \
_D(JOINT_ERR_FIRMWARE_UPDATE, 10033, "joint" _PH1_ " error: firmware update failure", "(a) Check robot’s environment and make sure the robot is operating within recommended limits. (b) Do a Complete rebooting sequence") \
_D(JOINT_ERR_BATTERY_LOW, 10034, "joint" _PH1_ " error: battery low", "(a) Check robot’s environment and make sure the robot is operating within recommended limits. (b) Do a Complete rebooting sequence") \
_D(JOINT_ERR_PHASE_ALIGN, 10035, "joint" _PH1_ " error: phase align", "(a) Check robot’s environment and make sure the robot is operating within recommended limits. (b) Do a Complete rebooting sequence") \
_D(JOINT_ERR_CAN_HW_FAULT, 10036, "joint" _PH1_ " error: CAN bus hw fault", "(a) Check robot’s environment and make sure the robot is operating within recommended limits. (b) Do a Complete rebooting sequence") \
_D(JOINT_ERR_POS_DISCONTINUOUS, 10037, "joint" _PH1_ " error: target position discontinuous", "(a) Check robot’s environment and make sure the robot is operating within recommended limits. (b) Do a Complete rebooting sequence") \
_D(JOINT_ERR_POS_INIT, 10038, "joint" _PH1_ " error: position initiallization failure", "(a) Check robot’s environment and make sure the robot is operating within recommended limits. (b) Do a Complete rebooting sequence") \
_D(JOINT_ERR_TORQUE_SENSOR, 10039, "joint" _PH1_ " error: torqure sensor failure", "(a) Check robot’s environment and make sure the robot is operating within recommended limits. (b) Do a Complete rebooting sequence") \
_D(JOINT_ERR_OFFLINE, 10040, "joint" _PH1_ " error: joint may be offline", "(a) Check joint's hardware. (b) Check joint's id.") \
_D(JOINT_ERR_BOOTLOADER, 10041, "joint" _PH1_ " error: The joint is in bootloader mode. Retry firmware update. ", "suggest...") \
_D(JOINT_ERR_SLAVE_OFFLINE, 10042, "slave joint" _PH1_ " error: slave joint may be offline", "(a) Check slave joint's hardware. (b) Check slave joint's id.") \
_D(JOINT_ERR_SLAVE_BOOTLOADER, 10043, "slave joint" _PH1_ " error: The slave joint is in bootloader mode. Retry firmware update. ", "suggest...") \
_D(JOINT_ERR_ETHERCAT_BUS, 10044, "joint" _PH1_ " error: ETHERCAT bus error", "suggest...")
// Joint extended error codes (ex_err_code), starting from 10401
#define JOINT_EX_ERRORS \
_D(EX_JOINT_EC_SHORT_CIRCUIT, 10401, "joint" _PH1_ " error: short circuit protection", "suggest...", 0x2130) \
_D(EX_JOINT_EC_SHORT_CURRENT, 10402, "joint" _PH1_ " error: over current", "suggest...", 0x2310) \
_D(EX_JOINT_EC_PHASEA_CURRENT, 10403, "joint" _PH1_ " error: phase A over current", "suggest...", 0x2311) \
_D(EX_JOINT_EC_PHASEB_CURRENT, 10404, "joint" _PH1_ " error: phase B over current", "suggest...", 0x2312) \
_D(EX_JOINT_EC_PHASEC_CURRENT, 10405, "joint" _PH1_ " error: phase C over current", "suggest...", 0x2313) \
_D(EX_JOINT_EC_PHASE_CURRENT, 10406, "joint" _PH1_ " error: phase over current", "suggest...", 0x2314) \
_D(EX_JOINT_EC_MOTOR_PHASE_LOSE, 10407, "joint" _PH1_ " error: motor phase loss", "suggest...", 0x3331) \
_D(EX_JOINT_EC_BUS_OVER_VOLTAGE, 10408, "joint" _PH1_ " error: bus over voltage", "suggest...", 0x3210) \
_D(EX_JOINT_EC_BUS_LOW_VOLTAGE, 10409, "joint" _PH1_ " error: bus under voltage", "suggest...", 0x3220) \
_D(EX_JOINT_EC_OVERLOAD, 10410, "joint" _PH1_ " error: overload", "suggest...", 0x3230) \
_D(EX_JOINT_EC_IPM_OVER_TEMP, 10411, "joint" _PH1_ " error: IPM over temperature", "suggest...", 0x4310) \
_D(EX_JOINT_EC_REDUCER_OVER_TEMP, 10412, "joint" _PH1_ " error: reducer over temperature", "suggest...", 0x4311) \
_D(EX_JOINT_EC_ADC_ZERO_OFFSET, 10413, "joint" _PH1_ " error: ADC zero offset", "suggest...", 0x5101) \
_D(EX_JOINT_EC_REDUCER_NTC, 10414, "joint" _PH1_ " error: reducer NTC fault", "suggest...", 0x5102) \
_D(EX_JOINT_EC_IPM_NTC, 10415, "joint" _PH1_ " error: IPM NTC fault", "suggest...", 0x5103) \
_D(EX_JOINT_EC_TORQUE_SENSOR, 10416, "joint" _PH1_ " error: torque sensor fault", "suggest...", 0x5104) \
_D(EX_JOINT_EC_TORQUE_SENSOR_COMM, 10417, "joint" _PH1_ " error: torque sensor communication fault", "suggest...", 0x5105) \
_D(EX_JOINT_EC_MOTOR_ABS_ENC_COMM, 10418, "joint" _PH1_ " error: motor-side absolute encoder communication fault", "suggest...", 0x5201) \
_D(EX_JOINT_EC_REDUCER_ABS_ENC_COMM, 10419, "joint" _PH1_ " error: reducer-side absolute encoder communication fault", "suggest...", 0x5202) \
_D(EX_JOINT_EC_REDUCER_ABS_ENC_DATA, 10420, "joint" _PH1_ " error: reducer-side absolute encoder data channel disabled warning", "suggest...", 0x5203) \
_D(EX_JOINT_EC_REDUCER_ABS_ENC_CMD, 10421, "joint" _PH1_ " error: reducer-side absolute encoder command invalid warning", "suggest...", 0x5204) \
_D(EX_JOINT_EC_REDUCER_ABS_ENC_ERR, 10422, "joint" _PH1_ " error: reducer-side absolute encoder fault", "suggest...", 0x5205) \
_D(EX_JOINT_EC_REDUCER_ABS_ENC_WARNING, 10423, "joint" _PH1_ " error: reducer-side absolute encoder warning", "suggest...", 0x5206) \
_D(EX_JOINT_EC_BRAKE, 10424, "joint" _PH1_ " error: brake fault", "suggest...", 0x5301) \
_D(EX_JOINT_EC_COMM_HWL, 10425, "joint" _PH1_ " error: communication hardware layer error", "suggest...", 0x5302) \
_D(EX_JOINT_EC_FIRMWARE_UPDATE, 10426, "joint" _PH1_ " error: firmware update failed", "suggest...", 0x6100) \
_D(EX_JOINT_EC_FLASH_OP, 10427, "joint" _PH1_ " error: flash operation failed", "suggest...", 0x6101) \
_D(EX_JOINT_EC_MU_SAVE, 10428, "joint" _PH1_ " error: multi-turn data error", "suggest...", 0x6102) \
_D(EX_JOINT_EC_DEMADATA_LOST, 10429, "joint" _PH1_ " error: calibration zero point data lost", "suggest...", 0x6103) \
_D(EX_JOINT_EC_PARAMETER, 10430, "joint" _PH1_ " error: parameter error", "suggest...", 0x6200) \
_D(EX_JOINT_EC_UVW_LOGIC, 10431, "joint" _PH1_ " error: hall signal fault", "suggest...", 0x7001) \
_D(EX_JOINT_EC_UVW_ABZ, 10432, "joint" _PH1_ " error: incremental encoder fault", "suggest...", 0x7002) \
_D(EX_JOINT_EC_ENC_Z_LOST, 10433, "joint" _PH1_ " error: encoder Z signal lost", "suggest...", 0x7305) \
_D(EX_JOINT_EC_ENC_POLLUTE, 10434, "joint" _PH1_ " error: encoder pollution", "suggest...", 0x7004) \
_D(EX_JOINT_EC_ENC_CALI, 10435, "joint" _PH1_ " error: encoder calibration failed", "suggest...", 0x7005) \
_D(EX_JOINT_EC_MT_ABS_DATA, 10436, "joint" _PH1_ " error: multi-turn absolute data error", "suggest...", 0x7006) \
_D(EX_JOINT_EC_ENC_TYPE_INFO, 10437, "joint" _PH1_ " error: encoder type identified and saved", "suggest...", 0x7007) \
_D(EX_JOINT_EC_ENC_TYPE_ERROR, 10438, "joint" _PH1_ " error: encoder type error", "suggest...", 0x7008) \
_D(EX_JOINT_EC_ENC_VERIFY, 10439, "joint" _PH1_ " error: encoder verification failed", "suggest...", 0x7009) \
_D(EX_JOINT_EC_DUAL_ENC_ERROR, 10440, "joint" _PH1_ " error: dual encoder deviation too large", "suggest...", 0x700A) \
_D(EX_JOINT_EC_DUAL_ENC_EANGLE, 10441, "joint" _PH1_ " error: dual encoder electrical angle deviation too large", "suggest...", 0x700B) \
_D(EX_JOINT_EC_OBJECT_DICT_ERROR, 10442, "joint" _PH1_ " error: object dictionary data error", "suggest...", 0x700C) \
_D(EX_JOINT_EC_MOTOR_STALL, 10443, "joint" _PH1_ " error: motor stall protection", "suggest...", 0x7121) \
_D(EX_JOINT_EC_ABS_ENC_LOW_VOLT, 10444, "joint" _PH1_ " error: absolute encoder low voltage", "suggest...", 0x7385) \
_D(EX_JOINT_EC_MT_BATTERY_LOW, 10445, "joint" _PH1_ " error: multi-turn battery low voltage", "suggest...", 0x7386) \
_D(EX_JOINT_EC_POS_CMD, 10446, "joint" _PH1_ " error: position command discontinuous", "suggest...", 0x8001) \
_D(EX_JOINT_EC_POS_OVER_LIMIT, 10447, "joint" _PH1_ " error: position over limit", "suggest...", 0x8002) \
_D(EX_JOINT_EC_COMM_PROTO, 10448, "joint" _PH1_ " error: communication protocol layer error", "suggest...", 0x8003) \
_D(EX_JOINT_EC_GRAVITY_PARA_WARNING, 10449, "joint" _PH1_ " error: gravity compensation parameter invalid", "suggest...", 0x8004) \
_D(EX_JOINT_EC_GRAVITY_COMPENSATE_ERROR, 10450, "joint" _PH1_ " error: gravity compensation value sudden change", "suggest...", 0x8005) \
_D(EX_JOINT_EC_LOW_RIGIDITY, 10451, "joint" _PH1_ " error: collision soft float abnormal", "suggest...", 0x8006) \
_D(EX_JOINT_EC_POS_CMD_WARNING, 10452, "joint" _PH1_ " error: position command unchanged during motion", "suggest...", 0x8007) \
_D(EX_JOINT_EC_SLAVE_COMM, 10453, "joint" _PH1_ " error: master-slave MCU communication fault", "suggest...", 0x8008) \
_D(EX_JOINT_EC_POS_ERR, 10454, "joint" _PH1_ " error: position following error too large", "suggest...", 0x8009) \
_D(EX_JOINT_EC_DUAL_POS_ERR, 10455, "joint" _PH1_ " error: dual servo position sync error too large", "suggest...", 0x800A) \
_D(EX_JOINT_EC_DUAL_COMM_ERR, 10456, "joint" _PH1_ " error: dual servo communication", "suggest...", 0x800B) \
_D(EX_JOINT_EC_CAN_BUSOFF, 10457, "joint" _PH1_ " error: CAN bus-off warning", "suggest...", 0x800C) \
_D(EX_JOINT_EC_SYNC_SNAKE, 10458, "joint" _PH1_ " error: sync frame jitter warning", "suggest...", 0x800D) \
_D(EX_JOINT_EC_SYNC_DISCON, 10459, "joint" _PH1_ " error: sync frame discontinuous warning", "suggest...", 0x800E) \
_D(EX_JOINT_EC_RPDO_LOST, 10460, "joint" _PH1_ " error: RPDO lost warning", "suggest...", 0x800F) \
_D(EX_JOINT_EC_RPDO_MANY, 10461, "joint" _PH1_ " error: multiple RPDO in one sync cycle warning", "suggest...", 0x8010) \
_D(EX_JOINT_EC_GRAVITY_LOST, 10462, "joint" _PH1_ " error: gravity compensation value lost", "suggest...", 0x8011) \
_D(EX_JOINT_EC_MAININT_TIME_WARN, 10463, "joint" _PH1_ " error: servo main interrupt runtime warning", "suggest...", 0x8012) \
_D(EX_JOINT_EC_MAININT_TIME_ERROR, 10464, "joint" _PH1_ " error: servo main interrupt runtime error", "suggest...", 0x8013) \
_D(EX_JOINT_EC_SPDINT_TIME_WARN, 10465, "joint" _PH1_ " error: servo speed loop interrupt runtime warning", "suggest...", 0x8014) \
_D(EX_JOINT_EC_SPDINT_TIME_ERROR, 10466, "joint" _PH1_ " error: servo speed loop interrupt runtime error", "suggest...", 0x8015) \
_D(EX_JOINT_EC_POS_CMD_JUMP_WARNING, 10467, "joint" _PH1_ " error: position command sudden jump during motion", "suggest...", 0x8016) \
_D(EX_JOINT_EC_SYNC_TIMCOARSE, 10468, "joint" _PH1_ " error: clock sync compensation status", "suggest...", 0x8017) \
_D(EX_JOINT_EC_ENC_Z_CNTS_ERR, 10469, "joint" _PH1_ " error: incremental encoder Z signal or CNTS abnormal", "suggest...", 0x8018) \
_D(EX_JOINT_EC_SLAVE_OVER_CURRENT, 10470, "joint" _PH1_ " error: slave MCU detected motor phase current over safe threshold", "suggest...", 0x8019) \
_D(EX_JOINT_EC_SLAVE_OVER_VOLTAGE, 10471, "joint" _PH1_ " error: slave MCU detected DC bus voltage over upper threshold", "suggest...", 0x801A) \
_D(EX_JOINT_EC_SLAVE_UNDER_VOLTAGE, 10472, "joint" _PH1_ " error: slave MCU detected DC bus voltage below lower threshold", "suggest...", 0x801B) \
_D(EX_JOINT_EC_SLAVE_POS_ERR, 10473, "joint" _PH1_ " error: slave MCU detected master-slave motor position deviation out of range", "suggest...", 0x801C) \
_D(EX_JOINT_EC_SLAVE_SPEED_ERR, 10474, "joint" _PH1_ " error: slave MCU detected master-slave motor speed deviation out of range", "suggest...", 0x801D) \
_D(EX_JOINT_EC_SLAVE_TRACE_ERR, 10475, "joint" _PH1_ " error: slave MCU detected position following error out of control range", "suggest...", 0x801E) \
_D(EX_JOINT_EC_SLAVE_ABS_ERR, 10476, "joint" _PH1_ " error: slave MCU detected absolute encoder feedback abnormal", "suggest...", 0x801F) \
_D(EX_JOINT_EC_SLAVE_ADC_ZERO_OFFSET, 10477, "joint" _PH1_ " error: slave MCU detected current sampling zero offset out of calibration range", "suggest...", 0x8020) \
_D(EX_JOINT_EC_SLAVE_ENC_POLLUTE, 10478, "joint" _PH1_ " error: slave MCU detected encoder signal quality degradation", "suggest...", 0x8021) \
_D(EX_JOINT_EC_SLAVE_ENC_Z_LOST, 10479, "joint" _PH1_ " error: slave MCU detected encoder Z reference signal lost", "suggest...", 0x8022) \
_D(EX_JOINT_EC_SLAVE_COMM_OVER_TM, 10480, "joint" _PH1_ " error: slave MCU detected master-slave communication timeout", "suggest...", 0x8023) \
_D(EX_JOINT_EC_SLAVE_TRQ_ERR, 10481, "joint" _PH1_ " error: slave MCU detected master-slave motor torque deviation out of range", "suggest...", 0x8024) \
_D(EX_JOINT_EC_BRAKE_TYPE_ERR, 10482, "joint" _PH1_ " error: brake type config mismatch with hardware", "suggest...", 0x8025) \
_D(EX_JOINT_EC_PHASE_ALIGN, 10483, "joint" _PH1_ " error: phase alignment failed", "suggest...", 0xFF02) \
_D(EX_JOINT_EC_POS_OVER_LIMIT_WARNING, 10484, "joint" _PH1_ " error: position over limit", "suggest...", 0x8026) \
_D(EX_JOINT_EC_PHASE_ALIGN_WARNING, 10485, "joint" _PH1_ " error: phase alignment warning", "suggest...", 0xFF03) \
_D(EX_JOINT_EC_TASK_STACK_SHORTAGE, 10486, "joint" _PH1_ " error: task stack insufficient", "suggest...", 0xFF04) \
_D(EX_JOINT_EC_TASK_STACK_OVERFLOW, 10487, "joint" _PH1_ " error: task stack overflow", "suggest...", 0xFF05) \
_D(EX_JOINT_EC_SERVO_STEP, 10488, "joint" _PH1_ " servo process step", "For information only. No action required.", 0x6105) \
_D(EX_JOINT_EC_UNKNOWN, 10800, "joint" _PH1_ " error: unknown error", "suggest...", 0xFFFF)
#define EXT_AXIS_ERRORS \
_D(EXT_AXIS_ERR_COMMON, 11001, "ext axis" _PH1_ " error: common", "Check communication with ext axis drive.") \
_D(EXT_AXIS_ERR_OVER_CURRENT, 11002, "ext axis" _PH1_ " error: over current", "Check wiring/short circuit; reboot; if repeated replace drive/motor.") \
_D(EXT_AXIS_ERR_OVER_VOLTAGE, 11003, "ext axis" _PH1_ " error: over voltage", "Check DC supply, regen, energy eater; reboot.") \
_D(EXT_AXIS_ERR_LOW_VOLTAGE, 11004, "ext axis" _PH1_ " error: low voltage", "Check DC supply and cabling; reboot.") \
_D(EXT_AXIS_ERR_OVER_TEMP, 11005, "ext axis" _PH1_ " error: over temperature", "Check environment/cooling; reboot.") \
_D(EXT_AXIS_ERR_HALL, 11006, "ext axis" _PH1_ " error: hall fault", "Check hall sensor and motor cabling.") \
_D(EXT_AXIS_ERR_ENCODER, 11007, "ext axis" _PH1_ " error: encoder fault", "Check encoder connection/cable/noise.") \
_D(EXT_AXIS_ERR_ABS_ENCODER, 11008, "ext axis" _PH1_ " error: absolute encoder fault", "Check abs encoder power/cable; reboot.") \
_D(EXT_AXIS_ERR_CUR_CALIB, 11009, "ext axis" _PH1_ " error: current calibration fault", "Reboot; check current sensing circuit.") \
_D(EXT_AXIS_ERR_Q_CURRENT, 11010, "ext axis" _PH1_ " error: current detect fault", "Reboot; check current sensing circuit.") \
_D(EXT_AXIS_ERR_ENC_POLL, 11011, "ext axis" _PH1_ " error: encoder pollution", "Check encoder contamination/noise; improve shielding.") \
_D(EXT_AXIS_ERR_ENC_Z_SIGNAL, 11012, "ext axis" _PH1_ " error: encoder Z signal fault", "Check encoder Z channel and wiring.") \
_D(EXT_AXIS_ERR_ENC_CAL, 11013, "ext axis" _PH1_ " error: encoder calibrate invalid", "Redo calibration; check encoder.") \
_D(EXT_AXIS_ERR_IMU, 11014, "ext axis" _PH1_ " error: IMU fault", "Check IMU sensor and connection.") \
_D(EXT_AXIS_ERR_TEMP_SENSOR, 11015, "ext axis" _PH1_ " error: temperature sensor fault", "Check temp sensor wiring; reboot.") \
_D(EXT_AXIS_ERR_ECAT_BUS, 11016, "ext axis" _PH1_ " error: EtherCAT bus error", "Check EtherCAT cabling/topology/sync; reboot master/drive.") \
_D(EXT_AXIS_ERR_ECAT_CONFIG, 11017, "ext axis" _PH1_ " error: EtherCAT config/ESI/SM/PDO fault", "Check ESI, Mailbox/SM/PDO mapping, vendor/product/revision match.") \
_D(EXT_AXIS_ERR_ECAT_SYNC, 11018, "ext axis" _PH1_ " error: EtherCAT sync/frame/period fault", "Check DC sync, cycle time, frame loss; verify NIC/IRQ affinity.") \
_D(EXT_AXIS_ERR_SYS_CUR, 11019, "ext axis" _PH1_ " error: system current fault", "Check current loop and load; reboot.") \
_D(EXT_AXIS_ERR_SYS_POS, 11020, "ext axis" _PH1_ " error: position out of range", "Check encoder/scale/limits; reboot.") \
_D(EXT_AXIS_ERR_OVER_SPEED, 11021, "ext axis" _PH1_ " error: over speed", "Check command limits and tuning parameters.") \
_D(EXT_AXIS_ERR_OVER_ACC, 11022, "ext axis" _PH1_ " error: over acceleration", "Reduce acceleration/jerk; check tuning.") \
_D(EXT_AXIS_ERR_FOLLOW_ERROR, 11023, "ext axis" _PH1_ " error: following error", "Check gains, load, saturation; verify feedback.") \
_D(EXT_AXIS_ERR_TAG_POS_OVER, 11024, "ext axis" _PH1_ " error: target position out of range", "Check target limits and homing.") \
_D(EXT_AXIS_ERR_TAG_SPEED_OVER, 11025, "ext axis" _PH1_ " error: target speed out of range", "Clamp speed; check profile settings.") \
_D(EXT_AXIS_ERR_TAG_CURRENT_OVER, 11026, "ext axis" _PH1_ " error: target current out of range", "Clamp current/torque; check load.") \
_D(EXT_AXIS_ERR_COLLISION, 11027, "ext axis" _PH1_ " error: collision", "Remove obstruction; check torque/force limits.") \
_D(EXT_AXIS_ERR_ADC_ZERO_OFFSET, 11028, "ext axis" _PH1_ " error: ADC zero offset", "Reboot; check ADC/current sensor offset.") \
_D(EXT_AXIS_ERR_IPM_NTC, 11029, "ext axis" _PH1_ " error: IPM NTC fault", "Check power module temperature sensing.") \
_D(EXT_AXIS_ERR_SHORT_CIRCUIT, 11030, "ext axis" _PH1_ " error: short circuit", "Check motor phase wiring; insulation test.") \
_D(EXT_AXIS_ERR_MOTOR_STALL, 11031, "ext axis" _PH1_ " error: motor stall", "Check mechanical jam/load; reduce accel; reboot.") \
_D(EXT_AXIS_ERR_ABS_MULTITURN, 11032, "ext axis" _PH1_ " error: abs encoder multiturn fault", "Check abs encoder battery/params; reboot.") \
_D(EXT_AXIS_ERR_PHASE_LOST, 11033, "ext axis" _PH1_ " error: motor phase lost", "Check phase wiring/connector; measure continuity.") \
_D(EXT_AXIS_ERR_BRAKE, 11034, "ext axis" _PH1_ " error: brake fault", "Check brake wiring/power; verify brake release.") \
_D(EXT_AXIS_ERR_REDUCER_OVER_TEMP, 11035, "ext axis" _PH1_ " error: reducer over temperature", "Check reducer temperature/cooling.") \
_D(EXT_AXIS_ERR_REDUCER_NTC, 11036, "ext axis" _PH1_ " error: reducer NTC fault", "Check reducer temperature sensor.") \
_D(EXT_AXIS_ERR_FIRMWARE_UPDATE, 11037, "ext axis" _PH1_ " error: firmware update fault", "Retry update; check power stability.") \
_D(EXT_AXIS_ERR_FLASH_OP, 11038, "ext axis" _PH1_ " error: flash operation fault", "Retry; if persistent replace drive.") \
_D(EXT_AXIS_ERR_EXT_ABS_ENC, 11039, "ext axis" _PH1_ " error: motor-side abs encoder comm fault", "Check external abs encoder link/power.") \
_D(EXT_AXIS_ERR_DRIVE_FAULT, 11040, "ext axis" _PH1_ " error: drive fault", "Check drive alarm code; reboot; replace if repeated.") \
_D(EXT_AXIS_ERR_OVERLOAD, 11041, "ext axis" _PH1_ " error: overload", "Reduce load; check mechanics and tuning.") \
_D(EXT_AXIS_ERR_HARDWARE_LIMIT, 11042, "ext axis" _PH1_ " error: hardware limit triggered", "Move away from limit; check limit switch.") \
_D(EXT_AXIS_ERR_SERVO_MODE_TIMEOUT, 11043, "ext axis" _PH1_ " error: switch servo mode timeout", "Check mode transition and comm; reboot.") \
_D(EXT_AXIS_ERR_UVW_ABZ, 11044, "ext axis" _PH1_ " error: UVW/ABZ fault", "Check phase/encoder signals wiring.") \
_D(EXT_AXIS_ERR_BATTERY_LOW, 11045, "ext axis" _PH1_ " error: battery low", "Replace encoder battery; reboot.") \
_D(EXT_AXIS_ERR_PHASE_ALIGN, 11046, "ext axis" _PH1_ " error: phase align fail", "Redo phase alignment; check motor params.") \
_D(EXT_AXIS_ERR_POS_DISCONTINUOUS, 11047, "ext axis" _PH1_ " error: position command discontinuous", "Check trajectory generation and limits.") \
_D(EXT_AXIS_ERR_POS_INIT, 11048, "ext axis" _PH1_ " error: position initialization failure", "Check encoder init/homing procedure.") \
_D(EXT_AXIS_ERR_TORQUE_SENSOR, 11049, "ext axis" _PH1_ " error: torque sensor fault", "Check torque sensor wiring/calibration.") \
_D(EXT_AXIS_ERR_ABS_ENC_LOW_VOLT, 11050, "ext axis" _PH1_ " error: abs encoder low voltage", "Check encoder supply voltage and cable.") \
_D(EXT_AXIS_ERR_OFFLINE, 11051, "ext axis" _PH1_ " error: ext axis offline", "Check hardware and axis id; check EtherCAT state.") \
_D(EXT_AXIS_ERR_BOOTLOADER, 11052, "ext axis" _PH1_ " error: ext axis in bootloader", "Retry firmware update.") \
_D(EXT_AXIS_ERR_SLAVE_OFFLINE, 11053, "ext axis slave" _PH1_ " error: slave offline", "Check slave hardware and id.") \
_D(EXT_AXIS_ERR_SLAVE_BOOTLOADER, 11054, "ext axis slave" _PH1_ " error: slave in bootloader", "Retry firmware update.") \
_D(EXT_AXIS_ERR_EEPROM, 11055, "ext axis" _PH1_ " error: EEPROM/param store fault", "Check EEPROM/parameter storage; power cycle.") \
_D(EXT_AXIS_ERR_PARAM_CONFIG, 11056, "ext axis" _PH1_ " error: parameter/config fault", "Verify parameter set; restore defaults if needed.") \
_D(EXT_AXIS_ERR_STO, 11057, "ext axis" _PH1_ " error: STO safety fault", "Check STO wiring/safety chain; reset safety.") \
_D(EXT_AXIS_ERR_ENCRYPT_CHIP, 11058, "ext axis" _PH1_ " error: encrypt chip/key fault", "Check encryption chip/keys/firmware compatibility.") \
_D(EXT_AXIS_ERR_BRAKE_RES_OVERLOAD, 11059, "ext axis" _PH1_ " error: brake resistor overload", "Check brake resistor/regen circuit; duty cycle.") \
_D(EXT_AXIS_ERR_POWER_LINE_OPEN, 11060, "ext axis" _PH1_ " error: motor power line open", "Check motor power cable continuity/connector.") \
_D(EXT_AXIS_ERR_HOMING, 11061, "ext axis" _PH1_ " error: homing fault", "Check homing sensor/origin procedure; retry.") \
_D(EXT_AXIS_ERR_TUNING_FAIL, 11062, "ext axis" _PH1_ " error: tuning fail", "Redo tuning; reduce resonance; check mechanics.") \
_D(EXT_AXIS_ERR_INERTIA_ID_FAIL, 11063, "ext axis" _PH1_ " error: inertia identification fail", "Check load; redo inertia ID; adjust conditions.") \
_D(EXT_AXIS_ERR_FLYAWAY, 11064, "ext axis" _PH1_ " error: flyaway", "Emergency stop; check feedback polarity/scale; inspect drive params.") \
_D(EXT_AXIS_ERR_SPEED_PULSE_OVER, 11065, "ext axis" _PH1_ " error: feedback pulse overspeed", "Check encoder feedback and scaling; reduce speed.") \
_D(EXT_AXIS_ERR_CTRL_LOOP, 11066, "ext axis" _PH1_ " error: control loop/timeout fault", "Check sampling/current loop/comm timeout; reboot.")
#define TOOL_ERRORS \
_D(TOOL_FLASH_VERIFY_FAILED, 40001, "Flash write verify failed", "suggest...") \
_D(TOOL_PROGRAM_CRC_FAILED, 40002, "Program flash checksum failed during bootloading", "suggest...") \
_D(TOOL_PROGRAM_CRC_FAILED2, 40003, "Program flash checksum failed at runtime", "suggest...") \
_D(TOOL_ID_UNDIFINED, 40004, "Tool ID is undefined", "suggest...") \
_D(TOOL_ILLEGAL_BL_CMD, 40005, "Illegal bootloader command", "suggest...") \
_D(TOOL_FW_WRONG, 40006, "Wrong firmware at the joint", "suggest...") \
_D(TOOL_HW_INVALID, 40007, "Invalid hardware revision", "suggest...") \
_D(TOOL_SHORT_CURCUIT_H, 40011, "Short circuit detected on Digital Output: " _PH1_ " high side", "suggest...") \
_D(TOOL_SHORT_CURCUIT_L, 40012, "Short circuit detected on Digital Output: " _PH1_ " low side", "suggest...") \
_D(TOOL_AVERAGE_CURR_HIGH, 40013, "10 second Average tool IO Current of " _PH1_ " A is outside of the allowed range.", "suggest...") \
_D(TOOL_POWER_PIN_OVER_CURR, 40014, "Current of " _PH1_ " A on the POWER pin is outside of the allowed range.", "suggest...") \
_D(TOOL_DOUT_PIN_OVER_CURR, 40015, "Current of " _PH1_ " A on the Digital Output pins is outside of the allowed range.", "suggest...") \
_D(TOOL_GROUND_PIN_OVER_CURR, 40016, "Current of " _PH1_ " A on the ground pin is outside of the allowed range.", "suggest...") \
_D(TOOL_RX_FRAMING, 40021, "RX framing error", "suggest...") \
_D(TOOL_RX_PARITY, 40022, "RX Parity error", "suggest...") \
_D(TOOL_48V_LOW, 40031, "48V input is too low", "suggest...") \
_D(TOOL_48V_HIGH, 40032, "48V input is too high", "suggest...") \
_D(TOOL_ERR_OFFLINE, 40033, "tool error: tool may be offline", "(a) Check tool's hardware. (b) Check joint's id.") \
_D(TOOL_ERR_BOOTLOADER, 40034, "tool error: The tool is in bootloader mode. Retry firmware update. ", "suggest...")
#define EX_TOOL_ERRORS \
_D(EX_TOOL_EC_LOW_VOLTAGE, 40101, "tool error: low voltage", "check tool power supply voltage") \
_D(EX_TOOL_EC_FORCESENSOR_COMM, 40102, "tool error: external force sensor communication error", "check external force sensor communication connection") \
_D(EX_TOOL_485_SENDFULL_COMM, 40103, "tool error: 485 transparent transmission buffer full", "check 485 communication load and transmission frequency") \
_D(EX_TOOL_FORCESENSOR_FILTER_ZERO, 40104, "tool error: force sensor filter parameter is zero", "check force sensor filter parameter configuration") \
_D(EX_TOOL_EC_UNKNOWN, 40200, "tool error: unknown error", "check controller logs and hardware status")
#define PEDSTRAL_ERRORS \
_D(PKG_LOST, 50001, "Lost package from pedestal", "suggest...") \
_D(PEDSTRAL_OFFLINE, 50002, "pedestal error: pedestal may be offline", "(a) Check pedestal's hardware. (b) Check pedestal's id.") \
_D(PEDESTAL_ERR_BOOTLOADER, 50003, "pedestal error: The pedestal is in bootloader mode. Retry firmware update. ", "suggest...")
#define EX_PEDSTRAL_ERRORS \
_D(EX_BASE_EC_LOW_VOLTAGE, 50101, "pedstral error: low voltage", "check power supply voltage and battery status") \
_D(EX_BASE_EC_OVER_TEMPERATURE_RES, 50102, "pedstral error: resistor over temperature", "check braking resistor temperature and cooling condition") \
_D(EX_BASE_EC_OVER_TARGET_BRAKE_OPEN_VOLT, 50103, "pedstral error: input voltage close to or exceeds regenerative brake activation voltage", "check input power voltage and regenerative braking configuration") \
_D(EX_BASE_EC_RES_BREAKAGE, 50104, "pedstral error: brake resistor breakage", "check whether the brake resistor is disconnected or damaged") \
_D(EX_BASE_EC_IMU_CALIBRATE, 50105, "pedstral error: IMU calibration required", "perform IMU calibration according to maintenance procedure") \
_D(EX_BASE_EC_TEMP_SENSOR_SHORT, 50106, "pedstral error: temperature sensor short circuit", "check temperature sensor wiring and solder joints for short circuit") \
_D(EX_BASE_EC_TEMP_SENSOR_BREAK, 50107, "pedstral error: temperature sensor open circuit", "check temperature sensor connection and cable continuity") \
_D(EX_BASE_EC_96V_INSTANT_OVER_VOLTAGE, 50108, "pedstral error: 96V instantaneous over voltage after regenerative braking", "check regenerative braking behavior and power bus voltage") \
_D(EX_BASE_EC_UNKNOWN, 50200, "pedstral error: unknown error", "check controller logs and hardware status")
#define SAFETY_INTERFACE_BOARD_ERRORS \
_D(IFB_ERR_ROBOTTYPE, 20001, "Robot error type!", "suggest...") \
_D(IFB_ERR_ADXL_SENS, 20002, "Base Acceleration sensor error!", "suggest...") \
_D(IFB_ERR_EN_LINE, 20003, "Encoder line error!", "suggest...") \
_D(IFB_ERR_ENTER_HDG_MODE, 20004, "Robot enter handguide mode!", "suggest...") \
_D(IFB_ERR_EXIT_HDG_MODE, 20005, "Robot exit handguide mode!", "suggest...") \
_D(IFB_ERR_MAC_DATA_BREAK, 20006, "MAC data break!", "suggest...") \
_D(IFB_ERR_DRV_FIRMWARE_VERSION, 20007, "Motor driver firmware version error!", "suggest...") \
_D(INIT_ERR_EN_DRV, 20008, "Motor driver enable failed!", "suggest...") \
_D(INIT_ERR_EN_AUTO_BACK, 20009, "Motor driver enable auto back failed!", "suggest...") \
_D(INIT_ERR_EN_CUR_LOOP, 20010, "Motor driver enable current loop failed!", "suggest...") \
_D(INIT_ERR_SET_TAG_CUR, 20011, "Motor driver set target current failed!", "suggest...") \
_D(INIT_ERR_RELEASE_BRAKE, 20012, "Motor driver release brake failed!", "suggest...") \
_D(INIT_ERR_EN_POS_LOOP, 20013, "Motor driver enable postion loop failed!", "suggest...") \
_D(INIT_ERR_SET_MAX_ACC, 20014, "Motor set max accelerate failed!", "suggest...") \
_D(SAFETY_ERR_PROTECTION_STOP_TIMEOUT, 20015, "Protective stop timeout!", "suggest...") \
_D(SAFETY_ERR_REDUCED_MODE_TIMEOUT, 20016, "Reduced mode timeout!", "suggest...") \
_D(SYS_ERR_MCU_COM, 20017, "Robot system error: mcu communication error!", "suggest...") \
_D(SYS_ERR_RS485_COM, 20018, "Robot system error: RS485 communication error!", "suggest...") \
_D(IFB_ERR_DISCONNECTED, 20019, "Interface board may be disconnected. Please check connection between IPC and Interface board.", "suggest...")\
_D(IFB_ERR_PAYLOAD_ERROR, 20020, "Payload error.", "suggest...") \
_D(IFB_OFFLINE, 20021, "ifaceboard error: ifaceboard may be offline", "(a) Check ifaceboard's hardware. (b) Check ifaceboard's id.") \
_D(IFB_ERR_BOOTLOADER, 20022, "ifaceboard error: The ifaceboard is in bootloader mode. Retry firmware update. ", "suggest...") \
_D(IFB_SLAVE_OFFLINE, 20023, "interface slave board error: interface slave board may be offline", "(a) Check interface slave board's hardware. (b) Check interface slave board's id.") \
_D(IFB_SLAVE_ERR_BOOTLOADER, 20024, "interface slave board error: The interface slave board is in bootloader mode. Retry firmware update. ", "suggest...") \
_D(IFB_TOOL_ERR_ADXL_SENS, 20025, "Tool Acceleration sensor error!", "suggest...") \
_D(HANDLE_OFFLINE, 20026, "handle error: handle may be offline", "(a) Check handle's hardware. (b) Check handle's id.") \
_D(HANDLE_ERR_BOOTLOADER, 20027, "handle error: The handle is in bootloader mode. Retry firmware update. ", "suggest...") \
_D(IFB_POWERLOSS_OFFLINE, 20028, "interface powerloss board error: interface powerloss board may be offline", "(a) Check interface powerloss board's hardware. (b) Check interface powerloss board's id.") \
_D(IFB_POWERLOSS_ERR_BOOTLOADER, 20029, "interface powerloss board error: The interface powerloss board is in bootloader mode. Retry firmware update. ", "suggest...") \
_D(HANDLE_COMM_ERROR, 20030, "handle error: handle comm error", "(a) Check handle's hardware. (b) Check handle's id.")
#define HARDWARE_INTERFACE_ERRORS \
_D(HW_SCB_SETUP_FAILED, 60001, "Setup of Interface Board failed", "suggest...") \
_D(HW_PKG_CNT_DISAGEE, 60002, "Packet counter disagreements", "suggest...") \
_D(HW_SCB_DISCONNECT, 60003, "Connection to Interface Board lost", "suggest...") \
_D(HW_SCB_PKG_LOST, 60004, "Package lost from Interface Board", "suggest...") \
_D(HW_SCB_CONN_INIT_FAILED, 60005, "Ethernet connection initialization with Interface Board failed", "suggest...") \
_D(HW_LOST_JOINT_PKG, 60006, "Lost package from joint " _PH1_ "", "suggest...") \
_D(HW_LOST_TOOL_PKG, 60007, "Lost package from tool", "suggest...") \
_D(HW_JOINT_PKG_CNT_DISAGREE, 60008, "Packet counter disagreement in packet from joint " _PH1_ "", "suggest...") \
_D(HW_TOOL_PKG_CNT_DISAGREE, 60009, "Packet counter disagreement in packet from tool", "suggest...") \
_D(HW_JOINTS_FAULT, 60011, "" _PH1_ " joint entered the Fault State", "suggest...") \
_D(HW_JOINTS_VIOLATION, 60012, "" _PH1_ " joint entered the Violation State", "suggest...") \
_D(HW_TP_FAULT, 60013, "Teach Pendant entered the Fault State", "suggest...") \
_D(HW_TP_VIOLATION, 60014, "Teach Pendant entered the Violation State", "suggest...") \
_D(HW_JOINT_MV_TOO_FAR, 60021, "" _PH1_ " joint moved too far before robot entered RUNNING State", "suggest...") \
_D(HW_JOINT_STOP_NOT_FAST, 60022, "Joint Not stopping fast enough", "suggest...") \
_D(HW_JOINT_MV_LIMIT, 60023, "Joint moved more than allowable limit", "suggest...") \
_D(HW_FT_SENSOR_DATA_INVALID, 60024, "Force-Torque Sensor data invalid", "suggest...") \
_D(HW_NO_FT_SENSOR, 60025, "Force-Torque sensor is expected, but it cannot be detected", "suggest...") \
_D(HW_FT_SENSOR_NOT_CALIB, 60026, "Force-Torque sensor is detected but not calibrated", "suggest...") \
_D(HW_RELEASE_BRAKE_FAILED, 60030, "Robot was not able to brake release, see log for details", "suggest...") \
_D(HW_OVERCURR_SHUTDOWN, 60040, "Overcurrent shutdown", "suggest...") \
_D(HW_ENERGEY_SURPLUS, 60050, "Energy surplus shutdown", "suggest...") \
_D(HW_IDLE_POWER_HIGH, 60060, "Idle power consumption to high", "suggest...") \
_D(HW_ENTER_COLLISION_TIMEOUT, 60071, "Enter collision stop procedure timeout", "suggest...") \
_D(HW_POWERON_TIMEOUT, 60072, "Poweron robot timeout", "suggest...") \
_D(HW_NO_NIC_FOUND, 60073, "No network cards found.", "suggest...") \
_D(HW_IFB_NOT_FOUND, 60074, "No Interface Board found.", "suggest...") \
_D(HW_IFB_BOOTLOAD, 60075, "The Interface Board is in bootloader mode. Update firmware firstly.", "suggest...") \
_D(HW_TOOL_NOT_FOUND, 60076, "No Tool Board found.", "suggest...") \
_D(HW_BASE_NOT_FOUND, 60077, "No Base Board found.", "suggest...") \
_D(HW_BRINGUP_TIMEOUT, 60078, "Poweron robot timeout", "suggest...") \
_D(HW_COLLISION_RECOVERY_FAILED, 60079, "Collision recovery failed", "suggest...") \
_D(HW_TP_ENABLED, 60080, "Teach pendant enabled status changed to " _PH1_, "suggest...")
// clang-format on
// 定义硬件抽象层的错误代码
#define HAL_ERRORS \
JOINT_ERRORS \
JOINT_EX_ERRORS \
EXT_AXIS_ERRORS \
SAFETY_INTERFACE_BOARD_ERRORS \
TOOL_ERRORS \
EX_TOOL_ERRORS \
PEDSTRAL_ERRORS \
EX_PEDSTRAL_ERRORS \
HARDWARE_INTERFACE_ERRORS
#endif // AUBO_SDK_JOINT_ERROR_H

View File

@ -0,0 +1,187 @@
/** @file rtm_error.h
* @brief 运行时错误码
*/
#ifndef AUBO_SDK_RTM_ERROR_H
#define AUBO_SDK_RTM_ERROR_H
// clang-format off
#define RTM_ERRORS \
_D(ROBOT_BE_PULLING, 30001, "Something is pulling the robot.","Please check TCP configuration,payload and mounting settings") \
_D(PSTOP_ELBOW_POS, 30002, "Protective Stop: Elbow position close to safety plane limits.","Please move robot Elbow joint away from the safety plane") \
_D(PSTOP_STOP_TIME, 30003, "Protective Stop: Exceeding user safety settings for stopping time.","(a) Check speeds and accelerations in the program (b) Check usage of TCP,payload and CoG correctly (c) Check external equipmentactivation if correctly set") \
_D(PSTOP_STOP_DISTANCE, 30004, "Protective Stop: Exceeding user safety settings for stopping distance.","(a) Check speeds and accelerations in the program (b) Check usage of TCP,payload and CoG correctly (c) Check external equipmentactivation if correctly set") \
_D(PSTOP_CLAMP, 30005, "Protective Stop: Danger of clamping between the Robot’s lower arm and tool.","(a) Check speeds and accelerations in the program (b) Check usage of TCP,payload and CoG correctly (c) Check external equipmentactivation if correctly set") \
_D(PSTOP_POS_LIMIT, 30006, "Protective Stop: Position close to joint limits", "suggest...") \
_D(PSTOP_ORI_LIMIT, 30007, "Protective Stop: Tool orientation close to limits", "suggest...") \
_D(PSTOP_PLANE_LIMIT, 30008, "Protective Stop: Position close to safety plane limits", "suggest...") \
_D(PSTOP_POS_DEVIATE, 30009, "Protective Stop: Position deviates from path", "Check payload, center of gravity and acceleration settings.") \
_D(JOINT_CHK_PAYLOAD, 30010, "Joint " _PH1_ ": Check payload, center of gravity and acceleration settings. Log screen may contain additional information.", "suggest...") \
_D(PSTOP_SINGULARITY, 30011, "Protective Stop: Position in singularity.","Please use MoveJ or change the motion") \
_D(PSTOP_CANNOT_MAINTAIN, 30012, "Protective Stop: Robot cannot maintain its position, check if payload is correct", "suggest...") \
_D(PSTOP_WRONG_PAYLOAD, 30013, "Protective Stop: Wrong payload or mounting detected, or something is pushing the robot when entering Freedrive mode","Verify that the TCP configuration and mounting in the used installation is correct") \
_D(PSTOP_JOINT_COLLISION, 30014, "Protective Stop: Collision detected by joint " _PH1_, "Make sure no objects are in the path of the robot and resume the program") \
_D(PSTOP_POS_DISAGREE, 30015, "Protective stop: The robot was powered off last time due to a joint position disagreement."," (a) Verify that the robot position in the 3D graphics matches the real robot, to ensure that the encoders function before releasing the brakes. Stand back and monitor the robot performing its first program cycle as expected. (b) If the position is not correct, the robot must be repaired. In this case, click Power Off Robot. (c) If the position is correct, please tick the check box below the 3D graphics and click Robot Position Verified") \
_D(TARGET_JOINT_SPEED_EXCEED, 30016, "Target joint speed exceed limits", "suggest...") \
_D(TARGET_POS_SUDDEN_CHG, 30017, "Sudden change in target position", "suggest...") \
_D(SUDDEN_STOP, 30018, "Sudden stop."," To abort a motion, use \"stopj\" or \"stopl\" script commands to generate a smooth deceleration before using \"wait\". Avoid aborting motions between waypoints with blend”") \
_D(ROBOT_STOP_ABNORMAL, 30019, "Robot has not stopped in the allowed reaction and braking time", "suggest...") \
_D(PROG_INVALID_SETP, 30020, "Robot program resulted in invalid setpoint.", "Please review waypoints in the program") \
_D(BLEND_INVALID_SETP, 30021, "Blending failed and resulted in an invalid setpoint.", "Try changing the blend radius or contact technical support") \
_D(APPROACH_SINGULARITY, 30022, "Robot approaching singularity – Acceleration threshold failed.","Review waypoints in the program, try using MoveJ instead of MoveL in the position close to singularity") \
_D(TSPEED_UNMATCH_POS, 30023, "Target speed does not match target position", "suggest...") \
_D(INCONSIS_TPOS_SPD, 30024, "Inconsistency between target position and speed", "suggest...") \
_D(JOINT_TSPD_UNMATCH_POS, 30025, "Target joint speed does not match target joint position change – Joint " _PH1_ "", "suggest...") \
_D(FIELDBUS_INPUT_DISCONN, 30026, "Fieldbus input disconnected.","Please check fieldbus connections (RTDE, ModBus, EtherNet/IP and Profinet) or disable the fieldbus in the installation. Check RTDE watchdog feature. Check if a URCap is using this feature.") \
_D(OPMODE_CHANGED, 30027, "Operational mode changed: " _PH1_ "", "suggest...") \
_D(NO_KIN_CALIB, 30028, "No Kinematic Calibration found (calibration.conf file is either corrupt or missing).","A new kinematics calibration may be needed if the robot needs to improve its kinematics, otherwise, ignore this message)") \
_D(KIN_CALIB_UNMATCH_JOINT, 30029, "Kinematic Calibration for the robot does not match the joint(s).", "If moving a program from a different robot to this one, rekinematic calibrate the second robot to improve kinematics, otherwise ignore this message.") \
_D(KIN_CALIB_UNMATCH_ROBOT, 30030, "Kinematic Calibration does not match the robot.","Please check if the serial number of the robot arm matches the Control Box") \
_D(JOINT_OFFSET_CHANGED, 30031, "Large movement of the robot detected while it was powered off. The joints were moved while it was powered off, or the encoders do not function", "suggest...") \
_D(OFFSET_CHANGE_HIGH, 30032, "Change in offset is too high", "suggest...") \
_D(JOINT_SPEED_LIMIT, 30033, "Close to joint speed safety limit.", "Review program speed and acceleration") \
_D(TOOL_SPEED_LIMIT, 30034, "Close to tool speed safety limit.", "Review program speed and acceleration") \
_D(MOMENTUM_LIMIT, 30035, "Close to momentum safety limit.", "Review program speed and acceleration") \
_D(ROBOT_MV_STOP, 30036, "Robot is moving when in Stop Mode", "suggest...") \
_D(HAND_PROTECTION, 30037, "Hand protection: Tool is too close to the lower arm: " _PH1_ " meter.","(a) Check wrist position. (b) Verify mounting (c) Do a Complete rebooting sequence (d) Update software (e) Contact your local AUBO Robots service provider for assistance") \
_D(WRONG_SAFETYMODE, 30038, "Wrong safety mode: " _PH1_, "suggest...") \
_D(SAFETYMODE_CHANGED, 30039, "Safety mode changed: " _PH1_, "suggest...") \
_D(JOINT_ACC_LIMIT, 30040, "Close to joint acceleration safety limit", "suggest...") \
_D(TOOL_ACC_LIMIT, 30041, "Close to tool acceleration safety limit", "suggest...") \
_D(JOINT_TEMPERATURE_LIMIT, 30042, "Joint " _PH1_ " temperature too high(>" _PH2_ "℃)", "suggest...") \
_D(CONTROL_BOX_TEMPERATURE_LIMIT, 30043, "Control box temperature too high(>" _PH1_ "℃)", "suggest...") \
_D(ROBOT_EMERGENCY_STOP, 30044, "Robot emergency stop", "suggest...") \
_D(ROBOTMODE_CHANGED, 30045, "Robot mode changed: " _PH1_, "suggest...") \
_D(ROBOTMODE_ERROR, 30046, "Wrong robot mode: " _PH1_, "suggest...") \
_D(POSE_OUT_OF_REACH, 30047, "Target pose [" _PH1_ "] out of reach", "suggest...") \
_D(TP_PLAN_FAILED, 30048, "Trajectory plan FAILED." , "suggest...") \
_D(START_FORCE_FAILED, 30049, "Start force control failed, because force sensor does not exist." , "suggest...") \
_D(OVER_SAFE_PLANE_LIMIT,30050, _PH1_ " axis exceeds the safety plane limit (Move_type:" _PH2_ " id:" _PH3_ ").","Please move the robot to the safety plane range.") \
_D(POWERON_FAIL_VIOLATION,30051, "Failed to power on because the robot safety mode is in violation", "suggest...") \
_D(POWERON_FAIL_SYSTEMEMERGENCYSTOP, 30052, "Failed to power on because the robot safety mode is in system emergency stop", "suggest...") \
_D(POWERON_FAIL_ROBOTEMERGENCYSTOP, 30053, "Failed to power on because the robot safety mode is in robot emergency stop", "Pop up the red emergency stop button on the teach pendant when the robot is in a safe range of motion") \
_D(POWERON_FAIL_FAULT, 30054, "Failed to power on because the robot safety mode is in fault", "suggest...") \
_D(STARTUP_FAIL_VIOLATION, 30055, "Failed to startup because the robot safety mode is in violation", "suggest...") \
_D(STARTUP_FAIL_SYSTEMEMERGENCYSTOP, 30056, "Failed to startup because the robot safety mode is in system emergency stop", "suggest...") \
_D(STARTUP_FAIL_ROBOTEMERGENCYSTOP, 30057, "Failed to startup because the robot safety mode is in robot emergency stop", "Pop up the red emergency stop button on the teach pendant when the robot is in a safe range of motion") \
_D(STARTUP_FAIL_FAULT, 30058, "Failed to startup because the robot safety mode is in fault", "suggest...") \
_D(BACKDRIVE_FAIL_VIOLATION, 30059, "Failed to backdrive because the robot safety mode is in violation", "suggest...") \
_D(BACKDRIVE_FAIL_SYSTEMEMERGENCYSTOP, 30060, "Failed to backdrive because the robot safety mode is in system emergency stop", "suggest...") \
_D(BACKDRIVE_FAIL_ROBOTEMERGENCYSTOP, 30061, "Failed to backdrive because the robot safety mode is in robot emergency stop", "Pop up the red emergency stop button on the teach pendant when the robot is in a safe range of motion") \
_D(BACKDRIVE_FAIL_FAULT, 30062, "Failed to backdrive because the robot safety mode is in fault", "suggest...") \
_D(SETSIM_FAIL_VIOLATION, 30063, "Switch sim mode failed because the robot safety mode is in violation", "suggest...") \
_D(SETSIM_FAIL_SYSTEMEMERGENCYSTOP, 30064, "Switch sim mode failed because the robot safety mode is in system emergency stop", "suggest...") \
_D(SETSIM_FAIL_ROBOTEMERGENCYSTOP, 30065, "Switch sim mode failed because the robot safety mode is in robot emergency stop", "Pop up the red emergency stop button on the teach pendant when the robot is in a safe range of motion") \
_D(SETSIM_FAIL_FAULT, 30066, "Switch sim mode failed because the robot safety mode is in fault", "suggest...") \
_D(FREEDRIVE_FAIL_VIOLATION, 30067, "Enable handguide mode failed because the robot safety mode is in violation", "suggest...") \
_D(FREEDRIVE_FAIL_SYSTEMEMERGENCYSTOP, 30068, "Enable handguide mode failed because the robot safety mode is in system emergency stop", "suggest...") \
_D(FREEDRIVE_FAIL_ROBOTEMERGENCYSTOP, 30069, "Enable handguide mode failed because the robot safety mode is in robot emergency stop", "Pop up the red emergency stop button on the teach pendant when the robot is in a safe range of motion") \
_D(FREEDRIVE_FAIL_FAULT, 30070, "Enable handguide mode failed because the robot safety mode is in fault", "suggest...") \
_D(UPFIRMWARE_FAIL_VIOLATION, 30071, "Firmware update failed because the robot safety mode is in violation", "suggest...") \
_D(UPFIRMWARE_FAIL_SYSTEMEMERGENCYSTOP, 30072, "Firmware update failed because the robot safety mode is in system emergency stop", "suggest...") \
_D(UPFIRMWARE_FAIL_ROBOTEMERGENCYSTOP, 30073, "Firmware update failed because the robot safety mode is in robot emergency stop", "Pop up the red emergency stop button on the teach pendant when the robot is in a safe range of motion") \
_D(UPFIRMWARE_FAIL_FAULT, 30074, "Firmware update failed because the robot safety mode is in fault", "suggest...") \
_D(SETPERSOSTENT_FAIL_VIOLATION, 30075, "Set persistent parameter failed because the robot safety mode is in violation", "suggest...") \
_D(SETPERSOSTENT_FAIL_SYSTEMEMERGENCYSTOP, 30076, "Set persistent parameter failed because the robot safety mode is in system emergency stop", "suggest...") \
_D(SETPERSOSTENT_FAIL_ROBOTEMERGENCYSTOP, 30077, "Set persistent parameter failed because the robot safety mode is in robot emergency stop", "Pop up the red emergency stop button on the teach pendant when the robot is in a safe range of motion") \
_D(SETPERSOSTENT_FAIL_FAULT, 30078, "Set persistent parameter failed because the robot safety mode is in fault", "suggest...") \
_D(SETPERSOSTENT_FAIL_PARAM_ERR, 30079, "Set persistent parameter failed", "(a) Check the parameter format, whether all are floating point numbers") \
_D(ROBOT_CABLE_DISCONN, 30080, "Robot cable not connected", "(a) Make sure the cable between Control Box and Robot Arm is correctly connected and it has no damage. (b) Check for loose connections (c) Do a Complete rebooting sequence (d) Update software (e) Contact your local AUBO Robots service provider for assistance Contact your local AUBO Robots service provider for assistance.") \
_D(TP_TOO_SHORT, 30081, "The generated trajectory is ignored because it is too short", "(a) Please check if the added waypoints are coincident (b) If it is an arc movement, please check whether the three points are collinear") \
_D(INV_KIN_FAIL, 30082, "Inverse kinematics solution failed. The target pose may be in a singular position or exceed the joint limits", "(a) Change the target pose and try moving again") \
_D(FREEDRIVE_ENABLED, 30083, "Freedrive status changed to " _PH1_ "", "suggest...") \
_D(TP_INV_FAIL_REFERENCE_JOINT_OUT_OF_LIMIT, 30084, "Inverse kinematics solution failed. Reference angle [" _PH1_ "] exceeds joint limit [" _PH2_ "].", "suggest...") \
_D(TP_INV_FAIL_NO_SOLUTION, 30085, "Inverse kinematics solution failed. The reference angle [" _PH1_ "] and the target angle [" _PH2_ "] are used as parameters. there is no solution in the calculation of the inverse solution process.", "suggest...")\
_D(SERVO_FAIL_VIOLATION, 30086, "Switch servo mode failed because the robot safety mode is in violation", "suggest...") \
_D(SERVO_FAIL_SYSTEMEMERGENCYSTOP, 30087, "Switch servo mode failed because the robot safety mode is in system emergency stop", "suggest...") \
_D(SERVO_FAIL_ROBOTEMERGENCYSTOP, 30088, "Switch servo mode failed because the robot safety mode is in robot emergency stop", "Pop up the red emergency stop button on the teach pendant when the robot is in a safe range of motion") \
_D(SERVO_FAIL_FAULT, 30089, "Switch servo mode failed because the robot safety mode is in fault", "suggest...") \
_D(FREEDRIVE_FAIL_NO_RUNNING, 30090, "Enable handguide mode failed because the robot mode type is " _PH1_ "(not running)", "suggest...") \
_D(RUNTIME_MACHINE_ERROR, 30091, "The state of the running machine is " _PH1_ ", not " _PH2_ ". " _PH3_ " function execution failed because the state is wrong." , "suggest...") \
_D(RESUME_FAR_PAUSE_PT, 30092, "Cannot resume from joint position [" _PH1_ "].\\nToo far away from paused point [" _PH2_ "]." , "suggest...") \
_D(PAYLOAD_LIGHTER_ERROR, 30093, "The payload setting is too small!" , "suggest...") \
_D(PAYLOAD_OVERLOAD_ERROR, 30094, "The payload setting is too large!" , "suggest...") \
_D(PAUSE_FAIL_NOT_POSITION_PLAN_MODE, 30095, "This motion does not support the pause function. The motion is stopping." , "suggest...") \
_D(TP_PLAN_FAILED_CIRCULAR_WAYPOINTS_COINCIDE, 30096, "The planning failed because the three waypoints of the arc were determined to coincide." , "Check the circular waypoints to make sure they are different.") \
_D(SERVO_WRONG_SAFETYMODE, 30097, "Switch servo mode failed because the robot safety mode is in " _PH1_ "." , "Check the circular waypoints to make sure they are different.") \
_D(SET_PERSTPARAM_WRONG_SAFETYMODE, 30098, "Set persistent parameter failed because the robot safety mode is in " _PH1_ , "suggest...") \
_D(SET_KINPARAM_WRONG_SAFETYMODE, 30099, "Set Kinematics Compensate parameters failed because the robot safety mode is in " _PH1_ , "suggest...") \
_D(SET_ROBOT_ZERO_WRONG_SAFETYMODE, 30100, "Set current joint angles to zero failed because the robot safety mode is in " _PH1_ , "suggest...") \
_D(UPFIRMWARE_WRONG_SAFETYMODE, 30101, "Firmware update failed because the robot safety mode is in " _PH1_, "suggest...") \
_D(POWERON_WRONG_SAFETYMODE, 30102, "Failed to power on because the robot safety mode is in " _PH1_, "suggest...") \
_D(STARTUP_WRONG_SAFETYMODE, 30103, "Failed to startup because the robot safety mode is in " _PH1_, "suggest...") \
_D(BACKDRIVE_WRONG_SAFETYMODE, 30104, "Failed to backdrive because the robot safety mode is in system emergency stop", "suggest...") \
_D(SETSIM_WRONG_SAFETYMODE, 30105, "Switch sim mode failed because the robot safety mode is in violation", "suggest...") \
_D(FREEDRIVE_WRONG_SAFETYMODE, 30106, "Enable handguide mode failed because the robot safety mode is in wrong safety mode: " _PH1_, "suggest...") \
_D(TP_PLAN_FAILED_JOINT_JUMP_BIGGER, 30107, "Inverse kinematics solution failed. The target point and the current point are in different robot configuration spaces.", "Add a few more points between the target point and the current point.") \
_D(RUN_PROGRAM_FAILED, 30108, "Run program " _PH1_ " failed.", "suggset...") \
_D(FREEDRIVE_FAIL_WRONG_RTMSTATE, 30109, "Unable to enter the HandGuide mode as the robot is not currently in a stopped or paused state.", "suggset...") \
_D(SAFEGUARDSTOP_CONFIGURABLE_INPUT, 30110, "Configurable safety input is triggered.", "suggset...") \
_D(SAFEGUARDSTOP_3PE, 30111, "3PE is triggered.", "suggset...") \
_D(SAFEGUARDSTOP_SI, 30112, "SI0/SI1 is triggered.", "suggset...") \
_D(ROBOT_TYPE_CHANGED, 30200, "Robot type changed to '" _PH1_ "', and robot subtype changed to '" _PH2_ "'", "suggest...") \
_D(LINKMODE_CHANGED, 30201, "Link mode changed to " _PH1_ "", "suggest...") \
_D(ROBOT_SELF_COLLISION, 30301, "Detect risk of robot self collision", "suggest...") \
_D(CONSTANT_INVALID, 30302, "Joint torque constants are invalid. HandGuide will be disabled, and the collision protection may be triggered by mistake.", "suggest...") \
_D(GRAVITY_INVALID, 30303, "Abnormal value of gravity acceleration sensor. HandGuide will be disabled, and the collision protection may be triggered by mistake.", "suggest...") \
_D(DYNAMICS_INVALID, 30304, "Robot dynamics parameters are invalid. HandGuide will be disabled, and the collision protection may be triggered by mistake.", "suggest...") \
_D(FRICTION_INVALID, 30305, "Joint friction parameters are invalid. HandGuide will be disabled, and the collision protection may be triggered by mistake.", "suggest...") \
_D(HANDGUIDE_UNDER_DEVELOP, 30306, "Robot type of " _PH1_ " function under development. HandGuide will be disabled, and the collision protection may be triggered by mistake.", "suggest...") \
_D(SLOW_DOWN_INFO, 30307, "Slow down level changed to " _PH1_ "(" _PH2_ "%)", "suggest...") \
_D(WRONG_JOINT_DESIGNED_LIMIT, 30308, "Joint designed ranges exceeds ranges read from hardware interface.", "suggest...") \
_D(FREEDRIVE_IN_SIMULATION, 30309, "Enable handguide mode failed because the robot is in simulation mode.", "suggest...") \
_D(ROBOT_STOPPING_TIMEOUT, 30310, "Robot stopping timeout.", "suggest...") \
_D(PSTOP_INCORRECT_FORCE_OFFSET, 30311, "Protective Stop: Sudden change in force control target position. Force sensor offset may be incorrect or force sensor fault.", "suggest...") \
_D(WRONG_JOINT_SAFETY_LIMIT, 30312, "Joint safety ranges exceeds designed ranges.", "suggest...") \
_D(PSTOP_TCP_PLANE_VIOLATION, 30401, "Protective Stop: TCP position close to safety plane limits.", "suggest...") \
_D(PSTOP_ELBOW_PLANE_VIOLATION, 30402, "Protective Stop: elbow position close to safety plane limits.", "suggest...") \
_D(PSTOP_JOINT_TORQUE_VIOLATION, 30403, "Protective Stop: joint" _PH1_ " exceeds torque limit.", "suggest...") \
_D(PSTOP_JOINT_POSITION_VIOLATION, 30404, "Protective Stop: joint" _PH1_ " exceeds position limit.", "suggest...") \
_D(PSTOP_JOINT_SPEED_VIOLATION, 30405, "Protective Stop: joint" _PH1_ " exceeds speed limit.", "suggest...") \
_D(PSTOP_TCP_SPEED_VIOLATION, 30406, "Protective Stop: TCP speed close to safety limits.", "suggest...") \
_D(PSTOP_ELBOW_SPEED_VIOLATION, 30407, "Protective Stop: elbow speed close to safety limits.", "suggest...") \
_D(PSTOP_TCP_FORCE_VIOLATION, 30408, "Protective Stop: TCP foece close to safety limits.", "suggest...") \
_D(PSTOP_ELBOW_TORQUE_VIOLATION, 30409, "Protective Stop: elbow torque close to safety limits.", "suggest...") \
_D(PSTOP_POWER_VIOLATION, 30410, "Protective Stop: robot power close to safety limits.", "suggest...") \
_D(PSTOP_MOMENTUM_VIOLATION, 30411, "Protective Stop: robot momentum close to safety limits.", "suggest...") \
_D(PSTOP_TCP_CUBE_VIOLATION, 30412, "Protective Stop: TCP position close to safety cube.", "suggest...") \
_D(PSTOP_ELBOW_CUBE_VIOLATION, 30413, "Protective Stop: TCP position close to safety cube.", "suggest...") \
_D(REDUCE_ELBOW_PLANE_TRIGGER, 30414, "Reduce mode: elbow close to safety plane triggers reduction mode.", "suggest...") \
_D(REDUCE_TCP_PLANE_TRIGGER, 30415, "Reduce mode: TCP close to safety plane triggers reduction mode.", "suggest...") \
_D(PSTOP_MOVE_OUT_RANGE, 30416, "Joint " _PH1_ " has exceeded the limit, please do not continue to move out of the range", "suggest...") \
_D(RESUME_PAUSE_FAILED, 30417, "Resume Failed: Safety mode type is " _PH1_ "", "suggest...") \
_D(FIRMWARE_UPDATE_FAIL_EMERGENCYSTOP, 30418, "Failed to firmware update because the robot safety mode is in " _PH1_ , "Release emergency stop when the robot is in a safe range of motion") \
_D(TOOL_SENSOR_CHANGED, 30419, "Tool sensor type changed to " _PH1_ "", "suggest...") \
_D(TOOL_SENSOR_REMOVED, 30420, "Tool sensor is removed.", "suggest...") \
_D(CAL_TARGET_CURRENT_ERR, 30421, "The calculation of the target current failed. Please try again later.", "suggest...") \
_D(CONVEYOR_MODE_CHANGED, 30422, "Conveyor" _PH1_ ": track mode changed to " _PH2_ ", track item id is " _PH3_, "suggest...") \
_D(CONVEYOR_ENQUEUE, 30423, "Conveyor" _PH1_ ": the queue has been changed, item" _PH2_ " is enqueue", "suggest...") \
_D(CONVEYOR_DEQUEUE_FINISH, 30424, "Conveyor" _PH1_ ": the queue has been changed, item" _PH2_ " dequeue due to track finished", "suggest...") \
_D(CONVEYOR_DEQUEUE_STARTWINDOW, 30425, "Conveyor" _PH1_ ": the queue has been changed, item" _PH2_ " dequeue due to exceeds startwindow", "suggest...") \
_D(CONVEYOR_DEQUEUE_LIMIT, 30426, "Conveyor" _PH1_ ": the queue has been changed, item" _PH2_ " dequeue due to exceed limit area", "suggest...") \
_D(CONVEYOR_DEQUEUE_CLEAR, 30427, "Conveyor" _PH1_ ": item queue is cleared", "suggest...") \
_D(CONVEYOR_NEXT_TRACK, 30428, "Conveyor" _PH1_ ": item" _PH2_ " inside the start window that can be tracked ", "suggest...") \
_D(CONVEYOR_EXCEED_LIMIT, 30429, "Conveyor" _PH1_ ": item" _PH2_ " exceeds the limit area during tracking", "suggest...") \
_D(WRONG_POWER_SAFETY_LIMIT, 30430, "Robot power safety value exceeds designed value.", "suggest...") \
_D(WRONG_POWER_DESIGNED_LIMIT, 30431, "Power designed value exceeds value read from hardware interface.", "suggest...") \
_D(TOOL_SENSOR_STATUS_CHANGED, 30432, "Tool sensor status changed to " _PH1_, "suggest...") \
_D(COLLISION_THRESHOLD_INVALID, 30433, "Robot collision threshold parameters are invalid.Please reidentify the threshold or modify the configuration to ensure that it does not cause accidental collisions.", "suggest...") \
_D(GRIPPER_DISCONNECT, 30434, "The gripper " _PH1_ " is disconnected.", "suggest...") \
_D(GRIPPER_UNKNOWN_FAULT, 30435, "There is an unknown fault with the gripper " _PH1_ , "suggest...") \
_D(GRIPPER_CURRENT_ANOMALY_FAULT, 30436, "There is an abnormal current fault with the gripper " _PH1_ , "suggest...") \
_D(GRIPPER_VOLTAGE_ANOMALY_FAULT, 30437, "There is an abnormal voltage fault with the gripper " _PH1_ , "suggest...") \
_D(GRIPPER_OVER_TEMPERATURE_FAULT, 30438, "There is an over-temperature fault with the gripper " _PH1_ , "suggest...") \
_D(GRIPPER_INTERNAL_FAULT, 30439, "There is an internal fault with the gripper " _PH1_ , "suggest...") \
_D(GRIPPER_COMMUNICATION_FAULT, 30440, "There is an communication fault with the gripper " _PH1_ , "suggest...") \
_D(GRIPPER_CONTROL_COMMAND_FAULT, 30441, "There is an control command fault with the gripper " _PH1_ , "suggest...") \
_D(GRIPPER_ENABLE_FAULT, 30442, "There is an enable fault with the gripper " _PH1_ , "suggest...") \
_D(WRIST_SINGULARITY_RISK, 30443,"Wrist singularity detected. Linear motion may cause excessive joint speed.Adjust robot posture to avoid J5 near 0° or 180°, or use joint motion instead of linear motion.","suggest...") \
_D(PSTOP_PATH_OFFSET_OVER_LIMIT, 30444, "Protective Stop: the offset of the robot has exceeded the limit.", "suggest...") \
_D(EXT_AXIS_SET_PARAM_FAILED_BUSY, 30445, "Set external axis parameter " _PH1_ " failed because the robot mode is in " _PH2_ ". Please power off the robot before changing this parameter.", "Power off the robot and try again.") \
_D(WRONG_JOINT_POS_LIMIT, 30446, "Joint limit max pos less than min pos.", "suggest...") \
_D(WRONG_JOINT_VEL_LIMIT, 30447, "Joint limit max vel is invalid.", "suggest...") \
_D(AUTO_RESUME_FAR_PAUSE_PT, 30448, "Robot is still paused after switching to automatic mode. Current joint position [" _PH1_ "] is too far away from pause position [" _PH2_ "]. Resuming directly may cause collision.", "Move the robot back to the pause position or stop the program before resuming.") \
_D(CONVEYOR_TRACK_CAPACITY_EXCEEDED, 30449, "Conveyor" _PH1_ ": item" _PH2_ " tracking capacity exceeded, tracking stop started. Capacity usage is " _PH3_ "%, actual conveyor speed is " _PH4_ " m/s.", "Reduce conveyor speed, shorten tracking distance, or adjust tracking posture.")
// clang-format on
#endif // AUBO_SDK_RTM_ERROR_H

View File

@ -0,0 +1,60 @@
/** @file system_error.h
* @brief 系统错误码
*/
#ifndef AUBO_SDK_SYSTEM_ERROR_H
#define AUBO_SDK_SYSTEM_ERROR_H
#define SYSTEM_ERRORS \
_D(DEBUG, 0, "Debug message " _PH1_, "suggest...") \
_D(POPUP, 1, "Popup title: " _PH1_ ", msg: " _PH2_ ", mode: " _PH3_, \
"suggest...") \
_D(POPUP_DISMISS, 2, _PH1_, "suggest...") \
_D(SYSTEM_HALT, 3, _PH1_, "suggest...") \
_D(INV_ARGUMENTS, 4, "Invalid arguments.", "suggest...") \
_D(USER_NOTIFY, 5, _PH1_, "suggest...") \
_D(POPUP_DISMISS_BY_ID, 6, _PH1_, "suggest...") \
_D(MODBUS_SIGNAL_CREATED, 10, "Modbus signal " _PH1_ " created.", \
"suggest...") \
_D(MODBUS_SIGNAL_REMOVED, 11, "Modbus signal " _PH1_ " removed.", \
"suggest...") \
_D(MODBUS_SIGNAL_VALUE_CHANGED, 12, \
"Modbus signal " _PH1_ " value changed to " _PH2_, "suggest...") \
_D(RUNTIME_CONTEXT, 13, \
"tid: " _PH1_ " lineno: " _PH2_ " index: " _PH3_ " comment: " _PH4_, \
"suggest...") \
_D(INTERP_CONTEXT, 14, \
"tid: " _PH1_ " lineno: " _PH2_ " index: " _PH3_ " comment: " _PH4_, \
"suggest...") \
_D(PROGRAM_LOADED, 15, "program loaded: " _PH1_, "suggest...") \
_D(TASK_DELETED, 16, "tid: " _PH1_, " was deleted") \
_D(MODBUS_SLAVE_BIT, 20, "Modbus slave address: " _PH1_ " value " _PH2_, \
"suggest...") \
_D(MODBUS_SLAVE_REG, 21, "Modbus slave address: " _PH1_ " value " _PH2_, \
"suggest...") \
_D(PNIO_SLAVE_SLOT_VALUE, 30, \
"PNIO slot: " _PH1_ " subslot " _PH2_ " index " _PH3_ " value " _PH4_, \
"suggest...") \
_D(PNIO_CONNECT_STATUS, 31, "PNIO connection status changed to " _PH1_, \
"suggest...") \
_D(PNIO_DEVICE_NAME, 32, "PNIO device name changed to " _PH1_, \
"suggest...") \
_D(PNIO_IP, 33, "PNIO ip " _PH1_ " mask " _PH2_ " gateway " _PH3_, \
"suggest...") \
_D(ICM_SERVER_STATUS, 40, " ICM server status changed to " _PH1_, \
"suggest...") \
_D(EIP_SLAVE_VALUE, 50, \
"EIP slave: trans_type " _PH1_ " index " _PH2_ " value " _PH3_, \
"suggest...") \
_D(EIP_SLAVE_CONNECT_STATUS, 51, \
"EIP slave connection status changed to " _PH1_, "suggest...") \
_D(LOG_PROGRAM_SUCCESS, 100, \
"[" _PH1_ "] Load program " _PH2_ " successful", "suggest...") \
_D(LOG_PROGRAM_FAILED, 101, \
"[" _PH1_ "] Load program " _PH2_ " failed, file not found", \
"suggest...") \
_D(LOG_PROGRAM_FAILED2, 102, \
"[" _PH1_ "] Load program " _PH2_ \
" failed, configuration file (.ins) does not match", \
"suggest...")
#endif // AUBO_SDK_SYSTEM_ERROR_H

View File

@ -0,0 +1,178 @@
/*
global_config.h
this file is generated. Do not change!
*/
#ifndef ARCS_GLOBALCONFIG_H
#define ARCS_GLOBALCONFIG_H
/* #undef ARCS_BUILD_SHARED_LIBS */
/* #undef ARCS_ENABLE_THREADING_SUPPORT */
//-------------------------------------------------------------------
// Header Availability
//-------------------------------------------------------------------
/* #undef ARCS_HAVE_CXXABI_H */
//-------------------------------------------------------------------
// Version information
//-------------------------------------------------------------------
#define INTERFACE_VERSION_MAJOR 0
#define INTERFACE_VERSION_MINOR 26
#define INTERFACE_VERSION_PATCH 0
#define INTERFACE_VERSION "0.26.0"
//-------------------------------------------------------------------
// Platform defines
//-------------------------------------------------------------------
#if defined(__APPLE__)
#define ARCS_PLATFORM_APPLE
#endif
#if defined(__linux__)
#define ARCS_PLATFORM_LINUX
#endif
#if defined(_WIN32) || defined(_WIN64)
#define ARCS_PLATFORM_WINDOWS
#else
#define ARCS_PLATFORM_POSIX
#endif
/* #undef ARCS_BIG_ENDIAN */
/* #undef ARCS_LITTLE_ENDIAN */
#define ARCS_LIB_PREFIX "lib"
#define ARCS_LIB_EXT ".so"
#define ARCS_EXE_EXT ""
#ifdef NDEBUG // Defined by cmake UNLESS Debug build type is chosen
#define ARCS_LIB_POSTFIX ""
#else
#define ARCS_LIB_POSTFIX \
"" // Set in top level CMakeList.txt
#endif
#define ARCS_FUNCTION // 函数接口
#define ARCS_INSTRUCT // 指令接口
///-------------------------------------------------------------------
// Macros for import/export declarations
//-------------------------------------------------------------------
#if defined(ARCS_PLATFORM_WINDOWS)
#define ARCS_ABI_EXPORT __declspec(dllexport)
#define ARCS_ABI_IMPORT __declspec(dllimport)
#define ARCS_ABI_LOCAL
#elif defined(ARCS_HAVE_VISIBILITY_ATTRIBUTE)
#define ARCS_ABI_EXPORT __attribute__((visibility("default")))
#define ARCS_ABI_IMPORT __attribute__((visibility("default")))
#define ARCS_ABI_LOCAL __attribute__((visibility("hidden")))
#else
#define ARCS_ABI_EXPORT
#define ARCS_ABI_IMPORT
#define ARCS_ABI_LOCAL
#endif
#ifdef ARCS_BUILDING_STAGE
#define ARCS_ABI ARCS_ABI_EXPORT
#else
#define ARCS_ABI ARCS_ABI_IMPORT
#endif
//-------------------------------------------------------------------
// Macros for suppressing warnings
//-------------------------------------------------------------------
#ifdef _MSC_VER
#define ARCS_MSVC_PUSH_DISABLE_WARNING(wn) \
__pragma(warning(push)) __pragma(warning(disable : wn))
#define ARCS_MSVC_POP_WARNING __pragma(warning(pop))
#define ARCS_MSVC_DISABLE_WARNING(wn) __pragma(warning(disable : wn))
#else
#define ARCS_MSVC_PUSH_DISABLE_WARNING(wn)
#define ARCS_MSVC_POP_WARNING
#define ARCS_MSVC_DISABLE_WARNING(wn)
#endif
#ifdef __GNUC__
#define aubo_gcc_pragma_expand(x) _Pragma(#x)
#define ARCS_GCC_PUSH_DISABLE_WARNING(wn) \
_Pragma("GCC diagnostic push") \
aubo_gcc_pragma_expand(GCC diagnostic ignored "-W" #wn)
#define ARCS_GCC_POP_WARNING _Pragma("GCC diagnostic pop")
#else
#define ARCS_GCC_PUSH_DISABLE_WARNING(wn)
#define ARCS_GCC_POP_WARNING
#endif
#if defined(__GNUC__)
#define ARCS_DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define ARCS_DEPRECATED __declspec(deprecated)
#else
#pragma message( \
"WARNING: You need to implement ARCS_DEPRECATED for your compiler!")
#define ARCS_DEPRECATED
#endif
// Do not warn about the usage of deprecated unsafe functions
ARCS_MSVC_DISABLE_WARNING(4996)
// Mark a variable or expression result as unused
#define ARCS_UNUSED(x) (void)(x)
//-------------------------------------------------------------------
// C++ Language features
//-------------------------------------------------------------------
/* #undef ARCS_HAVE_THREAD_LOCAL */
//-------------------------------------------------------------------
// C++ Library features
//-------------------------------------------------------------------
/* #undef ARCS_HAVE_REGEX */
//-------------------------------------------------------------------
// Hash Container
//-------------------------------------------------------------------
#define ARCS_HASH_FUNCTION_BEGIN(type) \
namespace std { \
template <> \
struct hash<type> \
{ \
std::size_t operator()(const type &arg) const \
{
#define ARCS_HASH_FUNCTION_END \
} \
} \
; \
}
//-------------------------------------------------------------------
// Utility macros
//-------------------------------------------------------------------
#define ARCS_STR_(x) #x
#define ARCS_STR(x) ARCS_STR_(x)
#define ARCS_CONCAT_(x, y) x##y
#define ARCS_CONCAT(x, y) ARCS_CONCAT_(x, y)
//-------------------------------------------------------------------
// Backwards compatibility macros
//-------------------------------------------------------------------
#if !defined(__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 7
#define ARCS_FUTURE_READY true
#define ARCS_FUTURE_TIMEOUT false
#else
#define ARCS_FUTURE_READY std::future_status::ready
#define ARCS_FUTURE_TIMEOUT std::future_status::timeout
#endif
#endif // ARCS_GLOBALCONFIG_H

View File

@ -0,0 +1,320 @@
/** @file gripper_interface.h
* @brief 通用夹爪接口
*/
#ifndef AUBO_SDK_GRIPPER_INTERFACE_H
#define AUBO_SDK_GRIPPER_INTERFACE_H
#include <aubo/sync_move.h>
#include <aubo/trace.h>
namespace arcs {
namespace common_interface {
/**
* \chinese
* @defgroup GripperInterface GripperInterface (夹爪)
* 通用夹爪API接口
* \endchinese
*
* \english
* @defgroup GripperInterface Gripper Interface
* Common Gripper API interface
* \endenglish
*/
class ARCS_ABI_EXPORT GripperInterface
{
public:
GripperInterface();
virtual ~GripperInterface();
/**
* @ingroup GripperInterface
* \chinese
* 获取支持的所有夹爪
*
* @return
* \endchinese
*/
std::vector<std::string> gripperGetSupportedModels();
/**
* @ingroup GripperInterface
* \chinese
* 扫描该型号下的所有设备
*
* @param model 夹爪品牌型号
* @param device_name 设备名
* @return 成功返回设备列表和0,失败返回错误码
* \endchinese
*/
ResultWithErrno2 gripperScanDevices(const std::string &model,
const std::string &device_name);
/**
* @ingroup GripperInterface
* \chinese
* 获取已添加的夹爪
* @return
*/
std::vector<std::string> gripperGetNames();
/**
* @ingroup GripperInterface
* \chinese
* 添加夹爪
*
* @param name 用户自定义名字,唯一
* @param model 夹爪品牌及型号
* @return 成功返回0,失败返回错误码
* \endchinese
*/
int gripperAdd(const std::string &name, const std::string &model);
/**
* @ingroup GripperInterface
* \chinese
* 删除夹爪
*
* @param name 用户自定义名字
* @return 成功返回0,失败返回错误码
* \endchinese
*/
int gripperDelete(const std::string &name);
/**
* @ingroup GripperInterface
* \chinese
* 删除所有夹爪
*
* @return 成功返回0,失败返回错误码
* \endchinese
*/
int gripperDeleteAll();
/**
* @ingroup GripperInterface
* \chinese
* 修改夹爪名
*
* @param name
* @param new_name 新名字
* @return 成功返回0,失败返回错误码
* \endchinese
*/
int gripperRename(const std::string &name, const std::string &new_name);
/**
* @ingroup GripperInterface
* \chinese
* 夹爪连接
*
* @param name
* @param device_name 设备名
* @return 成功返回0,失败返回错误码
* \endchinese
*/
int gripperConnect(const std::string &name, const std::string &device_name);
/**
* @ingroup GripperInterface
* \chinese
* 夹爪断开连接
*
* @param name
* @return 成功返回0,失败返回错误码
* \endchinese
*/
int gripperDisconnect(const std::string &name);
/**
* @ingroup GripperInterface
* \chinese
* 夹爪是否连接
*
* @param name
* @return 已连接返回true,未连接返回false
* \endchinese
*/
bool gripperIsConnected(const std::string &name);
/**
* @ingroup GripperInterface
* \chinese
* 设置工作模式
*
* @param name
* @param work_mode 工作模式
* @return 成功返回0,失败返回错误码
* \endchinese
*/
int gripperSetWorkMode(const std::string &name, int work_mode);
/**
* @ingroup GripperInterface
* \chinese
* 获取工作模式
*
* @param name
* @return 返回工作模式
* \endchinese
*/
int gripperGetWorkMode(const std::string &name);
/**
* @ingroup GripperInterface
* \chinese
* 设置夹爪安装偏移
*
* @param name
* @param isVisibled 是否显示
* @param pose 末端(不包括手指)相对法兰的位姿
* @return 成功返回true,失败返回false
* \endchinese
*/
int gripperSetMountPose(const std::string &name,
const std::vector<double> &pose,
bool enable_collision);
/**
* @brief 获取夹爪安装偏移
* @param name
* @return 返回夹爪安装偏移
*/
std::vector<double> gripperGetMountPose(const std::string &name);
/**
* @ingroup GripperInterface
* \chinese
* 使能夹爪
*
* @param name
* @return
* \endchinese
*/
int gripperEnable(const std::string &name, bool enable);
/**
* \chinese
* 等待夹爪使能完成(硬件激活),超时15s
* 初始化成功后再添加 gripper_link 到运动学模型
*
* @param name 夹爪名称
* @return 成功返回0,超时返回错误码
* \endchinese
*/
int gripperWaitEnableFinished(const std::string &name);
/**
* @ingroup GripperInterface
* \chinese
* 夹爪是否使能
*
* @param name
* @return
* \endchinese
*/
bool gripperIsEnabled(const std::string &name);
/**
* @ingroup GripperInterface
* \chinese
* 设置运动参数
*
* @param name
* @param position 位置,单位:m/Pa
* @param velocity_percent 速度,单位:%,范围:[0, 1]
* @param force 夹持力,单位:N
* @param angle 旋转角度,单位:rad
* @param r_velocity_percent 旋转速度,单位:%,范围:[0, 1]
* @param torque_percent 旋转扭矩,单位:%,范围:[0, 1]
*
* @return
* \endchinese
*/
int gripperSetPosition(const std::string &name, const double position);
int gripperSetVelocity(const std::string &name,
const double velocity_percent);
int gripperSetForce(const std::string &name, const double force);
int gripperSetAngle(const std::string &name, const double angle);
int gripperSetRVelocity(const std::string &name,
const double r_velocity_percent);
int gripperSetTorque(const std::string &name, const double torque_percent);
/**
* @ingroup GripperInterface
* \chinese
* 开始运动
*
* @param name
* @return
* \endchinese
*/
int gripperMove(const std::string &name);
/**
* @ingroup GripperInterface
* \chinese
* 停止运动
*
* @param name
* @return
* \endchinese
*/
int gripperStop(const std::string &name);
/**
* @ingroup GripperInterface
* \chinese
* 获取夹爪状态
*
* @param name
* @return
*
* @note 位置,速度,夹持力,旋转角度,旋转速度,旋转扭矩的单位与Set接口一致
*
* \endchinese
*/
std::string gripperGetHardwareVersion(const std::string &name);
std::string gripperGetSoftwareVersion(const std::string &name);
double gripperGetPosition(const std::string &name);
double gripperGetVelocity(const std::string &name);
double gripperGetForce(const std::string &name);
double gripperGetAngle(const std::string &name);
double gripperGetRVelocity(const std::string &name);
double gripperGetTorque(const std::string &name);
bool gripperGetObjectDetection(const std::string &name);
bool gripperGetMotionState(const std::string &name);
double gripperGetVoltage(const std::string &name);
double gripperGetTemperature(const std::string &name);
/**
* @ingroup GripperInterface
* \chinese
* 重置modbus从站ID
*
* @param name
* @param slave_id 从站Id
* @return
* \endchinese
*/
int gripperResetSlaveId(const std::string &name, const int slave_id);
/**
* @ingroup GripperInterface
* \chinese
* 获取夹爪状态
* @param name
* @return 状态
* \endchinese
*/
int gripperGetStatusCode(const std::string &name);
protected:
void *d_;
};
using GripperInterfacePtr = std::shared_ptr<GripperInterface>;
} // namespace common_interface
} // namespace arcs
#endif // AUBO_SDK_GRIPPER_INTERFACE_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,403 @@
/** @file robot_interface.h
* @brief 机器人API 接口
*/
#ifndef AUBO_SDK_ROBOT_INTERFACE_H
#define AUBO_SDK_ROBOT_INTERFACE_H
#include <aubo/sync_move.h>
#include <aubo/trace.h>
#include <aubo/robot/motion_control.h>
#include <aubo/robot/force_control.h>
#include <aubo/robot/io_control.h>
#include <aubo/robot/robot_algorithm.h>
#include <aubo/robot/robot_state.h>
#include <aubo/robot/robot_manage.h>
#include <aubo/robot/robot_config.h>
#include <aubo/global_config.h>
namespace arcs {
namespace common_interface {
/**
* \chinese
* @defgroup RobotInterface RobotInterface(机器人模块)
* 机器人模块
* \endchinese
*
* \english
* @defgroup RobotInterface Robot Module
* Robot Module
* \endenglish
*/
class ARCS_ABI_EXPORT RobotInterface
{
public:
RobotInterface();
virtual ~RobotInterface();
/**
* @ingroup RobotInterface
* @ref RobotConfig
* \chinese
* 获取RobotConfig接口
*
* @return RobotConfigPtr对象的指针
*
* @par Python函数原型
* getRobotConfig(self: pyaubo_sdk.RobotInterface) ->
* arcs::common_interface::RobotConfig
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* RobotConfigPtr ptr =
* rpc_cli->getRobotInterface(robot_name)->getRobotConfig();
* @endcode
* \endchinese
* \english
* Get RobotConfig interface
*
* @return Pointer to RobotConfig object
*
* @par Python function prototype
* getRobotConfig(self: pyaubo_sdk.RobotInterface) ->
* arcs::common_interface::RobotConfig
*
* @par C++ example
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* RobotConfigPtr ptr =
* rpc_cli->getRobotInterface(robot_name)->getRobotConfig();
* @endcode
* \endenglish
*/
RobotConfigPtr getRobotConfig();
/**
* @ingroup RobotInterface
* @ref MotionControl
* \chinese
* 获取运动规划接口
*
* @return MotionControlPtr对象的指针
*
* @par Python函数原型
* getMotionControl(self: pyaubo_sdk.RobotInterface) ->
* arcs::common_interface::MotionControl
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* MotionControlPtr ptr =
* rpc_cli->getRobotInterface(robot_name)->getMotionControl();
* @endcode
* \endchinese
* \english
* Get motion planning interface
*
* @return Pointer to MotionControl object
*
* @par Python function prototype
* getMotionControl(self: pyaubo_sdk.RobotInterface) ->
* arcs::common_interface::MotionControl
*
* @par C++ example
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* MotionControlPtr ptr =
* rpc_cli->getRobotInterface(robot_name)->getMotionControl();
* @endcode
* \endenglish
*/
MotionControlPtr getMotionControl();
/**
* @ingroup RobotInterface
* @ref ForceControl
* \chinese
* 获取力控接口
*
* @return ForceControlPtr对象的指针
*
* @par Python函数原型
* getForceControl(self: pyaubo_sdk.RobotInterface) ->
* arcs::common_interface::ForceControl
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* ForceControlPtr ptr =
* rpc_cli->getRobotInterface(robot_name)->getForceControl();
* @endcode
* \endchinese
* \english
* Get force control interface
*
* @return Pointer to ForceControl object
*
* @par Python function prototype
* getForceControl(self: pyaubo_sdk.RobotInterface) ->
* arcs::common_interface::ForceControl
*
* @par C++ example
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* ForceControlPtr ptr =
* rpc_cli->getRobotInterface(robot_name)->getForceControl();
* @endcode
* \endenglish
*/
ForceControlPtr getForceControl();
/**
* @ingroup RobotInterface
* @ref IoControl
* \chinese
* 获取IO控制的接口
*
* @return IoControlPtr对象的指针
*
* @par Python函数原型
* getIoControl(self: pyaubo_sdk.RobotInterface) ->
* arcs::common_interface::IoControl
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* IoControlPtr ptr =
* rpc_cli->getRobotInterface(robot_name)->getIoControl();
* @endcode
* \endchinese
* \english
* Get IO control interface
*
* @return Pointer to IoControl object
*
* @par Python function prototype
* getIoControl(self: pyaubo_sdk.RobotInterface) ->
* arcs::common_interface::IoControl
*
* @par C++ example
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* IoControlPtr ptr =
* rpc_cli->getRobotInterface(robot_name)->getIoControl();
* @endcode
* \endenglish
*/
IoControlPtr getIoControl();
/**
* @ingroup RobotInterface
* @ref SyncMove
* \chinese
* 获取同步运动接口
*
* @return SyncMovePtr对象的指针
*
* @par Python函数原型
* getSyncMove(self: pyaubo_sdk.RobotInterface) ->
* arcs::common_interface::SyncMove
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* SyncMovePtr ptr = rpc_cli->getRobotInterface(robot_name)->getSyncMove();
* @endcode
* \endchinese
* \english
* Get synchronized motion interface
*
* @return Pointer to SyncMove object
*
* @par Python function prototype
* getSyncMove(self: pyaubo_sdk.RobotInterface) ->
* arcs::common_interface::SyncMove
*
* @par C++ example
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* SyncMovePtr ptr = rpc_cli->getRobotInterface(robot_name)->getSyncMove();
* @endcode
* \endenglish
*/
SyncMovePtr getSyncMove();
/**
* @ingroup RobotInterface
* @ref RobotAlgorithm
* \chinese
* 获取机器人实用算法接口
*
* @return RobotAlgorithmPtr对象的指针
*
* @par Python函数原型
* getRobotAlgorithm(self: pyaubo_sdk.RobotInterface) ->
* arcs::common_interface::RobotAlgorithm
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* RobotAlgorithmPtr ptr =
* rpc_cli->getRobotInterface(robot_name)->getRobotAlgorithm();
* @endcode
* \endchinese
* \english
* Get robot utility algorithm interface
*
* @return Pointer to RobotAlgorithm object
*
* @par Python function prototype
* getRobotAlgorithm(self: pyaubo_sdk.RobotInterface) ->
* arcs::common_interface::RobotAlgorithm
*
* @par C++ example
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* RobotAlgorithmPtr ptr =
* rpc_cli->getRobotInterface(robot_name)->getRobotAlgorithm();
* @endcode
* \endenglish
*/
RobotAlgorithmPtr getRobotAlgorithm();
/**
* @ingroup RobotInterface
* @ref RobotManage
* \chinese
* 获取机器人管理接口(上电、启动、停止等)
*
* @return RobotManagePtr对象的指针
*
* @par Python函数原型
* getRobotManage(self: pyaubo_sdk.RobotInterface) ->
* arcs::common_interface::RobotManage
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* RobotManagePtr ptr =
* rpc_cli->getRobotInterface(robot_name)->getRobotManage();
* @endcode
* \endchinese
* \english
* Get robot management interface (power on, start, stop, etc.)
*
* @return Pointer to RobotManage object
*
* @par Python function prototype
* getRobotManage(self: pyaubo_sdk.RobotInterface) ->
* arcs::common_interface::RobotManage
*
* @par C++ example
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* RobotManagePtr ptr =
* rpc_cli->getRobotInterface(robot_name)->getRobotManage();
* @endcode
* \endenglish
*/
RobotManagePtr getRobotManage();
/**
* @ingroup RobotInterface
* @ref RobotState
* \chinese
* 获取机器人状态接口
*
* @return RobotStatePtr对象的指针
*
* @par Python函数原型
* getRobotState(self: pyaubo_sdk.RobotInterface) ->
* arcs::common_interface::RobotState
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* RobotStatePtr ptr =
* rpc_cli->getRobotInterface(robot_name)->getRobotState();
* @endcode
* \endchinese
* \english
* Get robot state interface
*
* @return Pointer to RobotState object
*
* @par Python function prototype
* getRobotState(self: pyaubo_sdk.RobotInterface) ->
* arcs::common_interface::RobotState
*
* @par C++ example
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* RobotStatePtr ptr =
* rpc_cli->getRobotInterface(robot_name)->getRobotState();
* @endcode
* \endenglish
*/
RobotStatePtr getRobotState();
/**
* @ingroup RobotInterface
* @ref Trace
* \chinese
* 获取告警信息接口
*
* @return TracePtr对象的指针
*
* @par Python函数原型
* getTrace(self: pyaubo_sdk.RobotInterface) ->
* arcs::common_interface::Trace
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* TracePtr ptr = rpc_cli->getRobotInterface(robot_name)->getTrace();
* @endcode
* \endchinese
* \english
* Get alarm information interface
*
* @return Pointer to Trace object
*
* @par Python function prototype
* getTrace(self: pyaubo_sdk.RobotInterface) ->
* arcs::common_interface::Trace
*
* @par C++ example
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* TracePtr ptr = rpc_cli->getRobotInterface(robot_name)->getTrace();
* @endcode
* \endenglish
*/
TracePtr getTrace();
protected:
void *d_;
};
using RobotInterfacePtr = std::shared_ptr<RobotInterface>;
} // namespace common_interface
} // namespace arcs
#endif // AUBO_SDK_ROBOT_INTERFACE_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,417 @@
/** @file serial.h
* @brief 串口通信
*/
#ifndef AUBO_SDK_SERIAL_INTERFACE_H
#define AUBO_SDK_SERIAL_INTERFACE_H
#include <vector>
#include <memory>
#include <aubo/type_def.h>
#include <aubo/global_config.h>
namespace arcs {
namespace common_interface {
/**
* \chinese
* @defgroup Serial Serial (串口通信)
* 串口通信
* \endchinese
*
* \english
* @defgroup Serial Serial Communication
* Serial communication
* \endenglish
*/
class ARCS_ABI_EXPORT Serial
{
public:
Serial();
virtual ~Serial();
/**
* @ingroup Serial
* \chinese
* 打开TCP/IP以太网通信串口
*
* @param device 设备名
* @param baud 波特率
* @param stop_bits 停止位
* @param even 校验位
* @param serial_name 串口名称
* @return 返回值
*
* @par Python函数原型
* serialOpen(self: pyaubo_sdk.Serial, arg0: str, arg1: int, arg2: float,
* arg3: int, arg4: str) -> int
*
* @par Lua函数原型
* serialOpen(device: string, baud: number, stop_bits: number, even: number,
* serial_name: string) -> nil
* \endchinese
* \english
* Open TCP/IP ethernet communication serial
*
* @param device
* @param baud
* @param stop_bits
* @param even
* @param serial_name
* @return
*
* @par Python function prototype
* serialOpen(self: pyaubo_sdk.Serial, arg0: str, arg1: int, arg2: float,
* arg3: int, arg4: str) -> int
*
* @par Lua function prototype
* serialOpen(device: string, baud: number, stop_bits: number, even: number,
* serial_name: string) -> nil
* \endenglish
*/
int serialOpen(const std::string &device, int baud, float stop_bits,
int even, const std::string &serial_name = "serial_0");
/**
* @ingroup Serial
* \chinese
* 关闭TCP/IP串口通信
* 关闭与服务器的串口连接。
*
* @param serial_name 串口名称
* @return 返回值
*
* @par Python函数原型
* serialClose(self: pyaubo_sdk.Serial, arg0: str) -> int
*
* @par Lua函数原型
* serialClose(serial_name: string) -> nil
* \endchinese
* \english
* Close TCP/IP serial communication
* Close down the serial connection to the server.
*
* @param serial_name
* @return
*
* @par Python function prototype
* serialClose(self: pyaubo_sdk.Serial, arg0: str) -> int
*
* @par Lua function prototype
* serialClose(serial_name: string) -> nil
* \endenglish
*/
int serialClose(const std::string &serial_name = "serial_0");
/**
* @ingroup Serial
* \chinese
* 从串口读取指定数量的字节。字节为网络字节序。一次最多可读取30个值。
*
* @param variable 变量
* @param serial_name 串口名称
* @return 返回值
*
* @par Python函数原型
* serialReadByte(self: pyaubo_sdk.Serial, arg0: str, arg1: str) -> int
*
* @par Lua函数原型
* serialReadByte(variable: string, serial_name: string) -> number
* \endchinese
* \english
* Reads a number of bytes from the serial. Bytes are in network byte
* order. A maximum of 30 values can be read in one command.
*
* @param variable
* @param serial_name
* @return
*
* @par Python function prototype
* serialReadByte(self: pyaubo_sdk.Serial, arg0: str, arg1: str) -> int
*
* @par Lua function prototype
* serialReadByte(variable: string, serial_name: string) -> number
* \endenglish
*/
int serialReadByte(const std::string &variable,
const std::string &serial_name = "serial_0");
/**
* @ingroup Serial
* \chinese
* 从串口读取指定数量的字节。字节为网络字节序。一次最多可读取30个值。
* 返回读取到的数字列表(int列表,长度=number+1)。
*
* @param number 读取的字节数
* @param variable 变量
* @param serial_name 串口名称
* @return 返回值
*
* @par Python函数原型
* serialReadByteList(self: pyaubo_sdk.Serial, arg0: int, arg1: str, arg2: str) -> int
*
* @par Lua函数原型
* serialReadByteList(number: number, variable: string, serial_name: string) -> number
* \endchinese
* \english
* Reads a number of bytes from the serial. Bytes are in network byte
* order. A maximum of 30 values can be read in one command.
* A list of numbers read (list of ints, length=number+1)
*
* @param number Number of bytes to read
* @param variable
* @param serial_name Serial port name
* @return Return value
*
* @par Python function prototype
* serialReadByteList(self: pyaubo_sdk.Serial, arg0: int, arg1: str, arg2: str) -> int
*
* @par Lua function prototype
* serialReadByteList(number: number, variable: string, serial_name: string) -> number
* \endenglish
*/
int serialReadByteList(int number, const std::string &variable,
const std::string &serial_name = "serial_0");
/**
* @ingroup Serial
* \chinese
* 从串口读取所有数据,并将数据作为字符串返回。
* 字节为网络字节序。
*
* 可选参数 "prefix" 和 "suffix" 用于指定从串口提取的内容。
* "prefix" 指定提取子串(消息)的起始位置。直到 "prefix" 结束的数据会被忽略并从串口移除。
* "suffix" 指定提取子串(消息)的结束位置。串口中 "suffix" 之后的剩余数据会被保留。
* 例如,如果串口服务器发送字符串 "noise>hello<",控制器可以通过设置 prefix=">" 和 suffix="<" 来接收 "hello"。
* 通过使用 "prefix" 和 "suffix",还可以一次向控制器发送多条字符串,因为 "suffix" 定义了消息的结束位置。
* 例如发送 ">hello<>world<"
*
* @param variable 变量
* @param serial_name 串口名称
* @param prefix 前缀
* @param suffix 后缀
* @param interpret_escape 是否解释转义字符
* @return 返回值
*
* @par Python函数原型
* serialReadString(self: pyaubo_sdk.Serial, arg0: str, arg1: str, arg2: str, arg3: str, arg4: bool) -> int
*
* @par Lua函数原型
* serialReadString(variable: string, serial_name: string, prefix: string, suffix: string, interpret_escape: boolean) -> number
* \endchinese
* \english
* Reads all data from the serial and returns the data as a string.
* Bytes are in network byte order.
*
* The optional parameters "prefix" and "suffix", can be used to express
* what is extracted from the serial. The "prefix" specifies the start
* of the substring (message) extracted from the serial. The data up to
* the end of the "prefix" will be ignored and removed from the serial.
* The "suffix" specifies the end of the substring (message) extracted
* from the serial. Any remaining data on the serial, after the "suffix",
* will be preserved. E.g. if the serial server sends a string
* "noise>hello<", the controller can receive the "hello" by calling this
* script function with the prefix=">" and suffix="<". By using the
* "prefix" and "suffix" it is also possible send multiple string to the
* controller at once, because the suffix defines where the message ends.
* E.g. sending ">hello<>world<"
*
* @param variable
* @param serial_name
* @param prefix
* @param suffix
* @param interpret_escape
* @return
*
* @par Python function prototype
* serialReadString(self: pyaubo_sdk.Serial, arg0: str, arg1: str, arg2: str, arg3: str, arg4: bool) -> int
*
* @par Lua function prototype
* serialReadString(variable: string, serial_name: string, prefix: string, suffix: string, interpret_escape: boolean) -> number
* \endenglish
*/
int serialReadString(const std::string &variable,
const std::string &serial_name = "serial_0",
const std::string &prefix = "",
const std::string &suffix = "",
bool interpret_escape = false);
/**
* @ingroup Serial
* \chinese
* 发送一个字节到服务器
* 通过串口发送字节 <value>。不期望有响应。可用于发送特殊的ASCII字符;10为换行符,2为文本开始,3为文本结束。
*
* @param value 字节值
* @param serial_name 串口名称
* @return 返回值
*
* @par Python函数原型
* serialSendByte(self: pyaubo_sdk.Serial, arg0: str, arg1: str) -> int
*
* @par Lua函数原型
* serialSendByte(value: string, serial_name: string) -> nil
* \endchinese
* \english
* Sends a byte to the server
* Sends the byte <value> through the serial. Expects no response. Can
* be used to send special ASCII characters; 10 is newline, 2 is start of
* text, 3 is end of text.
*
* @param value
* @param serial_name
* @return
*
* @par Python function prototype
* serialSendByte(self: pyaubo_sdk.Serial, arg0: str, arg1: str) -> int
*
* @par Lua function prototype
* serialSendByte(value: string, serial_name: string) -> nil
* \endenglish
*/
int serialSendByte(char value, const std::string &serial_name = "serial_0");
/**
* @ingroup Serial
* \chinese
* 发送一个整数(int32_t)到服务器
* 通过串口发送整数 <value>。以网络字节序发送。不期望有响应。
*
* @param value 整数值
* @param serial_name 串口名称
* @return 返回值
*
* @par Python函数原型
* serialSendInt(self: pyaubo_sdk.Serial, arg0: int, arg1: str) -> int
*
* @par Lua函数原型
* serialSendInt(value: number, serial_name: string) -> nil
* \endchinese
* \english
* Sends an int (int32_t) to the server
* Sends the int <value> through the serial. Send in network byte order.
* Expects no response.
*
* @param value
* @param serial_name
* @return
*
* @par Python function prototype
* serialSendInt(self: pyaubo_sdk.Serial, arg0: int, arg1: str) -> int
*
* @par Lua function prototype
* serialSendInt(value: number, serial_name: string) -> nil
* \endenglish
*/
int serialSendInt(int value, const std::string &serial_name = "serial_0");
/**
* @ingroup Serial
* \chinese
* 发送带有换行符的字符串到服务器
* 以ASCII编码通过串口发送字符串<str>,并在末尾添加换行符。不期望有响应。
*
* @param str 字符串
* @param serial_name 串口名称
* @return 返回值
*
* @par Python函数原型
* serialSendLine(self: pyaubo_sdk.Serial, arg0: str, arg1: str) -> int
*
* @par Lua函数原型
* serialSendLine(str: string, serial_name: string) -> nil
* \endchinese
* \english
* Sends a string with a newline character to the server
* Sends the string <str> through the serial in ASCII coding, appending a newline at the end. Expects no response.
*
* @param str
* @param serial_name
* @return
*
* @par Python function prototype
* serialSendLine(self: pyaubo_sdk.Serial, arg0: str, arg1: str) -> int
*
* @par Lua function prototype
* serialSendLine(str: string, serial_name: string) -> nil
* \endenglish
*/
int serialSendLine(const std::string &str,
const std::string &serial_name = "serial_0");
/**
* @ingroup Serial
* \chinese
* 发送字符串到服务器
* 以ASCII编码通过串口发送字符串<str>。不期望有响应。
*
* @param str 字符串
* @param serial_name 串口名称
* @return 返回值
*
* @par Python函数原型
* serialSendString(self: pyaubo_sdk.Serial, arg0: str, arg1: str) -> int
*
* @par Lua函数原型
* serialSendString(str: string, serial_name: string) -> nil
* \endchinese
* \english
* Sends a string to the server
* Sends the string <str> through the serial in ASCII coding. Expects no
* response.
*
* @param str
* @param serial_name
* @return
*
* @par Python function prototype
* serialSendString(self: pyaubo_sdk.Serial, arg0: str, arg1: str) -> int
*
* @par Lua function prototype
* serialSendString(str: string, serial_name: string) -> nil
* \endenglish
*/
int serialSendString(const std::string &str,
const std::string &serial_name = "serial_0");
/**
* @ingroup Serial
* \chinese
*
* @param is_check 是否校验
* @param str 字符串数组
* @param serial_name 串口名称
* @return 返回值
*
* @par Python函数原型
* serialSendAllString(self: pyaubo_sdk.Serial, arg0: bool, arg1: List[str], arg2: str) -> int
*
* @par Lua函数原型
* serialSendAllString(is_check: boolean, str: table, serial_name: string) -> nil
* \endchinese
* \english
*
* @param is_check Whether to check
* @param str Array of strings
* @param serial_name Serial port name
* @return Return value
*
* @par Python function prototype
* serialSendAllString(self: pyaubo_sdk.Serial, arg0: bool, arg1: List[str], arg2: str) -> int
*
* @par Lua function prototype
* serialSendAllString(is_check: boolean, str: table, serial_name: string) -> nil
* \endenglish
*/
int serialSendAllString(bool is_check, const std::vector<char> &str,
const std::string &serial_name = "serial_0");
protected:
void *d_;
};
using SerialPtr = std::shared_ptr<Serial>;
} // namespace common_interface
} // namespace arcs
#endif

View File

@ -0,0 +1,667 @@
/** @file socket.h
* @brief socket通信
*/
#ifndef AUBO_SDK_SOCKET_INTERFACE_H
#define AUBO_SDK_SOCKET_INTERFACE_H
#include <vector>
#include <memory>
#include <aubo/type_def.h>
#include <aubo/global_config.h>
namespace arcs {
namespace common_interface {
/**
* \chinese
* @defgroup Socket Socket (socket网络通信)
* 串口通信
* \endchinese
*
* \english
* @defgroup Socket Socket Network Communication
* Socket communication
* \endenglish
*/
class ARCS_ABI_EXPORT Socket
{
public:
Socket();
virtual ~Socket();
/**
* @ingroup Socket
* \english
* Open TCP/IP ethernet communication socket
*
* Instruction
*
* @param address
* @param port
* @param socket_name
* @return
*
* @par Python function prototype
* socketOpen(self: pyaubo_sdk.Socket, arg0: str, arg1: int, arg2: str) -> int
*
* @par Lua function prototype
* socketOpen(address: string, port: number, socket_name: string) -> nil
*
* @par JSON-RPC request example
* {"jsonrpc":"2.0","method":"Socket.socketOpen","params":["172.16.26.248",8000,"socket_0"],"id":1}
*
* @par JSON-RPC response example
* {"id":1,"jsonrpc":"2.0","result":0}
* \endenglish
* \chinese
* 打开TCP/IP以太网通信socket
*
* 指令
*
* @param address 地址
* @param port 端口
* @param socket_name 套接字名称
* @return 返回值
*
* @par Python函数原型
* socketOpen(self: pyaubo_sdk.Socket, arg0: str, arg1: int, arg2: str) -> int
*
* @par Lua函数原型
* socketOpen(address: string, port: number, socket_name: string) -> nil
*
* @par JSON-RPC请求示例
* {"jsonrpc":"2.0","method":"Socket.socketOpen","params":["172.16.26.248",8000,"socket_0"],"id":1}
*
* @par JSON-RPC响应示例
* {"id":1,"jsonrpc":"2.0","result":0}
* \endchinese
*/
int socketOpen(const std::string &address, int port,
const std::string &socket_name = "socket_0");
/**
* @ingroup Socket
* \english
* Closes TCP/IP socket communication
* Closes down the socket connection to the server.
*
* Instruction
*
* @param socket_name
* @return
*
* @par Python function prototype
* socketClose(self: pyaubo_sdk.Socket, arg0: str) -> int
*
* @par Lua function prototype
* socketClose(socket_name: string) -> nil
*
* @par JSON-RPC request example
* {"jsonrpc":"2.0","method":"Socket.socketClose","params":["socket_0"],"id":1}
*
* @par JSON-RPC response example
* {"id":1,"jsonrpc":"2.0","result":0}
* \endenglish
* \chinese
* 关闭TCP/IP socket 通信
* 关闭与服务器的 socket 连接。
*
* 指令
*
* @param socket_name 套接字名称
* @return 返回值
*
* @par Python函数原型
* socketClose(self: pyaubo_sdk.Socket, arg0: str) -> int
*
* @par Lua函数原型
* socketClose(socket_name: string) -> nil
*
* @par JSON-RPC请求示例
* {"jsonrpc":"2.0","method":"Socket.socketClose","params":["socket_0"],"id":1}
*
* @par JSON-RPC响应示例
* {"id":1,"jsonrpc":"2.0","result":0}
* \endchinese
*/
int socketClose(const std::string &socket_name = "socket_0");
/**
* @ingroup Socket
* \english
* Reads a number of ascii formatted floats from the socket. A maximum
* of 30 values can be read in one command.
* A list of numbers read (list of floats, length=number+1)
*
* Result will be stored in a register named reg_key. Use getFloatVec
* to retrieve data
*
* @param number
* @param variable
* @param socket_name
* @return
*
* @par Python function prototype
* socketReadAsciiFloat(self: pyaubo_sdk.Socket, arg0: int, arg1: str, arg2:
* str) -> int
*
* @par Lua function prototype
* socketReadAsciiFloat(number: number, variable: string, socket_name:
* string) -> number
* \endenglish
* \chinese
* 从socket读取指定数量的ASCII格式浮点数。一次最多可读取30个值。
* 读取到的数字列表(浮点数列表,长度=number+1)
*
* 结果将存储在名为reg_key的寄存器中。使用getFloatVec获取数据
*
* @param number 数量
* @param variable 变量名
* @param socket_name 套接字名称
* @return 返回值
*
* @par Python函数原型
* socketReadAsciiFloat(self: pyaubo_sdk.Socket, arg0: int, arg1: str, arg2:
* str) -> int
*
* @par Lua函数原型
* socketReadAsciiFloat(number: number, variable: string, socket_name:
* string) -> number
* \endchinese
*/
int socketReadAsciiFloat(int number, const std::string &variable,
const std::string &socket_name = "socket_0");
/**
* @ingroup Socket
* \english
* Reads a number of 32 bit integers from the socket. Bytes are in
* network byte order. A maximum of 30 values can be read in one
* command.
* A list of numbers read (list of ints, length=number+1)
*
* Instruction
*
* std::vector<int>
*
* @param number
* @param variable
* @param socket_name
* @return
*
* @par Python function prototype
* socketReadBinaryInteger(self: pyaubo_sdk.Socket, arg0: int, arg1: str,
* arg2: str) -> int
*
* @par Lua function prototype
* socketReadBinaryInteger(number: number, variable: string, socket_name:
* string) -> number
* \endenglish
* \chinese
* 从socket读取指定数量的32位整数。字节为网络字节序。一次最多可读取30个值。
* 读取到的数字列表(整数列表,长度=number+1)
*
* 指令
*
* std::vector<int>
*
* @param number 数量
* @param variable 变量名
* @param socket_name 套接字名称
* @return 返回值
*
* @par Python函数原型
* socketReadBinaryInteger(self: pyaubo_sdk.Socket, arg0: int, arg1: str,
* arg2: str) -> int
*
* @par Lua函数原型
* socketReadBinaryInteger(number: number, variable: string, socket_name:
* string) -> number
* \endchinese
*/
int socketReadBinaryInteger(int number, const std::string &variable,
const std::string &socket_name = "socket_0");
/**
* @ingroup Socket
* \english
* Reads a number of bytes from the socket. Bytes are in network byte
* order. A maximum of 30 values can be read in one command.
* A list of numbers read (list of ints, length=number+1)
*
* Instruction
*
* std::vector<char>
*
* @param number
* @param variable
* @param socket_name
* @return
*
* @par Python function prototype
* socketReadByteList(self: pyaubo_sdk.Socket, arg0: int, arg1: str, arg2:
* str) -> int
*
* @par Lua function prototype
* socketReadByteList(number: number, variable: string, socket_name: string)
* -> number
* \endenglish
* \chinese
* 从socket读取指定数量的字节。字节为网络字节序。一次最多可读取30个值。
* 读取到的数字列表(整数列表,长度=number+1)
*
* 指令
*
* std::vector<char>
*
* @param number 数量
* @param variable 变量名
* @param socket_name 套接字名称
* @return 返回值
*
* @par Python函数原型
* socketReadByteList(self: pyaubo_sdk.Socket, arg0: int, arg1: str, arg2:
* str) -> int
*
* @par Lua函数原型
* socketReadByteList(number: number, variable: string, socket_name: string)
* -> number
* \endchinese
*/
int socketReadByteList(int number, const std::string &variable,
const std::string &socket_name = "socket_0");
/**
* @ingroup Socket
* \english
* Reads all data from the socket and returns the data as a string.
* Bytes are in network byte order.
*
* The optional parameters "prefix" and "suffix", can be used to express
* what is extracted from the socket. The "prefix" specifies the start
* of the substring (message) extracted from the socket. The data up to
* the end of the "prefix" will be ignored and removed from the socket.
* The "suffix" specifies the end of the substring (message) extracted
* from the socket. Any remaining data on the socket, after the "suffix",
* will be preserved. E.g. if the socket server sends a string
* "noise>hello<", the controller can receive the "hello" by calling this
* script function with the prefix=">" and suffix="<". By using the
* "prefix" and "suffix" it is also possible send multiple string to the
* controller at once, because the suffix defines where the message ends.
* E.g. sending ">hello<>world<"
*
* Instruction
*
* std::string
*
* @param variable
* @param socket_name
* @param prefix
* @param suffix
* @param interpret_escape
* @return
*
* @par Python function prototype
* socketReadString(self: pyaubo_sdk.Socket, arg0: str, arg1: str, arg2:
* str, arg3: str, arg4: bool) -> int
*
* @par Lua function prototype
* socketReadString(variable: string, socket_name: string, prefix: string,
* suffix: string, interpret_escape: boolean) -> number
*
* @par JSON-RPC request example
* {"jsonrpc":"2.0","method":"Socket.socketReadString","params":["camera","socket_0","","",false],"id":1}
*
* @par JSON-RPC response example
* {"id":1,"jsonrpc":"2.0","result":0}
* \endenglish
* \chinese
* 从socket读取所有数据并将其作为字符串返回。
* 字节为网络字节序。
*
* 可选参数"prefix"和"suffix"可用于指定从socket中提取的内容。
* "prefix"指定提取子字符串(消息)的起始位置。直到"prefix"结尾的数据将被忽略并从socket中移除。
* "suffix"指定提取子字符串(消息)的结束位置。"suffix"之后的任何剩余数据将保留在socket中。
* 例如,如果socket服务器发送字符串"noise>hello<",控制器可以通过调用此脚本函数并设置prefix=">"和suffix="<"来接收"hello"。
* 通过使用"prefix"和"suffix",还可以一次向控制器发送多条字符串,因为"suffix"定义了消息的结束位置。例如发送">hello<>world<"
*
* 指令
*
* std::string
*
* @param variable 变量名
* @param socket_name 套接字名称
* @param prefix 前缀
* @param suffix 后缀
* @param interpret_escape 是否解释转义字符
* @return 返回值
*
* @par Python函数原型
* socketReadString(self: pyaubo_sdk.Socket, arg0: str, arg1: str, arg2:
* str, arg3: str, arg4: bool) -> int
*
* @par Lua函数原型
* socketReadString(variable: string, socket_name: string, prefix: string,
* suffix: string, interpret_escape: boolean) -> number
*
* @par JSON-RPC请求示例
* {"jsonrpc":"2.0","method":"Socket.socketReadString","params":["camera","socket_0","","",false],"id":1}
*
* @par JSON-RPC响应示例
* {"id":1,"jsonrpc":"2.0","result":0}
* \endchinese
*/
int socketReadString(const std::string &variable,
const std::string &socket_name = "socket_0",
const std::string &prefix = "",
const std::string &suffix = "",
bool interpret_escape = false);
/**
* @ingroup Socket
* \english
* Reads all data from the socket and returns the data as a vector of chars.
*
* Instruction
* std::vector<char>
*
* @param variable
* @param socket_name
* @return
*
* @par Python function prototype
* socketReadAllString(self: pyaubo_sdk.Socket, arg0: str, arg1: str) -> int
*
* @par Lua function prototype
* socketReadAllString(variable: string, socket_name: string) -> number
*
* @par JSON-RPC request example
* {"jsonrpc":"2.0","method":"Socket.socketReadAllString","params":["camera","socket_0"],"id":1}
*
* @par JSON-RPC response example
* {"id":1,"jsonrpc":"2.0","result":0}
* \endenglish
* \chinese
* 从socket读取所有数据并将其作为char向量返回。
*
* 指令
* std::vector<char>
*
* @param variable 变量名
* @param socket_name 套接字名称
* @return 返回值
*
* @par Python函数原型
* socketReadAllString(self: pyaubo_sdk.Socket, arg0: str, arg1: str) -> int
*
* @par Lua函数原型
* socketReadAllString(variable: string, socket_name: string) -> number
*
* @par JSON-RPC请求示例
* {"jsonrpc":"2.0","method":"Socket.socketReadAllString","params":["camera","socket_0"],"id":1}
*
* @par JSON-RPC响应示例
* {"id":1,"jsonrpc":"2.0","result":0}
* \endchinese
*/
int socketReadAllString(const std::string &variable,
const std::string &socket_name = "socket_0");
/**
* @ingroup Socket
* \english
* Sends a byte to the server
* Sends the byte <value> through the socket. Expects no response. Can
* be used to send special ASCII characters; 10 is newline, 2 is start of
* text, 3 is end of text.
*
* Instruction
*
* @param value
* @param socket_name
* @return
*
* @par Python function prototype
* socketSendByte(self: pyaubo_sdk.Socket, arg0: str, arg1: str) -> int
*
* @par Lua function prototype
* socketSendByte(value: string, socket_name: string) -> nil
*
* \endenglish
* \chinese
* 发送一个字节到服务器
* 通过socket发送字节<value>,不期望响应。可用于发送特殊ASCII字符;10为换行符,2为文本开始,3为文本结束。
*
* 指令
*
* @param value 字节值
* @param socket_name 套接字名称
* @return 返回值
*
* @par Python函数原型
* socketSendByte(self: pyaubo_sdk.Socket, arg0: str, arg1: str) -> int
*
* @par Lua函数原型
* socketSendByte(value: string, socket_name: string) -> nil
*
* \endchinese
*/
int socketSendByte(char value, const std::string &socket_name = "socket_0");
/**
* @ingroup Socket
* \english
* Sends an int (int32_t) to the server
* Sends the int <value> through the socket. Send in network byte order.
* Expects no response
*
* Instruction
*
* @param value
* @param socket_name
* @return
*
* @par Python function prototype
* socketSendInt(self: pyaubo_sdk.Socket, arg0: int, arg1: str) -> int
*
* @par Lua function prototype
* socketSendInt(value: number, socket_name: string) -> nil
*
* \endenglish
* \chinese
* 发送一个int(int32_t)到服务器
* 通过socket发送int <value>,以网络字节序发送。不期望响应。
*
* 指令
*
* @param value 整数值
* @param socket_name 套接字名称
* @return 返回值
*
* @par Python函数原型
* socketSendInt(self: pyaubo_sdk.Socket, arg0: int, arg1: str) -> int
*
* @par Lua函数原型
* socketSendInt(value: number, socket_name: string) -> nil
*
* \endchinese
*/
int socketSendInt(int value, const std::string &socket_name = "socket_0");
/**
* @ingroup Socket
* \english
* Sends a string with a newline character to the server
* Sends the string <str> through the socket in ASCII coding. Expects no
* response.
*
* Instruction
*
* @param str
* @param socket_name
* @return
*
* @par Python function prototype
* socketSendLine(self: pyaubo_sdk.Socket, arg0: str, arg1: str) -> int
*
* @par Lua function prototype
* socketSendLine(str: string, socket_name: string) -> nil
*
* @par JSON-RPC request example
* {"jsonrpc":"2.0","method":"Socket.socketSendLine","params":["abcd","socket_0"],"id":1}
*
* @par JSON-RPC response example
* {"id":1,"jsonrpc":"2.0","result":0}
* \endenglish
* \chinese
* 发送带有换行符的字符串到服务器.
* 通过socket以ASCII编码发送字符串<str>,不期望响应。
*
* 指令
*
* @param str 字符串
* @param socket_name 套接字名称
* @return 返回值
*
* @par Python函数原型
* socketSendLine(self: pyaubo_sdk.Socket, arg0: str, arg1: str) -> int
*
* @par Lua函数原型
* socketSendLine(str: string, socket_name: string) -> nil
*
* @par JSON-RPC请求示例
* {"jsonrpc":"2.0","method":"Socket.socketSendLine","params":["abcd","socket_0"],"id":1}
*
* @par JSON-RPC响应示例
* {"id":1,"jsonrpc":"2.0","result":0}
* \endchinese
*/
int socketSendLine(const std::string &str,
const std::string &socket_name = "socket_0");
/**
* @ingroup Socket
* \english
* Sends a string to the server
* Sends the string <str> through the socket in ASCII coding. Expects no
* response.
*
* Instruction
*
* @param str
* @param socket_name
* @return
*
* @par Python function prototype
* socketSendString(self: pyaubo_sdk.Socket, arg0: str, arg1: str) -> int
*
* @par Lua function prototype
* socketSendString(str: string, socket_name: string) -> nil
*
* @par JSON-RPC request example
* {"jsonrpc":"2.0","method":"Socket.socketSendString","params":["abcd","socket_0"],"id":1}
*
* @par JSON-RPC response example
* {"id":1,"jsonrpc":"2.0","result":0}
* \endenglish
* \chinese
* 发送字符串到服务器
* 通过socket以ASCII编码发送字符串<str>,不期望响应。
*
* 指令
*
* @param str 字符串
* @param socket_name 套接字名称
* @return 返回值
*
* @par Python函数原型
* socketSendString(self: pyaubo_sdk.Socket, arg0: str, arg1: str) -> int
*
* @par Lua函数原型
* socketSendString(str: string, socket_name: string) -> nil
*
* @par JSON-RPC请求示例
* {"jsonrpc":"2.0","method":"Socket.socketSendString","params":["abcd","socket_0"],"id":1}
*
* @par JSON-RPC响应示例
* {"id":1,"jsonrpc":"2.0","result":0}
* \endchinese
*/
int socketSendString(const std::string &str,
const std::string &socket_name = "socket_0");
/**
* @ingroup Socket
* \english
* Sends all data in the given vector of chars to the server.
*
* @param is_check Whether to check the sending status
* @param str The data to send as a vector of chars
* @param socket_name The name of the socket
* @return Status code
*
* @par Python function prototype
* socketSendAllString(self: pyaubo_sdk.Socket, arg0: bool, arg1: List[str], arg2: str) -> int
*
* @par Lua function prototype
* socketSendAllString(is_check: boolean, str: table, socket_name: string) -> nil
* \endenglish
* \chinese
* 发送给定char向量中的所有数据到服务器。
*
* @param is_check 是否检查发送状态
* @param str 要发送的数据,char向量
* @param socket_name 套接字名称
* @return 状态码
*
* @par Python函数原型
* socketSendAllString(self: pyaubo_sdk.Socket, arg0: bool, arg1: List[str], arg2: str) -> int
*
* @par Lua函数原型
* socketSendAllString(is_check: boolean, str: table, socket_name: string) -> nil
* \endchinese
*/
int socketSendAllString(bool is_check, const std::vector<char> &str,
const std::string &socket_name = "socket_0");
/**
* @ingroup Socket
* \english
* Check if the socket is connected
* @brief socketHasConnected
* @param socket_name
*
* @return
*
* @par Python function prototype
* socketHasConnected(self: pyaubo_sdk.Socket, arg0: str) -> bool
*
* @par Lua function prototype
* socketHasConnected(socket_name: string) -> boolean
* \endenglish
* \chinese
* 检测 socket 连接是否成功
* @brief socketHasConnected
* @param socket_name
*
* @return
*
* @par Python函数原型
* socketHasConnected(self: pyaubo_sdk.Socket, arg0: str) -> bool
*
* @par Lua函数原型
* socketHasConnected(socket_name: string) -> boolean
* \endchinese
*/
bool socketHasConnected(const std::string &socket_name = "socket_0");
protected:
void *d_;
};
using SocketPtr = std::shared_ptr<Socket>;
} // namespace common_interface
} // namespace arcs
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,359 @@
/** @file system_info.h
* @brief 获取系统信息接口,如接口板的版本号、示教器软件的版本号
*/
#ifndef AUBO_SDK_SYSTEM_INFO_INTERFACE_H
#define AUBO_SDK_SYSTEM_INFO_INTERFACE_H
#include <stdint.h>
#include <string>
#include <memory>
#include <aubo/global_config.h>
namespace arcs {
namespace common_interface {
/**
* \chinese
* @defgroup SystemInfo SystemInfo (系统信息)
* 系统信息
* \endchinese
*
* \english
* @defgroup SystemInfo System Information
* System Information
* \endenglish
*/
class ARCS_ABI_EXPORT SystemInfo
{
public:
SystemInfo();
virtual ~SystemInfo();
/**
* @ingroup SystemInfo
* \chinese
* 获取控制器软件版本号
*
* @return 返回控制器软件版本号
*
* @par Python函数原型
* getControlSoftwareVersionCode(self: pyaubo_sdk.SystemInfo) -> int
*
* @par Lua函数原型
* getControlSoftwareVersionCode() -> number
*
* @par C++示例
* @code
* int control_version =
* rpc_cli->getSystemInfo()->getControlSoftwareVersionCode();
* @endcode
*
* @par JSON-RPC请求示例
* {"jsonrpc":"2.0","method":"SystemInfo.getControlSoftwareVersionCode","params":[],"id":1}
*
* @par JSON-RPC响应示例
* {"id":1,"jsonrpc":"2.0","result":28003}
*
* \endchinese
* \english
* Get the controller software version code
*
* @return Returns the controller software version code
*
* @par Python prototype
* getControlSoftwareVersionCode(self: pyaubo_sdk.SystemInfo) -> int
*
* @par Lua prototype
* getControlSoftwareVersionCode() -> number
*
* @par C++ example
* @code
* int control_version =
* rpc_cli->getSystemInfo()->getControlSoftwareVersionCode();
* @endcode
*
* @par JSON-RPC request example
* {"jsonrpc":"2.0","method":"SystemInfo.getControlSoftwareVersionCode","params":[],"id":1}
*
* @par JSON-RPC response example
* {"id":1,"jsonrpc":"2.0","result":28003}
*
* \endenglish
*/
int getControlSoftwareVersionCode();
/**
* @ingroup SystemInfo
* \chinese
* 获取完整控制器软件版本号
*
* @return 返回完整控制器软件版本号
*
* @par Python函数原型
* getControlSoftwareFullVersion(self: pyaubo_sdk.SystemInfo) -> str
*
* @par Lua函数原型
* getControlSoftwareFullVersion() -> string
*
* @par C++示例
* @code
* std::string control_version =
* rpc_cli->getSystemInfo()->getControlSoftwareFullVersion();
* @endcode
*
* @par JSON-RPC请求示例
* {"jsonrpc":"2.0","method":"SystemInfo.getControlSoftwareFullVersion","params":[],"id":1}
*
* @par JSON-RPC响应示例
* {"id":1,"jsonrpc":"2.0","result":"0.31.0-alpha.16+20alc76"}
*
* \endchinese
* \english
* Get the full controller software version
*
* @return Returns the full controller software version
*
* @par Python prototype
* getControlSoftwareFullVersion(self: pyaubo_sdk.SystemInfo) -> str
*
* @par Lua prototype
* getControlSoftwareFullVersion() -> string
*
* @par C++ example
* @code
* std::string control_version =
* rpc_cli->getSystemInfo()->getControlSoftwareFullVersion();
* @endcode
*
* @par JSON-RPC request example
* {"jsonrpc":"2.0","method":"SystemInfo.getControlSoftwareFullVersion","params":[],"id":1}
*
* @par JSON-RPC response example
* {"id":1,"jsonrpc":"2.0","result":"0.31.0-alpha.16+20alc76"}
*
* \endenglish
*/
std::string getControlSoftwareFullVersion();
/**
* @ingroup SystemInfo
* \chinese
* 获取接口版本号
*
* @return 返回接口版本号
*
* @par Python函数原型
* getInterfaceVersionCode(self: pyaubo_sdk.SystemInfo) -> int
*
* @par Lua函数原型
* getInterfaceVersionCode() -> number
*
* @par C++示例
* @code
* int interface_version =
* rpc_cli->getSystemInfo()->getInterfaceVersionCode();
* @endcode
*
* @par JSON-RPC请求示例
* {"jsonrpc":"2.0","method":"SystemInfo.getInterfaceVersionCode","params":[],"id":1}
*
* @par JSON-RPC响应示例
* {"id":1,"jsonrpc":"2.0","result":22003}
*
* \endchinese
* \english
* Get the interface version code
*
* @return Returns the interface version code
*
* @par Python prototype
* getInterfaceVersionCode(self: pyaubo_sdk.SystemInfo) -> int
*
* @par Lua prototype
* getInterfaceVersionCode() -> number
*
* @par C++ example
* @code
* int interface_version =
* rpc_cli->getSystemInfo()->getInterfaceVersionCode();
* @endcode
*
* @par JSON-RPC request example
* {"jsonrpc":"2.0","method":"SystemInfo.getInterfaceVersionCode","params":[],"id":1}
*
* @par JSON-RPC response example
* {"id":1,"jsonrpc":"2.0","result":22003}
*
* \endenglish
*/
int getInterfaceVersionCode();
/**
* @ingroup SystemInfo
* \chinese
* 获取控制器软件构建时间
*
* @return 返回控制器软件构建时间
*
* @par Python函数原型
* getControlSoftwareBuildDate(self: pyaubo_sdk.SystemInfo) -> str
*
* @par Lua函数原型
* getControlSoftwareBuildDate() -> string
*
* @par C++示例
* @code
* std::string build_date =
* rpc_cli->getSystemInfo()->getControlSoftwareBuildDate();
* @endcode
*
* @par JSON-RPC请求示例
* {"jsonrpc":"2.0","method":"SystemInfo.getControlSoftwareBuildDate","params":[],"id":1}
*
* @par JSON-RPC响应示例
* {"id":1,"jsonrpc":"2.0","result":"2024-3-5 07:03:20"}
*
* \endchinese
* \english
* Get the controller software build date
*
* @return Returns the controller software build date
*
* @par Python prototype
* getControlSoftwareBuildDate(self: pyaubo_sdk.SystemInfo) -> str
*
* @par Lua prototype
* getControlSoftwareBuildDate() -> string
*
* @par C++ example
* @code
* std::string build_date =
* rpc_cli->getSystemInfo()->getControlSoftwareBuildDate();
* @endcode
*
* @par JSON-RPC request example
* {"jsonrpc":"2.0","method":"SystemInfo.getControlSoftwareBuildDate","params":[],"id":1}
*
* @par JSON-RPC response example
* {"id":1,"jsonrpc":"2.0","result":"2024-3-5 07:03:20"}
*
* \endenglish
*/
std::string getControlSoftwareBuildDate();
/**
* @ingroup SystemInfo
* \chinese
* 获取控制器软件git版本
*
* @return 返回控制器软件git版本
*
* @par Python函数原型
* getControlSoftwareVersionHash(self: pyaubo_sdk.SystemInfo) -> str
*
* @par Lua函数原型
* getControlSoftwareVersionHash() -> string
*
* @par C++示例
* @code
* std::string git_version =
* rpc_cli->getSystemInfo()->getControlSoftwareVersionHash();
* @endcode
*
* @par JSON-RPC请求示例
* {"jsonrpc":"2.0","method":"SystemInfo.getControlSoftwareVersionHash","params":[],"id":1}
*
* @par JSON-RPC响应示例
* {"id":1,"jsonrpc":"2.0","result":"fa4f64a"}
*
* \endchinese
* \english
* Get the controller software git version
*
* @return Returns the controller software git version
*
* @par Python prototype
* getControlSoftwareVersionHash(self: pyaubo_sdk.SystemInfo) -> str
*
* @par Lua prototype
* getControlSoftwareVersionHash() -> string
*
* @par C++ example
* @code
* std::string git_version =
* rpc_cli->getSystemInfo()->getControlSoftwareVersionHash();
* @endcode
*
* @par JSON-RPC request example
* {"jsonrpc":"2.0","method":"SystemInfo.getControlSoftwareVersionHash","params":[],"id":1}
*
* @par JSON-RPC response example
* {"id":1,"jsonrpc":"2.0","result":"fa4f64a"}
*
* \endenglish
*/
std::string getControlSoftwareVersionHash();
/**
* @ingroup SystemInfo
* \chinese
* 获取系统时间(软件启动时间 ns 纳秒)
*
* @return 返回系统时间(软件启动时间 ns 纳秒)
*
* @par Python函数原型
* getControlSystemTime(self: pyaubo_sdk.SystemInfo) -> int
*
* @par Lua函数原型
* getControlSystemTime() -> number
*
* @par C++示例
* @code
* std::string system_time =
* rpc_cli->getSystemInfo()->getControlSystemTime();
* @endcode
*
* @par JSON-RPC请求示例
* {"jsonrpc":"2.0","method":"SystemInfo.getControlSystemTime","params":[],"id":1}
*
* @par JSON-RPC响应示例
* {"id":1,"jsonrpc":"2.0","result":9287799079682}
*
* \endchinese
* \english
* Get the system time (software start time in nanoseconds)
*
* @return Returns the system time (software start time in nanoseconds)
*
* @par Python prototype
* getControlSystemTime(self: pyaubo_sdk.SystemInfo) -> int
*
* @par Lua prototype
* getControlSystemTime() -> number
*
* @par C++ example
* @code
* std::string system_time =
* rpc_cli->getSystemInfo()->getControlSystemTime();
* @endcode
*
* @par JSON-RPC request example
* {"jsonrpc":"2.0","method":"SystemInfo.getControlSystemTime","params":[],"id":1}
*
* @par JSON-RPC response example
* {"id":1,"jsonrpc":"2.0","result":9287799079682}
*
* \endenglish
*/
uint64_t getControlSystemTime();
protected:
void *d_;
};
using SystemInfoPtr = std::shared_ptr<SystemInfo>;
} // namespace common_interface
} // namespace arcs
#endif

View File

@ -0,0 +1,243 @@
/** @file trace.h
* \~chinese @brief 向控制器日志系统注入日志方面的接口 \~english @brief Interface for injecting logs into the controller's logging system
*/
#ifndef AUBO_SDK_TRACE_INTERFACE_H
#define AUBO_SDK_TRACE_INTERFACE_H
#include <string>
#include <vector>
#include <memory>
#include <sstream>
#include <aubo/global_config.h>
#include <aubo/type_def.h>
namespace arcs {
namespace common_interface {
/**
* \chinese
* @defgroup Trace Trace (日志与弹窗)
* 提供给控制器扩展程序的日志记录系统
* \endchinese
*
* \english
* @defgroup Trace Log and Pop-up
* Log recording system for controller extension programs
* \endenglish
*/
class ARCS_ABI_EXPORT Trace
{
public:
Trace();
virtual ~Trace();
/**
* @ingroup Trace
* \~chinese 向 aubo_control 日志注入告警信息 \~english Injects alarm information into the aubo_control log
*
* TraceLevel: \n
* 0 - FATAL \n
* 1 - ERROR \n
* 2 - WARNING \n
* 3 - INFO \n
* 4 - DEBUG \n
*
* \~chinese code定义参考 error_stack \~english Code definitions refer to error_stack
*
* @param level
* @param code
* @param args
* @return
*
* \~chinese @par Python函数原型 \~english @par Python function prototype
* alarm(self: pyaubo_sdk.Trace, arg0: arcs::common_interface::TraceLevel,
* arg1: int, arg2: List[str]) -> int
*
* \~chinese @par Lua函数原型 \~english @par Lua function prototype
* alarm(level: number, code: number, args: table) -> nil
*
* \~chinese @par JSON-RPC请求示例 \~english @par JSON-RPC request example
* {"jsonrpc":"2.0","method":"rob1.Trace.alarm","params":["",1,["Error","Trajectory
* planning failed!","1"]],"id":1}
*
* \~chinese @par JSON-RPC响应示例 \~engish @par JSON-RPC response example
* {"id":1,"jsonrpc":"2.0","result":0}
*
*/
int alarm(TraceLevel level, int code,
const std::vector<std::string> &args = {});
/**
* @ingroup Trace
* \chinese
* 打印文本信息到日志中
*
* @param msg 文本信息
* @return
*
* @par Python函数原型
* textmsg(self: pyaubo_sdk.Trace, arg0: str) -> int
*
* @par Lua函数原型
* textmsg(msg: string) -> nil
*
* @par JSON-RPC请求示例
* {"jsonrpc":"2.0","method":"rob1.Trace.textmsg","params":["test"],"id":1}
*
* @par JSON-RPC响应示例
* {"id":1,"jsonrpc":"2.0","result":0}
* \endchinese
* \english
* print message into log
*
* @param msg message information
* @return
*
* @par Python function prototype
* textmsg(self: pyaubo_sdk.Trace, arg0: str) -> int
*
* @par Lua function prototype
* textmsg(msg: string) -> nil
*
* @par JSON-RPC request example
* {"jsonrpc":"2.0","method":"rob1.Trace.textmsg","params":["test"],"id":1}
*
* @par JSON-RPC responose example
* {"id":1,"jsonrpc":"2.0","result":0}
* \endenglish
*/
int textmsg(const std::string &msg);
/**
* \~chinese 通知上位机 \~english Notify the system
*
* @param msg
* @return
*/
int notify(const std::string &msg);
/**
* @ingroup Trace
* \chinese
* 向连接的 RTDE 客户端发送弹窗请求
*
* @param level
* @param title
* @param msg
* @param mode 模式 \n
* 0: 普通模式 \n
* 1: 阻塞模式 \n
* 2: 输入模式 bool \n
* 3: 输入模式 int \n
* 4: 输入模式 double \n
* 5: 输入模式 string \n
* @return
*
* @par Python函数原型
* popup(self: pyaubo_sdk.Trace, arg0: arcs::common_interface::TraceLevel,
* arg1: str, arg2: str, arg3: int) -> int
*
* @par Lua函数原型
* popup(level: number, title: string, msg: string, mode: number) -> nil
*
* @par JSON-RPC请求示例
* {"jsonrpc":"2.0","method":"rob1.Trace.popup","params":["","Error","Trajectory
* planning failed!",1],"id":1}
*
* @par JSON-RPC响应示例
* {"id":1,"jsonrpc":"2.0","result":0}
* \endchinese
* \english
* Send a popup request to the connected RTDE client
*
* @param level
* @param title
* @param msg
* @param mode mode \n
* 0: normal mode \n
* 1: blocking mode \n
* 2: input mode bool \n
* 3: input mode int \n
* 4: input mode double \n
* 5: input mode string \n
* @return
*
* @par Python function prototype
* popup(self: pyaubo_sdk.Trace, arg0: arcs::common_interface::TraceLevel,
* arg1: str, arg2: str, arg3: int) -> int
*
* @par Lua function prototype
* popup(level: number, title: string, msg: string, mode: number) -> nil
*
* @par JSON-RPC request example
* {"jsonrpc":"2.0","method":"rob1.Trace.popup","params":["","Error","Trajectory
* planning failed!",1],"id":1}
*
* @par JSON-RPC response example
* {"id":1,"jsonrpc":"2.0","result":0}
* \endenglish
*/
int popup(TraceLevel level, const std::string &title,
const std::string &msg, int mode);
/**
* @ingroup Trace
* \chinese
* peek最新的 AlarmInfo(上次一获取之后)
*
* last_time设置为0时,可以获取到所有的AlarmInfo
*
* @param num
* @param last_time
* @return
*
* @par Python函数原型
* peek(self: pyaubo_sdk.Trace, arg0: int, arg1: int) ->
* List[arcs::common_interface::RobotMsg]
*
* @par Lua函数原型
* peek(num: number, last_time: number) -> table
*
* @par JSON-RPC请求示例
* {"jsonrpc":"2.0","method":"rob1.Trace.peek","params":[1,0],"id":1}
*
* @par JSON-RPC响应示例
* {{"id":1,"jsonrpc":"2.0","result":[{"args":["RobotModeType.Running"],
* "code":30045,"level":"INFO","source":"rob1","timestamp":5102883064300}]}
* \endchinese
* \english
* peek the latest AlarmInfo (after the last retrieval)
*
* When last_time is set as 0, retrieve all AlarmInfo
*
* @param num
* @param last_time
* @return
*
* @par Python function prototype
* peek(self: pyaubo_sdk.Trace, arg0: int, arg1: int) ->
* List[arcs::common_interface::RobotMsg]
*
* @par Lua function prototype
* peek(num: number, last_time: number) -> table
*
* @par JSON-RPC request example
* {"jsonrpc":"2.0","method":"rob1.Trace.peek","params":[1,0],"id":1}
*
* @par JSON-RPC response example
* {{"id":1,"jsonrpc":"2.0","result":[{"args":["RobotModeType.Running"],
* "code":30045,"level":"INFO","source":"rob1","timestamp":5102883064300}]}
* \endenglish
*/
RobotMsgVector peek(size_t num, uint64_t last_time = 0);
protected:
void *d_;
};
using TracePtr = std::shared_ptr<Trace>;
} // namespace common_interface
} // namespace arcs
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,53 @@
#ifndef AUBO_SDK_Math_C_H
#define AUBO_SDK_Math_C_H
#include <aubo_sdk/type_def_c.h>
#ifdef __cplusplus
extern "C" {
#endif
ARCS_ABI int poseAdd(MATH_HANDLER h, const double *p1, const double *p2,
double *result);
ARCS_ABI int poseSub(MATH_HANDLER h, const double *p1, const double *p2,
double *result);
ARCS_ABI int interpolatePose(MATH_HANDLER h, const double *p1, const double *p2,
double alpha, double *result);
ARCS_ABI int poseTrans(MATH_HANDLER h, const double *pose_from,
const double *pose_from_to, double *result);
ARCS_ABI int poseTransInv(MATH_HANDLER h, const double *pose_from,
const double *pose_to_from, double *result);
ARCS_ABI int poseInverse(MATH_HANDLER h, const double *pose, double *result);
ARCS_ABI double poseDistance(MATH_HANDLER h, const double *p1,
const double *p2);
ARCS_ABI double poseAngleDistance(MATH_HANDLER h, const double *p1,
const double *p2);
ARCS_ABI BOOL poseEqual(MATH_HANDLER h, const double *p1, const double *p2,
double eps);
ARCS_ABI int transferRefFrame(MATH_HANDLER h, const double *F_b_a_old,
Vector3d_C V_in_a, int type, double *result);
ARCS_ABI int poseRotation(MATH_HANDLER h, const double *pose,
const double *rotv, double *result);
ARCS_ABI int rpyToQuaternion(MATH_HANDLER h, const double *rpy, double *result);
ARCS_ABI int quaternionToRpy(MATH_HANDLER h, const double *quant,
double *result);
ARCS_ABI int tcpOffsetIdentify(MATH_HANDLER h, const double *poses, int rows,
double *result);
ARCS_ABI int calibrateCoordinate(MATH_HANDLER h, const double *poses, int rows,
int type, double *result);
ARCS_ABI int calculateCircleFourthPoint(MATH_HANDLER h, const double *p1,
const double *p2, const double *p3,
int mode, double *result);
ARCS_ABI int forceTrans(MATH_HANDLER h, const double *pose_a_in_b,
const double *force_in_a, double *result);
ARCS_ABI int getDeltaPoseBySensorDistance(MATH_HANDLER h,
const double *distances,
double position, double radius,
double track_scale, double *result);
ARCS_ABI int deltaPoseTrans(MATH_HANDLER h, const double *pose_a_in_b,
const double *ft_in_a, double *result);
ARCS_ABI int deltaPoseAdd(MATH_HANDLER h, const double *pose_a_in_b,
const double *v_in_b, double *result);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,120 @@
#ifndef AUBO_SDK_RegisterControl_C_H
#define AUBO_SDK_RegisterControl_C_H
#include <aubo_sdk/type_def_c.h>
#ifdef __cplusplus
extern "C" {
#endif
ARCS_ABI BOOL getBoolInput(REGISTER_CONTROL_HANDLER h, uint32_t address);
ARCS_ABI int setBoolInput(REGISTER_CONTROL_HANDLER h, uint32_t address,
BOOL value);
ARCS_ABI int getInt32Input(REGISTER_CONTROL_HANDLER h, uint32_t address);
ARCS_ABI int setInt32Input(REGISTER_CONTROL_HANDLER h, uint32_t address,
int value);
ARCS_ABI float getFloatInput(REGISTER_CONTROL_HANDLER h, uint32_t address);
ARCS_ABI int setFloatInput(REGISTER_CONTROL_HANDLER h, uint32_t address,
float value);
ARCS_ABI double getDoubleInput(REGISTER_CONTROL_HANDLER h, uint32_t address);
ARCS_ABI int setDoubleInput(REGISTER_CONTROL_HANDLER h, uint32_t address,
double value);
ARCS_ABI BOOL getBoolOutput(REGISTER_CONTROL_HANDLER h, uint32_t address);
ARCS_ABI int setBoolOutput(REGISTER_CONTROL_HANDLER h, uint32_t address,
BOOL value);
ARCS_ABI int getInt32Output(REGISTER_CONTROL_HANDLER h, uint32_t address);
ARCS_ABI int setInt32Output(REGISTER_CONTROL_HANDLER h, uint32_t address,
int value);
ARCS_ABI float getFloatOutput(REGISTER_CONTROL_HANDLER h, uint32_t address);
ARCS_ABI int setFloatOutput(REGISTER_CONTROL_HANDLER h, uint32_t address,
float value);
ARCS_ABI double getDoubleOutput(REGISTER_CONTROL_HANDLER h, uint32_t address);
ARCS_ABI int setDoubleOutput(REGISTER_CONTROL_HANDLER h, uint32_t address,
double value);
ARCS_ABI int16_t getInt16Register(REGISTER_CONTROL_HANDLER h, uint32_t address);
ARCS_ABI int setInt16Register(REGISTER_CONTROL_HANDLER h, uint32_t address,
int16_t value);
ARCS_ABI BOOL variableUpdated(REGISTER_CONTROL_HANDLER h, const char *key,
uint64_t since);
ARCS_ABI BOOL hasNamedVariable(REGISTER_CONTROL_HANDLER h, const char *key);
ARCS_ABI int getNamedVariableType(REGISTER_CONTROL_HANDLER h, const char *key,
char *result);
ARCS_ABI BOOL getBool(REGISTER_CONTROL_HANDLER h, const char *key,
BOOL default_value);
ARCS_ABI int setBool(REGISTER_CONTROL_HANDLER h, const char *key, BOOL value);
ARCS_ABI int getVecChar(REGISTER_CONTROL_HANDLER h, const char *key,
const char *default_value, char *result, int sz);
ARCS_ABI int setVecChar(REGISTER_CONTROL_HANDLER h, const char *key,
const char *value, int sz);
ARCS_ABI int getInt32(REGISTER_CONTROL_HANDLER h, const char *key,
int default_value);
ARCS_ABI int setInt32(REGISTER_CONTROL_HANDLER h, const char *key, int value);
ARCS_ABI int getVecInt32(REGISTER_CONTROL_HANDLER h, const char *key,
int32_t *default_value, int *result);
ARCS_ABI int setVecInt32(REGISTER_CONTROL_HANDLER h, const char *key,
int32_t *value);
ARCS_ABI float getFloat(REGISTER_CONTROL_HANDLER h, const char *key,
float default_value);
ARCS_ABI int setFloat(REGISTER_CONTROL_HANDLER h, const char *key, float value);
ARCS_ABI int getVecFloat(REGISTER_CONTROL_HANDLER h, const char *key,
const float *default_value, float *result);
ARCS_ABI int setVecFloat(REGISTER_CONTROL_HANDLER h, const char *key,
const float *value);
ARCS_ABI double getDouble(REGISTER_CONTROL_HANDLER h, const char *key,
double default_value);
ARCS_ABI int setDouble(REGISTER_CONTROL_HANDLER h, const char *key,
double value);
ARCS_ABI int getVecDouble(REGISTER_CONTROL_HANDLER h, const char *key,
const double *default_value, double *result);
ARCS_ABI int setVecDouble(REGISTER_CONTROL_HANDLER h, const char *key,
const double *value);
ARCS_ABI int getString(REGISTER_CONTROL_HANDLER h, const char *key,
const char *default_value, char *result);
ARCS_ABI int setString(REGISTER_CONTROL_HANDLER h, const char *key,
const char *value);
ARCS_ABI int clearNamedVariable(REGISTER_CONTROL_HANDLER h, const char *key);
ARCS_ABI int setWatchDog(REGISTER_CONTROL_HANDLER h, const char *key,
double timeout, int action);
ARCS_ABI int getWatchDogAction(REGISTER_CONTROL_HANDLER h, const char *key);
ARCS_ABI int getWatchDogTimeout(REGISTER_CONTROL_HANDLER h, const char *key);
ARCS_ABI int modbusAddSignal(REGISTER_CONTROL_HANDLER h,
const char *device_info, int slave_number,
int signal_address, int signal_type,
const char *signal_name, BOOL sequential_mode);
ARCS_ABI int modbusDeleteSignal(REGISTER_CONTROL_HANDLER h,
const char *signal_name);
ARCS_ABI int modbusDeleteAllSignals(REGISTER_CONTROL_HANDLER h);
ARCS_ABI int modbusGetSignalStatus(REGISTER_CONTROL_HANDLER h,
const char *signal_name);
ARCS_ABI int modbusGetSignalNames(REGISTER_CONTROL_HANDLER h, char **result);
ARCS_ABI int modbusGetSignalTypes(REGISTER_CONTROL_HANDLER h, int *result);
ARCS_ABI int modbusGetSignalValues(REGISTER_CONTROL_HANDLER h, int *result);
ARCS_ABI int modbusGetSignalErrors(REGISTER_CONTROL_HANDLER h, int *result);
ARCS_ABI int modbusSendCustomCommand(REGISTER_CONTROL_HANDLER h, const char *IP,
int slave_number, int function_code,
uint8_t *data, int sz);
ARCS_ABI int modbusSetDigitalInputAction(REGISTER_CONTROL_HANDLER h,
const char *robot_name,
const char *signal_name,
StandardInputAction_C action);
ARCS_ABI int modbusSetOutputRunstate(REGISTER_CONTROL_HANDLER h,
const char *robot_name,
const char *signal_name,
StandardOutputRunState_C runstate);
ARCS_ABI int modbusSetOutputSignal(REGISTER_CONTROL_HANDLER h,
const char *signal_name, uint16_t value);
ARCS_ABI int modbusSetOutputSignalPulse(REGISTER_CONTROL_HANDLER h,
const char *signal_name, uint16_t value,
double duration);
ARCS_ABI int modbusSetSignalUpdateFrequency(REGISTER_CONTROL_HANDLER h,
const char *signal_name,
int update_frequency);
ARCS_ABI int modbusGetSignalIndex(REGISTER_CONTROL_HANDLER h,
const char *signal_name);
ARCS_ABI int modbusGetSignalError(REGISTER_CONTROL_HANDLER h,
const char *signal_name);
ARCS_ABI int getModbusDeviceStatus(REGISTER_CONTROL_HANDLER h,
const char *device_name);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,78 @@
#ifndef AUBO_SDK_ForceControl_C_H
#define AUBO_SDK_ForceControl_C_H
#include <aubo_sdk/type_def_c.h>
#ifdef __cplusplus
extern "C" {
#endif
ARCS_ABI int fcEnable(FORCE_CONTROL_HANDLER h);
ARCS_ABI int fcDisable(FORCE_CONTROL_HANDLER h);
ARCS_ABI BOOL isFcEnabled(FORCE_CONTROL_HANDLER h);
ARCS_ABI int setTargetForce(FORCE_CONTROL_HANDLER h, const double *feature,
const uint8_t *compliance, const double *wrench,
const double *limits, TaskFrameType_C type);
ARCS_ABI int setDynamicModel(FORCE_CONTROL_HANDLER h, const double *m,
const double *d, const double *k);
ARCS_ABI DynamicsModel_C getDynamicModel(FORCE_CONTROL_HANDLER h);
ARCS_ABI int setDynamicModelContact(FORCE_CONTROL_HANDLER h,
const double *env_stiff,
const double *damp_scale,
const double *stiff_scale);
ARCS_ABI int setCondForce(FORCE_CONTROL_HANDLER h, const double *min,
const double *max, BOOL outside, double timeout);
ARCS_ABI int setCondOrient(FORCE_CONTROL_HANDLER h, const double *frame,
double max_angle, double max_rot, BOOL outside,
double timeout);
ARCS_ABI int setCondPlane(FORCE_CONTROL_HANDLER h, const double *plane,
double timeout);
ARCS_ABI int setCondCylinder(FORCE_CONTROL_HANDLER h, const double *axis,
double radius, BOOL outside, double timeout);
ARCS_ABI int setCondSphere(FORCE_CONTROL_HANDLER h, const double *center,
double radius, BOOL outside, double timeout);
ARCS_ABI int setCondTcpSpeed(FORCE_CONTROL_HANDLER h, const double *min,
const double *max, BOOL outside, double timeout);
ARCS_ABI int setCondActive(FORCE_CONTROL_HANDLER h);
ARCS_ABI int setCondDistance(FORCE_CONTROL_HANDLER h, double distance,
double timeout);
ARCS_ABI int setCondAdvanced(FORCE_CONTROL_HANDLER h, const char *type,
const double *args, double timeout);
ARCS_ABI BOOL isCondFullfiled(FORCE_CONTROL_HANDLER h);
ARCS_ABI int setSupvForce(FORCE_CONTROL_HANDLER h, const double *min,
const double *max);
ARCS_ABI int setSupvOrient(FORCE_CONTROL_HANDLER h, const double *frame,
double max_angle, double max_rot, BOOL outside);
ARCS_ABI int setSupvPosBox(FORCE_CONTROL_HANDLER h, const double *frame,
const double *box);
ARCS_ABI int setSupvPosCylinder(FORCE_CONTROL_HANDLER h, const double *frame,
const double *cylinder);
ARCS_ABI int setSupvPosSphere(FORCE_CONTROL_HANDLER h, const double *frame,
const double *sphere);
ARCS_ABI int setSupvReoriSpeed(FORCE_CONTROL_HANDLER h,
const double *speed_limit, BOOL outside,
double timeout);
ARCS_ABI int setSupvTcpSpeed(FORCE_CONTROL_HANDLER h, const double *speed_limit,
BOOL outside, double timeout);
ARCS_ABI int setLpFilter(FORCE_CONTROL_HANDLER h, const double *cutoff_freq);
ARCS_ABI int resetLpFilter(FORCE_CONTROL_HANDLER h);
ARCS_ABI int speedChangeTune(FORCE_CONTROL_HANDLER h, int speed_levels,
double speed_ratio_min);
ARCS_ABI int speedChangeEnable(FORCE_CONTROL_HANDLER h, double ref_force);
ARCS_ABI int speedChangeDisable(FORCE_CONTROL_HANDLER h);
ARCS_ABI int setDamping(FORCE_CONTROL_HANDLER h, const double *damping,
double ramp_time);
ARCS_ABI int resetDamping(FORCE_CONTROL_HANDLER h);
ARCS_ABI int softFloatEnable(FORCE_CONTROL_HANDLER h);
ARCS_ABI int softFloatDisable(FORCE_CONTROL_HANDLER h);
ARCS_ABI BOOL isSoftFloatEnabled(FORCE_CONTROL_HANDLER h);
ARCS_ABI int setSoftFloatParams(FORCE_CONTROL_HANDLER h, BOOL joint_space,
const uint8_t *select,
const double *stiff_percent,
const double *stiff_damp_ratio,
const double *force_threshold,
const double *force_limit);
ARCS_ABI int toolContact(FORCE_CONTROL_HANDLER h, const uint8_t *direction);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,113 @@
#ifndef AUBO_SDK_IoControl_C_H
#define AUBO_SDK_IoControl_C_H
#include <aubo_sdk/type_def_c.h>
#ifdef __cplusplus
extern "C" {
#endif
ARCS_ABI int getStandardDigitalInputNum(IO_CONTROL_HANDLER h);
ARCS_ABI int getToolDigitalInputNum(IO_CONTROL_HANDLER h);
ARCS_ABI int getConfigurableDigitalInputNum(IO_CONTROL_HANDLER h);
ARCS_ABI int getStandardDigitalOutputNum(IO_CONTROL_HANDLER h);
ARCS_ABI int getToolDigitalOutputNum(IO_CONTROL_HANDLER h);
ARCS_ABI int setToolIoInput(IO_CONTROL_HANDLER h, int index, BOOL input);
ARCS_ABI BOOL isToolIoInput(IO_CONTROL_HANDLER h, int index);
ARCS_ABI int getConfigurableDigitalOutputNum(IO_CONTROL_HANDLER h);
ARCS_ABI int getStandardAnalogInputNum(IO_CONTROL_HANDLER h);
ARCS_ABI int getToolAnalogInputNum(IO_CONTROL_HANDLER h);
ARCS_ABI int getStandardAnalogOutputNum(IO_CONTROL_HANDLER h);
ARCS_ABI int getToolAnalogOutputNum(IO_CONTROL_HANDLER h);
ARCS_ABI int setDigitalInputActionDefault(IO_CONTROL_HANDLER h);
ARCS_ABI int setStandardDigitalInputAction(IO_CONTROL_HANDLER h, int index,
StandardInputAction_C action);
ARCS_ABI int setToolDigitalInputAction(IO_CONTROL_HANDLER h, int index,
StandardInputAction_C action);
ARCS_ABI int setConfigurableDigitalInputAction(IO_CONTROL_HANDLER h, int index,
StandardInputAction_C action);
ARCS_ABI StandardInputAction_C
getStandardDigitalInputAction(IO_CONTROL_HANDLER h, int index);
ARCS_ABI StandardInputAction_C getToolDigitalInputAction(IO_CONTROL_HANDLER h,
int index);
ARCS_ABI StandardInputAction_C
getConfigurableDigitalInputAction(IO_CONTROL_HANDLER h, int index);
ARCS_ABI int setDigitalOutputRunstateDefault(IO_CONTROL_HANDLER h);
ARCS_ABI int setStandardDigitalOutputRunstate(
IO_CONTROL_HANDLER h, int index, StandardOutputRunState_C runstate);
ARCS_ABI int setToolDigitalOutputRunstate(IO_CONTROL_HANDLER h, int index,
StandardOutputRunState_C runstate);
ARCS_ABI int setConfigurableDigitalOutputRunstate(
IO_CONTROL_HANDLER h, int index, StandardOutputRunState_C runstate);
ARCS_ABI StandardOutputRunState_C
getStandardDigitalOutputRunstate(IO_CONTROL_HANDLER h, int index);
ARCS_ABI StandardOutputRunState_C
getToolDigitalOutputRunstate(IO_CONTROL_HANDLER h, int index);
ARCS_ABI StandardOutputRunState_C
getConfigurableDigitalOutputRunstate(IO_CONTROL_HANDLER h, int index);
ARCS_ABI int setStandardAnalogOutputRunstate(IO_CONTROL_HANDLER h, int index,
StandardOutputRunState_C runstate);
ARCS_ABI int setToolAnalogOutputRunstate(IO_CONTROL_HANDLER h, int index,
StandardOutputRunState_C runstate);
ARCS_ABI StandardOutputRunState_C
getStandardAnalogOutputRunstate(IO_CONTROL_HANDLER h, int index);
ARCS_ABI StandardOutputRunState_C
getToolAnalogOutputRunstate(IO_CONTROL_HANDLER h, int index);
ARCS_ABI int setStandardAnalogInputDomain(IO_CONTROL_HANDLER h, int index,
int domain);
ARCS_ABI int setToolAnalogInputDomain(IO_CONTROL_HANDLER h, int index,
int domain);
ARCS_ABI int getStandardAnalogInputDomain(IO_CONTROL_HANDLER h, int index);
ARCS_ABI int getToolAnalogInputDomain(IO_CONTROL_HANDLER h, int index);
ARCS_ABI int setStandardAnalogOutputDomain(IO_CONTROL_HANDLER h, int index,
int domain);
ARCS_ABI int setToolAnalogOutputDomain(IO_CONTROL_HANDLER h, int index,
int domain);
ARCS_ABI int setToolVoltageOutputDomain(IO_CONTROL_HANDLER h, int domain);
ARCS_ABI int getToolVoltageOutputDomain(IO_CONTROL_HANDLER h);
ARCS_ABI int getStandardAnalogOutputDomain(IO_CONTROL_HANDLER h, int index);
ARCS_ABI int getToolAnalogOutputDomain(IO_CONTROL_HANDLER h, int index);
ARCS_ABI int setStandardDigitalOutput(IO_CONTROL_HANDLER h, int index,
BOOL value);
ARCS_ABI int setStandardDigitalOutputPulse(IO_CONTROL_HANDLER h, int index,
BOOL value, double duration);
ARCS_ABI int setToolDigitalOutput(IO_CONTROL_HANDLER h, int index, BOOL value);
ARCS_ABI int setToolDigitalOutputPulse(IO_CONTROL_HANDLER h, int index,
BOOL value, double duration);
ARCS_ABI int setConfigurableDigitalOutput(IO_CONTROL_HANDLER h, int index,
BOOL value);
ARCS_ABI int setConfigurableDigitalOutputPulse(IO_CONTROL_HANDLER h, int index,
BOOL value, double duration);
ARCS_ABI int setStandardAnalogOutput(IO_CONTROL_HANDLER h, int index,
double value);
ARCS_ABI int setToolAnalogOutput(IO_CONTROL_HANDLER h, int index, double value);
ARCS_ABI BOOL getStandardDigitalInput(IO_CONTROL_HANDLER h, int index);
ARCS_ABI uint32_t getStandardDigitalInputs(IO_CONTROL_HANDLER h);
ARCS_ABI BOOL getToolDigitalInput(IO_CONTROL_HANDLER h, int index);
ARCS_ABI uint32_t getToolDigitalInputs(IO_CONTROL_HANDLER h);
ARCS_ABI BOOL getConfigurableDigitalInput(IO_CONTROL_HANDLER h, int index);
ARCS_ABI uint32_t getConfigurableDigitalInputs(IO_CONTROL_HANDLER h);
ARCS_ABI double getStandardAnalogInput(IO_CONTROL_HANDLER h, int index);
ARCS_ABI double getToolAnalogInput(IO_CONTROL_HANDLER h, int index);
ARCS_ABI BOOL getStandardDigitalOutput(IO_CONTROL_HANDLER h, int index);
ARCS_ABI uint32_t getStandardDigitalOutputs(IO_CONTROL_HANDLER h);
ARCS_ABI BOOL getToolDigitalOutput(IO_CONTROL_HANDLER h, int index);
ARCS_ABI uint32_t getToolDigitalOutputs(IO_CONTROL_HANDLER h);
ARCS_ABI BOOL getConfigurableDigitalOutput(IO_CONTROL_HANDLER h, int index);
ARCS_ABI uint32_t getConfigurableDigitalOutputs(IO_CONTROL_HANDLER h);
ARCS_ABI double getStandardAnalogOutput(IO_CONTROL_HANDLER h, int index);
ARCS_ABI double getToolAnalogOutput(IO_CONTROL_HANDLER h, int index);
ARCS_ABI int getStaticLinkInputNum(IO_CONTROL_HANDLER h);
ARCS_ABI int getStaticLinkOutputNum(IO_CONTROL_HANDLER h);
ARCS_ABI uint32_t getStaticLinkInputs(IO_CONTROL_HANDLER h);
ARCS_ABI uint32_t getStaticLinkOutputs(IO_CONTROL_HANDLER h);
ARCS_ABI BOOL hasEncoderSensor(IO_CONTROL_HANDLER h);
ARCS_ABI int setEncDecoderType(IO_CONTROL_HANDLER h, int type, int range_id);
ARCS_ABI int setEncTickCount(IO_CONTROL_HANDLER h, int tick);
ARCS_ABI int getEncDecoderType(IO_CONTROL_HANDLER h);
ARCS_ABI int getEncTickCount(IO_CONTROL_HANDLER h);
ARCS_ABI int unwindEncDeltaTickCount(IO_CONTROL_HANDLER h, int delta_count);
ARCS_ABI BOOL getToolButtonStatus(IO_CONTROL_HANDLER h);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,157 @@
#ifndef AUBO_SDK_MotionControl_C_H
#define AUBO_SDK_MotionControl_C_H
#include <aubo_sdk/type_def_c.h>
#ifdef __cplusplus
extern "C" {
#endif
ARCS_ABI double getEqradius(MOTION_CONTROL_HANDLER h);
ARCS_ABI int setEqradius(MOTION_CONTROL_HANDLER h, double eqradius);
ARCS_ABI double getSpeedFraction(MOTION_CONTROL_HANDLER h);
ARCS_ABI int setSpeedFraction(MOTION_CONTROL_HANDLER h, double fraction);
ARCS_ABI int speedFractionCritical(MOTION_CONTROL_HANDLER h, BOOL enable);
ARCS_ABI BOOL isSpeedFractionCritical(MOTION_CONTROL_HANDLER h);
ARCS_ABI BOOL isBlending(MOTION_CONTROL_HANDLER h);
ARCS_ABI int pathOffsetEnable(MOTION_CONTROL_HANDLER h);
ARCS_ABI int pathOffsetSet(MOTION_CONTROL_HANDLER h, const double *offset,
int type);
ARCS_ABI int pathOffsetDisable(MOTION_CONTROL_HANDLER h);
ARCS_ABI int jointOffsetEnable(MOTION_CONTROL_HANDLER h);
ARCS_ABI int jointOffsetSet(MOTION_CONTROL_HANDLER h, const double *offset,
int type);
ARCS_ABI int jointOffsetDisable(MOTION_CONTROL_HANDLER h);
ARCS_ABI int getTrajectoryQueueSize(MOTION_CONTROL_HANDLER h);
ARCS_ABI int getQueueSize(MOTION_CONTROL_HANDLER h);
ARCS_ABI int getExecId(MOTION_CONTROL_HANDLER h);
ARCS_ABI double getDuration(MOTION_CONTROL_HANDLER h, int id);
ARCS_ABI double getMotionLeftTime(MOTION_CONTROL_HANDLER h, int id);
ARCS_ABI double getProgress(MOTION_CONTROL_HANDLER h);
ARCS_ABI int setWorkObjectHold(MOTION_CONTROL_HANDLER h,
const char *module_name,
const double *mounting_pose);
ARCS_ABI char *getWorkObjectHold(MOTION_CONTROL_HANDLER h);
ARCS_ABI int getPauseJointPositions(MOTION_CONTROL_HANDLER h, double *result);
ARCS_ABI int setServoMode(MOTION_CONTROL_HANDLER h, BOOL enable);
ARCS_ABI BOOL isServoModeEnabled(MOTION_CONTROL_HANDLER h);
ARCS_ABI int setServoModeSelect(MOTION_CONTROL_HANDLER h, int mode);
ARCS_ABI int getServoModeSelect(MOTION_CONTROL_HANDLER h);
ARCS_ABI int servoJoint(MOTION_CONTROL_HANDLER h, const double *q, double a,
double v, double t, double lookahead_time, double gain);
ARCS_ABI int servoCartesian(MOTION_CONTROL_HANDLER h, const double *pose,
double a, double v, double t, double lookahead_time,
double gain);
ARCS_ABI int servoJointWithAxes(MOTION_CONTROL_HANDLER h, const double *q,
const double *extq, double a, double v,
double t, double lookahead_time, double gain);
ARCS_ABI int servoCartesianWithAxes(MOTION_CONTROL_HANDLER h,
const double *pose, const double *extq,
double a, double v, double t,
double lookahead_time, double gain);
ARCS_ABI int trackJoint(MOTION_CONTROL_HANDLER h, const double *q, double t,
double smooth_scale, double delay_sacle);
ARCS_ABI int trackCartesian(MOTION_CONTROL_HANDLER h, const double *pose,
double t, double smooth_scale, double delay_sacle);
ARCS_ABI int followJoint(MOTION_CONTROL_HANDLER h, const double *q);
ARCS_ABI int followLine(MOTION_CONTROL_HANDLER h, const double *pose);
ARCS_ABI int speedJoint(MOTION_CONTROL_HANDLER h, const double *qd, double a,
double t);
ARCS_ABI int resumeSpeedJoint(MOTION_CONTROL_HANDLER h, const double *qd,
double a, double t);
ARCS_ABI int speedLine(MOTION_CONTROL_HANDLER h, const double *xd, double a,
double t);
ARCS_ABI int resumeSpeedLine(MOTION_CONTROL_HANDLER h, const double *xd,
double a, double t);
ARCS_ABI int moveSpline(MOTION_CONTROL_HANDLER h, const double *q, double a,
double v, double duration);
ARCS_ABI int moveJoint(MOTION_CONTROL_HANDLER h, const double *q, double a,
double v, double blend_radius, double duration);
ARCS_ABI int resumeMoveJoint(MOTION_CONTROL_HANDLER h, const double *q,
double a, double v, double duration);
ARCS_ABI int moveLine(MOTION_CONTROL_HANDLER h, const double *pose, double a,
double v, double blend_radius, double duration);
ARCS_ABI int moveProcess(MOTION_CONTROL_HANDLER h, const double *pose, double a,
double v, double blend_radius);
ARCS_ABI int resumeMoveLine(MOTION_CONTROL_HANDLER h, const double *pose,
double a, double v, double duration);
ARCS_ABI int moveCircle(MOTION_CONTROL_HANDLER h, const double *via_pose,
const double *end_pose, double a, double v,
double blend_radius, double duration);
ARCS_ABI int setCirclePathMode(MOTION_CONTROL_HANDLER h, int mode);
ARCS_ABI int moveCircle2(MOTION_CONTROL_HANDLER h,
const CircleParameters_C *param);
ARCS_ABI int pathBufferAlloc(MOTION_CONTROL_HANDLER h, const char *name,
int type, int size);
ARCS_ABI int pathBufferAppend(MOTION_CONTROL_HANDLER h, const char *name,
const double *waypoints, int rows);
ARCS_ABI int pathBufferEval(MOTION_CONTROL_HANDLER h, const char *name,
const double *a, const double *v, double t);
ARCS_ABI BOOL pathBufferValid(MOTION_CONTROL_HANDLER h, const char *name);
ARCS_ABI int pathBufferFree(MOTION_CONTROL_HANDLER h, const char *name);
ARCS_ABI int pathBufferList(MOTION_CONTROL_HANDLER h, char **result);
ARCS_ABI int movePathBuffer(MOTION_CONTROL_HANDLER h, const char *name);
ARCS_ABI int moveIntersection(MOTION_CONTROL_HANDLER h, const double *poses,
int rows, double a, double v,
double main_pipe_radius, double sub_pipe_radius,
double normal_distance, double normal_alpha);
ARCS_ABI int stopJoint(MOTION_CONTROL_HANDLER h, double acc);
ARCS_ABI int resumeStopJoint(MOTION_CONTROL_HANDLER h, double acc);
ARCS_ABI int stopLine(MOTION_CONTROL_HANDLER h, double acc, double acc_rot);
ARCS_ABI int resumeStopLine(MOTION_CONTROL_HANDLER h, double acc,
double acc_rot);
ARCS_ABI int weaveStart(MOTION_CONTROL_HANDLER h, const char *params);
ARCS_ABI int weaveEnd(MOTION_CONTROL_HANDLER h);
ARCS_ABI int storePath(MOTION_CONTROL_HANDLER h, BOOL keep_sync);
ARCS_ABI int stopMove(MOTION_CONTROL_HANDLER h, BOOL quick, BOOL all_tasks);
ARCS_ABI int startMove(MOTION_CONTROL_HANDLER h);
ARCS_ABI int clearPath(MOTION_CONTROL_HANDLER h);
ARCS_ABI int restoPath(MOTION_CONTROL_HANDLER h);
ARCS_ABI int setFuturePointSamplePeriod(MOTION_CONTROL_HANDLER h,
double sample_time);
ARCS_ABI int getFuturePathPointsJoint(MOTION_CONTROL_HANDLER h,
double **result);
ARCS_ABI int conveyorTrackCircle(MOTION_CONTROL_HANDLER h, int encoder_id,
const double *center, BOOL rotate_tool);
ARCS_ABI int conveyorTrackLine(MOTION_CONTROL_HANDLER h, int encoder_id,
const double *direction);
ARCS_ABI int conveyorTrackStop(MOTION_CONTROL_HANDLER h, int encoder_id,
double a);
ARCS_ABI int setConveyorTrackEncoder(MOTION_CONTROL_HANDLER h, int encoder_id,
int tick_per_meter);
ARCS_ABI int setConveyorTrackLimit(MOTION_CONTROL_HANDLER h, int encoder_id,
double limit);
ARCS_ABI int setConveyorTrackStartWindow(MOTION_CONTROL_HANDLER h,
int encoder_id, double window_min,
double window_max);
ARCS_ABI int setConveyorTrackSensorOffset(MOTION_CONTROL_HANDLER h,
int encoder_id, double offset);
ARCS_ABI int setConveyorTrackSyncSeparation(MOTION_CONTROL_HANDLER h,
int encoder_id, double distance,
double time);
ARCS_ABI int setConveyorTrackCompensate(MOTION_CONTROL_HANDLER h,
int encoder_id, double comp);
ARCS_ABI BOOL isConveyorTrackSync(MOTION_CONTROL_HANDLER h, int encoder_id);
ARCS_ABI BOOL isConveyorTrackExceed(MOTION_CONTROL_HANDLER h, int encoder_id);
ARCS_ABI int getConveyorTrackQueue(MOTION_CONTROL_HANDLER h, int encoder_id,
double *result);
ARCS_ABI int getConveyorTrackNextItem(MOTION_CONTROL_HANDLER h, int encoder_id);
ARCS_ABI int conveyorTrackCreatItem(MOTION_CONTROL_HANDLER h, int encoder_id,
int item_id, const double *offset);
ARCS_ABI BOOL hasItemOnConveyorToTrack(MOTION_CONTROL_HANDLER h,
int encoder_id);
ARCS_ABI BOOL conveyorTrackSwitch(MOTION_CONTROL_HANDLER h, int encoder_id);
ARCS_ABI int conveyorTrackClearItems(MOTION_CONTROL_HANDLER h, int encoder_id);
ARCS_ABI int setConveyorItemTrigIO(MOTION_CONTROL_HANDLER h, int encoder_id,
RobotIOType_C io_type, int io_index,
BOOL trig_edge);
ARCS_ABI int moveSpiral(MOTION_CONTROL_HANDLER h,
const SpiralParameters_C *param, double blend_radius,
double v, double a, double t);
ARCS_ABI int pathOffsetLimits(MOTION_CONTROL_HANDLER h, double v, double a);
ARCS_ABI int pathOffsetCoordinate(MOTION_CONTROL_HANDLER h, int ref_coord);
ARCS_ABI int getLookAheadSize(MOTION_CONTROL_HANDLER h);
ARCS_ABI int setLookAheadSize(MOTION_CONTROL_HANDLER h, int size);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,73 @@
#ifndef AUBO_SDK_RobotAlgorithm_C_H
#define AUBO_SDK_RobotAlgorithm_C_H
#include <aubo_sdk/type_def_c.h>
#ifdef __cplusplus
extern "C" {
#endif
ARCS_ABI ForceSensorCalibResult_C
calibrateTcpForceSensor(ROBOT_ALGORITHM_HANDLER h, const double *forces,
int forces_rows, const double *poses, int poses_rows);
ARCS_ABI ForceSensorCalibResult_C
calibrateTcpForceSensor2(ROBOT_ALGORITHM_HANDLER h, const double *forces,
int forces_rows, const double *poses, int poses_rows);
ARCS_ABI int payloadIdentify(ROBOT_ALGORITHM_HANDLER h,
const char *data_no_payload,
const char *data_with_payload);
ARCS_ABI int payloadIdentify1(ROBOT_ALGORITHM_HANDLER h, const char *file_name);
ARCS_ABI int payloadCalculateFinished(ROBOT_ALGORITHM_HANDLER h);
ARCS_ABI Payload_C getPayloadIdentifyResult(ROBOT_ALGORITHM_HANDLER h);
ARCS_ABI int generatePayloadIdentifyTraj(ROBOT_ALGORITHM_HANDLER h,
const char *name,
const TrajConfig_C *traj_config);
ARCS_ABI int payloadIdentifyTrajGenFinished(ROBOT_ALGORITHM_HANDLER h);
ARCS_ABI BOOL frictionModelIdentify(ROBOT_ALGORITHM_HANDLER h, const double *q,
int q_rows, const double *qd, int qd_rows,
const double *qdd, int qdd_rows,
const double *temp, int temp_rows);
ARCS_ABI int calibWorkpieceCoordinatePara(ROBOT_ALGORITHM_HANDLER h,
const double *q, int q_rows, int type,
double *result);
ARCS_ABI int forwardDynamics(ROBOT_ALGORITHM_HANDLER h, const double *q,
const double *torqs, double *result);
ARCS_ABI int forwardKinematics(ROBOT_ALGORITHM_HANDLER h, const double *q,
double *result);
ARCS_ABI int forwardToolKinematics(ROBOT_ALGORITHM_HANDLER h, const double *q,
double *result);
ARCS_ABI int forwardDynamics1(ROBOT_ALGORITHM_HANDLER h, const double *q,
const double *torqs, const double *tcp_offset,
double *result);
ARCS_ABI int forwardKinematics1(ROBOT_ALGORITHM_HANDLER h, const double *q,
const double *tcp_offset, double *result);
ARCS_ABI int inverseKinematics(ROBOT_ALGORITHM_HANDLER h, const double *qnear,
const double *pose, double *result);
ARCS_ABI int inverseKinematicsAll(ROBOT_ALGORITHM_HANDLER h, const double *pose,
double **result);
ARCS_ABI int inverseKinematics1(ROBOT_ALGORITHM_HANDLER h, const double *qnear,
const double *pose, const double *tcp_offset,
double *result);
ARCS_ABI int inverseKinematicsAll1(ROBOT_ALGORITHM_HANDLER h,
const double *pose, const double *tcp_offset,
double **result);
ARCS_ABI int inverseToolKinematics(ROBOT_ALGORITHM_HANDLER h,
const double *qnear, const double *pose,
double *result);
ARCS_ABI int inverseToolKinematicsAll(ROBOT_ALGORITHM_HANDLER h,
const double *pose, double **result);
ARCS_ABI int pathMovej(ROBOT_ALGORITHM_HANDLER h, const double *q1, double r1,
const double *q2, double r2, double d, double **result);
ARCS_ABI int pathBlend3Points(ROBOT_ALGORITHM_HANDLER h, int type,
const double *q_start, const double *q_via,
const double *q_to, double r, double d,
double **result);
ARCS_ABI int pathBlend3Points1(ROBOT_ALGORITHM_HANDLER h, int type,
const double *q_start, const double *q_via,
const double *q_to, double r, double d,
double **result);
ARCS_ABI int calcJacobian(ROBOT_ALGORITHM_HANDLER h, const double *q,
BOOL base_or_end, double *result);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,92 @@
#ifndef AUBO_SDK_RobotConfig_C_H
#define AUBO_SDK_RobotConfig_C_H
#include <aubo_sdk/type_def_c.h>
#ifdef __cplusplus
extern "C" {
#endif
ARCS_ABI int getDof(ROBOT_CONFIG_HANDLER h);
ARCS_ABI int getName(ROBOT_CONFIG_HANDLER h, char *result);
ARCS_ABI double getCycletime(ROBOT_CONFIG_HANDLER h);
ARCS_ABI int setSlowDownFraction(ROBOT_CONFIG_HANDLER h, int level,
double fraction);
ARCS_ABI double getSlowDownFraction(ROBOT_CONFIG_HANDLER h, int level);
ARCS_ABI int getRobotType(ROBOT_CONFIG_HANDLER h, char *result);
ARCS_ABI int getRobotSubType(ROBOT_CONFIG_HANDLER h, char *result);
ARCS_ABI int getControlBoxType(ROBOT_CONFIG_HANDLER h, char *result);
ARCS_ABI double getDefaultToolAcc(ROBOT_CONFIG_HANDLER h);
ARCS_ABI double getDefaultToolSpeed(ROBOT_CONFIG_HANDLER h);
ARCS_ABI double getDefaultJointAcc(ROBOT_CONFIG_HANDLER h);
ARCS_ABI double getDefaultJointSpeed(ROBOT_CONFIG_HANDLER h);
ARCS_ABI int setMountingPose(ROBOT_CONFIG_HANDLER h, const double *pose);
ARCS_ABI int getMountingPose(ROBOT_CONFIG_HANDLER h, double *result);
ARCS_ABI int setCollisionLevel(ROBOT_CONFIG_HANDLER h, int level);
ARCS_ABI int getCollisionLevel(ROBOT_CONFIG_HANDLER h);
ARCS_ABI int setCollisionStopType(ROBOT_CONFIG_HANDLER h, int type);
ARCS_ABI int getCollisionStopType(ROBOT_CONFIG_HANDLER h);
ARCS_ABI int setHomePosition(ROBOT_CONFIG_HANDLER h, const double *positions);
ARCS_ABI int getHomePosition(ROBOT_CONFIG_HANDLER h, double *result);
ARCS_ABI int setFreedriveDamp(ROBOT_CONFIG_HANDLER h, const double *damp);
ARCS_ABI int getFreedriveDamp(ROBOT_CONFIG_HANDLER h, double *result);
ARCS_ABI int getTcpForceSensorNames(ROBOT_CONFIG_HANDLER h, char **result);
ARCS_ABI int selectTcpForceSensor(ROBOT_CONFIG_HANDLER h, const char *name);
ARCS_ABI BOOL hasTcpForceSensor(ROBOT_CONFIG_HANDLER h);
ARCS_ABI int setTcpForceOffset(ROBOT_CONFIG_HANDLER h,
const double *force_offset);
ARCS_ABI int getTcpForceOffset(ROBOT_CONFIG_HANDLER h, double *result);
ARCS_ABI int getBaseForceSensorNames(ROBOT_CONFIG_HANDLER h, char **result);
ARCS_ABI int selectBaseForceSensor(ROBOT_CONFIG_HANDLER h, const char *name);
ARCS_ABI BOOL hasBaseForceSensor(ROBOT_CONFIG_HANDLER h);
ARCS_ABI int setBaseForceOffset(ROBOT_CONFIG_HANDLER h,
const double *force_offset);
ARCS_ABI int getBaseForceOffset(ROBOT_CONFIG_HANDLER h, double *result);
ARCS_ABI int setPersistentParameters(ROBOT_CONFIG_HANDLER h, const char *param);
ARCS_ABI int setKinematicsCompensate(ROBOT_CONFIG_HANDLER h,
const DHParam_C *param);
ARCS_ABI int setHardwareCustomParameters(ROBOT_CONFIG_HANDLER h,
const char *param);
ARCS_ABI int getHardwareCustomParameters(ROBOT_CONFIG_HANDLER h,
const char *param, char *result);
ARCS_ABI int setRobotZero(ROBOT_CONFIG_HANDLER h);
ARCS_ABI DHParam_C *getKinematicsParam(ROBOT_CONFIG_HANDLER h, BOOL real);
ARCS_ABI DHComp_C *getKinematicsCompensate(ROBOT_CONFIG_HANDLER h,
double ref_temperature);
ARCS_ABI uint32_t getSafetyParametersCheckSum(ROBOT_CONFIG_HANDLER h);
ARCS_ABI int confirmSafetyParameters(
ROBOT_CONFIG_HANDLER h, const RobotSafetyParameterRange_C *parameters);
ARCS_ABI uint32_t calcSafetyParametersCheckSum(
ROBOT_CONFIG_HANDLER h, const RobotSafetyParameterRange_C *parameters);
ARCS_ABI int getJointMaxPositions(ROBOT_CONFIG_HANDLER h, double *result);
ARCS_ABI int getJointMinPositions(ROBOT_CONFIG_HANDLER h, double *result);
ARCS_ABI int getJointMaxSpeeds(ROBOT_CONFIG_HANDLER h, double *result);
ARCS_ABI int getJointMaxAccelerations(ROBOT_CONFIG_HANDLER h, double *result);
ARCS_ABI int getTcpMaxSpeeds(ROBOT_CONFIG_HANDLER h, double *result);
ARCS_ABI int getTcpMaxAccelerations(ROBOT_CONFIG_HANDLER h, double *result);
ARCS_ABI BOOL toolSpaceInRange(ROBOT_CONFIG_HANDLER h, const double *pose);
ARCS_ABI int setPayload(ROBOT_CONFIG_HANDLER h, double m, const double *cog,
const double *aom, const double *inertia);
ARCS_ABI Payload_C getPayload(ROBOT_CONFIG_HANDLER h);
ARCS_ABI int getTcpOffset(ROBOT_CONFIG_HANDLER h, double *result);
ARCS_ABI int getGravity(ROBOT_CONFIG_HANDLER h, double *result);
ARCS_ABI int setGravity(ROBOT_CONFIG_HANDLER h, const double *gravity);
ARCS_ABI int setTcpOffset(ROBOT_CONFIG_HANDLER h, const double *offset);
ARCS_ABI int setToolInertial(ROBOT_CONFIG_HANDLER h, double m,
const double *com, const double *inertial);
ARCS_ABI int firmwareUpdate(ROBOT_CONFIG_HANDLER h, const char *fw);
ARCS_ABI double getFirmwareUpdateProcess(ROBOT_CONFIG_HANDLER h);
ARCS_ABI int setTcpForceSensorPose(ROBOT_CONFIG_HANDLER h,
const double *sensor_pose);
ARCS_ABI int getTcpForceSensorPose(ROBOT_CONFIG_HANDLER h, double *result);
ARCS_ABI int getLimitJointMaxPositions(ROBOT_CONFIG_HANDLER h, double *result);
ARCS_ABI int getLimitJointMinPositions(ROBOT_CONFIG_HANDLER h, double *result);
ARCS_ABI int getLimitJointMaxSpeeds(ROBOT_CONFIG_HANDLER h, double *result);
ARCS_ABI int getLimitJointMaxAccelerations(ROBOT_CONFIG_HANDLER h,
double *result);
ARCS_ABI double getLimitTcpMaxSpeed(ROBOT_CONFIG_HANDLER h);
ARCS_ABI SafeguedStopType_C getSafeguardStopType(ROBOT_CONFIG_HANDLER h);
ARCS_ABI int getSafeguardStopSource(ROBOT_CONFIG_HANDLER h);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,22 @@
#ifndef AUBO_SDK_RobotInterface_C_H
#define AUBO_SDK_RobotInterface_C_H
#include <aubo_sdk/type_def_c.h>
#ifdef __cplusplus
extern "C" {
#endif
ARCS_ABI ROBOT_CONFIG_HANDLER robot_getRobotConfig(ROBOT_HANDLER robot);
ARCS_ABI MOTION_CONTROL_HANDLER robot_getMotionControl(ROBOT_HANDLER robot);
ARCS_ABI FORCE_CONTROL_HANDLER robot_getForceControl(ROBOT_HANDLER robot);
ARCS_ABI IO_CONTROL_HANDLER robot_getIoControl(ROBOT_HANDLER robot);
ARCS_ABI SYNC_MOVE_HANDLER robot_getSyncMove(ROBOT_HANDLER robot);
ARCS_ABI ROBOT_ALGORITHM_HANDLER robot_getRobotAlgorithm(ROBOT_HANDLER robot);
ARCS_ABI ROBOT_MANAGE_HANDLER robot_getRobotManage(ROBOT_HANDLER robot);
ARCS_ABI ROBOT_STATE_HANDLER robot_getRobotState(ROBOT_HANDLER robot);
ARCS_ABI TRACE_HANDLER robot_getTrace(ROBOT_HANDLER robot);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,38 @@
#ifndef AUBO_SDK_RobotManage_C_H
#define AUBO_SDK_RobotManage_C_H
#include <aubo_sdk/type_def_c.h>
#ifdef __cplusplus
extern "C" {
#endif
ARCS_ABI int poweron(ROBOT_MANAGE_HANDLER h);
ARCS_ABI int startup(ROBOT_MANAGE_HANDLER h);
ARCS_ABI int poweroff(ROBOT_MANAGE_HANDLER h);
ARCS_ABI int backdrive(ROBOT_MANAGE_HANDLER h, BOOL enable);
ARCS_ABI int freedrive(ROBOT_MANAGE_HANDLER h, BOOL enable);
ARCS_ABI int handguideMode(ROBOT_MANAGE_HANDLER h, int32_t *freeAxes,
const double *feature);
ARCS_ABI int exitHandguideMode(ROBOT_MANAGE_HANDLER h);
ARCS_ABI int getHandguideStatus(ROBOT_MANAGE_HANDLER h);
ARCS_ABI int getHandguideTrigger(ROBOT_MANAGE_HANDLER h);
ARCS_ABI BOOL isHandguideEnabled(ROBOT_MANAGE_HANDLER h);
ARCS_ABI int setSim(ROBOT_MANAGE_HANDLER h, BOOL enable);
ARCS_ABI int setOperationalMode(ROBOT_MANAGE_HANDLER h,
OperationalModeType_C mode);
ARCS_ABI OperationalModeType_C getOperationalMode(ROBOT_MANAGE_HANDLER h);
ARCS_ABI RobotControlModeType_C getRobotControlMode(ROBOT_MANAGE_HANDLER h);
ARCS_ABI BOOL isSimulationEnabled(ROBOT_MANAGE_HANDLER h);
ARCS_ABI BOOL isFreedriveEnabled(ROBOT_MANAGE_HANDLER h);
ARCS_ABI BOOL isBackdriveEnabled(ROBOT_MANAGE_HANDLER h);
ARCS_ABI int setUnlockProtectiveStop(ROBOT_MANAGE_HANDLER h);
ARCS_ABI int startRecord(ROBOT_MANAGE_HANDLER h, const char *file_name);
ARCS_ABI int stopRecord(ROBOT_MANAGE_HANDLER h);
ARCS_ABI int pauseRecord(ROBOT_MANAGE_HANDLER h, BOOL pause);
ARCS_ABI int restartInterfaceBoard(ROBOT_MANAGE_HANDLER h);
ARCS_ABI int setLinkModeEnable(ROBOT_MANAGE_HANDLER h, BOOL enable);
ARCS_ABI BOOL isLinkModeEnabled(ROBOT_MANAGE_HANDLER h);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,78 @@
#ifndef AUBO_SDK_RobotState_C_H
#define AUBO_SDK_RobotState_C_H
#include <aubo_sdk/type_def_c.h>
#ifdef __cplusplus
extern "C" {
#endif
ARCS_ABI RobotModeType_C getRobotModeType(ROBOT_STATE_HANDLER h);
ARCS_ABI SafetyModeType_C getSafetyModeType(ROBOT_STATE_HANDLER h);
ARCS_ABI BOOL isPowerOn(ROBOT_STATE_HANDLER h);
ARCS_ABI BOOL isSteady(ROBOT_STATE_HANDLER h);
ARCS_ABI BOOL isCollisionOccurred(ROBOT_STATE_HANDLER h);
ARCS_ABI BOOL isWithinSafetyLimits(ROBOT_STATE_HANDLER h);
ARCS_ABI int getTcpPose(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getActualTcpOffset(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getTargetTcpPose(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getToolPose(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getTcpSpeed(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getTcpForce(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getElbowPosistion(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getElbowVelocity(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getBaseForce(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getTcpTargetPose(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getTcpTargetSpeed(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getTcpTargetForce(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getJointState(ROBOT_STATE_HANDLER h, JointStateType_C *result);
ARCS_ABI int getJointServoMode(ROBOT_STATE_HANDLER h,
JointServoModeType_C *result);
ARCS_ABI int getJointPositions(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getJointPositionsHistory(ROBOT_STATE_HANDLER h, int steps,
double *result);
ARCS_ABI int getJointSpeeds(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getJointAccelerations(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getJointTorqueSensors(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getJointContactTorques(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getBaseForceSensor(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getTcpForceSensors(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getJointCurrents(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getJointVoltages(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getJointTemperatures(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getJointUniqueIds(ROBOT_STATE_HANDLER h, char **result);
ARCS_ABI int getJointFirmwareVersions(ROBOT_STATE_HANDLER h, int *result);
ARCS_ABI int getJointHardwareVersions(ROBOT_STATE_HANDLER h, int *result);
ARCS_ABI int getMasterBoardUniqueId(ROBOT_STATE_HANDLER h, char *result);
ARCS_ABI int getMasterBoardFirmwareVersion(ROBOT_STATE_HANDLER h);
ARCS_ABI int getMasterBoardHardwareVersion(ROBOT_STATE_HANDLER h);
ARCS_ABI int getSlaveBoardUniqueId(ROBOT_STATE_HANDLER h, char *result);
ARCS_ABI int getSlaveBoardFirmwareVersion(ROBOT_STATE_HANDLER h);
ARCS_ABI int getSlaveBoardHardwareVersion(ROBOT_STATE_HANDLER h);
ARCS_ABI int getToolUniqueId(ROBOT_STATE_HANDLER h, char *result);
ARCS_ABI int getToolFirmwareVersion(ROBOT_STATE_HANDLER h);
ARCS_ABI int getToolHardwareVersion(ROBOT_STATE_HANDLER h);
ARCS_ABI int getToolCommMode(ROBOT_STATE_HANDLER h);
ARCS_ABI int getPedestalUniqueId(ROBOT_STATE_HANDLER h, char *result);
ARCS_ABI int getPedestalFirmwareVersion(ROBOT_STATE_HANDLER h);
ARCS_ABI int getPedestalHardwareVersion(ROBOT_STATE_HANDLER h);
ARCS_ABI int getJointTargetPositions(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getJointTargetSpeeds(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getJointTargetAccelerations(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getJointTargetTorques(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI int getJointTargetCurrents(ROBOT_STATE_HANDLER h, double *result);
ARCS_ABI double getControlBoxTemperature(ROBOT_STATE_HANDLER h);
ARCS_ABI double getControlBoxHumidity(ROBOT_STATE_HANDLER h);
ARCS_ABI double getMainVoltage(ROBOT_STATE_HANDLER h);
ARCS_ABI double getMainCurrent(ROBOT_STATE_HANDLER h);
ARCS_ABI double getRobotVoltage(ROBOT_STATE_HANDLER h);
ARCS_ABI double getRobotCurrent(ROBOT_STATE_HANDLER h);
ARCS_ABI int getSlowDownLevel(ROBOT_STATE_HANDLER h);
ARCS_ABI HandleStateType_C getHandleState(ROBOT_STATE_HANDLER h);
ARCS_ABI HandleModeType_C getHandleMode(ROBOT_STATE_HANDLER h);
ARCS_ABI int getHandleUniqueId(ROBOT_STATE_HANDLER h, char *result);
ARCS_ABI int getHandleFirmwareVersion(ROBOT_STATE_HANDLER h);
ARCS_ABI int getHandleHardwareVersion(ROBOT_STATE_HANDLER h);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,179 @@
/** @file rpc.h
* @brief 用于RPC模块的交互,如登录、连接等功能
*/
#ifndef AUBO_SDK_RPC_H
#define AUBO_SDK_RPC_H
#include <memory>
#include <aubo/aubo_api.h>
#include <aubo/global_config.h>
namespace arcs {
namespace aubo_sdk {
using namespace arcs::common_interface;
/// RPC客户端
class ARCS_ABI RpcClient : public AuboApi
{
public:
enum Event
{
Connected = 0,
Disconnected = 1,
};
/**
* @brief RpcClient
* @param mode 0-TCP 1-UDS
*/
RpcClient(int mode = 0);
~RpcClient();
/**
* 设置日志处理器
*
* 此函数可设置自定义的日志处理函数来处理日志消息。 \n
* Aubo SDK 有一套默认的日志系统,按照默认的格式输出到默认的文件。
* 如果用户不希望采用默认的格式或者不希望输出到默认的文件,那就可以通过这个接口重新自定义格式,或者输出路径。
* 这个函数可以将用户自定义的日志系统与 Aubo SDK 默认的日志系统合并。
*
* @note setLogHandler函数要放在即将触发的日志之前,
* 否则会按照默认的形式输出日志。
*
* @param handler 日志处理函数 \n
* 此日志处理函数的下定义如下: \n
* void handler(int level, const char* filename, int line, const
* std::string& message) \n
* level 表示日志等级 \n
* &nbsp; 0: LOGLEVEL_FATAL 严重的错误 \n
* &nbsp; 1: LOGLEVEL_ERROR 错误 \n
* &nbsp; 2: LOGLEVEL_WARNING 警告 \n
* &nbsp; 3: LOGLEVEL_INFO 通知 \n
* &nbsp; 4: LOGLEVEL_DEBUG 调试 \n
* &nbsp; 5: LOGLEVEL_BACKTRACE 跟踪 \n
* filename 表示文件名 \n
* line 表示代码行号 \n
* message 表示日志信息 \n
* @return 无
*/
void setLogHandler(
std::function<void(int /*level*/, const char * /*filename*/,
int /*line*/, const std::string & /*message*/)>
handler);
/**
* 连接到RPC服务
*
* @param ip IP地址
* @param port 端口号,RPC的端口号是30004
* @param ip和port为空时,采用unix domain sockets通讯方式
* @retval 0 RPC连接成功
* @retval -8 RPC连接失败,RPC连接被拒绝
* @retval -15 RPC连接失败,SDK版本与Server版本不兼容
*/
int connect(const std::string &ip = "", int port = 0);
/**
* 断开RPC连接
*
* @retval 0 成功
* @retval -1 失败
*/
int disconnect();
/**
* 判断是否连接RPC
*
* @retval true 已连接RPC
* @retval false 未连接RPC
*/
bool hasConnected() const;
/**
* 登录
*
* @param usrname 用户名
* @param passwd 密码
* @return 0
*/
int login(const std::string &usrname, const std::string &passwd);
/**
* 登出
*
* @return 0
*/
int logout();
/**
* 判断是否登录
*
* @retval true 已登录
* @retval false 未登录
*/
bool hasLogined();
/**
* 设置RPC请求超时时间
*
* @param timeout 请求超时时间,单位 ms
* @return 0
*/
int setRequestTimeout(int timeout = 100);
/**
* 设置事件处理
*
* @param cb
* @return
*/
int setEventHandler(std::function<void(int /*event*/)> cb);
/**
* 是否关闭异常抛出
*
* @param enable
* @return
*/
int setExceptionFree(bool enable);
/**
* 返回错误代码
*
* @return
*/
int errorCode() const;
/**
* 设备关机
*
* @return
*/
int shutdown();
/**
* 控制服务端RPC日志打印
*
* @param enable true 启用服务端日志打印,false 禁用服务端日志打印
* @return 0 成功
*/
int enableServerRpcLogging(bool enable);
};
using RpcClientPtr = std::shared_ptr<RpcClient>;
} // namespace aubo_sdk
} // namespace arcs
#ifdef __cplusplus
extern "C" {
#endif
ARCS_ABI arcs::aubo_sdk::RpcClient *createRpcClient(int mode = 0);
ARCS_ABI void destroyRpcClient(arcs::aubo_sdk::RpcClient *cli);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,321 @@
/** @file rpc_c.h
* @brief 用于RPC模块的交互,如登录、连接等功能
*/
#ifndef AUBO_SDK_RPC_C_H
#define AUBO_SDK_RPC_C_H
#include <aubo_sdk/type_def_c.h>
#ifdef __cplusplus
extern "C" {
#endif
enum Event
{
Event_Connected = 0,
Event_Disconnected = 1,
};
ARCS_ABI RPC_HANDLER rpc_create_client(int mode = 0);
ARCS_ABI void rpc_destroy_client(RPC_HANDLER cli);
/**
* 设置日志处理器
*
* 此函数可设置自定义的日志处理函数来处理日志消息。 \n
* Aubo SDK 有一套默认的日志系统,按照默认的格式输出到默认的文件。
* 如果用户不希望采用默认的格式或者不希望输出到默认的文件,那就可以通过这个接口重新自定义格式,或者输出路径。
* 这个函数可以将用户自定义的日志系统与 Aubo SDK 默认的日志系统合并。
*
* @note setLogHandler函数要放在即将触发的日志之前,
* 否则会按照默认的形式输出日志。
*
* @param handler 日志处理函数 \n
* 此日志处理函数的下定义如下: \n
* void handler(int level, const char* filename, int line, const
* std::string& message) \n
* level 表示日志等级 \n
* &nbsp; 0: LOGLEVEL_FATAL 严重的错误 \n
* &nbsp; 1: LOGLEVEL_ERROR 错误 \n
* &nbsp; 2: LOGLEVEL_WARNING 警告 \n
* &nbsp; 3: LOGLEVEL_INFO 通知 \n
* &nbsp; 4: LOGLEVEL_DEBUG 调试 \n
* &nbsp; 5: LOGLEVEL_BACKTRACE 跟踪 \n
* filename 表示文件名 \n
* line 表示代码行号 \n
* message 表示日志信息 \n
* @return 无
*/
ARCS_ABI void rpc_setLogHandler(RPC_HANDLER cli, LOG_HANDLER handler);
/**
* 连接到RPC服务
*
* @param ip IP地址
* @param port 端口号,RPC的端口号是30004
* @param ip和port为空时,采用unix domain sockets通讯方式
* @retval 0 RPC连接成功
* @retval -8 RPC连接失败,RPC连接被拒绝
* @retval -15 RPC连接失败,SDK版本与Server版本不兼容
*/
ARCS_ABI int rpc_connect(RPC_HANDLER cli, const char *ip = "", int port = 0);
/**
* 断开RPC连接
*
* @retval 0 成功
* @retval -1 失败
*/
ARCS_ABI int rpc_disconnect(RPC_HANDLER cli);
/**
* 判断是否连接RPC
*
* @retval true 已连接RPC
* @retval false 未连接RPC
*/
ARCS_ABI bool rpc_hasConnected(RPC_HANDLER cli);
/**
* 登录
*
* @param usrname 用户名
* @param passwd 密码
* @return 0
*/
ARCS_ABI int rpc_login(RPC_HANDLER cli, const char *usrname,
const char *passwd);
/**
* 登出
*
* @return 0
*/
ARCS_ABI int rpc_logout(RPC_HANDLER cli);
/**
* 判断是否登录
*
* @retval true 已登录
* @retval false 未登录
*/
ARCS_ABI bool rpc_hasLogined(RPC_HANDLER cli);
/**
* 设置RPC请求超时时间
*
* @param timeout 请求超时时间,单位 ms
* @return 0
*/
ARCS_ABI int rpc_setRequestTimeout(RPC_HANDLER cli, int timeout = 10);
/**
* 设置事件处理
*
* @param cb
* @return
*/
ARCS_ABI int rpc_setEventHandler(RPC_HANDLER cli, EVENT_CALLBACK cb);
/**
* 是否关闭异常抛出
*
* @param enable
* @return
*/
ARCS_ABI int rpc_set_exception_free(RPC_HANDLER cli, bool enable);
/**
* 返回错误代码
*
* @return
*/
ARCS_ABI int rpc_errorCode(RPC_HANDLER cli);
/**
* 设备关机
*
* @return
*/
ARCS_ABI int rpc_shutdown(RPC_HANDLER cli);
/**
* 获取纯数学相关接口
*
* @return MathPtr对象的指针
*
* @par Python函数原型
* getMath(self: pyaubo_sdk.AuboApi) -> pyaubo_sdk.Math
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* MathPtr ptr = rpc_cli->getMath();
* @endcode
*
*/
ARCS_ABI MATH_HANDLER rpc_getMath(RPC_HANDLER cli);
/**
* 获取系统信息
*
* @return SystemInfoPtr对象的指针
*
* @par Python函数原型
* getSystemInfo(self: pyaubo_sdk.AuboApi) -> pyaubo_sdk.SystemInfo
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* SystemInfoPtr ptr = rpc_cli->getSystemInfo();
* @endcode
*
*/
ARCS_ABI SYSTEM_INFO_HANDLER rpc_getSystemInfo(RPC_HANDLER cli);
/**
* 获取运行时接口
*
* @return RuntimeMachinePtr对象的指针
*
* @par Python函数原型
* getRuntimeMachine(self: pyaubo_sdk.AuboApi) -> pyaubo_sdk.RuntimeMachine
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* RuntimeMachinePtr ptr = rpc_cli->getRuntimeMachine();
* @endcode
*
*/
ARCS_ABI RUNTIME_MACHINE_HANDLER rpc_getRuntimeMachine(RPC_HANDLER cli);
/**
* 对外寄存器接口
*
* @return RegisterControlPtr对象的指针
*
* @par Python函数原型
* getRegisterControl(self: pyaubo_sdk.AuboApi) ->
* pyaubo_sdk.RegisterControl
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* RegisterControlPtr ptr = rpc_cli->getRegisterControl();
* @endcode
*
*/
ARCS_ABI REGISTER_CONTROL_HANDLER rpc_getRegisterControl(RPC_HANDLER cli);
/**
* 获取机器人列表
*
* @return 机器人列表
*
* @par Python函数原型
* getRobotNames(self: pyaubo_sdk.AuboApi) -> List[str]
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* @endcode
*
* @par JSON-RPC请求示例
* {"jsonrpc":"2.0","method":"getRobotNames","params":[],"id":1}
*
* @par JSON-RPC响应示例
* {"id":1,"jsonrpc":"2.0","result":["rob1"]}
*
*/
ARCS_ABI int rpc_getRobotNames(RPC_HANDLER cli, char **names);
/**
* 根据名字获取 RobotInterfacePtr 接口
*
* @param name 机器人名字
* @return RobotInterfacePtr对象的指针
*
* @par Python函数原型
* getRobotInterface(self: pyaubo_sdk.AuboApi, arg0: str) ->
* pyaubo_sdk.RobotInterface
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* auto robot_name = rpc_cli->getRobotNames().front();
* RobotInterfacePtr ptr = rpc_cli->getRobotInterface(robot_name);
* @endcode
*
*/
ARCS_ABI ROBOT_HANDLER rpc_getRobotInterface(RPC_HANDLER cli, const char *name);
/**
* 获取外部轴列表
*
* @return
*/
ARCS_ABI int rpc_getAxisNames(RPC_HANDLER cli, char **names);
/**
* 获取外部轴接口
*
* @param name
* @return
*/
ARCS_ABI AXIS_HANDLER rpc_getAxisInterface(RPC_HANDLER cli, const char *name);
/// 获取独立 IO 模块接口
/**
* 获取 socket
* @return SocketPtr对象的指针
*
* @par Python函数原型
* getSocket(self: pyaubo_sdk.AuboApi) -> arcs::common_interface::Socket
* @endcode
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* SocketPtr ptr = rpc_cli->getSocket();
* @endcode
*
*/
ARCS_ABI SOCKET_HANDLER rpc_getSocket(RPC_HANDLER cli);
/**
*
* @return SerialPtr对象的指针
*
* @par Python函数原型
* getSerial(self: pyaubo_sdk.AuboApi) -> arcs::common_interface::Serial
*
* @par C++示例
* @code
* auto rpc_cli = std::make_shared<RpcClient>();
* SerialPtr ptr = rpc_cli->getSerial();
* @endcode
*/
ARCS_ABI SERIAL_HANDLER rpc_getSerial(RPC_HANDLER cli);
/**
* 获取同步运动接口
*
* @return SyncMovePtr对象的指针
*/
ARCS_ABI SYNC_MOVE_HANDLER rpc_getSyncMove(RPC_HANDLER cli, const char *name);
/**
* 获取告警信息接口
*
* @return TracePtr对象的指针
*/
ARCS_ABI TRACE_HANDLER rpc_getTrace(RPC_HANDLER cli, const char *name);
#ifdef __cplusplus
}
#endif
#endif // #define AUBO_SDK_RPC_C_H

View File

@ -0,0 +1,305 @@
/** @file rtde.h
* @brief 用于RPC模块的交互,如订阅、发布等功能
*/
#ifndef AUBO_SDK_RTDE_H
#define AUBO_SDK_RTDE_H
#include <string>
#include <vector>
#include <functional>
#include <memory>
#include <map>
#include <unordered_map>
#include <aubo/type_def.h>
#include <aubo/global_config.h>
namespace arcs {
namespace aubo_sdk {
class RtdeClient;
/// 向输出数据中增加
class ARCS_ABI OutputBuilder
{
public:
OutputBuilder();
~OutputBuilder();
OutputBuilder &push(int val);
OutputBuilder &push(double val);
OutputBuilder &push(const std::vector<double> &val);
OutputBuilder &push(const std::tuple<int, bool> &val);
OutputBuilder &push(int16_t &val);
OutputBuilder &push(const std::vector<int16_t> &val);
OutputBuilder &push(const std::vector<int> &val);
OutputBuilder &push(const std::string &val);
OutputBuilder &push(char val);
OutputBuilder &push(const common_interface::RtdeRecipe &val);
private:
friend RtdeClient;
class Impl;
Impl *impl;
};
/// 解析输入
class ARCS_ABI InputParser
{
public:
InputParser();
~InputParser();
bool popBool();
int popInt32();
int64_t popInt64();
int16_t popInt16();
double popDouble();
char popChar();
std::vector<int> popVectorInt();
std::vector<int16_t> popVectorInt16();
std::vector<double> popVectorDouble();
std::vector<std::vector<double>> popVectorVectorDouble();
std::vector<common_interface::JointStateType> popVectorJointStateType();
common_interface::RobotModeType popRobotModeType();
common_interface::OperationalModeType popOperationalModeType();
common_interface::SafetyModeType popSafetyModeType();
common_interface::RuntimeState popRuntimeState();
common_interface::RobotMsgVector popRobotMsgVector();
common_interface::Payload popPayload();
common_interface::GripperStatusVector popGripperStatusVector();
common_interface::HandleStateType popHandleStateType();
common_interface::HandleModeType popHandleModeType();
private:
friend RtdeClient;
class Impl;
Impl *impl;
};
/// RTDE客户端
class ARCS_ABI RtdeClient
{
public:
enum Event
{
Connected,
Disconnected,
};
/**
* RTDE客户端初始化
*
* @param mode 设置通讯方式, 0 tcp通讯 1 uds通讯
*/
RtdeClient(int mode = 0);
~RtdeClient();
/**
* 设置日志处理器
*
* 此函数可设置自定义的日志处理函数来处理日志消息。 \n
* Aubo SDK 有一套默认的日志系统,按照默认的格式输出到默认的文件。
* 如果用户不希望采用默认的格式或者不希望输出到默认的文件,那就可以通过这个接口重新自定义格式,或者输出路径。
* 这个函数可以将用户自定义的日志系统与 Aubo SDK 默认的日志系统合并。
*
* @note setLogHandler函数要放在即将触发的日志之前,
* 否则会按照默认的形式输出日志。
*
* @param handler 日志处理函数 \n
* 此日志处理函数的下定义如下: \n
* void handler(int level, const char* filename, int line, const
* std::string& message) \n
* level 表示日志等级 \n
* &nbsp; 0: LOGLEVEL_FATAL 严重的错误 \n
* &nbsp; 1: LOGLEVEL_ERROR 错误 \n
* &nbsp; 2: LOGLEVEL_WARNING 警告 \n
* &nbsp; 3: LOGLEVEL_INFO 通知 \n
* &nbsp; 4: LOGLEVEL_DEBUG 调试 \n
* &nbsp; 5: LOGLEVEL_BACKTRACE 跟踪 \n
* filename 表示文件名 \n
* line 表示代码行号 \n
* message 表示日志信息 \n
* @return 无
*/
void setLogHandler(
std::function<void(int /*level*/, const char * /*filename*/,
int /*line*/, const std::string & /*message*/)>
handler);
/**
* 连接到服务器
*
* @param ip IP地址
* @param port 端口号,RTDE 端口号为30010
* @retval 0 连接成功
* @retval 1 在执行函数前,已连接
* @retval -1 连接失败
*/
int connect(const std::string &ip = "", int port = 0);
/**
* socket 是否已连接
*
* @retval true 已连接socket
* @retval false 未连接socket
*/
bool hasConnected() const;
/**
* socket 是否已连接
*
* @param callback
* @retval true 已连接socket
* @retval false 未连接socket
*/
bool hasConnected1(std::function<void(bool)> callback);
/**
* 登录
*
* @param usrname 用户名
* @param passwd 密码
* @retval 0 成功
* @retval -1 失败
*/
int login(const std::string &usrname, const std::string &passwd);
/**
* 是否已经登录
*
* @retval true 已登录
* @retval false 未登录
*/
bool hasLogined();
/**
* 登出
*
* @return 0
*/
int logout();
/**
* 断开连接
*
* @retval 0 成功
* @retval -1 失败
*/
int disconnect();
/**
* 获取协议版本号
*
* @return 协议版本号
*/
int getProtocolVersion();
/**
* 获取输入列表
*
* @return 输入列表
*/
std::map<std::string, int> getInputMaps();
/**
* 获取输出列表
*
* @return 输出列表
*/
std::map<std::string, int> getOutputMaps();
/**
* 设置话题
*
* @param to_server 数据流向。
* true 表示客户端给服务器发送消息,false 表示服务器给客户端发送消息
* @param names 服务器推送的信息列表
* @param freq 服务器推送信息的频率
* @param expected_chanel 通道。
* 取值范围:0~99,
* 发布不同的话题走不同的通道
* @retval expected_chanel参数的值 成功
* @retval -1 失败
*/
int setTopic(bool to_server, const std::vector<std::string> &names,
double freq, int expected_chanel);
/**
* 取消订阅
*
* @param to_server 数据流向
* true 表示客户端给服务器发送消息,false 表示服务器给客户端发送消息
* @param chanel 通道
* @retval 0 成功
* @retval 1 失败
*/
int removeTopic(bool to_server, int chanel);
/**
* 获取已注册的输入菜单
*
* @return 已注册的输入菜单
*/
std::unordered_map<int, common_interface::RtdeRecipe>
getRegisteredInputRecipe();
/**
* 获取已注册的输出菜单
*
* @return 已注册的输出菜单
*/
std::unordered_map<int, common_interface::RtdeRecipe>
getRegisteredOutputRecipe();
/**
* 订阅 subscribe from output
*
* @param chanel 通道
* @param callback 回调函数,用于处理订阅的输入信息。\n
* 回调函数的定义如下:
* void callback(InputParser &parser)
* @return 0
*/
int subscribe(int chanel, std::function<void(InputParser &)> callback);
/**
* 发布 publish to input
*
* @param chanel 通道
* @param callback 回调函数,用于构建发布的输出信息。\n
* 回调函数的定义如下:
* void callback(OutputBuilder &builder)
* @retval 0 成功
* @retval -1 失败
*/
int publish(int chanel, std::function<void(OutputBuilder &)> callback);
/**
* 设置事件处理
*
* @param cb
* @return
*/
int setEventHandler(std::function<void(int /*event*/)> cb);
private:
class Impl;
Impl *impl;
};
using RtdeClientPtr = std::shared_ptr<RtdeClient>;
} // namespace aubo_sdk
} // namespace arcs
#ifdef __cplusplus
extern "C" {
#endif
ARCS_ABI arcs::aubo_sdk::RtdeClient *createRtdeClient(int mode = 0);
ARCS_ABI void destroyRtdeClient(arcs::aubo_sdk::RtdeClient *cli);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,180 @@
#ifndef AUBO_SDK_RTDE_C_H
#define AUBO_SDK_RTDE_C_H
#include <aubo_sdk/type_def_c.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief 创建 RTDE 客户端实例。
*
* @param mode 设置通讯方式,0 表示 TCP 通讯,1 表示 UDS 通讯。
* @return 成功返回 RTDE 客户端句柄,失败返回 NULL。
*/
ARCS_ABI RTDE_HANDLE rtde_create_client(int mode);
/**
* @brief 销毁 RTDE 客户端实例。
*
* @param cli RTDE 客户端句柄。
*/
ARCS_ABI void rtde_destroy_client(RTDE_HANDLE cli);
/**
* @brief 设置日志处理器。
*
* @param cli RTDE 客户端句柄。
* @param handler 日志处理函数。
*/
ARCS_ABI void rtde_setLogHandler(RTDE_HANDLE cli,
void (*handler)(int level,
const char *filename, int line,
const char *message));
/**
* @brief 连接到服务器。
*
* @param cli RTDE 客户端句柄。
* @param ip IP 地址,NULL 表示使用默认地址。
* @param port 端口号,0 表示使用默认端口。
* @return 0 表示成功,-1 表示失败。
*/
ARCS_ABI int rtde_connect(RTDE_HANDLE cli, const char *ip, int port);
/**
* @brief 检查是否已连接。
*
* @param cli RTDE 客户端句柄。
* @return true 表示已连接,false 表示未连接。
*/
ARCS_ABI bool rtde_hasConnected(RTDE_HANDLE cli);
/**
* @brief 登录到服务器。
*
* @param cli RTDE 客户端句柄。
* @param username 用户名。
* @param password 密码。
* @return 0 表示成功,-1 表示失败。
*/
ARCS_ABI int rtde_login(RTDE_HANDLE cli, const char *username,
const char *password);
/**
* @brief 检查是否已登录。
*
* @param cli RTDE 客户端句柄。
* @return true 表示已登录,false 表示未登录。
*/
ARCS_ABI bool rtde_hasLogined(RTDE_HANDLE cli);
/**
* @brief 登出。
*
* @param cli RTDE 客户端句柄。
* @return 0 表示成功。
*/
ARCS_ABI int rtde_logout(RTDE_HANDLE cli);
/**
* @brief 断开连接。
*
* @param cli RTDE 客户端句柄。
* @return 0 表示成功,-1 表示失败。
*/
ARCS_ABI int rtde_disconnect(RTDE_HANDLE cli);
/**
* @brief 获取协议版本号。
*
* @param cli RTDE 客户端句柄。
* @return 协议版本号。
*/
ARCS_ABI int rtde_getProtocolVersion(RTDE_HANDLE cli);
/**
* @brief 设置话题。
*
* @param cli RTDE 客户端句柄。
* @param to_server 数据流向,true 表示客户端发送消息,false
* 表示服务器发送消息。
* @param names 信息列表(逗号分隔的字符串)。
* @param freq 推送频率。
* @param expected_chanel 通道号。
* @return 成功返回通道号,失败返回 -1。
*/
ARCS_ABI int rtde_setTopic(RTDE_HANDLE cli, bool to_server, const char *names,
double freq, int expected_chanel);
/**
* @brief 取消订阅。
*
* @param cli RTDE 客户端句柄。
* @param to_server 数据流向。
* @param chanel 通道号。
* @return 0 表示成功,-1 表示失败。
*/
ARCS_ABI int rtde_removeTopic(RTDE_HANDLE cli, bool to_server, int chanel);
/**
* @brief 订阅主题。
*
* @param cli RTDE 客户端句柄。
* @param chanel 通道号。
* @param callback 回调函数,用于处理订阅的数据。
* @return 0 表示成功,-1 表示失败。
*/
ARCS_ABI int rtde_subscribe(RTDE_HANDLE cli, int chanel,
void (*callback)(void *parser));
/**
* @brief 发布数据。
*
* @param cli RTDE 客户端句柄。
* @param chanel 通道号。
* @param callback 回调函数,用于生成发布数据。
* @return 0 表示成功,-1 表示失败。
*/
ARCS_ABI int rtde_publish(RTDE_HANDLE cli, int chanel,
void (*callback)(void *builder));
// OutputBuilder
ARCS_ABI int rtde_pushInt(OUTPUT_BUILDER_HANDLE builder, int val);
ARCS_ABI int rtde_pushDouble(OUTPUT_BUILDER_HANDLE builder, double val);
ARCS_ABI int rtde_pushVectorDouble(OUTPUT_BUILDER_HANDLE builder, const double* val, int size);
ARCS_ABI int rtde_pushTupleIntBool(OUTPUT_BUILDER_HANDLE builder, int first, bool second);
ARCS_ABI int rtde_pushInt16(OUTPUT_BUILDER_HANDLE builder, int16_t val);
ARCS_ABI int rtde_pushVectorInt16(OUTPUT_BUILDER_HANDLE builder, const int16_t* val, int size);
ARCS_ABI int rtde_pushVectorInt(OUTPUT_BUILDER_HANDLE builder, const int* val, int size);
ARCS_ABI int rtde_pushString(OUTPUT_BUILDER_HANDLE builder, const char* val);
ARCS_ABI int rtde_pushChar(OUTPUT_BUILDER_HANDLE builder, char val);
ARCS_ABI int rtde_pushRtdeRecipe(OUTPUT_BUILDER_HANDLE builder, const struct RtdeRecipe_C* val);
// InputParser
ARCS_ABI bool rtde_popBool(INPUT_PARSER_HANDLE parser);
ARCS_ABI int32_t rtde_popInt32(INPUT_PARSER_HANDLE parser);
ARCS_ABI int64_t rtde_popInt64(INPUT_PARSER_HANDLE parser);
ARCS_ABI int16_t rtde_popInt16(INPUT_PARSER_HANDLE parser);
ARCS_ABI double rtde_popDouble(INPUT_PARSER_HANDLE parser);
ARCS_ABI char rtde_popChar(INPUT_PARSER_HANDLE parser);
ARCS_ABI int rtde_popVectorInt(INPUT_PARSER_HANDLE* parser, int* data, int size);
ARCS_ABI int rtde_popVectorInt16(INPUT_PARSER_HANDLE parser, int16_t* data, int size);
ARCS_ABI int rtde_popVectorDouble(INPUT_PARSER_HANDLE parser, double* data, int size);
ARCS_ABI int rtde_popVectorVectorDouble(INPUT_PARSER_HANDLE parser, double*** data, int rows, int cols);
ARCS_ABI JointStateType_C rtde_popVectorJointStateType(INPUT_PARSER_HANDLE parser);
ARCS_ABI RobotModeType_C rtde_popRobotModeType(INPUT_PARSER_HANDLE parser);
ARCS_ABI OperationalModeType_C rtde_popOperationalModeType(INPUT_PARSER_HANDLE parser);
ARCS_ABI SafetyModeType_C rtde_popSafetyModeType(INPUT_PARSER_HANDLE parser);
ARCS_ABI RuntimeState_C rtde_popRuntimeState(INPUT_PARSER_HANDLE parser);
ARCS_ABI int rtde_popRobotMsgVector(INPUT_PARSER_HANDLE parser, struct RobotMsgVector_C* robot_msg_vec);
ARCS_ABI int rtde_popPayload(INPUT_PARSER_HANDLE parser, struct Payload_C* payload);
#ifdef __cplusplus
}
#endif
#endif // AUBO_SDK_RTDE_C_H

View File

@ -0,0 +1,60 @@
#ifndef AUBO_SDK_RuntimeMachine_C_H
#define AUBO_SDK_RuntimeMachine_C_H
#include <aubo_sdk/type_def_c.h>
#ifdef __cplusplus
extern "C" {
#endif
ARCS_ABI int newTask(RUNTIME_MACHINE_HADNLER h, BOOL daemon);
ARCS_ABI int deleteTask(RUNTIME_MACHINE_HADNLER h, int tid);
ARCS_ABI int detachTask(RUNTIME_MACHINE_HADNLER h, int tid);
ARCS_ABI BOOL isTaskAlive(RUNTIME_MACHINE_HADNLER h, int tid);
ARCS_ABI int nop(RUNTIME_MACHINE_HADNLER h);
ARCS_ABI int switchTask(RUNTIME_MACHINE_HADNLER h, int tid);
ARCS_ABI int setLabel(RUNTIME_MACHINE_HADNLER h, int tid, const char *lineno);
ARCS_ABI int setPlanContext(RUNTIME_MACHINE_HADNLER h, int tid, int lineno,
const char *comment);
ARCS_ABI int gotoLine(RUNTIME_MACHINE_HADNLER h, int lineno);
ARCS_ABI int getAdvancePlanContext(RUNTIME_MACHINE_HADNLER h, int tid,
struct PlanContext_C *result);
ARCS_ABI int getAdvancePtr(RUNTIME_MACHINE_HADNLER h, int tid);
ARCS_ABI int getMainPtr(RUNTIME_MACHINE_HADNLER h, int tid);
ARCS_ABI int getInterpPtr(RUNTIME_MACHINE_HADNLER h, int tid);
ARCS_ABI int getPlanContext(RUNTIME_MACHINE_HADNLER h, int tid,
struct PlanContext_C *result);
ARCS_ABI int getExecutionStatus(RUNTIME_MACHINE_HADNLER h,
struct ExecutionStatus_C *result);
ARCS_ABI int getExecutionStatus1(RUNTIME_MACHINE_HADNLER h,
struct ExecutionStatus1_C *result);
ARCS_ABI int loadProgram(RUNTIME_MACHINE_HADNLER h, const char *program);
ARCS_ABI int runProgram(RUNTIME_MACHINE_HADNLER h);
ARCS_ABI int start(RUNTIME_MACHINE_HADNLER h);
ARCS_ABI int stop(RUNTIME_MACHINE_HADNLER h);
ARCS_ABI int abort1(RUNTIME_MACHINE_HADNLER h);
ARCS_ABI int pause(RUNTIME_MACHINE_HADNLER h);
ARCS_ABI int step(RUNTIME_MACHINE_HADNLER h);
ARCS_ABI int setResumeWait(RUNTIME_MACHINE_HADNLER h, BOOL wait);
ARCS_ABI int resume(RUNTIME_MACHINE_HADNLER h);
ARCS_ABI RuntimeState_C getStatus(RUNTIME_MACHINE_HADNLER h);
ARCS_ABI RuntimeState_C getRuntimeState(RUNTIME_MACHINE_HADNLER h);
ARCS_ABI int setBreakPoint(RUNTIME_MACHINE_HADNLER h, int lineno);
ARCS_ABI int removeBreakPoint(RUNTIME_MACHINE_HADNLER h, int lineno);
ARCS_ABI int clearBreakPoints(RUNTIME_MACHINE_HADNLER h);
ARCS_ABI int timerStart(RUNTIME_MACHINE_HADNLER h, const char *name);
ARCS_ABI int timerStop(RUNTIME_MACHINE_HADNLER h, const char *name);
ARCS_ABI int timerReset(RUNTIME_MACHINE_HADNLER h, const char *name);
ARCS_ABI int timerDelete(RUNTIME_MACHINE_HADNLER h, const char *name);
ARCS_ABI double getTimer(RUNTIME_MACHINE_HADNLER h, const char *name);
ARCS_ABI int triggBegin(RUNTIME_MACHINE_HADNLER h, double distance,
double delay);
ARCS_ABI int triggEnd(RUNTIME_MACHINE_HADNLER h);
ARCS_ABI int triggInterrupt(RUNTIME_MACHINE_HADNLER h, double distance,
double delay);
ARCS_ABI int getTriggInterrupts(RUNTIME_MACHINE_HADNLER h, int *result);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,209 @@
/** @file script.h
* @brief 用于SCRIPT模块的交互,如向服务器发送脚本
*/
#ifndef AUBO_SDK_SCRIPT_H
#define AUBO_SDK_SCRIPT_H
#include <string>
#include <memory>
#include <functional>
#include <aubo/global_config.h>
namespace arcs {
namespace aubo_sdk {
class ScriptWriter
{
public:
virtual ~ScriptWriter() = default;
virtual ScriptWriter &append(const std::string &line) = 0;
virtual ScriptWriter &append(const char *buf, size_t len) = 0;
virtual ScriptWriter &moveJoint() = 0;
virtual ScriptWriter &moveLine() = 0;
virtual ScriptWriter &ifCondition() = 0;
virtual ScriptWriter &elseCondition() = 0;
virtual ScriptWriter &elseIfCondition() = 0;
virtual ScriptWriter &whileCondition() = 0;
virtual ScriptWriter &end() = 0;
};
/// SCRIPT客户端
class ARCS_ABI ScriptClient
{
public:
enum Event
{
Connected,
Disconnected,
};
ScriptClient(int mode = 0);
~ScriptClient();
/**
* 设置日志处理器
*
* 此函数可设置自定义的日志处理函数来处理日志消息。 \n
* Aubo SDK 有一套默认的日志系统,按照默认的格式输出到默认的文件。
* 如果用户不希望采用默认的格式或者不希望输出到默认的文件,那就可以通过这个接口重新自定义格式,或者输出路径。
* 这个函数可以将用户自定义的日志系统与 Aubo SDK 默认的日志系统合并。
*
* @note setLogHandler函数要放在即将触发的日志之前,
* 否则会按照默认的形式输出日志。
*
* @param handler 日志处理函数 \n
* 此日志处理函数的下定义如下: \n
* void handler(int level, const char* filename, int line, const
* std::string& message) \n
* level 表示日志等级 \n
* &nbsp; 0: LOGLEVEL_FATAL 严重的错误 \n
* &nbsp; 1: LOGLEVEL_ERROR 错误 \n
* &nbsp; 2: LOGLEVEL_WARNING 警告 \n
* &nbsp; 3: LOGLEVEL_INFO 通知 \n
* &nbsp; 4: LOGLEVEL_DEBUG 调试 \n
* &nbsp; 5: LOGLEVEL_BACKTRACE 跟踪 \n
* filename 表示文件名 \n
* line 表示代码行号 \n
* message 表示日志信息 \n
* @return 无
*/
void setLogHandler(
std::function<void(int /*level*/, const char * /*filename*/,
int /*line*/, const std::string & /*message*/)>
handler);
/**
* 连接到服务器
*
* @param ip IP地址
* @param port 端口号。SCRIPT端口号为30004
* @retval 0 连接成功
* @retval 1 在执行函数前,已连接
* @retval -1 连接失败
*/
int connect(const std::string &ip = "", int port = 0);
/**
* 是否处于连接状态
*
* @retval true 已连接
* @retval false 未连接
*/
bool hasConnected() const;
/**
* 登录
*
* @param usrname 用户名
* @param passwd 密码
* @retval 0 成功
* @retval -1 失败
*/
int login(const std::string &usrname, const std::string &passwd);
/**
* 返回客户端是否登录
*
* @retval true 已登录
* @retval false 未登录
*/
bool hasLogined();
/**
* 登出
*
* @return 0
*/
int logout();
/**
* 断开连接
*
* @retval 0 成功
* @retval -1 失败
*/
int disconnect();
/**
* 发送脚本文件
*
* 远程调用机器人的脚本
*
* @param path 文件在机器人端的路径
* @retval 0 成功
* @retval -1 失败
*/
int sendFile(const std::string &path);
/**
* 发送脚本内容
*
* 调用本地的脚本
*
* @param script 脚本内容
* @retval 0 成功
* @retval -1 失败
*/
int sendString(const std::string &script);
/**
* 使用ScriptWriter构建服务器脚本
*
* @param chunck_name
* @param cb
* @retval 0 成功
* @retval -1 失败
*/
int send(const std::string &chunck_name,
std::function<int(ScriptWriter &)> cb);
/**
* 设置服务器脚本的全局变量
*
* @param cb 脚本的全局变量
* @return 0
*/
int subscribeVariableUpdate(
std::function<void(const std::string &, const std::string &)> cb);
/**
* 设置服务器脚本的错误码
*
* @param cb 脚本的错误码
* @return 0
*/
ARCS_DEPRECATED int subscribeScriptError(
std::function<void(const std::string &)> cb);
int subscribeScriptError2(
std::function<void(const std::string &, const std::string &)> cb);
/**
* 设置事件处理
*
* @param cb
* @return
*/
int setEventHandler(std::function<void(int /*event*/)> cb);
private:
class Impl;
Impl *impl;
};
using ScriptClientPtr = std::shared_ptr<ScriptClient>;
} // namespace aubo_sdk
} // namespace arcs
#ifdef __cplusplus
extern "C" {
#endif
ARCS_ABI arcs::aubo_sdk::ScriptClient *createScriptClient(int mode = 0);
ARCS_ABI void destroyScriptClient(arcs::aubo_sdk::ScriptClient *cli);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,32 @@
#ifndef AUBO_SDK_Serial_C_H
#define AUBO_SDK_Serial_C_H
#include <aubo_sdk/type_def_c.h>
#ifdef __cplusplus
extern "C" {
#endif
ARCS_ABI int serialOpen(SERIAL_HANDLER h, const char *device, int baud,
float stop_bits, int even, const char *serial_name);
ARCS_ABI int serialClose(SERIAL_HANDLER h, const char *serial_name);
ARCS_ABI int serialReadByte(SERIAL_HANDLER h, const char *variable,
const char *serial_name);
ARCS_ABI int serialReadByteList(SERIAL_HANDLER h, int number,
const char *variable, const char *serial_name);
ARCS_ABI int serialReadString(SERIAL_HANDLER h, const char *variable,
const char *serial_name, const char *prefix,
const char *suffix, BOOL interpret_escape);
ARCS_ABI int serialSendByte(SERIAL_HANDLER h, char value,
const char *serial_name);
ARCS_ABI int serialSendInt(SERIAL_HANDLER h, int value,
const char *serial_name);
ARCS_ABI int serialSendLine(SERIAL_HANDLER h, const char *str,
const char *serial_name);
ARCS_ABI int serialSendString(SERIAL_HANDLER h, const char *str,
const char *serial_name);
ARCS_ABI int serialSendAllString(SERIAL_HANDLER h, BOOL is_check,
const char *str, const char *serial_name);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,38 @@
#ifndef AUBO_SDK_Socket_C_H
#define AUBO_SDK_Socket_C_H
#include <aubo_sdk/type_def_c.h>
#ifdef __cplusplus
extern "C" {
#endif
ARCS_ABI int socketOpen(SOCKET_HANDLER h, const char *address, int port,
const char *socket_name);
ARCS_ABI int socketClose(SOCKET_HANDLER h, const char *socket_name);
ARCS_ABI int socketReadAsciiFloat(SOCKET_HANDLER h, int number,
const char *variable,
const char *socket_name);
ARCS_ABI int socketReadBinaryInteger(SOCKET_HANDLER h, int number,
const char *variable,
const char *socket_name);
ARCS_ABI int socketReadByteList(SOCKET_HANDLER h, int number,
const char *variable, const char *socket_name);
ARCS_ABI int socketReadString(SOCKET_HANDLER h, const char *variable,
const char *socket_name, const char *prefix,
const char *suffix, BOOL interpret_escape);
ARCS_ABI int socketReadAllString(SOCKET_HANDLER h, const char *variable,
const char *socket_name);
ARCS_ABI int socketSendByte(SOCKET_HANDLER h, char value,
const char *socket_name);
ARCS_ABI int socketSendInt(SOCKET_HANDLER h, int value,
const char *socket_name);
ARCS_ABI int socketSendLine(SOCKET_HANDLER h, const char *str,
const char *socket_name);
ARCS_ABI int socketSendString(SOCKET_HANDLER h, const char *str,
const char *socket_name);
ARCS_ABI int socketSendAllString(SOCKET_HANDLER h, BOOL is_check,
const char *str, const char *socket_name);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,22 @@
#ifndef AUBO_SDK_SyncMove_C_H
#define AUBO_SDK_SyncMove_C_H
#include <aubo_sdk/type_def_c.h>
#ifdef __cplusplus
extern "C" {
#endif
ARCS_ABI int syncMoveOn(SYNC_MOVE_HANDLER h, const char *syncident,
const char **taskset);
ARCS_ABI BOOL syncMoveSegment(SYNC_MOVE_HANDLER h, int id);
ARCS_ABI int syncMoveOff(SYNC_MOVE_HANDLER h, const char *syncident);
ARCS_ABI int syncMoveUndo(SYNC_MOVE_HANDLER h);
ARCS_ABI int waitSyncTasks(SYNC_MOVE_HANDLER h, const char *syncident,
const char **taskset);
ARCS_ABI BOOL isSyncMoveOn(SYNC_MOVE_HANDLER h);
ARCS_ABI int syncMoveSuspend(SYNC_MOVE_HANDLER h);
ARCS_ABI int syncMoveResume(SYNC_MOVE_HANDLER h);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,18 @@
#ifndef AUBO_SDK_SystemInfo_C_H
#define AUBO_SDK_SystemInfo_C_H
#include <aubo_sdk/type_def_c.h>
#ifdef __cplusplus
extern "C" {
#endif
ARCS_ABI int getControlSoftwareVersionCode(SYSTEM_INFO_HANDLER h);
ARCS_ABI int getControlSoftwareFullVersion(SYSTEM_INFO_HANDLER h, char *result);
ARCS_ABI int getInterfaceVersionCode(SYSTEM_INFO_HANDLER h);
ARCS_ABI int getControlSoftwareBuildDate(SYSTEM_INFO_HANDLER h, char *result);
ARCS_ABI int getControlSoftwareVersionHash(SYSTEM_INFO_HANDLER h, char *result);
ARCS_ABI uint64_t getControlSystemTime(SYSTEM_INFO_HANDLER h);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,20 @@
#ifndef AUBO_SDK_Trace_C_H
#define AUBO_SDK_Trace_C_H
#include <aubo_sdk/type_def_c.h>
#ifdef __cplusplus
extern "C" {
#endif
ARCS_ABI int alarm(TRACE_HANDLER h, TraceLevel_C level, int code,
const char **args);
ARCS_ABI int popup(TRACE_HANDLER h, TraceLevel_C level, const char *title,
const char *msg, int mode);
ARCS_ABI int textmsg(TRACE_HANDLER h, const char *msg);
ARCS_ABI int notify(TRACE_HANDLER h, const char *msg);
ARCS_ABI int peek(TRACE_HANDLER h, uint64_t num, uint64_t last_time,
struct RobotMsg_C *result);
#ifdef __cplusplus
}
#endif
#endif

Some files were not shown because too many files have changed in this diff Show More