revert: rollback dev to fb304df94c

This commit is contained in:
lgv 2026-06-25 09:26:23 +08:00
parent b4468809da
commit a6d749f679
89 changed files with 123 additions and 12838 deletions

View File

@ -122,8 +122,6 @@ target_link_libraries(cmvr_es PRIVATE
cmvr_es::device::humanoid_robot
cmvr_es::common
cmvr_es::applications
cmvr_es::device::agv_src1100
)
install(TARGETS cmvr_es RUNTIME DESTINATION bin)

View File

@ -1,30 +0,0 @@
src1100_agvs {
id: "agv_src1100"
ip: "192.168.192.5"
port_status: 19204
port_control: 19205
port_nav: 19206
port_config: 19207
port_other: 19210
port_push: 19302
enable: true
}
src1100_agvs {
id: "agv_src2200"
ip: "192.168.192.5"
port_status: 19204
port_control: 19205
port_nav: 19206
port_config: 19207
port_other: 19210
port_push: 19301
enable: true
}

View File

@ -1,27 +0,0 @@
bioheads {
id: "bio_head"
serial: "/dev/ttyUSB0"
ctrlFreq: 50
enable: false
eyebrow {
serial: "64:0~3"
offest: "90 90 90 90"
jLmtUp: "90 170 155 110"
jLmtLow: "20 77 90 20"
}
eye {
serial: "64:4~9"
offest: "90 90 90 90 90 90"
jLmtUp: "90 150 165 90 120 115"
jLmtLow: "20 90 90 25 70 75"
}
mouth {
serial: "65:0~9"
offest: "90 90 90 90 90 90 90 90 90 90"
jLmtUp: "150 110 130 140 100 105 110 125 90 95"
jLmtLow: "70 30 80 80 65 55 45 80 85 90"
}
}

View File

@ -27,7 +27,7 @@ realsense_cameras {
align_mode: ALIGN_MODE_COLOR
buffer_size: 30
sync: false
enable: false
enable: true
}
realsense_cameras {

View File

@ -1,6 +1,6 @@
rh56dftp_dexhands {
id: "hand1"
ip: "192.168.1.223"
ip: "192.168.1.213"
port: 6000
poll_interval_ms: 10
enable: false
@ -11,7 +11,7 @@ rh56dftp_dexhands {
ip: "192.168.1.224"
port: 6000
poll_interval_ms: 10
enable: false
enable: true
}
px_6ax_gen3 {
@ -32,5 +32,5 @@ px_6ax_gen3 {
sensor_name: "Paxini Gen3末端压力"
polling_read_mode: PX_6AX_GEN3_POLLING_READ_MODE_RESULTANT_FORCE
auto_calibrate: false
enable: false
enable: true
}

View File

@ -1,25 +0,0 @@
# 监控管理器配置
monitor_manager {
disk_monitor {
id: "file_monitor"
freq: 1
enable: false
folders {
fileDir: "/home/share/assets/audio"
maxVolume: 1000
}
folders {
fileDir: "/home/share/assets/image"
maxVolume: 1000
}
folders {
fileDir: "/home/share/assets/video"
maxVolume: 1000
}
folders {
fileDir: "../log"
maxVolume: 1000
}
}
}

View File

@ -1,36 +0,0 @@
ethercat_robots {
id: "ec_robot_01"
dof: 6
urdf: "/home/cmvr/Projects/cmvr-es/model/xiaoyan_description/dual_arm.urdf"
baseLink: "PELVIS_S"
jointNames: "L_SHOULDER_P,L_SHOULDER_R,L_SHOULDER_Y,L_ELBOW_R,L_WRIST_P,L_WRIST_Y,L_WRIST_R,R_SHOULDER_P,R_SHOULDER_R,R_SHOULDER_Y,R_ELBOW_R,R_WRIST_P,R_WRIST_Y,R_WRIST_R"
linkNames: "PELVIS_S,L_SHOULDER_P_S,L_SHOULDER_R_S,L_SHOULDER_Y_S,L_ELBOW_R_S,L_WRIST_P_S,L_WRIST_Y_S,L_WRIST_R_S,R_SHOULDER_P_S,R_SHOULDER_R_S,R_SHOULDER_Y_S,R_ELBOW_R_S,R_WRIST_P_S,R_WRIST_Y_S,R_WRIST_R_S,R_FINGER_TIP,R_CAM"
bufferSize: 100
verbose: true
updFreq: 1000
enable: true
# EtherCAT主站配置
master {
interface: "enp1s0"
cycle_time_us: 1000
enable: true
}
# 电机配置列表
motors {
slave: 1
jointName: "L_SHOULDER_P"
limitQLb: -3.14
limitQUb: 3.14
limitQd: 3.0
}
motors {
slave: 2
jointName: "L_SHOULDER_R"
limitQLb: -3.14
limitQUb: 3.14
limitQd: 3.0
}
}

View File

@ -1,3 +0,0 @@
grpc_server {
port: "50052"
}

View File

@ -10,10 +10,6 @@
#include "cmvr/config/microphone_config/microphone_config.pb.h"
#include "cmvr/config/speaker_config/speaker_conifg.pb.h"
#include "cmvr/config/touch_screen_app_config/touch_screen_app_config.pb.h"
#include "cmvr/config/agv_config/agv_config.grpc.pb.h"
#include "cmvr/config/biohead_config/biohead_config.pb.h"
#include "cmvr/config/robot_config/robot_config.pb.h"
#include "cmvr/config/server_config/server_config.pb.h"
#define GET_CONFIG(file, para) \
([&]() -> bool { \
@ -86,26 +82,6 @@ namespace cmvr
return SET_CONFIG(config, touch_screen_app_config_file);
}
static bool getAgvConfig(config::AGVConfig& config)
{
return GET_CONFIG(agv_config_file, config);
}
static bool getHeadConfig(config::HeadConfig& config)
{
return GET_CONFIG(biohead_config_file, config);
}
static bool getRobotConfig(config::RobotConfig& config)
{
return GET_CONFIG(robot_config_file, config);
}
static bool getServerConfig(config::ServerConfig& config)
{
return GET_CONFIG(server_config_file, config);
}
private:
// Make macros able to call these (macros call ::cmvr::ConfigHelper::xxx)
template <class T>

View File

@ -6,8 +6,3 @@ DECLARE_string(dexhand_config_file);
DECLARE_string(microphone_config_file);
DECLARE_string(speaker_config_file);
DECLARE_string(touch_screen_app_config_file);
DECLARE_string(agv_config_file);
DECLARE_string(biohead_config_file);
DECLARE_string(robot_config_file);
DECLARE_string(server_config_file);

View File

@ -88,19 +88,3 @@ DEFINE_string(speaker_config_file,
DEFINE_string(touch_screen_app_config_file,
basePath() + "touch_screen_app_config/touch_screen_app_config.pb.txt",
"The configuration file for TouchScreenApp");
DEFINE_string(agv_config_file,
basePath() + "agv_config/agv_config.pb.txt",
"AGV config file");
DEFINE_string(biohead_config_file,
basePath() + "biohead_config/biohead_config.pb.txt",
"The configuration file for BioHead");
DEFINE_string(robot_config_file,
basePath() + "robot_config/robot_config.pb.txt",
"The configuration file for Robot");
DEFINE_string(server_config_file,
basePath() + "server_config/server_config.pb.txt",
"The configuration file for Server");

View File

@ -1,53 +0,0 @@
// FrameData.h
#pragma once
#include <opencv2/opencv.hpp>
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
}
namespace ffmpeg {
struct FrameData {
AVFrame* av_frame = nullptr; // 编码用帧YUV格式
cv::Mat rgb_image; // OpenCV用图像BGR格式
int64_t pts = 0; // 时间戳
int64_t frame_index = 0; // 帧序号
FrameData() = default;
~FrameData() {
if (av_frame) {
av_frame_free(&av_frame);
}
}
// 禁止拷贝
FrameData(const FrameData&) = delete;
FrameData& operator=(const FrameData&) = delete;
// 允许移动
FrameData(FrameData&& other) noexcept
: av_frame(other.av_frame),
rgb_image(std::move(other.rgb_image)),
pts(other.pts),
frame_index(other.frame_index) {
other.av_frame = nullptr;
}
FrameData& operator=(FrameData&& other) noexcept {
if (this != &other) {
if (av_frame) av_frame_free(&av_frame);
av_frame = other.av_frame;
rgb_image = std::move(other.rgb_image);
pts = other.pts;
frame_index = other.frame_index;
other.av_frame = nullptr;
}
return *this;
}
};
} // namespace ffmpeg

View File

@ -11,7 +11,6 @@ target_link_libraries(data_center PRIVATE
cmvr_es::utils
cmvr_es::device::canbus
cmvr_es::device::ti5motor
cmvr_es::device::eyoumotor
protobuf
glog
)

View File

@ -23,9 +23,8 @@ namespace cmvr {
public:
~MotorsInfo(){};
void init(const XmlNode &cfg);
void init(const cmvr::config::HumanRobotConfig& config);
void init(const cmvr::config::EthercatRobotConfig& config);
static MotorsInfo *getInstance() {
static MotorsInfo instance;

View File

@ -3,8 +3,6 @@
//
#include "data_center/include/motors_info.h"
#include "motor/eyou_motor/eyou_motor.h"
#include "motor/ti5_motor/canopen/ti5_motor_canopen_protocol.h"
#include "motor/ti5_motor/ti5_motor.h"
@ -96,10 +94,7 @@ void MotorsInfo::init(const XmlNode &cfg) {
};
// 创建 MotorManager
if (!motor_manager_)
{
motor_manager_ = std::make_shared<MotorManager>();
}
std::vector<std::future<void> > tasks;
@ -156,155 +151,6 @@ void MotorsInfo::init(const XmlNode &cfg) {
LOG(INFO) << "All enabled motors initialized successfully.";
}
void MotorsInfo::init(const cmvr::config::HumanRobotConfig& config) {
const auto& can_manager = config.can_manager();
// 读取enable状态
left_arm_enabled_ = can_manager.left_arm().enable();
right_arm_enabled_ = can_manager.right_arm().enable();
waist_enabled_ = can_manager.waist().enable();
head_enabled_ = can_manager.head().enable();
// 局部变量存储电机配置
std::vector<cmvr::config::MotorConfig> l_motors_cfg;
std::vector<cmvr::config::MotorConfig> r_motors_cfg;
std::vector<cmvr::config::MotorConfig> waist_motors_cfg;
std::vector<cmvr::config::MotorConfig> head_motors_cfg;
// 左臂
if (left_arm_enabled_) {
const auto& left_arm = can_manager.left_arm();
for (const auto& motor : left_arm.motors()) {
l_motors_cfg.push_back(motor);
}
l_can_client_ = std::make_shared<SocketCanClientRaw>(left_arm);
l_can_sender_ = std::make_shared<CanSender<msgs::RobotDetail>>();
l_can_receiver_ = std::make_shared<CanReceiver<msgs::RobotDetail>>();
l_message_manager_ = std::make_shared<MessageManager<msgs::RobotDetail>>();
}
// 右臂
if (right_arm_enabled_) {
const auto& right_arm = can_manager.right_arm();
for (const auto& motor : right_arm.motors()) {
r_motors_cfg.push_back(motor);
}
r_can_client_ = std::make_shared<SocketCanClientRaw>(right_arm);
r_can_sender_ = std::make_shared<CanSender<msgs::RobotDetail>>();
r_can_receiver_ = std::make_shared<CanReceiver<msgs::RobotDetail>>();
r_message_manager_ = std::make_shared<MessageManager<msgs::RobotDetail>>();
}
// 腰部
if (waist_enabled_) {
const auto& waist = can_manager.waist();
for (const auto& motor : waist.motors()) {
waist_motors_cfg.push_back(motor);
}
waist_can_client_ = std::make_shared<SocketCanClientRaw>(waist);
waist_can_sender_ = std::make_shared<CanSender<msgs::RobotDetail>>();
waist_can_receiver_ = std::make_shared<CanReceiver<msgs::RobotDetail>>();
waist_message_manager_ = std::make_shared<MessageManager<msgs::RobotDetail>>();
}
// 头部
if (head_enabled_) {
const auto& head = can_manager.head();
for (const auto& motor : head.motors()) {
head_motors_cfg.push_back(motor);
}
head_can_client_ = std::make_shared<SocketCanClientRaw>(head);
head_can_sender_ = std::make_shared<CanSender<msgs::RobotDetail>>();
head_can_receiver_ = std::make_shared<CanReceiver<msgs::RobotDetail>>();
head_message_manager_ = std::make_shared<MessageManager<msgs::RobotDetail>>();
}
// 初始化 limbs
struct Limb {
std::string name;
bool enabled;
std::shared_ptr<AbstractCanbus> client;
std::shared_ptr<CanSender<msgs::RobotDetail>> sender;
std::shared_ptr<CanReceiver<msgs::RobotDetail>> receiver;
std::shared_ptr<MessageManager<msgs::RobotDetail>> message_manager;
std::vector<cmvr::config::MotorConfig> motor_cfgs;
};
std::vector<Limb> limbs{
{"WAIST", waist_enabled_, waist_can_client_, waist_can_sender_, waist_can_receiver_, waist_message_manager_, waist_motors_cfg},
{"LEFT_ARM", left_arm_enabled_, l_can_client_, l_can_sender_, l_can_receiver_, l_message_manager_, l_motors_cfg},
{"RIGHT_ARM", right_arm_enabled_, r_can_client_, r_can_sender_, r_can_receiver_, r_message_manager_, r_motors_cfg},
{"HEAD", head_enabled_, head_can_client_, head_can_sender_, head_can_receiver_, head_message_manager_, head_motors_cfg}
};
if (!motor_manager_)
{
motor_manager_ = std::make_shared<MotorManager>();
}
std::vector<std::future<void>> tasks;
for (auto &limb : limbs) {
if (!limb.enabled) continue;
if (limb.client) limb.client->init();
if (limb.sender && limb.receiver && limb.client) {
auto ret = limb.sender->Init(limb.client.get(), false);
if (ret != ErrorCode::OK)
LOG(ERROR) << "Failed to init " << limb.name << " CAN sender.";
ret = limb.receiver->Init(limb.client.get(), limb.message_manager.get(), false);
if (ret != ErrorCode::OK)
LOG(ERROR) << "Failed to init " << limb.name << " CAN receiver.";
limb.client->start();
ret = limb.sender->Start();
if (ret != ErrorCode::OK)
LOG(ERROR) << "Failed to start " << limb.name << " CAN sender.";
ret = limb.receiver->Start();
if (ret != ErrorCode::OK)
LOG(ERROR) << "Failed to start " << limb.name << " CAN receiver.";
}
std::shared_ptr<Ti5MotorCanopenProtocol> protocol = nullptr;
if (limb.sender && limb.message_manager) {
protocol = std::make_shared<Ti5MotorCanopenProtocol>(limb.sender, limb.message_manager);
}
if (!limb.motor_cfgs.empty()) {
tasks.push_back(std::async(std::launch::async, [this, protocol, &limb] {
LOG(INFO) << "[Thread " << std::this_thread::get_id() << "] Start initializing " << limb.name << " motors...";
for (const auto& motor_cfg : limb.motor_cfgs) {
auto motor = std::make_shared<Ti5Motor>(motor_cfg);
if (protocol) motor->setProtocol(protocol);
motor->init();
motor_manager_->addMotor(motor);
}
}));
}
}
for (auto& task : tasks) task.get();
LOG(INFO) << "All enabled motors initialized successfully.";
}
void MotorsInfo::init(const cmvr::config::EthercatRobotConfig& config)
{
if (!motor_manager_)
{
motor_manager_ = std::make_shared<MotorManager>();
}
auto protocol = std::make_shared<EYouEthercatProtocol>(config.master().interface());
for (const auto& motor_cfg : config.motors()) {
auto motor = std::make_shared<EYouMotor>(motor_cfg);
if (protocol) motor->setProtocol(protocol);
motor->init();
motor_manager_->addMotor(motor);
}
}
bool MotorsInfo::getJointsQ(const std::vector<std::string> &joints_name,
std::unordered_map<std::string, double> &joint_qs) const {
auto res{true};

View File

@ -15,7 +15,6 @@ target_link_libraries(device_manager PRIVATE
cmvr_es::device::rh56dftp_dexhand
cmvr_es::device::px_6ax_gen3
cmvr::device::head_esp32
cmvr_es::device::agv_src1100
osqp
cmvr_es::device::humanoid_robot
# cmvr_es::device::aubo_robot

View File

@ -28,7 +28,7 @@ namespace cmvr::device {
template <typename DeviceType, typename ConfigType>
std::shared_ptr<DeviceType> createFromConfig(const ConfigType& cfg);
private:
std::shared_ptr<AbstractAgv> create_agv_(const XmlNode& cfg);
std::shared_ptr<AbstractAGV> create_agv_(const XmlNode& cfg);
std::shared_ptr<AbstractBattery> create_battery_(const XmlNode& cfg);
std::shared_ptr<AbstractCamera> create_camera_(const XmlNode& cfg);
std::shared_ptr<AbstractDexHand> create_dexhand_(const XmlNode& cfg);

View File

@ -16,7 +16,7 @@
namespace cmvr::device {
using DeviceVariant = std::variant<
std::shared_ptr<AbstractAgv>,
std::shared_ptr<AbstractAGV>,
std::shared_ptr<AbstractBattery>,
std::shared_ptr<AbstractCamera>,
std::shared_ptr<AbstractDexHand>,

View File

@ -15,13 +15,12 @@
//#include "robot/ti5_robot/ti5_robot.h"
#include "cmvr/api/system_command.pb.h"
#include "data_center/include/motors_info.h"
#include "devices/agv/agv_src1100/include/agv_src1100.h"
//#include "devices/robot/aubo_robot/include/aubo_robot.h"
using namespace std;
using namespace cmvr::device;
template std::shared_ptr<AbstractAgv> DeviceFactory::create<AbstractAgv>(const XmlNode&);
template std::shared_ptr<AbstractAGV> DeviceFactory::create<AbstractAGV>(const XmlNode&);
template std::shared_ptr<AbstractBattery> DeviceFactory::create<AbstractBattery>(const XmlNode&);
template std::shared_ptr<AbstractCamera> DeviceFactory::create<AbstractCamera>(const XmlNode&);
template std::shared_ptr<AbstractDexHand> DeviceFactory::create<AbstractDexHand>(const XmlNode&);
@ -33,7 +32,7 @@ template std::shared_ptr<AbstractBiohead> DeviceFactory::create<AbstractBiohead>
template <typename DeviceType>
std::shared_ptr<DeviceType> DeviceFactory::create(const XmlNode& cfg) {
if constexpr (std::is_same_v<DeviceType, AbstractAgv>) {
if constexpr (std::is_same_v<DeviceType, AbstractAGV>) {
return create_agv_(cfg);
} else if constexpr (std::is_same_v<DeviceType, AbstractBattery>) {
return create_battery_(cfg);
@ -58,7 +57,7 @@ std::shared_ptr<DeviceType> DeviceFactory::create(const XmlNode& cfg) {
}
}
std::shared_ptr<AbstractAgv> DeviceFactory::create_agv_(const XmlNode& cfg) {
std::shared_ptr<AbstractAGV> DeviceFactory::create_agv_(const XmlNode& cfg) {
return nullptr;
}
@ -185,11 +184,6 @@ template std::shared_ptr<AbstractDexHand> DeviceFactory::createFromConfig<Abstra
template std::shared_ptr<AbstractDexHand> DeviceFactory::createFromConfig<AbstractDexHand>(const config::PX6AXGen3& cfg);
template std::shared_ptr<AbstractMicrophone> DeviceFactory::createFromConfig<AbstractMicrophone>(const config::FFMpegMicroPhoneConfig& cfg);
template std::shared_ptr<AbstractSpeaker> DeviceFactory::createFromConfig<AbstractSpeaker>(const config::FFMpegSpeakerConfig& cfg);
template std::shared_ptr<AbstractAgv> DeviceFactory::createFromConfig<AbstractAgv>(const config::AGVsrc1100Config& cfg);
template std::shared_ptr<AbstractBiohead> DeviceFactory::createFromConfig<AbstractBiohead>(const config::BioHeadConfig& cfg);
template std::shared_ptr<AbstractRobot> DeviceFactory::createFromConfig<AbstractRobot>(const config::HumanRobotConfig& cfg);
template std::shared_ptr<AbstractRobot> DeviceFactory::createFromConfig<AbstractRobot>(const config::EthercatRobotConfig& cfg);
template <typename DeviceType, typename ConfigType>
std::shared_ptr<DeviceType> DeviceFactory::createFromConfig(const ConfigType& cfg)
{
@ -250,50 +244,6 @@ std::shared_ptr<DeviceType> DeviceFactory::createFromConfig(const ConfigType& cf
throw runtime_error("[DeviceFactory]: Unsupported microphone device type");
}
}
else if constexpr (std::is_same_v<DeviceType, AbstractBiohead>)
{
if constexpr (std::is_same_v<ConfigType, config::BioHeadConfig>)
{
return std::make_shared<BioHeadRobot>(cfg);
}
else
{
LOG(ERROR) << "[DeviceFactory]: Unsupported microphone device type ";
throw runtime_error("[DeviceFactory]: Unsupported microphone device type");
}
}
else if constexpr (std::is_same_v<DeviceType, AbstractRobot>)
{
if constexpr (std::is_same_v<ConfigType, config::HumanRobotConfig>)
{
auto motos_info = MotorsInfo::getInstance();
motos_info->init(cfg);
return std::make_shared<HumanoidRobot<14>>(cfg);
}
else if constexpr (std::is_same_v<ConfigType, config::EthercatRobotConfig>)
{
auto motos_info = MotorsInfo::getInstance();
motos_info->init(cfg);
return std::make_shared<HumanoidRobot<14>>(cfg);
}
else
{
LOG(ERROR) << "[DeviceFactory]: Unsupported microphone device type ";
throw runtime_error("[DeviceFactory]: Unsupported microphone device type");
}
}
else if constexpr (std::is_same_v<DeviceType, AbstractAgv>)
{
if constexpr (std::is_same_v<ConfigType, config::AGVsrc1100Config>)
{
return std::make_shared<AgvSrc1100>(cfg);
}
else
{
LOG(ERROR) << "[DeviceFactory]: Unsupported agv device type ";
throw runtime_error("[DeviceFactory]: Unsupported agv device type");
}
}
else {
LOG(ERROR) << "[DeviceFactory]: Unsupported device type";
throw runtime_error("[DeviceFactory]: Unsupported device type");

View File

@ -9,7 +9,7 @@ using namespace std;
using namespace cmvr::device;
using namespace cmvr::device;
template std::shared_ptr<AbstractAgv> DeviceManager::getDevice(const std::string& device_id);
template std::shared_ptr<AbstractAGV> DeviceManager::getDevice(const std::string& device_id);
template std::shared_ptr<AbstractBattery> DeviceManager::getDevice(const std::string& device_id);
template std::shared_ptr<AbstractCamera> DeviceManager::getDevice(const std::string& device_id);
template std::shared_ptr<AbstractDexHand> DeviceManager::getDevice(const std::string& device_id);
@ -152,7 +152,7 @@ void DeviceManager::getDeviceList(std::list<std::pair<std::string, std::string>>
string dev_type;
std::visit([&](const auto& ptr) {
using T = std::decay_t<decltype(ptr)>;
if constexpr (std::is_same_v<T, std::shared_ptr<AbstractAgv>>) {
if constexpr (std::is_same_v<T, std::shared_ptr<AbstractAGV>>) {
dev_type = "AGV";
} else if constexpr (std::is_same_v<T, std::shared_ptr<AbstractBattery>>) {
dev_type = "Battery";
@ -223,12 +223,12 @@ void DeviceManager::init_devices_() {
LOG(ERROR) << "[DeviceManager]: Duplicate AGV Device ID" << id;
throw runtime_error("[DeviceManager]: Duplicate AGV Device ID" + id);
}
auto device = dev_factory_->create<AbstractAgv>(node);
auto device = dev_factory_->create<AbstractAGV>(node);
if (device == nullptr) {
throw std::runtime_error("[DeviceManager]: Factory returned nullptr for device ID: " + id);
}
devices_[id] = device;
std::get<std::shared_ptr<AbstractAgv>>(devices_[id])->init();
std::get<std::shared_ptr<AbstractAGV>>(devices_[id])->init();
LOG(INFO) << "[DeviceManager]: Init AGV " << id << " Success";
}
@ -312,24 +312,6 @@ void DeviceManager::init_devices_() {
LOG(INFO) << "[DeviceManager]: Init Robot " << id << " Success";
}
// EYOU的先用新版的
config::RobotConfig robot_config;
ConfigHelper::getRobotConfig(robot_config);
for (int i = 0; i < robot_config.ethercat_robots().size(); i++) {
auto robot = robot_config.ethercat_robots(i);
if (!robot.enable())
continue;
auto id = robot.id();
if (devices_.count(id)) {
LOG(ERROR) << "[DeviceManager]: Duplicate Robot Device ID" << id;
throw runtime_error("[DeviceManager]: Duplicate Robot Device ID" + id);
}
std::cout << "DexHand[" << i << "]: " << id << std::endl;
auto device = dev_factory_->createFromConfig<AbstractRobot,config::EthercatRobotConfig>(robot);
devices_[id] = device;
std::get<std::shared_ptr<AbstractRobot>>(devices_[id])->init();
}
config::MicroPhoneConfig micro_phone_config;
ConfigHelper::getMicroPhonesConfig(micro_phone_config);
for (int i = 0; i < micro_phone_config.ffmpeg_microphones().size(); i++) {
@ -364,38 +346,22 @@ void DeviceManager::init_devices_() {
std::get<std::shared_ptr<AbstractSpeaker>>(devices_[id])->init();
}
config::HeadConfig head_cfg;
ConfigHelper::getHeadConfig(head_cfg);
for (int i = 0; i < head_cfg.bioheads().size(); i++) {
auto head = head_cfg.bioheads(i);
if (!head.enable())
continue;
auto id = head.id();
if (devices_.count(id)) {
LOG(ERROR) << "[DeviceManager]: Duplicate Biohead Device ID" << id;
throw runtime_error("[DeviceManager]: Duplicate Biohead Device ID" + id);
auto biohead_node = dmgr_node.getChild("BioHead");
for (auto &node: biohead_node.getChildren()){
string id = node.getAttrString("id");
if (devices_.count(id)){
LOG(ERROR) << "[DeviceManager]: Duplicate AbstractBiohead Device ID" << id;
throw runtime_error("[DeviceManager]: Duplicate AbstractBiohead Device ID" + id);
}
auto device = dev_factory_->create<AbstractBiohead>(node);
if (device == nullptr){
throw std::runtime_error("[DeviceManager]: Factory returned nullptr for device ID: " + id);
}
std::cout << "Biohead[" << i << "]: " << id << std::endl;
auto device = dev_factory_->createFromConfig<AbstractBiohead,config::BioHeadConfig>(head);
devices_[id] = device;
std::get<std::shared_ptr<AbstractBiohead>>(devices_[id])->init();
}
config::AGVConfig agv_config;
ConfigHelper::getAgvConfig(agv_config);
LOG(INFO) << "[BioHead]: Init biohead " << id << " Success";
for (int i = 0; i < agv_config.src1100_agvs().size(); i++) {
auto agv = agv_config.src1100_agvs(i);
if (!agv.enable())
continue;
auto id = agv.id();
if (devices_.count(id)) {
LOG(ERROR) << "[DeviceManager]: Duplicate agv Device ID" << id;
throw runtime_error("[DeviceManager]: Duplicate agv Device ID" + id);
}
std::cout << "AgvSrc1100[" << i << "]: " << id << std::endl;
auto device = dev_factory_->createFromConfig<AbstractAgv,config::AGVsrc1100Config>(agv);
devices_[id] = device;
std::get<std::shared_ptr<AbstractAgv>>(devices_[id])->init();
}
}
catch (const exception& e) {

View File

@ -6,4 +6,3 @@ add_subdirectory(biohead)
add_subdirectory(robot)
add_subdirectory(canbus)
add_subdirectory(motor)
add_subdirectory(agv)

View File

@ -1,2 +0,0 @@
add_subdirectory(agv_src1100)

View File

@ -1,869 +1,36 @@
//
// Created by xtkuang on 2025/5/6.
// Created by xtkuang on 2025/5/8.
//
/**
* @file abstract_agv.h
* @brief AGV设备抽象基类定义
* AGV实现SRC-1100
* @note API对应的结构体
*/
#ifndef CMVR_ES_ABSTRACT_AGV_H
#define CMVR_ES_ABSTRACT_AGV_H
#pragma once
#include <cmath>
#include <cstdint>
#include <memory>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
#include <json/json.h>
#include "../abstract_device.h"
#include "devices/abstract_device.h"
namespace cmvr::device{
class AbstractAGV: public AbstractDevice {
public:
explicit AbstractAGV(const XmlNode &config): AbstractDevice(config) {};
~AbstractAGV() override=default;
// 注意这里只include不使用
#include "cmvr/config/agv_config/agv_config.pb.h"
virtual void getState(AGVState &state) {}
namespace cmvr::device {
// navigation
virtual void eStop() {}
virtual void goHome() {}
virtual void moveto(math::Pose2d &location, double speed_ratio) {}
virtual void setVelocity(math::Vec3 linear, math::Vec3 angular) {}
/**
* @brief AGV
*
* AbstractDevice AGV
*
* AGV
*/
class AbstractAgv : public AbstractDevice {
public:
/**
* @brief AGV
*/
enum class Status {
CREATED, ///< 已创建,未初始化
INITIALIZED, ///< 已初始化,未运行
RUNNING, ///< 运行中
PAUSED, ///< 暂停
STOPPED, ///< 已停止
FAULT ///< 故障
// map
virtual void initMap(float resolution, int width, int height) {}
virtual void updateMap() {}
virtual void saveMap(const std::string& file_path) {}
virtual void loadMap(const std::string& file_path) {}
protected:
AGVState state_;
};
}
// ==================== 状态与信息结构体 ====================
/**
* @brief
*
* API 1000 (0x03E8)
*/
struct AgvStatusInfo {
std::string id; ///< 设备唯一标识
std::string vehicle_id; ///< 车辆编号(如 "agv_001"
std::string robot_note; ///< 机器人备注(用户自定义)
std::string version; ///< 软件版本号
std::string model; ///< 车型(如 "SRC-1100"
std::string dsp_version; ///< DSP 固件版本
std::string gyro_version; ///< 陀螺仪版本
std::string map_version; ///< 地图版本
std::string model_version; ///< 模型版本
std::string netprotocol_version; ///< 网络协议版本
std::string modbus_version; ///< Modbus 协议版本
std::string current_map; ///< 当前加载的地图名称
std::string current_map_md5; ///< 当前地图的 MD5 校验值
std::string model_md5; ///< 模型文件 MD5
std::string ssid; ///< 当前连接的 Wi-Fi SSID
int rssi = 0; ///< Wi-Fi 信号强度 (RSSI, 0~100)
std::string ap_addr; ///< 接入点 MAC 地址
std::string current_ip; ///< 当前 IP 地址
std::string mac; ///< 设备 MAC 地址
std::string echoid_type; ///< 回音 ID 类型
std::string echoid; ///< 回音 ID
int ret_code = 0; ///< 返回码0 表示成功非0 表示错误
std::string err_msg; ///< 错误信息(失败时填充)
/**
* @brief ID 0
*/
bool isValid() const {
return !id.empty() && ret_code == 0;
}
};
/**
* @brief
*
* API 1007 (0x03EF)
*/
struct BatteryStatus
{
double battery_level = 0.0; ///< 电池电量百分比 (0~100)
double battery_temp = 0.0; ///< 电池温度(摄氏度)
bool charging = false; ///< 是否正在充电
double voltage = 0.0; ///< 当前电压V
double current = 0.0; ///< 当前电流A
double max_charge_voltage = -1.0; ///< 最大充电电压(-1 表示未知)
double max_charge_current = -1.0; ///< 最大充电电流(-1 表示未知)
bool manual_charge = false; ///< 是否连接手动充电器(仅 SRC-2000
bool auto_charge = false; ///< 是否连接自动充电桩(仅 SRC-2000
int32_t battery_cycle = 0; ///< 电池循环次数(从 BMS 读取,可能不准确)
std::string battery_user_data; ///< 电池用户自定义数据(字符串)
std::string extra; ///< 额外扩展字段(预留)
int32_t ret_code = 0; ///< 返回码0 表示成功
std::string create_on; ///< 数据创建时间戳ISO 8601
std::string err_msg; ///< 错误信息
};
/**
* @brief
*
* API 1004 (0x03EC)
*/
struct RobotLocation
{
double x = 0.0; ///< 世界坐标系 X 坐标(米)
double y = 0.0; ///< 世界坐标系 Y 坐标(米)
double angle = 0.0; ///< 朝向角(弧度),逆时针为正
double confidence = 0.0; ///< 定位置信度0~1
std::string current_station; ///< 当前所在站点 ID若在站点上
std::string last_station; ///< 上一个经过的站点 ID
int32_t loc_method = 0; ///< 定位方法0: 自然轮廓, 1: 反光柱, 2: 二维码, 3: 里程计, ...
int32_t ret_code = 0; ///< 返回码0 表示成功
std::string create_on; ///< 数据创建时间戳
std::string err_msg; ///< 错误信息
};
/**
* @brief
*
* API 4011 (0x0FAB)
*/
struct DownloadMapResult
{
std::string map_name; ///< 地图名称
std::string map_content; ///< 地图文件内容JSON 字符串)
int32_t ret_code = 0; ///< 返回码0 表示成功
std::string create_on; ///< 数据创建时间戳
std::string err_msg; ///< 错误信息
};
/**
* @brief
*/
struct MapFileInfo
{
std::string name; ///< 文件名
std::string modified; ///< 最后修改时间
int64_t size = 0; ///< 文件大小(字节)
};
/**
* @brief
*
* API 1300 (0x0514)
*/
struct MapStatus
{
std::string current_map; ///< 当前加载的地图名称
std::string current_map_md5; ///< 当前地图的 MD5
std::vector<std::string> maps; ///< 所有地图名称列表
std::vector<MapFileInfo> map_files_info; ///< 每个地图文件的详细信息
int32_t ret_code = 0; ///< 返回码0 表示成功
std::string create_on; ///< 数据创建时间戳
std::string err_msg; ///< 错误信息
};
/**
* @brief
*
* API 4010 (0x0FAA)
*/
struct UploadMapResult
{
int32_t ret_code = 0; ///< 返回码0 表示成功
std::string create_on; ///< 数据创建时间戳
std::string err_msg; ///< 错误信息
};
/**
* @brief
*
* API 4005 (0x0FA5)
*/
struct LockResult
{
int32_t ret_code = 0; ///< 返回码0 表示成功
std::string create_on; ///< 数据创建时间戳
std::string err_msg; ///< 错误信息
};
/**
* @brief
*
* API 1060 (0x0424)
*/
struct CurrentLockStatus
{
bool locked = false; ///< 是否被锁定(有控制权持有者)
std::string ip; ///< 持有者 IP 地址
int32_t port = 0; ///< 持有者端口
uint8_t type = 0; ///< 持有者类型0: 未知, 1: 调度系统, 2: 示教器, ...
std::string nick_name; ///< 持有者昵称(自定义标识)
int64_t time_t = 0; ///< 锁定时间戳Unix 秒)
std::string desc; ///< 描述信息
int32_t ret_code = 0; ///< 返回码0 表示成功
std::string create_on; ///< 数据创建时间戳
std::string err_msg; ///< 错误信息
};
// ==================== 运动控制相关结构体 ====================
/**
* @brief
*
* API 2010 (0x07DA)
* vx/vy/w steer/real_steer
*/
struct MotionCtrlReq
{
double vx = 0.0; ///< 机器人坐标系 X 方向线速度m/s
double vy = 0.0; ///< 机器人坐标系 Y 方向线速度m/s
double w = 0.0; ///< 角速度rad/s逆时针为正
double steer = 0.0; ///< 舵轮转向角(仅单舵轮,单位 rad
double real_steer = 0.0; ///< 实际舵轮角度(反馈,仅单舵轮)
int64_t duration = -1; ///< 运动持续时间(毫秒),-1 表示一直运动直到下次指令
};
/**
* @brief
*/
struct MotionCtrlRes
{
int ret_code = 0; ///< 返回码0 表示成功
std::string create_on; ///< 数据创建时间戳
std::string err_msg; ///< 错误信息
};
/**
* @brief
*
* API 2022 (0x07E6)
*/
struct LoadMapReq
{
std::string map_name; ///< 目标地图名称(必须已存在于机器人中)
};
/**
* @brief
*/
struct LoadMapRes
{
int ret_code = 0; ///< 返回码0 表示成功
std::string create_on; ///< 数据创建时间戳
std::string err_msg; ///< 错误信息
};
/**
* @brief
*
* API 1022 (0x03FE)
*/
struct QueryLoadMapStatusRes
{
int32_t loadmap_status = 0; ///< 地图加载状态0=失败, 1=成功, 2=载入中
int ret_code = 0; ///< 返回码0 表示成功
std::string create_on; ///< 数据创建时间戳
std::string err_msg; ///< 错误信息
};
/**
* @brief
*
* API 1301 (0x0515)
*/
struct StationItem
{
std::string id; ///< 站点 ID唯一标识
std::string type; ///< 站点类型(如 "LocationMark", "ChargePoint", "ActionPoint"
double x = 0.0; ///< 站点 X 坐标(米)
double y = 0.0; ///< 站点 Y 坐标(米)
double r = 0.0; ///< 站点朝向角(弧度)
std::string desc; ///< 描述信息
std::string executor; ///< 执行器信息(用于动作)
std::string prepoint; ///< 前置点 ID若需要先到前置点
std::string recfile; ///< 识别文件路径(用于视觉识别)
bool spin = false; ///< 是否允许自旋(原地旋转)
bool use_down_pgv = false; ///< 是否使用下视 PGV 二维码
};
/**
* @brief
*/
struct QueryStationRes
{
std::vector<StationItem> stations; ///< 站点列表
int ret_code = 0; ///< 返回码0 表示成功
std::string create_on; ///< 数据创建时间戳
std::string err_msg; ///< 错误信息
};
/**
* @brief
*
* API 3066 (0x0BFA) move_task_list
*/
struct MoveTaskItem
{
std::string task_id; ///< 任务 ID必须全局唯一
std::string source_id; ///< 起始站点 ID
std::string id; ///< 目标站点 ID
std::string operation; ///< 到达后执行的动作(如 "JackLoad", "WaitDI", 等)
double jack_height = 0.0; ///< 顶升高度(当 operation 为顶升相关时使用)
};
/**
* @brief
*
* API 3066
*/
struct GoTargetListReq
{
std::vector<MoveTaskItem> move_task_list; ///< 导航任务序列(必须按顺序且相邻站点间有直接路径)
};
/**
* @brief
*/
struct GoTargetListRes
{
int ret_code = 0; ///< 返回码0 表示成功
std::string create_on; ///< 数据创建时间戳
std::string err_msg; ///< 错误信息
};
// ==================== 导航料箱信息 ====================
/**
* @brief
*/
struct NavContainerItem
{
std::string container_name; ///< 料箱名称
std::string desc; ///< 描述
std::string goods_id; ///< 绑定的货物 ID
bool has_goods = false; ///< 是否已绑定货物
};
// ==================== 1020 实时导航查询 ====================
/**
* @brief 1020
*
* API 1020 (0x03FC)
*/
struct RobotStatusTaskCurrentReq
{
bool simple = false; ///< 若为 true只返回 task_status 字段
};
/**
* @brief 1020
*
* API 1020
*/
struct RobotStatusTaskCurrentRes
{
int task_status = 0; ///< 任务状态0=NONE, 1=WAITING, 2=RUNNING, 3=SUSPENDED, 4=COMPLETED, 5=FAILED, 6=CANCELED
int task_type = 0; ///< 任务类型0=无, 1=自由导航到坐标, 2=自由导航到站点, 3=路径导航到站点, 7=平动转动, 100=其他
std::string target_id; ///< 目标站点 ID若 task_type 为 2 或 3
std::vector<double> target_point; ///< 目标坐标 [x, y, r](若 task_type 为 1
std::vector<std::string> finished_path; ///< 已经过的站点列表
std::vector<std::string> unfinished_path; ///< 尚未经过的站点列表
std::string move_status_info; ///< 导航附加信息(如错误描述)
std::vector<NavContainerItem> containers; ///< 料箱信息(若有)
int ret_code = 0; ///< 返回码0 表示成功
std::string create_on; ///< 数据创建时间戳
std::string err_msg; ///< 错误信息
};
// ==================== 1110 批量任务查询 ====================
/**
* @brief
*/
struct SingleTaskStatusItem
{
std::string task_id; ///< 任务 ID
int status = 0; ///< 状态码(同上述 task_status
int type = 0; ///< 任务类型(同上述 task_type
};
/**
* @brief
*
* API 1110 (0x0456) task_status_package
*/
struct TaskStatusPackage
{
std::string closest_target; ///< 最近站点 ID
std::string source_name; ///< 起点站点名称
std::string target_name; ///< 终点站点名称
double percentage = 0.0; ///< 任务进度百分比0~100
double distance = 0.0; ///< 剩余距离(米)
std::string info; ///< 附加信息
std::vector<SingleTaskStatusItem> task_status_list; ///< 所有任务状态列表
};
/**
* @brief 1110
*/
struct QueryTaskStatusPackageReq
{
std::vector<std::string> task_ids; ///< 要查询的任务 ID 列表,若为空则查询所有未完成+最近一条完成
};
/**
* @brief 1110
*/
struct QueryTaskStatusPackageRes
{
TaskStatusPackage task_status_package; ///< 任务状态包
int ret_code = 0; ///< 返回码0 表示成功
std::string create_on; ///< 数据创建时间戳
std::string err_msg; ///< 错误信息
};
// ==================== DI / DO / 音频 / PGV / 脚本等通用类型 ====================
/**
* @brief DI
*/
struct DIItem
{
int id = 0; ///< DI 编号
bool status = false; ///< 状态true=高电平, false=低电平)
};
/**
* @brief DO
*/
struct DOItem
{
int id = 0; ///< DO 编号
bool status = false; ///< 状态true=高电平, false=低电平)
};
/**
* @brief
*/
struct SoundArgs
{
std::string name; ///< 音频文件名
int loop = 0; ///< 循环次数0=播放一次, 1=循环播放)
int stop = 0; ///< 1=停止播放
};
/**
* @brief WaitDI
*/
struct WaitDIArgs
{
std::vector<DIItem> DI; ///< 需要等待的 DI 条件列表
double timeout = 0.0; ///< 超时时间0 表示无限等待
};
/**
* @brief SetDO
*/
struct SetDOArgs
{
std::vector<DOItem> DO; ///< 要设置的 DO 列表
};
/**
* @brief PGV
*/
struct PgvParam
{
bool use_pgv = false; ///< 是否使用上视 PGV
bool use_down_pgv = false; ///< 是否使用下视 PGV
double pgv_adjust_dist = 0.0; ///< 最大调整半径(米)
double pgv_adjust_cx = 0.0; ///< 二维码坐标系下的 X 偏移(米)
double pgv_adjust_cy = 0.0; ///< 二维码坐标系下的 Y 偏移(米)
double pgv_x_adjust = 0.0; ///< 仅调整 X 方向误差(米)
};
/**
* @brief x, y, theta
*/
struct FreeGoPoint
{
double x = 0.0; ///< X 坐标(米)
double y = 0.0; ///< Y 坐标(米)
double theta = 0.0; ///< 朝向角(弧度)
};
/**
* @brief
*/
struct ScriptArgs
{
std::map<std::string, std::string> str_kv; ///< 字符串键值对
std::map<std::string, double> num_kv; ///< 数字键值对
std::vector<DOItem> do_list; ///< DO 列表(用于 setDO 等)
std::vector<DIItem> di_list; ///< DI 列表(用于 waitDI 等)
};
// ==================== 3051 单点导航 ====================
/**
* @brief 3051
*
* API 3051 (0x0BEB)
*
* @attention
* - **/**
* -
* - warning/error
* - freeGo
*/
struct RobotGoTargetReq
{
// -------- 必填字段 --------
std::string source_id; ///< 起始站点 ID若为 "SELF_POSITION" 表示从当前位置出发)
std::string id; ///< 目标站点 ID若为 "SELF_POSITION" 表示原地执行 operation
std::string task_id; ///< 任务 ID非强制但建议提供
// -------- 可选速度/角度控制 --------
double angle = 0.0; ///< 目标点朝向角(弧度),仅对自由导航或目标站点有方向要求时使用
std::string method; ///< 运动方式:"forward"(正走)或 "backward"(倒走)
double max_speed = 0.0; ///< 最大线速度m/s0 表示使用默认
double max_wspeed = 0.0; ///< 最大角速度rad/s
double max_acc = 0.0; ///< 最大加速度m/s²
double max_wacc = 0.0; ///< 最大角加速度rad/s²
int64_t duration = 0; ///< 到达后等待时间(毫秒)
int32_t orientation = 0; ///< 全向车保持的角度(暂不使用)
bool spin = false; ///< 是否随动(用于托盘旋转)
int64_t delay = 0; ///< 延迟结束导航状态的时间(毫秒),缺省为 0
int32_t start_rot_dir = 0; ///< 起步原地旋转方向:-1=顺时针, 0=就近, 1=逆时针
int32_t end_rot_dir = 0; ///< 到点原地旋转方向(同上)
double reach_dist = 0.0; ///< 到点位置精度(米),默认由系统决定
double reach_angle = 0.0; ///< 到点角度精度(弧度)
std::string skill_name; ///< 技能名称:"Action"(动作)或 "GotoSpecifiedPose"(路径导航)
// -------- PGV 二次定位 --------
PgvParam pgv; ///< PGV 参数
// -------- 设备操作(顶升/货叉/辊筒/牵引等) --------
std::string operation; ///< 操作类型,如 "JackLoad", "ForkUnload", "RollerLoad", "HookLoad", "WaitDI", "SetDO", "sound", "Script" 等
double jack_height = 0.0; ///< 顶升高度(米),用于 JackLoad/JackUnload/JackHeight
double start_height = 0.0; ///< 货叉起步前举升高度(米)
double end_height = 0.0; ///< 货叉到点后举升高度(米)
double fork_mid_height = 0.0; ///< 货叉行走过程中举升高度(米)
double fork_dist = 0.0; ///< 货叉前移距离(米),用于 ForkForward
std::string direction; ///< 方向:"left"/"right"/"front"/"back",用于辊筒或货叉
bool recognize = false; ///< 是否启用视觉识别(用于货叉/顶升加载)
std::string recfile; ///< 识别文件路径(如 "shelf/s0002.shelf"
SoundArgs sounds_args; ///< 音频参数(当 operation="sound" 时)
WaitDIArgs wait_di_args; ///< WaitDI 参数
SetDOArgs set_do_args; ///< SetDO 参数
std::string script_name; ///< 脚本文件名(当 operation="Script" 时)
ScriptArgs script_args; ///< 脚本参数
int32_t script_stage = 2; ///< 脚本执行阶段0=导航前, 1=导航中, 2=导航后, 3=脚本控制导航
// -------- 原地旋转(特殊用法) --------
double move_angle = 0.0; ///< 旋转角度(弧度),仅当 skill_name="GoByOdometer" 时使用
double speed_w = 0.0; ///< 旋转角速度rad/s
int32_t loc_mode = 0; ///< 定位模式1=激光定位, 0=里程定位
// -------- 自由导航(仅支持双轮差速底盘) --------
FreeGoPoint freeGo; ///< 自由导航目标坐标(若提供此字段,则忽略 id 字段,使用坐标导航)
};
/**
* @brief 3051
*/
struct RobotGoTargetRes
{
int ret_code = 0; ///< 返回码0 表示成功
std::string create_on; ///< 数据创建时间戳
std::string err_msg; ///< 错误信息
};
//新增暂停导航响应结构体
struct RobotTaskPauseRes {
int ret_code = 0;
std::string create_on;
std::string err_msg;
};
// 继续导航响应结构体
struct RobotTaskResumeRes {
int ret_code = 0;
std::string create_on;
std::string err_msg;
};
// ==================== robot_control_stop 停止开环运动响应 ====================
// 0x07D0 robot_control_stop 停止开环运动返回
struct RobotControlStopRes
{
int ret_code = 0;
std::string create_on;
std::string err_msg;
};
// 取消导航响应结构体
struct RobotTaskCancelRes {
int ret_code = 0;
std::string create_on;
std::string err_msg;
};
// ==================== 类型别名(兼容旧代码) ====================
using AgvState = AgvStatusInfo;
public:
AbstractAgv() = default;
~AbstractAgv() override = default;
// 禁用拷贝,允许移动
AbstractAgv(const AbstractAgv&) = delete;
AbstractAgv& operator=(const AbstractAgv&) = delete;
AbstractAgv(AbstractAgv&&) = default;
AbstractAgv& operator=(AbstractAgv&&) = default;
// ==================== 纯虚接口 ====================
/**
* @brief
* @return Status
*/
virtual Status state() const = 0;
/**
* @brief
* @return
*/
virtual std::string lastError() const = 0;
/**
* @brief
*/
void start() override = 0;
/**
* @brief
*/
void stop() override = 0;
/**
* @brief
*/
void update() override = 0;
/**
* @brief AGV getStatusInfo
* @param state AgvState
*/
virtual void getState(AgvState& state) {
state = AgvState{};
getStatusInfo(state);
}
/**
* @brief AGV 1000
* @param info AgvStatusInfo
*/
virtual void getStatusInfo(AgvStatusInfo& info) = 0;
/**
* @brief 1007
* @param info BatteryStatus
* @param simple true
*/
virtual void getBatteryStatus(BatteryStatus& info, bool simple = false) = 0;
/**
* @brief 1004
* @param info RobotLocation
*/
virtual void getRobotLocation(RobotLocation& info) = 0;
/**
* @brief 4011
* @param info DownloadMapResult
* @param map_name
*/
virtual void downloadMap(DownloadMapResult& info, const std::string& map_name) = 0;
/**
* @brief 1300
* @param info MapStatus
*/
virtual void getMapStatus(MapStatus& info) = 0;
/**
* @brief 4010
* @param info UploadMapResult
* @param map_json JSON
*/
virtual void uploadMap(UploadMapResult& info, const std::string& map_json) = 0;
/**
* @brief 4005
* @param info LockResult
* @param nick_name
*/
virtual void lockRobotControl(LockResult& info, const std::string& nick_name) = 0;
/**
* @brief 2010
*
* 使19205
* vx/vy/w
*
* @param res
* @param req vx/vy/w/steer/real_steer/duration
*/
virtual void robotMotionControl(MotionCtrlRes& res, const MotionCtrlReq& req) = 0;
/**
* @brief 2022
*
* 使19205
*
* @param res
* @param req
*/
virtual void robotLoadMap(LoadMapRes& res, const LoadMapReq& req) = 0;
/**
* @brief 1020
*
* 使19204
* @param res
* @param req simple=true task_status
*/
virtual void robotStatusTaskCurrent(RobotStatusTaskCurrentRes& res, const RobotStatusTaskCurrentReq& req) = 0;
/**
* @brief
*
* logic_error
* @param vx X (m/s)
* @param vy Y (m/s)
* @param vw (rad/s)
*/
virtual void move(double vx, double vy, double vw) {
throw std::logic_error("move not implemented");
}
/**
* @brief
*
* logic_error
*/
virtual void stopMove() {
throw std::logic_error("stopMove not implemented");
}
/**
* @brief 1060
* @param info CurrentLockStatus
*/
virtual void getCurrentLockStatus(CurrentLockStatus& info) = 0;
/**
* @brief 1022
*
* 使19204
* @param res loadmap_status0=, 1=, 2=
* @note 2
*/
virtual void queryLoadMapStatus(QueryLoadMapStatusRes& res) = 0;
/**
* @brief 1301
*
* 使19204
* @param res
*/
virtual void queryStationList(QueryStationRes& res) = 0;
/**
* @brief 3066
*
* 使19206
*
* @param res ret_code=0
* @param req task_id, source_id, id
* @attention
* - source_id id 线
* -
* -
*/
virtual void robotGoTargetList(GoTargetListRes& res, const GoTargetListReq& req) = 0;
/**
* @brief 1110
*
* 使19204
* @param res +
* @param req task_id +
*/
virtual void robotStatusTaskPackage(QueryTaskStatusPackageRes& res, const QueryTaskStatusPackageReq& req) = 0;
/**
* @brief 3051
*
* 使19206
* @param res ret_code=0
* @param req
* @warning
* - ****/
* -
* - **** warning/error
* - freeGo
*/
virtual void robotGoTarget(RobotGoTargetRes& res, const RobotGoTargetReq& req) = 0;
/**
* @brief 2000(0x07D0) robot_control_stop_req
* @param res
*/
virtual void robotControlStop(RobotControlStopRes& res) = 0;
/**
* @brief 3001, 0x0BB9
* @param res
*/
virtual void robotTaskPause(RobotTaskPauseRes& res) = 0;
/**
* @brief 3002, 0x0BBA
* @param res
*/
virtual void robotTaskResume(RobotTaskResumeRes& res) = 0;
/**
* @brief 3003, 0x0BBB
* @param res
*/
virtual void robotTaskCancel(RobotTaskCancelRes& res) = 0;
protected:
// ==================== 保护成员变量 ====================
std::string id_; ///< 设备 ID唯一标识
std::string ip_; ///< 设备 IP 地址
// 多端口配置(对应 proto 定义)
int port_status_{0}; ///< 状态查询端口(默认 19204
int port_control_{0}; ///< 控制 API 端口(默认 19205
int port_nav_{0}; ///< 导航 API 端口(默认 19206
int port_config_{0}; ///< 配置 API 端口(默认 19207
int port_other_{0}; ///< 其他 API 端口(默认 19210
int port_push_{0}; ///< 推送端口(默认 19301
bool enable_{false}; ///< 设备启用标志
};
} // namespace cmvr::device
#endif // CMVR_ES_ABSTRACT_AGV_H
#endif //CMVR_ES_ABSTRACT_AGV_H

View File

@ -1,20 +0,0 @@
add_library(agv_src1100 SHARED src/agv_src1100.cpp)
target_include_directories(agv_src1100 PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${JSONCPP_INCLUDE_DIRS}
)
add_library(cmvr_es::device::agv_src1100 ALIAS agv_src1100)
# PRIVATE -> PUBLIC
target_link_libraries(agv_src1100 PUBLIC
jsoncpp
cmvr_es::common
cmvr_es::proto
glog
pthread
)
install(TARGETS agv_src1100 LIBRARY DESTINATION lib)

View File

@ -1,307 +0,0 @@
//
// Created by linbo on 2025/6/20.
//
/**
* @file agv_src1100.h
* @brief SRC-1100/2200 AGV
* AbstractAgv TCP
*/
#ifndef AGV_SRC1100_H
#define AGV_SRC1100_H
#pragma once
#include "./agv/abstract_agv.h"
#include <mutex>
#include <atomic>
#include <thread>
#include "nlohmann/json.hpp"
using json = nlohmann::json;
namespace cmvr::device {
/**
* @brief SRC-1100/2200 AGV
*
* AbstractAgv SRC
*
*
* @note 线访
*/
class AgvSrc1100 final : public AbstractAgv {
public:
// ==================== 构造 / 析构 ====================
/**
* @brief XML 使
* @param cfg XML IDIP
*/
explicit AgvSrc1100(const XmlNode& cfg);
/**
* @brief Protobuf
* @param cfg AGVsrc1100Config IDIP
*/
explicit AgvSrc1100(const config::AGVsrc1100Config& cfg);
/**
* @brief
*/
~AgvSrc1100() override;
// ==================== 生命周期管理(通用) ====================
/**
* @brief
* @return Status CREATED / INITIALIZED / RUNNING / PAUSED / STOPPED / FAULT
*/
Status state() const override;
/**
* @brief
* @return
*/
std::string lastError() const override;
/**
* @brief
* @note socket
*/
void start() override;
/**
* @brief TCP
*/
void stop() override;
/**
* @brief
* @note
*/
void update() override;
// ==================== 端口 19204 机器人状态 API允许 10 个连接) ====================
// 功能:查询机器人各种状态信息(只读操作,不改变机器人状态)
/**
* @brief 1000, robot_status_info_req
* @param info AgvStatusInfo
* @note IPMACWi-Fi
*/
void getStatusInfo(AgvStatusInfo& info) override;
/**
* @brief 1007, robot_status_battery_req
* @param info BatteryStatus
* @param simple true
* @note
*/
void getBatteryStatus(BatteryStatus& info, bool simple = false) override;
/**
* @brief 1004, robot_status_loc_req
* @param info RobotLocation
* @note X/Y
*/
void getRobotLocation(RobotLocation& info) override;
/**
* @brief 1300, robot_status_map_req
* @param info MapStatus
* @note
*/
void getMapStatus(MapStatus& info) override;
/**
* @brief 1060, robot_status_current_lock_req
* @param info CurrentLockStatus
* @note IP//
*/
void getCurrentLockStatus(CurrentLockStatus& info) override;
/**
* @brief 1022, robot_status_loadmap_req
* @param res loadmap_status
* @note loadmap_status: 0=, 1=, 2=
*/
void queryLoadMapStatus(QueryLoadMapStatusRes& res) override;
/**
* @brief 1301, robot_status_station_req
* @param res QueryStationRes
* @note ID
*/
void queryStationList(QueryStationRes& res) override;
/**
* @brief 1020, robot_status_task_req
* @param res RobotStatusTaskCurrentRes
* @param req simple=true task_status
* @note //
*/
void robotStatusTaskCurrent(RobotStatusTaskCurrentRes& res, const RobotStatusTaskCurrentReq& req) override;
/**
* @brief 1110, robot_status_task_status_package_req
* @param res QueryTaskStatusPackageRes
* @param req task_ids +
* @note ID//
*/
void robotStatusTaskPackage(QueryTaskStatusPackageRes& res, const QueryTaskStatusPackageReq& req) override;
// ==================== 端口 19205 机器人控制 API允许 5 个连接) ====================
// 功能:下发控制指令,改变机器人运动或状态(非导航类指令)
/**
* @brief 2010, robot_control_motion_req
* @param res
* @param req vx/vy/w/steer/real_steer/duration
* @warning
* @note vx/vy/w steer/real_steer
*/
void robotMotionControl(MotionCtrlRes& res, const MotionCtrlReq& req) override;
/**
* @brief 2022, robot_control_loadmap_req
* @param res
* @param req
* @note
*/
void robotLoadMap(LoadMapRes& res, const LoadMapReq& req) override;
// ==================== 端口 19206 机器人导航 API允许 5 个连接) ====================
// 功能:下发导航任务
/**
* @brief 3066, robot_task_gotargetlist_req
* @param res ret_code=0
* @param req move_task_list
* @attention
* - task_idsource_idid
* - source_id id 线
* -
* -
*/
void robotGoTargetList(GoTargetListRes& res, const GoTargetListReq& req) override;
/**
* @brief 3051, robot_task_gotarget_req
* @param res ret_code=0
* @param req freeGo
* @warning
* - ****/
* -
* - warning/error
* - freeGo
*/
void robotGoTarget(RobotGoTargetRes& res, const RobotGoTargetReq& req) override;
// ==================== 端口 19207 机器人配置 API允许 5 个连接) ====================
// 功能:配置类操作(地图上传/下载、控制权管理、参数修改等)
/**
* @brief 4005, robot_config_lock_req
* @param info LockResult
* @param nick_name
* @note
*/
void lockRobotControl(LockResult& info, const std::string& nick_name) override;
/**
* @brief 4010, robot_config_uploadmap_req
* @param info UploadMapResult
* @param map_json JSON
* @note JSON
*/
void uploadMap(UploadMapResult& info, const std::string& map_json) override;
/**
* @brief 4011, robot_config_downloadmap_req
* @param info DownloadMapResult JSON
* @param map_name
* @note JSON info.map_content
*/
void downloadMap(DownloadMapResult& info, const std::string& map_name) override;
// ==================== 端口 19210 其他 API允许 5 个连接) ====================
// 功能:外设控制(顶升/货叉/辊筒/音频/IO 等)
// 当前未实现具体方法,预留扩展
// ==================== 端口 19301 机器人推送 API允许 10 个连接) ====================
// 功能:接收机器人主动推送的实时状态数据
// 相关配置方法(如 9300可能在此当前未实现
// ---------- 新增任务控制接口3001/3002/3003及停止运动2000 ----------
void robotTaskPause(RobotTaskPauseRes& res) override;
void robotTaskResume(RobotTaskResumeRes& res) override;
void robotTaskCancel(RobotTaskCancelRes& res) override;
void robotControlStop(RobotControlStopRes& res) override;
private:
// ==================== 私有通信辅助函数 ====================
/**
* @brief
* @param sock socket
* @param port 19204/19205/19206/19207/19210/19301
* @note 线 sock
*/
void asyncConnect(int& sock, int port);
/**
* @brief
* @param sock socket
* @param header 16
* @return true current_json_ JSONfalse
* @note JSON
*/
bool sendAndRecv(int sock, const uint8_t* header);
/**
* @brief socket
* @param sock socket
* @note
*/
void flushSocket(int sock);
/**
* @brief socket
* @param sock socket
* @param timeout_ms 0
*/
void setSocketTimeout(int sock, int timeout_ms);
/**
* @brief JSON
* @param json_str JSON
* @param root json
* @param err_msg
* @return true false
*/
bool parseJson(const std::string& json_str, json& root, std::string& err_msg);
// ==================== 成员变量 ====================
mutable std::mutex mutex_; ///< 保护状态和错误信息的互斥锁
std::atomic<Status> status_{Status::CREATED}; ///< 当前设备运行状态(原子变量)
std::string last_error_; ///< 最后一次错误信息
std::string current_json_; ///< 最近一次响应的 JSON 内容(由 sendAndRecv 填充)
// ---------- 各端口 Socket 文件描述符 ----------
int sock_status_ = -1; ///< 19204 状态 API 端口
int sock_control_ = -1; ///< 19205 控制 API 端口
int sock_nav_ = -1; ///< 19206 导航 API 端口
int sock_config_ = -1; ///< 19207 配置 API 端口
int sock_other_ = -1; ///< 19210 其他 API 端口
int sock_push_ = -1; ///< 19301 推送 API 端口
std::vector<std::thread> connect_threads_; ///< 各端口异步连接线程
mutable std::mutex connect_mutex_; ///< 保护 connect_threads_ 的互斥锁
};
} // namespace cmvr::device
#endif // AGV_SRC1100_H

File diff suppressed because it is too large Load Diff

View File

@ -58,7 +58,6 @@ namespace cmvr::device {
// 抽象头部类
class AbstractBiohead : public AbstractDevice {
public:
AbstractBiohead() = default;
explicit AbstractBiohead(const XmlNode &config) : AbstractDevice(config) {}
~AbstractBiohead() override = default;

View File

@ -7,7 +7,7 @@
#include <string>
#include <memory>
#include <mutex>
#include "cmvr/config/biohead_config/biohead_config.pb.h"
namespace cmvr::device {
struct ServoChannel {
@ -18,7 +18,6 @@ namespace cmvr::device {
class BioHeadRobot : public AbstractBiohead {
public:
explicit BioHeadRobot(const XmlNode &config);
BioHeadRobot(const cmvr::config::BioHeadConfig& config);
~BioHeadRobot() override = default;
// 接口实现
@ -67,7 +66,7 @@ namespace cmvr::device {
std::shared_ptr<std::thread> speak_thread_;
std::atomic<bool> speak_running_{false};
cmvr::config::BioHeadConfig config_;
};

View File

@ -26,219 +26,6 @@ BioHeadRobot::BioHeadRobot(const XmlNode &config) : AbstractBiohead(config) {
}
BioHeadRobot::BioHeadRobot(const cmvr::config::BioHeadConfig& config) : config_(config) {
// 从config中读取串口参数
port_name_ = config_.serial();
serial_ = std::make_shared<SerialPort>();
if (!serial_->open(port_name_, 115200)) {
LOG(ERROR) << "[BioHeadRobot] Failed to open serial port: " << port_name_;
} else {
serial_->wakeupESP32(port_name_);
LOG(INFO) << "[BioHeadRobot] Serial port opened and ESP32 woken up.";
}
// 解析眉毛配置
if (config_.has_eyebrow()) {
const auto& eyebrow = config_.eyebrow();
std::string serial_str = eyebrow.serial();
std::string offset_str = eyebrow.offest();
std::string min_angles_str = eyebrow.jlmtlow();
std::string max_angles_str = eyebrow.jlmtup();
// 解析偏移角
std::vector<double> offsets;
std::istringstream oss(offset_str);
double val;
while (oss >> val) offsets.push_back(val);
// 解析角度限制
std::vector<double> min_angles;
if (!min_angles_str.empty()) {
std::istringstream min_ss(min_angles_str);
while (min_ss >> val) min_angles.push_back(val);
}
std::vector<double> max_angles;
if (!max_angles_str.empty()) {
std::istringstream max_ss(max_angles_str);
while (max_ss >> val) max_angles.push_back(val);
}
// 解析 channel如 64:0~3
size_t colon = serial_str.find(':');
if (colon != std::string::npos) {
uint8_t addr = std::stoi(serial_str.substr(0, colon));
std::string range = serial_str.substr(colon + 1);
size_t tilde = range.find('~');
if (tilde != std::string::npos) {
int ch_start = std::stoi(range.substr(0, tilde));
int ch_end = std::stoi(range.substr(tilde + 1));
int channel_count = ch_end - ch_start + 1;
// 添加舵机通道
for (int ch = ch_start; ch <= ch_end; ++ch) {
channels_.push_back({addr, static_cast<uint8_t>(ch)});
}
// 添加角度限制
if (min_angles.size() == 1) {
min_angles_.insert(min_angles_.end(), channel_count, min_angles[0]);
} else if (min_angles.size() >= channel_count) {
min_angles_.insert(min_angles_.end(), min_angles.begin(), min_angles.begin() + channel_count);
} else {
min_angles_.insert(min_angles_.end(), channel_count, 0.0);
}
if (max_angles.size() == 1) {
max_angles_.insert(max_angles_.end(), channel_count, max_angles[0]);
} else if (max_angles.size() >= channel_count) {
max_angles_.insert(max_angles_.end(), max_angles.begin(), max_angles.begin() + channel_count);
} else {
max_angles_.insert(max_angles_.end(), channel_count, 180.0);
}
}
}
}
// 解析眼睛配置
if (config_.has_eye()) {
const auto& eye = config_.eye();
std::string serial_str = eye.serial();
std::string offset_str = eye.offest();
std::string min_angles_str = eye.jlmtlow();
std::string max_angles_str = eye.jlmtup();
// 解析偏移角
std::vector<double> offsets;
std::istringstream oss(offset_str);
double val;
while (oss >> val) offsets.push_back(val);
// 解析角度限制
std::vector<double> min_angles;
if (!min_angles_str.empty()) {
std::istringstream min_ss(min_angles_str);
while (min_ss >> val) min_angles.push_back(val);
}
std::vector<double> max_angles;
if (!max_angles_str.empty()) {
std::istringstream max_ss(max_angles_str);
while (max_ss >> val) max_angles.push_back(val);
}
// 解析 channel如 64:4~9
size_t colon = serial_str.find(':');
if (colon != std::string::npos) {
uint8_t addr = std::stoi(serial_str.substr(0, colon));
std::string range = serial_str.substr(colon + 1);
size_t tilde = range.find('~');
if (tilde != std::string::npos) {
int ch_start = std::stoi(range.substr(0, tilde));
int ch_end = std::stoi(range.substr(tilde + 1));
int channel_count = ch_end - ch_start + 1;
// 添加舵机通道
for (int ch = ch_start; ch <= ch_end; ++ch) {
channels_.push_back({addr, static_cast<uint8_t>(ch)});
}
// 添加角度限制
if (min_angles.size() == 1) {
min_angles_.insert(min_angles_.end(), channel_count, min_angles[0]);
} else if (min_angles.size() >= channel_count) {
min_angles_.insert(min_angles_.end(), min_angles.begin(), min_angles.begin() + channel_count);
} else {
min_angles_.insert(min_angles_.end(), channel_count, 0.0);
}
if (max_angles.size() == 1) {
max_angles_.insert(max_angles_.end(), channel_count, max_angles[0]);
} else if (max_angles.size() >= channel_count) {
max_angles_.insert(max_angles_.end(), max_angles.begin(), max_angles.begin() + channel_count);
} else {
max_angles_.insert(max_angles_.end(), channel_count, 180.0);
}
}
}
}
// 解析嘴巴配置
if (config_.has_mouth()) {
const auto& mouth = config_.mouth();
std::string serial_str = mouth.serial();
std::string offset_str = mouth.offest();
std::string min_angles_str = mouth.jlmtlow();
std::string max_angles_str = mouth.jlmtup();
// 解析偏移角
std::vector<double> offsets;
std::istringstream oss(offset_str);
double val;
while (oss >> val) offsets.push_back(val);
// 解析角度限制
std::vector<double> min_angles;
if (!min_angles_str.empty()) {
std::istringstream min_ss(min_angles_str);
while (min_ss >> val) min_angles.push_back(val);
}
std::vector<double> max_angles;
if (!max_angles_str.empty()) {
std::istringstream max_ss(max_angles_str);
while (max_ss >> val) max_angles.push_back(val);
}
// 解析 channel如 65:0~9
size_t colon = serial_str.find(':');
if (colon != std::string::npos) {
uint8_t addr = std::stoi(serial_str.substr(0, colon));
std::string range = serial_str.substr(colon + 1);
size_t tilde = range.find('~');
if (tilde != std::string::npos) {
int ch_start = std::stoi(range.substr(0, tilde));
int ch_end = std::stoi(range.substr(tilde + 1));
int channel_count = ch_end - ch_start + 1;
// 添加舵机通道
for (int ch = ch_start; ch <= ch_end; ++ch) {
channels_.push_back({addr, static_cast<uint8_t>(ch)});
}
// 添加角度限制
if (min_angles.size() == 1) {
min_angles_.insert(min_angles_.end(), channel_count, min_angles[0]);
} else if (min_angles.size() >= channel_count) {
min_angles_.insert(min_angles_.end(), min_angles.begin(), min_angles.begin() + channel_count);
} else {
min_angles_.insert(min_angles_.end(), channel_count, 0.0);
}
if (max_angles.size() == 1) {
max_angles_.insert(max_angles_.end(), channel_count, max_angles[0]);
} else if (max_angles.size() >= channel_count) {
max_angles_.insert(max_angles_.end(), max_angles.begin(), max_angles.begin() + channel_count);
} else {
max_angles_.insert(max_angles_.end(), channel_count, 180.0);
}
}
}
}
// 确保所有向量大小一致
if (min_angles_.size() != channels_.size()) {
min_angles_.resize(channels_.size(), 0.0);
}
if (max_angles_.size() != channels_.size()) {
max_angles_.resize(channels_.size(), 180.0);
}
current_joints_.resize(channels_.size(), 90.0);
last_joints_ = current_joints_;
}
void BioHeadRobot::parseXmlConfig(const XmlNode &node) {

View File

@ -54,7 +54,6 @@ namespace cmvr::device {
class AbstractCanbus : public AbstractDevice {
public:
AbstractCanbus() = default;
AbstractCanbus(const XmlNode &cfg) : AbstractDevice(cfg) {}
~AbstractCanbus() {}
/**

View File

@ -35,17 +35,6 @@ namespace cmvr {
// LOG(ERROR) << "[SocketCanClientRaw] ([SocketCanClientRaw]): Failed to parse XML: " << e.what();
}
SocketCanClientRaw::SocketCanClientRaw(const cmvr::config::CanDeviceConfig& config):config_(config)
{
auto channel_id = config_.channelid();
port_ = static_cast<CANCardParameter::CANChannelId>(channel_id);
interface_ = CANCardParameter::NATIVE;
enable_can_err_check_ = false;
}
void SocketCanClientRaw::init() {
// if (!parameter.has_channel_id()) {

View File

@ -26,7 +26,6 @@
#include "gflags/gflags.h"
#include "../../abstract_canbus.h"
#include "canbus/common/canbus_consts.h"
#include "cmvr/config/robot_config/robot_config.pb.h"
namespace cmvr {
namespace device {
@ -37,7 +36,6 @@ namespace cmvr {
class SocketCanClientRaw final : public AbstractCanbus {
public:
explicit SocketCanClientRaw(const XmlNode &cfg);
SocketCanClientRaw(const cmvr::config::CanDeviceConfig& config);
~SocketCanClientRaw();
void init() override;
void start() override;
@ -75,8 +73,6 @@ namespace cmvr {
//
bool enable_can_err_check_{false};
cmvr::config::CanDeviceConfig config_;
};
}
}

View File

@ -1,5 +1,5 @@
add_subdirectory(ti5_motor)
add_subdirectory(eyou_motor)
# --------------------------------------------------------
# Unit test
# --------------------------------------------------------

View File

@ -41,7 +41,6 @@ namespace cmvr::device{
} JointStatus;
public:
AbstractMotor() = default;
explicit AbstractMotor(const XmlNode &config): AbstractDevice(config) {}
AbstractMotor(const XmlNode &config,uint8_t node_id): AbstractDevice(config) ,node_id_(node_id) {}
~AbstractMotor() override = default;

View File

@ -1,21 +0,0 @@
add_library(eyoumotor SHARED
${CMAKE_CURRENT_SOURCE_DIR}/ethercat/protocol/ec_xml_parser.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ethercat/protocol/ec_master.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ethercat/eyou_motor_ethercat_protocol.cpp
${CMAKE_CURRENT_SOURCE_DIR}/eyou_motor.cpp
)
target_include_directories(eyoumotor PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
add_library(cmvr_es::device::eyoumotor ALIAS eyoumotor)
target_link_libraries(eyoumotor
PRIVATE
-lsoem
protobuf
glog
)
install(TARGETS eyoumotor LIBRARY DESTINATION lib)

View File

@ -1,747 +0,0 @@
//
// Created by cmvr on 2026/3/30.
//
#include "eyou_motor_ethercat_protocol.h"
#include "canbus/canopen/register.h"
#include "motor/ti5_motor/canopen/protocol/ti5_motor_tpdo1.h"
#include "motor/ti5_motor/canopen/protocol/ti5_motor_tpdo2.h"
#include "motor/ti5_motor/canopen/protocol/ti5_motor_sdo_response.h"
#include "canbus/canopen/nmt_response_protocol.h"
#include <cmath>
#include <thread>
#include <chrono>
using namespace cmvr::device;
// 辅助函数:获取操作模式字符串
static const char* getOpModeString(int8_t mode) {
switch (mode) {
case 1: return "Profile Position (PP)";
case 2: return "Velocity (VL)";
case 3: return "Profile Velocity (PV)";
case 4: return "Profile Torque (PT)";
case 6: return "Homing (HM)";
case 8: return "Cyclic Sync Position (CSP)";
case 9: return "Cyclic Sync Velocity (CSV)";
case 10: return "Cyclic Sync Torque (CST)";
default: return "Unknown";
}
}
// 构造函数
EYouEthercatProtocol::EYouEthercatProtocol(std::string ifName, const std::string& xmlPath)
: interface_name_(ifName),
xml_config_path_(xmlPath),
initialized_(false),
slave_count_(0),
use_fixed_pdo_(xmlPath.empty()) {
comm_proto = CommProto::ETHERCAT;
try {
// 初始化message_manager
message_manager_ = std::make_shared<device::MessageManager<msgs::RobotDetail>>();
// 创建 EcMaster 实例
master_ = std::make_unique<EcMaster>();
// 初始化主站
int cycleTimeUs = 1000; // 1ms周期
int slaveCount = master_->init(interface_name_.c_str(), cycleTimeUs);
if (slaveCount < 0) {
throw std::runtime_error("[EYouEthercatProtocol] master init failed");
}
slave_count_ = slaveCount;
EcSlaveConfig config = createFixedSlaveConfig(1);
std::vector<uint16_t> rxPdos = config.availableRxPdos;
std::vector<uint16_t> txPdos = config.availableTxPdos;
if (rxPdos.empty() || txPdos.empty()) {
LOG(ERROR) << "[EYouEthercatProtocol] No available PDOs found\n";
throw std::runtime_error("[EYouEthercatProtocol] No available PDOs found ");
}
const EcPdo* rxPdo = &config.modules[0].rxPdos[0];
const EcPdo* txPdo = &config.modules[0].txPdos[0];
for (int slaveId = 1; slaveId <= slave_count_; slaveId++) {
if (master_->configurePdo(slaveId, rxPdo, txPdo) != 0) {
throw std::runtime_error("[EYouEthercatProtocol] PDO configuration failed for slave " + std::to_string(slaveId));
}
}
master_->setupMappingAndDc();
// 等待配置生效
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// 进入OP状态
if (master_->gotoOperational() != 0) {
throw std::runtime_error("[EYouEthercatProtocol] OPERATIONAL state failed");
}
std::this_thread::sleep_for(std::chrono::milliseconds(500));
if (!master_->isOperational()) {
LOG(WARNING) << "[EYouEthercatProtocol] Master reports not operational";
} else {
LOG(INFO) << "[EYouEthercatProtocol] EtherCAT in OPERATIONAL state";
}
// 初始化从站状态
for (int i = 1; i <= slave_count_; i++) {
node_states_[i] = NodeState();
uint16_t status = master_->getStatusWord(i);
LOG(INFO) << "[EYouEthercatProtocol] Slave " << i << " initial status word: 0x" << std::hex << status << std::dec;
}
initialized_ = true;
LOG(INFO) << "[EYouEthercatProtocol] Initialized successfully";
// 添加NMT响应协议
for (int i = 1; i <= slave_count_; i++) {
message_manager_->AddRecvProtocolData<NmtResponseProtocol<cmvr::msgs::RobotDetail>, false>(i);
}
} catch (const std::exception& e) {
LOG(ERROR) << "[EYouEthercatProtocol] Constructor failed: " << e.what();
throw std::runtime_error(e.what());
}
}
// 析构函数
EYouEthercatProtocol::~EYouEthercatProtocol() {
if (master_) {
// 失能所有电机
for (auto& node : node_states_) {
if (node.second.enabled) {
master_->disable(node.first);
LOG(INFO) << "[EYouEthercatProtocol] Disabled motor " << node.first;
}
}
master_->shutdown();
LOG(INFO) << "[EYouEthercatProtocol] Master shutdown successfully";
}
}
// 执行电机使能序列
bool EYouEthercatProtocol::performEnableSequence(uint8_t node_id) {
if (node_id > slave_count_) {
LOG(ERROR) << "[EYouEthercatProtocol] Node " << node_id << " out of range";
return false;
}
// 读取状态字
uint16_t status = master_->getStatusWord(node_id);
LOG(INFO) << "[EYouEthercatProtocol] Node " << node_id << " status: 0x" << std::hex << status << std::dec;
// 如果处于故障状态,先复位
if (status & 0x0008) {
LOG(INFO) << "[EYouEthercatProtocol] Fault detected, resetting...";
master_->faultReset(node_id);
std::this_thread::sleep_for(std::chrono::milliseconds(200));
status = master_->getStatusWord(node_id);
}
// 如果处于 Switch On Disabled 状态,执行使能序列
if (status & 0x0040) {
LOG(INFO) << "[EYouEthercatProtocol] Node " << (int)node_id << " in Switch On Disabled, enabling...";
// 获取当前位置并同步目标位置(防止抖动)
int32_t actualPos = master_->getActualPosition(node_id);
master_->setTargetPosition(node_id, actualPos);
master_->setModeOfOperation(node_id,EcMaster::EcOperationMode_ProfilePosition);
// Shutdown
master_->setControlWord(node_id, 0x06);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
// Switch On
master_->setControlWord(node_id, 0x07);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
// Enable Operation
master_->setControlWord(node_id, 0x0F);
std::this_thread::sleep_for(std::chrono::milliseconds(200));
status = master_->getStatusWord(node_id);
}
// 验证使能成功
bool enabled = (status & 0x0004) != 0;
if (enabled) {
LOG(INFO) << "[EYouEthercatProtocol] Node " << node_id << " enabled successfully";
} else {
LOG(ERROR) << "[EYouEthercatProtocol] Node " << node_id << " enable failed, status: 0x"
<< std::hex << status << std::dec;
}
return enabled;
}
// 操作模式转换 (msgs::RunMode -> EcOperationMode)
int8_t EYouEthercatProtocol::runModeToEcMode(msgs::RunMode mode) {
switch (mode) {
case msgs::RUN_MODE_PROFILE_POSITION:
return EcMaster::EcOperationMode_ProfilePosition; // 1
case msgs::RUN_MODE_PROFILE_VELOCITY:
return EcMaster::EcOperationMode_ProfileVelocity; // 3
case msgs::RUN_MODE_TORQUE: // 需要确认是否有这个枚举
return EcMaster::EcOperationMode_ProfileTorque; // 4
case msgs::RUN_MODE_INTERPOLATED_POSITION:
return EcMaster::EcOperationMode_InterpolatedPosition; // 7
case msgs::RUN_MODE_CYCLIC_SYNC_POSITION:
return EcMaster::EcOperationMode_CyclicSyncPosition; // 8
case msgs::RUN_MODE_CYCLIC_SYNC_VELOCITY:
return EcMaster::EcOperationMode_CyclicSyncVelocity; // 9
case msgs::RUN_MODE_CYCLIC_SYNC_CURRENT: // 名称统一
return EcMaster::EcOperationMode_CyclicSyncTorque; // 10
default:
return 0;
}
}
// 操作模式转换 (EcOperationMode -> msgs::RunMode)
cmvr::msgs::RunMode EYouEthercatProtocol::ecModeToRunMode(int8_t mode) {
switch (mode) {
case EcMaster::EcOperationMode_ProfilePosition:
return msgs::RUN_MODE_PROFILE_POSITION;
case EcMaster::EcOperationMode_ProfileVelocity:
return msgs::RUN_MODE_PROFILE_VELOCITY;
case EcMaster::EcOperationMode_ProfileTorque:
return msgs::RUN_MODE_TORQUE; // 需要确认枚举存在
case EcMaster::EcOperationMode_InterpolatedPosition:
return msgs::RUN_MODE_INTERPOLATED_POSITION;
case EcMaster::EcOperationMode_CyclicSyncPosition:
return msgs::RUN_MODE_CYCLIC_SYNC_POSITION;
case EcMaster::EcOperationMode_CyclicSyncVelocity:
return msgs::RUN_MODE_CYCLIC_SYNC_VELOCITY;
case EcMaster::EcOperationMode_CyclicSyncTorque:
return msgs::RUN_MODE_CYCLIC_SYNC_CURRENT;
default:
return msgs::RUN_MODE_UNSPECIFIED;
}
}
// 初始化节点
bool EYouEthercatProtocol::initNode(uint8_t node_id) {
try {
if (node_id > slave_count_) {
LOG(ERROR) << "[EYouEthercatProtocol] Node " << node_id << " out of range (max: " << slave_count_ << ")";
return false;
}
// 执行使能序列
if (!performEnableSequence(node_id)) {
LOG(ERROR) << "[EYouEthercatProtocol] Failed to enable node " << node_id;
return false;
}
node_states_[node_id].initialized = true;
node_states_[node_id].enabled = true;
node_states_[node_id].current_mode = msgs::RUN_MODE_PROFILE_POSITION;
LOG(INFO) << "[EYouEthercatProtocol] Node " << node_id << " initialized successfully";
return true;
} catch (const std::exception& e) {
LOG(ERROR) << "[EYouEthercatProtocol] Failed to init node " << node_id << ": " << e.what();
return false;
}
}
// 设置运行模式
void EYouEthercatProtocol::setMode(uint8_t node_id, msgs::RunMode mode) {
int8_t ec_mode = runModeToEcMode(mode);
master_->setModeOfOperation(node_id, ec_mode);
// 验证模式设置
std::this_thread::sleep_for(std::chrono::milliseconds(20));
int8_t actual_mode = master_->getModeOfOperationDisplay(node_id);
if (actual_mode == ec_mode) {
node_states_[node_id].current_mode = mode;
LOG(INFO) << "[EYouEthercatProtocol] Node " << (int)node_id << " mode set to "
<< getOpModeString(ec_mode);
} else {
LOG(WARNING) << "[EYouEthercatProtocol] Node " << node_id << " mode set failed, "
<< "expected " << getOpModeString(ec_mode)
<< ", got " << getOpModeString(actual_mode);
}
}
// 设置目标位置和速度
void EYouEthercatProtocol::setTarget(uint8_t node_id, double angle_rad, double vel) {
auto pos_cmd = angleToPos(angle_rad);
auto speed = static_cast<uint32_t>(std::abs(velToSpeed(vel)));
msgs::RunMode current_mode = getMode(node_id);
switch (current_mode) {
case msgs::RUN_MODE_PROFILE_POSITION: {
// 先设置轮廓速度
master_->setProfileVelocity(node_id, speed);
// 设置目标位置
master_->setTargetPosition(node_id, pos_cmd);
node_states_[node_id].target_position = pos_cmd;
// 构建控制字:使能状态 + 立即更新标志
uint16_t ctlword = 0x0F | 0x20; // 0x0F使能, 0x20立即更新
// 触发位置更新
master_->setControlWord(node_id, ctlword);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
// 启动新位置命令
master_->setControlWord(node_id, ctlword | 0x10);
break;
}
case msgs::RUN_MODE_CYCLIC_SYNC_POSITION:
master_->setTargetPosition(node_id, pos_cmd);
node_states_[node_id].target_position = pos_cmd;
break;
default:
LOG(WARNING) << "[EYouEthercatProtocol] setTarget(pos,vel) called in unsupported mode for node " << node_id;
break;
}
}
// 设置目标速度
void EYouEthercatProtocol::setTarget(uint8_t node_id, double vel) {
auto speed = static_cast<int32_t>(velToSpeed(vel));
msgs::RunMode current_mode = getMode(node_id);
switch (current_mode) {
case msgs::RUN_MODE_VELOCITY:
case msgs::RUN_MODE_PROFILE_VELOCITY:
case msgs::RUN_MODE_CYCLIC_SYNC_VELOCITY:
master_->setTargetVelocity(node_id, speed);
break;
default:
LOG(WARNING) << "[EYouEthercatProtocol] setTarget(vel) called in unsupported mode for node " << node_id;
break;
}
}
// 设置目标位置
void EYouEthercatProtocol::setQ(uint8_t node_id, double angle_rad) {
auto pos_cmd = angleToPos(angle_rad);
msgs::RunMode current_mode = getMode(node_id);
switch (current_mode) {
case msgs::RUN_MODE_CYCLIC_SYNC_POSITION:
{
master_->setTargetPosition(node_id, pos_cmd);
node_states_[node_id].target_position = pos_cmd;
break;
}
case msgs::RUN_MODE_PROFILE_POSITION:
{
// 1. 设置目标位置
master_->setTargetPosition(node_id, pos_cmd);
node_states_[node_id].target_position = pos_cmd;
// 2. 构建控制字:使能状态 + 立即更新标志
uint16_t ctlword = 0x0F | 0x20; // 0x0F使能, 0x20立即更新
// 3. 触发位置更新
master_->setControlWord(node_id, ctlword);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
// 4. 启动新位置命令
master_->setControlWord(node_id, ctlword | 0x10);
break;
}
default:
{
LOG(WARNING) << "[EYouEthercatProtocol] setQ called in unsupported mode for node " << node_id;
break;
}
}
}
// 设置位置限制
void EYouEthercatProtocol::setLimitQ(uint8_t node_id, double ub, double lb) {
int32_t lb_val = angleToPos(lb);
int32_t ub_val = angleToPos(ub);
// 开启软件位置限制 (0x4C494D54 = "LIMT")
uint32_t limitEnable = 0x4C494D54;
if (master_->writeSdo(node_id, 0x2003, 0x00, &limitEnable, EcDataType::Uint32, 100) != 0) {
LOG(ERROR) << "[EYouEthercatProtocol] Failed to enable software position limit for node " << node_id;
}
// 设置软件位置限制
if (master_->writeSdo(node_id, 0x607D, 0x01, &lb_val, EcDataType::Int32, 100) != 0) {
LOG(ERROR) << "[EYouEthercatProtocol] Failed to set lower position limit for node " << node_id;
}
if (master_->writeSdo(node_id, 0x607D, 0x02, &ub_val, EcDataType::Int32, 100) != 0) {
LOG(ERROR) << "[EYouEthercatProtocol] Failed to set upper position limit for node " << node_id;
}
LOG(INFO) << "[EYouEthercatProtocol] Position limits set for node " << node_id
<< ": [" << lb << ", " << ub << "] rad";
}
// 设置速度限制
void EYouEthercatProtocol::setLimitQd(uint8_t node_id, double qd) {
auto speed = static_cast<uint32_t>(std::abs(velToSpeed(qd)));
// 设置最大速度限制
if (master_->writeSdo(node_id, 0x607F, 0x00, &speed, EcDataType::Uint32, 100) != 0) {
LOG(ERROR) << "[EYouEthercatProtocol] Failed to set max speed limit for node " << node_id;
}
if (master_->writeSdo(node_id, 0x6081, 0x00, &speed, EcDataType::Uint32, 100) != 0) {
LOG(ERROR) << "[EYouEthercatProtocol] Failed to set profile speed for node " << node_id;
}
LOG(INFO) << "[EYouEthercatProtocol] Speed limit set for node " << node_id << ": " << qd << " rad/s";
}
// 设置加速度限制
void EYouEthercatProtocol::setLimitQdd(uint8_t node_id, double u_qdd, double l_qdd) {
// u_qdd: rad/s² (最大加速度)
// l_qdd: rad/s² (最大减速度)
// 转换为电机加速度(脉冲/秒²)
// 圈数/秒² = 弧度/秒² / 2π
// 脉冲/秒² = 圈数/秒² * GearRatio * PULSE_PER_REV
auto accel = static_cast<uint32_t>((std::abs(u_qdd) / (2.0 * M_PI)) * GearRatio * PULSE_PER_REV);
auto decel = static_cast<uint32_t>((std::abs(l_qdd) / (2.0 * M_PI)) * GearRatio * PULSE_PER_REV);
// 通过SDO写入加速度和减速度限制
if (master_->writeSdo(node_id, 0x6083, 0x00, &accel, EcDataType::Uint32, 100) != 0) {
LOG(ERROR) << "[EYouEthercatProtocol] Failed to set acceleration limit for node " << node_id;
}
if (master_->writeSdo(node_id, 0x6084, 0x00, &decel, EcDataType::Uint32, 100) != 0) {
LOG(ERROR) << "[EYouEthercatProtocol] Failed to set deceleration limit for node " << node_id;
}
LOG(INFO) << "[EYouEthercatProtocol] Acceleration limits set for node " << node_id
<< ": accel=" << u_qdd << ", decel=" << l_qdd << " rad/s²";
}
// 零位校准
bool EYouEthercatProtocol::calibrateZeroQ(uint8_t node_id) {
try {
int32_t pos;
int32_t offset = 0;
int32_t rev = 0;
// 读取当前位置
if (master_->readSdo(node_id, 0x6064, 0x00, &pos, EcDataType::Int32, 20000) != 0) {
LOG(ERROR) << "[EYouEthercatProtocol] read actual position failed";
return false;
}
LOG(INFO) << "[EYouEthercatProtocol] Actual position: " << pos;
// 读取home offset
if (master_->readSdo(node_id, 0x607C, 0x00, &offset, EcDataType::Int32, 20000) != 0) {
LOG(ERROR) << "[EYouEthercatProtocol] read home offset failed";
return false;
}
LOG(INFO) << "[EYouEthercatProtocol] Home offset before: " << offset;
// 先将home offset设为0
offset = 0;
if (master_->writeSdo(node_id, 0x607C, 0x00, &offset, EcDataType::Int32, 20000) != 0) {
LOG(ERROR) << "[EYouEthercatProtocol] write home offset 0 failed";
return false;
}
LOG(INFO) << "[EYouEthercatProtocol] Home offset set to 0";
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// 读取实际位置
if (master_->readSdo(node_id, 0x6064, 0x00, &pos, EcDataType::Int32, 20000) != 0) {
LOG(ERROR) << "[EYouEthercatProtocol] read actual position after offset reset failed";
return false;
}
LOG(INFO) << "[EYouEthercatProtocol] Actual position after offset reset: " << pos;
// 获取轴转数,超圈处理
if (master_->readSdo(node_id, 0x6091, 0x02, &rev, EcDataType::Int32, 20000) != 0) {
LOG(ERROR) << "[EYouEthercatProtocol] read gear ratio shaft revolution failed";
return false;
}
LOG(INFO) << "[EYouEthercatProtocol] Gear ratio shaft revolution: " << rev;
// 处理超出编码器范围的情况
long long r = rev;
int temp = static_cast<int>(r / 2);
if (pos > temp || pos < -temp) {
pos = pos % static_cast<int>(r);
if (pos > temp || pos < -temp) {
if (pos > temp) {
pos = pos - static_cast<int>(r);
} else if (pos < -temp) {
pos = pos + static_cast<int>(r);
}
}
LOG(WARNING) << "[EYouEthercatProtocol] Position out of encoder range, adjusted to " << pos;
}
// 写home offset偏移
offset = -pos;
if (master_->writeSdo(node_id, 0x607C, 0x00, &offset, EcDataType::Int32, 20000) != 0) {
LOG(ERROR) << "[EYouEthercatProtocol] write home offset failed";
return false;
}
LOG(INFO) << "[EYouEthercatProtocol] Home offset set to: " << offset;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// 读取实际位置
if (master_->readSdo(node_id, 0x6064, 0x00, &pos, EcDataType::Int32, 20000) != 0) {
LOG(ERROR) << "[EYouEthercatProtocol] read actual position after calibration failed";
return false;
}
LOG(INFO) << "[EYouEthercatProtocol] Actual position after calibration: " << pos;
// 保存参数
uint32_t saveValue = 0x65766173; // "evas"
if (master_->writeSdo(node_id, 0x1010, 0x01, &saveValue, EcDataType::Uint32, 20000) != 0) {
LOG(ERROR) << "[EYouEthercatProtocol] save parameters failed";
return false;
}
LOG(INFO) << "[EYouEthercatProtocol] Parameters saved";
LOG(INFO) << "[EYouEthercatProtocol] Motor " << node_id << " calibrated successfully";
return true;
} catch (const std::exception& e) {
LOG(ERROR) << "[EYouEthercatProtocol] Calibration failed for node " << node_id << ": " << e.what();
return false;
}
}
// 刹车(快速停机)
void EYouEthercatProtocol::brake(uint8_t node_id) {
// 发送快速停机命令
uint16_t ctlword = 0x0002; // Quick Stop
master_->setControlWord(node_id, ctlword);
LOG(INFO) << "[EYouEthercatProtocol] Brake (quick stop) applied to motor " << node_id;
}
// 检查是否到达目标位置
bool EYouEthercatProtocol::reachedTargetQ(uint8_t node_id) {
uint16_t status_word = getStatusWord(node_id);
// 检查状态字的bit 10目标到达位
return (status_word & 0x0400) != 0;
}
// 获取当前位置
double EYouEthercatProtocol::getQ(uint8_t node_id) {
int32_t position = master_->getActualPosition(node_id);
return posToAngle(position);
}
// 获取当前速度
double EYouEthercatProtocol::getQd(uint8_t node_id) {
int32_t velocity = master_->getActualVelocity(node_id);
return speedToVel(velocity);
}
// 设置速度
void EYouEthercatProtocol::setQd(uint8_t node_id, double qd) {
auto speed = static_cast<uint32_t>(std::abs(velToSpeed(qd)));
msgs::RunMode current_mode = getMode(node_id);
switch (current_mode) {
case msgs::RUN_MODE_CYCLIC_SYNC_POSITION:
case msgs::RUN_MODE_PROFILE_POSITION:
master_->setProfileVelocity(node_id, speed);
last_Qd_[node_id] = speed;
break;
case msgs::RUN_MODE_PROFILE_VELOCITY:
case msgs::RUN_MODE_CYCLIC_SYNC_VELOCITY:
master_->setTargetVelocity(node_id, static_cast<int32_t>(speed));
break;
default:
LOG(WARNING) << "[EYouEthercatProtocol] setQd called in unsupported mode for node " << node_id;
break;
}
}
// 设置加速度
void EYouEthercatProtocol::setQdd(uint8_t node_id, double qdd) {
// qdd: rad/s² (加速度)
// 转换为电机加速度(脉冲/秒²)
uint32_t accel = static_cast<uint32_t>((std::abs(qdd) / (2.0 * M_PI)) * GearRatio * PULSE_PER_REV);
if (last_Qdd_[node_id] != accel) {
master_->setProfileAcceleration(node_id, accel);
master_->setProfileDeceleration(node_id, accel);
last_Qdd_[node_id] = accel;
}
}
// 力矩关闭
void EYouEthercatProtocol::torqueOff(uint8_t node_id) {
auto ret = master_->disable(node_id);
node_states_[node_id].enabled = false;
LOG(INFO) << "[EYouEthercatProtocol] Torque off for motor " << node_id << ", ret = " << ret;
}
// 获取运行模式
cmvr::msgs::RunMode EYouEthercatProtocol::getMode(uint8_t node_id) {
int8_t mode = master_->getModeOfOperationDisplay(node_id);
return ecModeToRunMode(mode);
}
// 配置轮廓参数
void EYouEthercatProtocol::configProfile(uint8_t node_id, uint32_t speed, uint32_t accel, uint32_t decel) {
master_->setProfileVelocity(node_id, speed);
master_->setProfileAcceleration(node_id, accel);
master_->setProfileDeceleration(node_id, decel);
LOG(INFO) << "[EYouEthercatProtocol] Profile configured for node " << node_id
<< ": speed=" << speed << ", accel=" << accel << ", decel=" << decel;
}
// 获取力矩
double EYouEthercatProtocol::getTorque(uint8_t node_id) {
int16_t torque = master_->getActualTorque(node_id);
// 返回实际力矩值(取决于具体驱动器,这里假设是额定力矩的倍数)
return torque / 1000.0;
}
// 获取状态字
uint16_t EYouEthercatProtocol::getStatusWord(uint8_t node_id) {
uint16_t status_word = master_->getStatusWord(node_id);
node_states_[node_id].status_word = status_word;
return status_word;
}
// 检查电机是否使能
bool EYouEthercatProtocol::isEnabled(uint8_t node_id) {
uint16_t status_word = getStatusWord(node_id);
// 检查状态字的bit 2操作使能和bit 3故障
return (status_word & 0x000C) == 0x0008;
}
// 检查是否有故障
bool EYouEthercatProtocol::isFault(uint8_t node_id) {
uint16_t status_word = getStatusWord(node_id);
return (status_word & 0x0008) != 0;
}
// 故障复位
void EYouEthercatProtocol::faultReset(uint8_t node_id) {
if (isFault(node_id)) {
if (master_->faultReset(node_id) == 0) {
LOG(INFO) << "[EYouEthercatProtocol] Fault reset for motor " << node_id;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
} else {
LOG(ERROR) << "[EYouEthercatProtocol] Failed to reset fault for motor " << node_id;
}
}
}
// 等待目标到达
bool EYouEthercatProtocol::waitForTargetReached(uint8_t node_id, int timeout_ms) {
return waitUntil([this, node_id]() { return reachedTargetQ(node_id); }, timeout_ms);
}
// 获取RobotDetail数据
std::unique_ptr<cmvr::msgs::RobotDetail> EYouEthercatProtocol::GetRobotDetail() {
if (message_manager_) {
auto data_ptr = std::make_unique<msgs::RobotDetail>();
message_manager_->GetSensorData(data_ptr.get());
return data_ptr;
}
return std::make_unique<msgs::RobotDetail>();
}
// 辅助函数实现(弧度制版本)
double EYouEthercatProtocol::posToAngle(int32_t pos) const {
// 脉冲数 -> 弧度
// 圈数 = 脉冲数 / (GearRatio * PULSE_PER_REV)
// 弧度 = 圈数 * 2π
return (pos * 2.0 * M_PI) / (GearRatio * PULSE_PER_REV);
}
int32_t EYouEthercatProtocol::angleToPos(double angle) const {
// 弧度 -> 脉冲数
// 圈数 = 弧度 / 2π
// 脉冲数 = 圈数 * GearRatio * PULSE_PER_REV
return static_cast<int32_t>((angle / (2.0 * M_PI)) * GearRatio * PULSE_PER_REV);
}
double EYouEthercatProtocol::velToSpeed(double vel) const {
// vel: rad/s (角速度)
// 输出:电机速度(脉冲/秒)
// 圈数/秒 = vel / 2π
// 脉冲/秒 = 圈数/秒 * GearRatio * PULSE_PER_REV
return (vel / (2.0 * M_PI)) * GearRatio * PULSE_PER_REV;
}
double EYouEthercatProtocol::speedToVel(int32_t speed) const {
// speed: 电机速度(脉冲/秒)
// 输出rad/s
// 圈数/秒 = speed / (GearRatio * PULSE_PER_REV)
// 弧度/秒 = 圈数/秒 * 2π
return (speed * 2.0 * M_PI) / (GearRatio * PULSE_PER_REV);
}
bool EYouEthercatProtocol::waitUntil(std::function<bool()> condition, int timeout_ms) {
auto start = std::chrono::steady_clock::now();
while (!condition()) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
if (std::chrono::steady_clock::now() - start > std::chrono::milliseconds(timeout_ms)) {
return false;
}
}
return true;
}
void EYouEthercatProtocol::updateNodeState(uint8_t node_id) {
// 更新状态字
node_states_[node_id].status_word = master_->getStatusWord(node_id);
// 可以根据需要更新其他状态信息
}

View File

@ -1,125 +0,0 @@
//
// Created by cmvr on 2026/3/30.
//
#pragma once
#include "cmvr/msgs/motor.pb.h"
#include "motor/motor_protocol_interface.h"
#include "../../../canbus/abstract_canbus.h"
#include "canbus/can_comm/can_receiver.h"
#include "canbus/can_comm/can_sender.h"
#include "canbus/can_comm/message_manager.h"
#include "cmvr/msgs/error_code.pb.h"
#include "cmvr/msgs/robot_detail.pb.h"
// 替换原有的 eu_ethercat 头文件
#include "protocol/ec_master.h"
#include "protocol/ec_xml_parser.h"
#include "protocol/ec_pdo_config.h"
#include <cmath>
#include <unordered_map>
#include <functional>
#include <memory>
#include <chrono>
#include <thread>
#include <mutex>
namespace cmvr {
namespace device {
// 节点状态结构体
struct NodeState {
bool enabled = false;
bool initialized = false;
msgs::RunMode current_mode = msgs::RUN_MODE_UNSPECIFIED;
uint16_t status_word = 0;
int32_t position_offset = 0;
int32_t target_position = 0;
};
class EYouEthercatProtocol : public MotorProtocolInterface {
public:
explicit EYouEthercatProtocol(std::string ifName, const std::string& xmlPath = "");
~EYouEthercatProtocol() override;
// 基础接口实现
bool initNode(uint8_t node_id) override;
void setMode(uint8_t node_id, msgs::RunMode mode) override;
void setTarget(uint8_t node_id, double angle_rad, double vel) override;
void setTarget(uint8_t node_id, double vel) override;
void setQ(uint8_t node_id, double angle_rad) override;
void setLimitQ(uint8_t node_id, double ub, double lb) override;
void setLimitQd(uint8_t node_id, double qd) override;
void setLimitQdd(uint8_t node_id, double u_qdd, double l_qdd) override;
bool calibrateZeroQ(uint8_t node_id) override;
void brake(uint8_t node_id) override;
bool reachedTargetQ(uint8_t node_id) override;
double getQ(uint8_t node_id) override;
double getQd(uint8_t node_id) override;
void setQd(uint8_t node_id, double qd) override;
void setQdd(uint8_t node_id, double qdd) override;
void torqueOff(uint8_t node_id) override;
msgs::RunMode getMode(uint8_t node_id) override;
// 配置接口
void configProfile(uint8_t node_id, uint32_t speed, uint32_t accel, uint32_t decel);
// 扩展功能接口
double getTorque(uint8_t node_id);
uint16_t getStatusWord(uint8_t node_id);
bool isEnabled(uint8_t node_id);
bool isFault(uint8_t node_id);
void faultReset(uint8_t node_id);
bool waitForTargetReached(uint8_t node_id, int timeout_ms);
// 数据获取接口
std::unique_ptr<msgs::RobotDetail> GetRobotDetail();
int getSlaveCount() const { return slave_count_; }
private:
// 常量定义
static constexpr double GearRatio = 101.0;
static constexpr double RADTODEG = 180.0 / M_PI;
static constexpr double PULSE_PER_REV = 65536.0;
// 辅助函数
double posToAngle(int32_t pos) const;
int32_t angleToPos(double angle) const;
double velToSpeed(double vel) const;
double speedToVel(int32_t speed) const;
bool waitUntil(std::function<bool()> condition, int timeout_ms);
void updateNodeState(uint8_t node_id);
bool performEnableSequence(uint8_t node_id);
int8_t runModeToEcMode(msgs::RunMode mode);
msgs::RunMode ecModeToRunMode(int8_t mode);
// 成员变量
std::unordered_map<uint8_t, NodeState> node_states_;
std::unordered_map<uint8_t, double> last_Qd_;
std::unordered_map<uint8_t, uint32_t> last_Qdd_;
std::shared_ptr<device::CanSender<msgs::RobotDetail>> can_sender_;
std::shared_ptr<device::MessageManager<msgs::RobotDetail>> message_manager_;
std::string interface_name_;
std::string xml_config_path_;
bool initialized_;
int slave_count_;
std::unique_ptr<EcMaster> master_;
std::unique_ptr<EcXmlParser> parser_;
EcSlaveConfig slave_config_;
bool use_fixed_pdo_;
std::mutex master_mutex_;
};
} // namespace device
} // namespace cmvr

View File

@ -1,328 +0,0 @@
// ec_master.h
#ifndef EC_MASTER_H
#define EC_MASTER_H
#include "ec_types.h"
#include <map>
#include <atomic>
#include <cstring>
#include <vector>
#ifdef __cplusplus
extern "C" {
#endif
#include "soem/soem.h"
#include "soem/osal.h"
#ifdef __cplusplus
}
#endif
// 错误码定义
#define EC_SUCCESS 0
#define EC_FAILED_INIT 1
#define EC_FAILED_NOSLAVE 2
#ifndef EC_TIMEOUTMON
#define EC_TIMEOUTMON 500
#endif
#ifndef EC_TIMEOUTRET
#define EC_TIMEOUTRET 2000
#endif
#ifndef EC_TIMEOUTSTATE
#define EC_TIMEOUTSTATE 2000
#endif
#ifndef EC_TIMEOUTRXM
#define EC_TIMEOUTRXM 2000
#endif
// EtherCAT 主站类
class EcMaster {
public:
// 操作模式枚举(符合 CiA 402 标准)
enum EcOperationMode : int8_t {
// 轮廓模式 (Profile Modes)
EcOperationMode_ProfilePosition = 1, // PP 模式
EcOperationMode_ProfileVelocity = 3, // PV 模式
EcOperationMode_ProfileTorque = 4, // PT 模式
// 插补模式
EcOperationMode_InterpolatedPosition = 7, // IP 模式
// 循环同步模式 (Cyclic Sync Modes)
EcOperationMode_CyclicSyncPosition = 8, // CSP 模式
EcOperationMode_CyclicSyncVelocity = 9, // CSV 模式
EcOperationMode_CyclicSyncTorque = 10, // CST 模式
};
public:
EcMaster();
~EcMaster();
EcMaster(const EcMaster&) = delete;
EcMaster& operator=(const EcMaster&) = delete;
// 初始化
int init(const char* ifName, int cycleTimeUs = 1000);
void close() { shutdown(); }
int getSlaveCount() const { return slaveCount; }
bool isOperational() const { return inOp; }
// 状态控制
int setState(uint16_t slaveId, uint8_t targetState);
int preOperational(uint16_t slaveId) { return setState(slaveId, EC_STATE_PRE_OP); }
int safeOperational(uint16_t slaveId) { return setState(slaveId, EC_STATE_SAFE_OP); }
int operational(uint16_t slaveId) { return setState(slaveId, EC_STATE_OPERATIONAL); }
int gotoOperational();
void shutdown();
// PDO 配置
int configurePdo(uint16_t slaveId, const EcPdo* rxPdo, const EcPdo* txPdo);
int setupMappingAndDc(); // 配置所有从站的映射和DC
int setupPdoOffsets(uint16_t slaveId, const EcPdo* rxPdo, const EcPdo* txPdo);
// PDO 数据访问(高性能,零拷贝)
void setControlWord(uint16_t slaveId, uint16_t value);
uint16_t getStatusWord(uint16_t slaveId);
void setTargetPosition(uint16_t slaveId, int32_t value);
int32_t getActualPosition(uint16_t slaveId);
void setTargetVelocity(uint16_t slaveId, int32_t value);
int32_t getActualVelocity(uint16_t slaveId);
void setTargetTorque(uint16_t slaveId, int16_t value);
int16_t getActualTorque(uint16_t slaveId);
void setModeOfOperation(uint16_t slaveId, int8_t value);
int8_t getModeOfOperationDisplay(uint16_t slaveId);
void setProfileVelocity(uint16_t slaveId, uint32_t value);
void setProfileAcceleration(uint16_t slaveId, uint32_t value);
void setProfileDeceleration(uint16_t slaveId, uint32_t value);
int16_t getCurrentValue(uint16_t slaveId);
uint16_t getErrorCode(uint16_t slaveId);
// 电机控制高级接口
int enable(uint16_t slaveId);
int disable(uint16_t slaveId);
int faultReset(uint16_t slaveId);
// 周期操作
int sendOutputs() { return ecx_send_processdata(&ctx); }
int receiveInputs() { return ecx_receive_processdata(&ctx, EC_TIMEOUTRET); }
// 影子缓冲区同步接口
void syncSlaveOutputs(uint16_t slaveId); // 同步指定从站的输出
void syncAllOutputs(); // 同步所有从站的输出
// 原始数据访问
uint8_t* getInputs(uint16_t slaveId) {
auto it = inputs.find(slaveId);
return (it != inputs.end()) ? it->second : nullptr;
}
uint8_t* getOutputs(uint16_t slaveId) {
auto it = outputs.find(slaveId);
return (it != outputs.end()) ? it->second : nullptr;
}
int getInputSize(uint16_t slaveId) {
auto it = inputSizes.find(slaveId);
return (it != inputSizes.end()) ? it->second : 0;
}
int getOutputSize(uint16_t slaveId) {
auto it = outputSizes.find(slaveId);
return (it != outputSizes.end()) ? it->second : 0;
}
// SDO 读写(仅用于配置阶段)
int readSdo(uint16_t slaveId, uint16_t index, uint8_t subindex, void* value, EcDataType type, int timeoutMs = 100);
int writeSdo(uint16_t slaveId, uint16_t index, uint8_t subindex, void* value, EcDataType type, int timeoutMs = 100);
// SM/FMMU 配置校验(调试用)
void verifySmConfiguration(uint16_t slaveId);
void verifyAllSlavesSmConfiguration();
// 模板便捷接口
template<typename T>
int readSdo(uint16_t slaveId, uint16_t index, uint8_t subindex, T* value, int timeoutMs = 100) {
EcDataType type;
if constexpr (std::is_same_v<T, int8_t>) type = EcDataType::Int8;
else if constexpr (std::is_same_v<T, uint8_t>) type = EcDataType::Uint8;
else if constexpr (std::is_same_v<T, int16_t>) type = EcDataType::Int16;
else if constexpr (std::is_same_v<T, uint16_t>) type = EcDataType::Uint16;
else if constexpr (std::is_same_v<T, int32_t>) type = EcDataType::Int32;
else if constexpr (std::is_same_v<T, uint32_t>) type = EcDataType::Uint32;
else if constexpr (std::is_same_v<T, float>) type = EcDataType::Real32;
else if constexpr (std::is_same_v<T, double>) type = EcDataType::Real64;
else return -1;
return readSdo(slaveId, index, subindex, value, type, timeoutMs);
}
template<typename T>
int writeSdo(uint16_t slaveId, uint16_t index, uint8_t subindex, T* value, int timeoutMs = 100) {
EcDataType type;
if constexpr (std::is_same_v<T, int8_t>) type = EcDataType::Int8;
else if constexpr (std::is_same_v<T, uint8_t>) type = EcDataType::Uint8;
else if constexpr (std::is_same_v<T, int16_t>) type = EcDataType::Int16;
else if constexpr (std::is_same_v<T, uint16_t>) type = EcDataType::Uint16;
else if constexpr (std::is_same_v<T, int32_t>) type = EcDataType::Int32;
else if constexpr (std::is_same_v<T, uint32_t>) type = EcDataType::Uint32;
else if constexpr (std::is_same_v<T, float>) type = EcDataType::Real32;
else if constexpr (std::is_same_v<T, double>) type = EcDataType::Real64;
else return -1;
return writeSdo(slaveId, index, subindex, value, type, timeoutMs);
}
private:
// ========== 影子缓冲区结构(每个从站独立) ==========
struct SlaveShadowBuffer {
uint8_t* data = nullptr; // 影子缓冲区数据指针
size_t size = 0; // 缓冲区大小
bool dirty = false; // 是否有待同步的数据
SlaveShadowBuffer() = default;
explicit SlaveShadowBuffer(size_t sz) : size(sz) {
if (sz > 0) {
data = new uint8_t[sz];
memset(data, 0, sz);
}
}
~SlaveShadowBuffer() {
delete[] data;
data = nullptr;
}
// 禁止拷贝
SlaveShadowBuffer(const SlaveShadowBuffer&) = delete;
SlaveShadowBuffer& operator=(const SlaveShadowBuffer&) = delete;
// 允许移动
SlaveShadowBuffer(SlaveShadowBuffer&& other) noexcept
: data(other.data), size(other.size), dirty(other.dirty) {
other.data = nullptr;
other.size = 0;
other.dirty = false;
}
SlaveShadowBuffer& operator=(SlaveShadowBuffer&& other) noexcept {
if (this != &other) {
delete[] data;
data = other.data;
size = other.size;
dirty = other.dirty;
other.data = nullptr;
other.size = 0;
other.dirty = false;
}
return *this;
}
// 重新分配缓冲区
void reallocate(size_t newSize) {
if (data) {
delete[] data;
data = nullptr;
}
size = newSize;
if (newSize > 0) {
data = new uint8_t[newSize];
memset(data, 0, newSize);
}
dirty = false;
}
};
// SOEM 上下文
ecx_contextt ctx;
uint8_t IOmap[4096];
// 每个从站的影子缓冲区映射
std::map<uint16_t, SlaveShadowBuffer> shadowBuffers;
std::atomic<bool> anyPdoDirty{false}; // 是否有任何影子缓冲区有更新
int slaveCount = 0;
int expectedWKC = 0;
int currentgroup = 0;
// 状态标志
std::atomic<bool> inOp{false};
std::atomic<bool> isRunning{false};
std::atomic<int> mappingdone{0};
std::atomic<int> dorun{0};
std::atomic<int> cyclicWkcErrorCount{0};
int64_t cycleTimeNs = 1000000;
OSAL_THREAD_HANDLE cyclicThread;
OSAL_THREAD_HANDLE checkThread;
// PDO 数据指针映射
std::map<uint16_t, uint8_t*> inputs;
std::map<uint16_t, uint8_t*> outputs;
std::map<uint16_t, int> inputSizes;
std::map<uint16_t, int> outputSizes;
std::map<uint16_t, uint16_t> outputOffsets;
// PDO 偏移映射
std::map<uint16_t, EcPdoOffsets> pdoOffsets;
// 辅助函数
template<typename T>
void writePdo(uint16_t slaveId, uint16_t offset, T value);
template<typename T>
T readPdo(uint16_t slaveId, uint16_t offset);
// 获取从站的影子缓冲区
SlaveShadowBuffer* getShadowBuffer(uint16_t slaveId);
// 线程函数
static OSAL_THREAD_FUNC_RT cyclicThreadFunc(void* arg);
static OSAL_THREAD_FUNC checkThreadFunc(void* arg);
void runCyclic();
void runCheck();
};
// ==================== 模板实现(必须放在头文件中) ====================
template<typename T>
void EcMaster::writePdo(uint16_t slaveId, uint16_t offset, T value) {
if (inOp) {
auto* shadow = getShadowBuffer(slaveId);
if (shadow && shadow->data) {
if (offset + sizeof(T) <= shadow->size) {
*(T*)(shadow->data + offset) = value;
shadow->dirty = true;
anyPdoDirty = true;
return;
}
}
}
// 降级:直接写 IOmap配置阶段使用
auto outIt = outputs.find(slaveId);
if (outIt != outputs.end() && outIt->second) {
auto sizeIt = outputSizes.find(slaveId);
if (sizeIt != outputSizes.end() && offset + sizeof(T) <= (uint16_t)sizeIt->second) {
*(T*)(outIt->second + offset) = value;
}
}
}
template<typename T>
T EcMaster::readPdo(uint16_t slaveId, uint16_t offset) {
auto it = pdoOffsets.find(slaveId);
if (it == pdoOffsets.end() || offset == 0xFFFF) return 0;
auto inIt = inputs.find(slaveId);
if (inIt != inputs.end() && inIt->second) {
auto sizeIt = inputSizes.find(slaveId);
if (sizeIt != inputSizes.end() && offset + sizeof(T) <= (uint16_t)sizeIt->second) {
return *(T*)(inIt->second + offset);
}
}
return 0;
}
#endif // EC_MASTER_H

View File

@ -1,75 +0,0 @@
// ec_pdo_config.h - 固定 PDO 配置(替代 XML 解析)
#ifndef EC_PDO_CONFIG_H
#define EC_PDO_CONFIG_H
#include "ec_types.h"
// 创建固定的 RxPDO 配置(对应 XML 中的 #x1600
inline EcPdo createFixedRxPdo() {
EcPdo rxPdo;
rxPdo.index = 0x1600;
rxPdo.mapCount = 10; // 9个有效条目 + 1个结束标志
rxPdo.name = "Outputs";
rxPdo.isRxPdo = true;
// 按XML顺序填充 Entry
rxPdo.entries.push_back({0x6040, 0, 16, "Control Word", EcDataType::Uint16});
rxPdo.entries.push_back({0x607A, 0, 32, "Target Position", EcDataType::Int32});
rxPdo.entries.push_back({0x60FF, 0, 32, "Target Velocity", EcDataType::Int32});
rxPdo.entries.push_back({0x6071, 0, 16, "Target Torque", EcDataType::Int16});
rxPdo.entries.push_back({0x6083, 0, 32, "Profile Acceleration", EcDataType::Uint32});
rxPdo.entries.push_back({0x6084, 0, 32, "Profile Deceleration", EcDataType::Uint32});
rxPdo.entries.push_back({0x6081, 0, 32, "Profile Velocity", EcDataType::Uint32});
rxPdo.entries.push_back({0x6087, 0, 32, "Torque Slope", EcDataType::Uint32});
rxPdo.entries.push_back({0x6060, 0, 8, "Modes Of Operation", EcDataType::Int8});
rxPdo.entries.push_back({0x0000, 0, 8, "End Marker", EcDataType::Uint8});
return rxPdo;
}
// 创建固定的 TxPDO 配置(对应 XML 中的 #x1a00
inline EcPdo createFixedTxPdo() {
EcPdo txPdo;
txPdo.index = 0x1A00;
txPdo.mapCount = 8; // 7个有效条目 + 1个结束标志
txPdo.name = "Inputs";
txPdo.isRxPdo = false;
// 按XML顺序填充 Entry
txPdo.entries.push_back({0x6041, 0, 16, "Status Word", EcDataType::Uint16});
txPdo.entries.push_back({0x6064, 0, 32, "Actual Position", EcDataType::Int32});
txPdo.entries.push_back({0x606C, 0, 32, "Actual Velocity", EcDataType::Int32});
txPdo.entries.push_back({0x6077, 0, 16, "Actual Torque", EcDataType::Int16});
txPdo.entries.push_back({0x6061, 0, 8, "Mode Of Operation Display", EcDataType::Int8});
txPdo.entries.push_back({0x603F, 0, 16, "Error Code", EcDataType::Uint16});
txPdo.entries.push_back({0x6078, 0, 16, "Actual Current Value", EcDataType::Int16});
txPdo.entries.push_back({0x0000, 0, 8, "End Marker", EcDataType::Uint8});
return txPdo;
}
// 创建完整的从站配置 - 可以直接替换 XML 解析结果
inline EcSlaveConfig createFixedSlaveConfig(uint16_t slaveId) {
EcSlaveConfig config;
config.slaveId = slaveId;
config.productCode = 0x00000000;
config.revisionNo = 0;
config.name = "Axis (csv,csp,cst)";
EcModule module;
module.moduleIdent = 0x119800; // 对应 XML 中的 ModuleIdent="#x119800"
module.name = "dynamic switchbewteen csp/csv";
module.rxPdos.push_back(createFixedRxPdo());
module.txPdos.push_back(createFixedTxPdo());
// 记录可用的PDO索引对应 parser.getAvailableRxPdos/getAvailableTxPdos 的返回值)
config.availableRxPdos.push_back(0x1600);
config.availableTxPdos.push_back(0x1A00);
config.modules.push_back(module);
return config;
}
#endif // EC_PDO_CONFIG_H

View File

@ -1,111 +0,0 @@
// ec_types.h - 公共类型定义
#ifndef EC_TYPES_H
#define EC_TYPES_H
#include <string>
#include <vector>
#include <cstdint>
// 数据类型枚举
enum class EcDataType : uint8_t {
Boolean = 0x01,
Int8 = 0x02,
Int16 = 0x03,
Int32 = 0x04,
Uint8 = 0x05,
Uint16 = 0x06,
Uint32 = 0x07,
Real32 = 0x08,
Real64 = 0x09
};
// 从站状态枚举
enum class EcState : uint8_t {
Init = 0x01,
PreOp = 0x02,
SafeOp = 0x04,
Operational = 0x08
};
// 操作模式枚举
enum class EcOperateMode : int8_t {
ProfilePosition = 1,
Velocity = 2,
ProfileVelocity = 3,
ProfileTorque = 4,
Homing = 6,
CyclicSyncPosition = 8,
CyclicSyncVelocity = 9,
CyclicSyncTorque = 10
};
// PDO 条目
struct EcPdoEntry {
uint16_t index = 0;
uint8_t subindex = 0;
uint8_t bitlen = 0;
std::string name;
EcDataType dataType = EcDataType::Uint8;
uint32_t makeMapValue() const {
return ((uint32_t)index << 16) | ((uint32_t)subindex << 8) | bitlen;
}
};
// PDO
struct EcPdo {
uint16_t index = 0;
uint8_t mapCount = 0;
std::vector<EcPdoEntry> entries;
std::string name;
bool isRxPdo = false;
void updateMapCount() {
mapCount = entries.size();
}
};
// 模块信息
struct EcModule {
uint32_t moduleIdent = 0;
std::string name;
std::vector<EcPdo> rxPdos;
std::vector<EcPdo> txPdos;
};
// 从站配置信息
struct EcSlaveConfig {
uint16_t slaveId = 0;
uint32_t productCode = 0;
uint32_t revisionNo = 0;
std::string name;
std::vector<EcModule> modules;
std::vector<uint16_t> availableRxPdos;
std::vector<uint16_t> availableTxPdos;
};
// PDO 偏移映射
// ec_types.h 或 ec_master.h 中
struct EcPdoOffsets {
// RxPDO 偏移量 (主站 -> 从站)
uint16_t controlWord = 0xFFFF; // 0x6040
uint16_t targetPosition = 0xFFFF; // 0x607A
uint16_t targetVelocity = 0xFFFF; // 0x60FF
uint16_t targetTorque = 0xFFFF; // 0x6071
uint16_t profileAcceleration = 0xFFFF; // 0x6083 (PP模式)
uint16_t profileDeceleration = 0xFFFF; // 0x6084 (PP模式)
uint16_t profileVelocity = 0xFFFF; // 0x6081 (PP模式)
uint16_t torqueSlope = 0xFFFF; // 0x6087 (PT模式)
uint16_t modeOfOperation = 0xFFFF; // 0x6060
// TxPDO 偏移量 (从站 -> 主站)
uint16_t statusWord = 0xFFFF; // 0x6041
uint16_t actualPosition = 0xFFFF; // 0x6064
uint16_t actualVelocity = 0xFFFF; // 0x606C
uint16_t actualTorque = 0xFFFF; // 0x6077
uint16_t modeOfOperationDisplay = 0xFFFF;// 0x6061
uint16_t errorCode = 0xFFFF; // 0x603F
uint16_t actualCurrent = 0xFFFF; // 0x6078 当前电流值
};
#endif // EC_TYPES_H

View File

@ -1,317 +0,0 @@
// ec_xml_parser.cpp
#include "ec_xml_parser.h"
#include "rapidxml/xml_parser.h"
#include <cstdlib>
#include <cstdio>
#include <map>
using namespace rapidxml;
static EcDataType stringToDataType(const std::string& typeName) {
if (typeName == "BOOL") return EcDataType::Boolean;
if (typeName == "SINT") return EcDataType::Int8;
if (typeName == "INT") return EcDataType::Int16;
if (typeName == "DINT") return EcDataType::Int32;
if (typeName == "USINT") return EcDataType::Uint8;
if (typeName == "UINT") return EcDataType::Uint16;
if (typeName == "UDINT") return EcDataType::Uint32;
if (typeName == "REAL") return EcDataType::Real32;
return EcDataType::Uint8;
}
static uint32_t parseHexValue(const std::string& str) {
if (str.empty()) return 0;
if (str[0] == '#' && str[1] == 'x') {
return strtoul(str.c_str() + 2, nullptr, 16);
}
return strtoul(str.c_str(), nullptr, 16);
}
class EcXmlParser::Impl {
public:
std::map<uint16_t, EcSlaveConfig> slaveConfigs;
std::unique_ptr<XmlNode> xmlDoc;
bool loadXmlFile(const std::string& path) {
try {
xmlDoc = std::make_unique<XmlNode>(path);
return true;
} catch (const std::exception& e) {
printf("Failed to load XML file: %s, error: %s\n", path.c_str(), e.what());
return false;
}
}
void parsePdoEntry(const XmlNode& entryNode, EcPdoEntry& entry) {
if (entryNode.hasChild("Index")) {
XmlNode idxNode = entryNode.getChild("Index");
entry.index = (uint16_t)parseHexValue(idxNode.getNodeValue());
}
if (entryNode.hasChild("SubIndex")) {
XmlNode subIdxNode = entryNode.getChild("SubIndex");
entry.subindex = (uint8_t)atoi(subIdxNode.getNodeValue().c_str());
}
if (entryNode.hasChild("BitLen")) {
XmlNode bitLenNode = entryNode.getChild("BitLen");
entry.bitlen = (uint8_t)atoi(bitLenNode.getNodeValue().c_str());
}
if (entryNode.hasChild("Name")) {
XmlNode nameEntryNode = entryNode.getChild("Name");
entry.name = nameEntryNode.getNodeValue();
}
if (entryNode.hasChild("DataType")) {
XmlNode dataTypeNode = entryNode.getChild("DataType");
entry.dataType = stringToDataType(dataTypeNode.getNodeValue());
}
}
void parsePdoMapping(const XmlNode& pdoNode, bool isRxPdo, EcModule& module) {
if (!pdoNode.hasChild("Index")) {
printf("Warning: PDO missing Index node, skipping\n");
return;
}
XmlNode indexNode = pdoNode.getChild("Index");
uint16_t index = (uint16_t)parseHexValue(indexNode.getNodeValue());
EcPdo pdo;
pdo.index = index;
pdo.isRxPdo = isRxPdo;
if (pdoNode.hasChild("Name")) {
XmlNode nameNode = pdoNode.getChild("Name");
pdo.name = nameNode.getNodeValue();
}
std::vector<XmlNode> entries = pdoNode.getChildren("Entry");
for (const auto& entryNode : entries) {
EcPdoEntry entry;
parsePdoEntry(entryNode, entry);
pdo.entries.push_back(entry);
}
pdo.updateMapCount();
if (isRxPdo) {
module.rxPdos.push_back(pdo);
} else {
module.txPdos.push_back(pdo);
}
}
void parseModule(const XmlNode& moduleNode, EcSlaveConfig& config) {
if (!moduleNode.hasChild("Type")) {
printf("Warning: Module missing Type node, skipping\n");
return;
}
auto typeNode = moduleNode.getChild("Type");
std::string moduleIdentStr = typeNode.getAttrDefault("ModuleIdent", "");
if (moduleIdentStr.empty()) {
printf("Warning: Module missing ModuleIdent attribute, skipping\n");
return;
}
EcModule module;
module.moduleIdent = (uint32_t)parseHexValue(moduleIdentStr);
if (moduleNode.hasChild("Name")) {
XmlNode nameNode = moduleNode.getChild("Name");
module.name = nameNode.getNodeValue();
}
if (moduleNode.hasChild("RxPdo")) {
auto rxPdoNode = moduleNode.getChild("RxPdo");
parsePdoMapping(rxPdoNode, true, module);
}
if (moduleNode.hasChild("TxPdo")) {
auto txPdoNode = moduleNode.getChild("TxPdo");
parsePdoMapping(txPdoNode, false, module);
}
config.modules.push_back(module);
for (const auto& pdo : module.rxPdos) {
config.availableRxPdos.push_back(pdo.index);
}
for (const auto& pdo : module.txPdos) {
config.availableTxPdos.push_back(pdo.index);
}
printf(" Parsed module: 0x%08X - %s\n", module.moduleIdent, module.name.c_str());
printf(" RxPDOs: %zu, TxPDOs: %zu\n", module.rxPdos.size(), module.txPdos.size());
}
bool parseSlaveConfigById(uint16_t slaveId, EcSlaveConfig& outConfig) {
if (!xmlDoc) return false;
XmlNode rootNode = xmlDoc->getRoot();
if (rootNode.getNodeName() != "EtherCATInfo") {
printf("Root node is not EtherCATInfo\n");
return false;
}
if (!rootNode.hasChild("Descriptions")) {
printf("No Descriptions node found\n");
return false;
}
XmlNode descNode = rootNode.getChild("Descriptions");
outConfig = EcSlaveConfig();
outConfig.slaveId = slaveId;
if (descNode.hasChild("Devices")) {
XmlNode devicesNode = descNode.getChild("Devices");
if (devicesNode.hasChild("Device")) {
XmlNode deviceNode = devicesNode.getChild("Device");
if (deviceNode.hasChild("Type")) {
XmlNode typeNode = deviceNode.getChild("Type");
std::string productCode = typeNode.getAttrDefault("ProductCode", "");
if (!productCode.empty()) {
outConfig.productCode = (uint32_t)parseHexValue(productCode);
}
std::string revision = typeNode.getAttrDefault("RevisionNo", "");
if (!revision.empty()) {
outConfig.revisionNo = (uint32_t)atoi(revision.c_str());
}
}
if (deviceNode.hasChild("Name")) {
XmlNode nameNode = deviceNode.getChild("Name");
outConfig.name = nameNode.getNodeValue();
}
}
}
if (!descNode.hasChild("Modules")) {
printf("Warning: No Modules node found under Descriptions\n");
return !outConfig.modules.empty();
}
XmlNode modulesNode = descNode.getChild("Modules");
printf("Found Modules node under Descriptions, parsing PDO configurations...\n");
std::vector<XmlNode> moduleNodes = modulesNode.getChildren("Module");
if (moduleNodes.empty()) {
printf("Warning: No Module element found under Modules\n");
return !outConfig.modules.empty();
}
for (const auto& moduleNode : moduleNodes) {
parseModule(moduleNode, outConfig);
}
printf("Total %zu modules parsed\n", moduleNodes.size());
return true;
}
};
// ==================== EcXmlParser 公共接口 ====================
EcXmlParser::EcXmlParser() : pImpl(std::make_unique<Impl>()) {}
EcXmlParser::~EcXmlParser() = default;
bool EcXmlParser::loadXmlFile(const std::string& xmlPath) {
return pImpl->loadXmlFile(xmlPath);
}
bool EcXmlParser::parseSlaveConfig(uint16_t slaveId, EcSlaveConfig& outConfig) {
if (!pImpl->parseSlaveConfigById(slaveId, outConfig)) {
return false;
}
pImpl->slaveConfigs[slaveId] = outConfig;
return true;
}
EcSlaveConfig* EcXmlParser::getSlaveConfig(uint16_t slaveId) {
auto it = pImpl->slaveConfigs.find(slaveId);
return (it != pImpl->slaveConfigs.end()) ? &it->second : nullptr;
}
const EcSlaveConfig* EcXmlParser::getSlaveConfig(uint16_t slaveId) const {
auto it = pImpl->slaveConfigs.find(slaveId);
return (it != pImpl->slaveConfigs.end()) ? &it->second : nullptr;
}
std::vector<uint16_t> EcXmlParser::getAvailableRxPdos(uint16_t slaveId) const {
auto it = pImpl->slaveConfigs.find(slaveId);
return (it != pImpl->slaveConfigs.end()) ? it->second.availableRxPdos : std::vector<uint16_t>();
}
std::vector<uint16_t> EcXmlParser::getAvailableTxPdos(uint16_t slaveId) const {
auto it = pImpl->slaveConfigs.find(slaveId);
return (it != pImpl->slaveConfigs.end()) ? it->second.availableTxPdos : std::vector<uint16_t>();
}
const EcPdo* EcXmlParser::findPdo(uint16_t slaveId, uint16_t pdoIndex, bool isRxPdo) const {
auto it = pImpl->slaveConfigs.find(slaveId);
if (it == pImpl->slaveConfigs.end()) return nullptr;
for (const auto& module : it->second.modules) {
const auto& pdos = isRxPdo ? module.rxPdos : module.txPdos;
for (const auto& pdo : pdos) {
if (pdo.index == pdoIndex) return &pdo;
}
}
return nullptr;
}
const EcModule* EcXmlParser::findModuleByIndex(uint16_t slaveId, uint16_t pdoIndex, bool isRxPdo) const {
auto it = pImpl->slaveConfigs.find(slaveId);
if (it == pImpl->slaveConfigs.end()) return nullptr;
for (const auto& module : it->second.modules) {
const auto& pdos = isRxPdo ? module.rxPdos : module.txPdos;
for (const auto& pdo : pdos) {
if (pdo.index == pdoIndex) return &module;
}
}
return nullptr;
}
const EcModule* EcXmlParser::findModuleByIdent(uint16_t slaveId, uint32_t moduleIdent) const {
auto it = pImpl->slaveConfigs.find(slaveId);
if (it == pImpl->slaveConfigs.end()) return nullptr;
for (const auto& module : it->second.modules) {
if (module.moduleIdent == moduleIdent) return &module;
}
return nullptr;
}
void EcXmlParser::printSlaveInfo(uint16_t slaveId) const {
auto it = pImpl->slaveConfigs.find(slaveId);
if (it == pImpl->slaveConfigs.end()) {
printf("Slave %d not configured\n", slaveId);
return;
}
const EcSlaveConfig& config = it->second;
printf("\n========== Slave %d Configuration ==========\n", slaveId);
printf("Name: %s\n", config.name.c_str());
printf("Product Code: 0x%08X\n", config.productCode);
printf("Revision: %u\n", config.revisionNo);
for (const auto& module : config.modules) {
printf("\n[Module 0x%08X] %s\n", module.moduleIdent, module.name.c_str());
for (const auto& pdo : module.rxPdos) {
printf(" RxPDO 0x%04X - %s (%d entries)\n", pdo.index, pdo.name.c_str(), pdo.mapCount);
for (const auto& entry : pdo.entries) {
printf(" -> 0x%04X:%02X (%d bits) - %s\n",
entry.index, entry.subindex, entry.bitlen, entry.name.c_str());
}
}
for (const auto& pdo : module.txPdos) {
printf(" TxPDO 0x%04X - %s (%d entries)\n", pdo.index, pdo.name.c_str(), pdo.mapCount);
for (const auto& entry : pdo.entries) {
printf(" <- 0x%04X:%02X (%d bits) - %s\n",
entry.index, entry.subindex, entry.bitlen, entry.name.c_str());
}
}
}
printf("==========================================\n");
}
void EcXmlParser::clear() {
pImpl->slaveConfigs.clear();
}

View File

@ -1,41 +0,0 @@
// ec_xml_parser.h
#ifndef EC_XML_PARSER_H
#define EC_XML_PARSER_H
#include "ec_types.h"
#include <memory>
#include <vector>
#include <cstdint>
// XML PDO配置解析器类仅负责解析XML
class EcXmlParser {
public:
EcXmlParser();
~EcXmlParser();
bool loadXmlFile(const std::string& xmlPath);
bool parseSlaveConfig(uint16_t slaveId, EcSlaveConfig& outConfig);
// 获取已解析的配置
EcSlaveConfig* getSlaveConfig(uint16_t slaveId);
const EcSlaveConfig* getSlaveConfig(uint16_t slaveId) const;
// 查询接口
std::vector<uint16_t> getAvailableRxPdos(uint16_t slaveId) const;
std::vector<uint16_t> getAvailableTxPdos(uint16_t slaveId) const;
const EcPdo* findPdo(uint16_t slaveId, uint16_t pdoIndex, bool isRxPdo) const;
const EcModule* findModuleByIndex(uint16_t slaveId, uint16_t pdoIndex, bool isRxPdo) const;
const EcModule* findModuleByIdent(uint16_t slaveId, uint32_t moduleIdent) const;
// 打印信息
void printSlaveInfo(uint16_t slaveId) const;
// 清空所有配置
void clear();
private:
class Impl;
std::unique_ptr<Impl> pImpl;
};
#endif // EC_XML_PARSER_H

View File

@ -1,5 +0,0 @@
//
// Created by cmvr on 2026/3/30.
//
#include "eyou_motor.h"

View File

@ -1,46 +0,0 @@
//
// Created by cmvr on 2026/3/30.
//
#pragma once
#include "../abstract_motor.h"
#include "motor/motor_protocol_interface.h"
#include "motor/eyou_motor/ethercat/eyou_motor_ethercat_protocol.h"
namespace cmvr {
namespace device {
class EYouMotor : public AbstractMotor {
public:
EYouMotor(const XmlNode &config,uint8_t node_id):AbstractMotor(config,node_id){}
EYouMotor(const XmlNode &config):AbstractMotor(config) {
info_.id = config.getAttrDefault("slave", -1);
info_.joint_name = config.getAttrString("jointName");
info_.limitQ = config.getAttrDefault("limitQ", 3.14f);
info_.limitQd = config.getAttrDefault("limitQd", 0.5f);
node_id_ = info_.id;
}
EYouMotor(const cmvr::config::EthercatMotorConfig& config) : AbstractMotor() {
info_.id = config.slave();
info_.joint_name = config.jointname();
info_.limitQ = config.limitqlb();
info_.limitQd = config.limitqd();
node_id_ = info_.id;
}
/**
*
*/
void init() override {
if (!protocol_) {
throw std::runtime_error("Protocol not set for motor");
}
if (protocol_->comm_proto == MotorProtocolInterface::CommProto::ETHERCAT ) {
auto ethercat_protocol = std::dynamic_pointer_cast<EYouEthercatProtocol>(protocol_);
ethercat_protocol->initNode(node_id_);
ethercat_protocol->setQdd(node_id_,1);
}
}
};
}
}

View File

@ -15,8 +15,7 @@ namespace cmvr {
public:
enum class CommProto : uint8_t {
CANOPEN = 1,
ETHERCAT = 2,
CUSTOM = 3
CUSTOM = 2
};
virtual ~MotorProtocolInterface() = default;

View File

@ -1,12 +1,11 @@
//
// Created by lgv on 2025/8/1.
//
#pragma once
#include "../abstract_motor.h"
#include "motor/motor_protocol_interface.h"
#include "motor/ti5_motor/canopen/ti5_motor_canopen_protocol.h"
#include "cmvr/config/robot_config/robot_config.pb.h"
/**
* class: Ti5Motor protocol
*/
@ -23,15 +22,6 @@ namespace cmvr {
node_id_ = info_.id;
}
Ti5Motor(const cmvr::config::MotorConfig& config) : AbstractMotor() {
info_.id = config.id();
info_.joint_name = config.jointname();
info_.limitQ = config.limitqlb();
info_.limitQd = config.limitqd();
node_id_ = info_.id;
}
/**
*
*/

View File

@ -41,7 +41,6 @@ namespace cmvr::device{
class AbstractRobot: public AbstractDevice {
public:
AbstractRobot() = default;
explicit AbstractRobot(const XmlNode &config): AbstractDevice(config) {}
~AbstractRobot() override=default;

View File

@ -35,8 +35,6 @@
#include "planner/joint_space_planner/include/joint_space_planner_creator.h"
#include "planner/joint_space_planner/include/joint_space_planner.h"
#include "ik_solver/include/pinocchio_dls_ik_solver.h"
#include "cmvr/config/robot_config/robot_config.pb.h"
namespace cmvr::device{
@ -51,10 +49,12 @@ namespace cmvr::device{
ROBOT_ERROR
} RobotStateMachine;
// typedef enum {
// PPM_MODE, PVM_MODE, PTM_MODE, CSP_MODE, CSV_MODE, CSC_MODE
// } RobotRunningMode;
public:
explicit HumanoidRobot(const XmlNode& cfg);
HumanoidRobot(const cmvr::config::HumanRobotConfig& config);
HumanoidRobot(const cmvr::config::EthercatRobotConfig& config);
~HumanoidRobot();
void init() override;
@ -232,7 +232,6 @@ namespace cmvr::device{
std::atomic<bool> is_head_busy_{false}, is_waist_busy_{false};
std::string urdf_path_ = "";
};

View File

@ -49,87 +49,6 @@ HumanoidRobot<DOF>::HumanoidRobot(const XmlNode &cfg) : AbstractRobot(cfg) {
}
}
template<int DOF>
HumanoidRobot<DOF>::HumanoidRobot(const cmvr::config::HumanRobotConfig& config) {
try {
id_ = config.id();
urdf_path_ = config.urdf();
dof_ = DOF;
if (!pathExists(config.urdf())) {
throw runtime_error("urdf file does not exist");
}
auto rcfg = cmvr::dyn::LoadRobotFromURDF(
config.urdf(), config.baselink());
m_robot_ = std::make_shared<cmvr::dyn::Robot<DOF> >(rcfg);
// 解析jointNames字符串按逗号分隔
joint_names_ = splitString(config.jointnames(), ",");
// 解析linkNames字符串按逗号分隔
link_names_ = splitString(config.linknames(), ",");
if (joint_names_.size() != dof_) {
throw runtime_error("joint names size mismatched with dof");
}
m_state_ = m_robot_->MakeState(link_names_, joint_names_);
m_cctrl_ = make_shared<ctrl::CartesianController<DOF> >(m_robot_);
upd_freq_ = config.updfreq();
CSP_buffer_ = make_shared<SPMCRingBuffer<JointPoint> >(config.buffersize());
CSV_buffer_ = make_shared<SPMCRingBuffer<JointVelocityCommand> >(config.buffersize());
CSC_buffer_ = make_shared<SPMCRingBuffer<JointCurrentCommand> >(config.buffersize());
upd_freq_ = 1000;
upd_timer_ = make_shared<FDTimer>();
upd_timer_->start(chrono::nanoseconds(1000 / upd_freq_ * 1000),
[this] { update_state_(); });
rsm_.store(ROBOT_READY);
} catch (exception &e) {
LOG(ERROR) << "HumanoidRobot init failed, id=" << id_;
throw runtime_error(e.what());
}
}
template<int DOF>
HumanoidRobot<DOF>::HumanoidRobot(const cmvr::config::EthercatRobotConfig& config) {
try {
id_ = config.id();
urdf_path_ = config.urdf();
dof_ = DOF;
if (!pathExists(config.urdf())) {
throw runtime_error("urdf file does not exist");
}
auto rcfg = cmvr::dyn::LoadRobotFromURDF(
config.urdf(), config.baselink());
m_robot_ = std::make_shared<cmvr::dyn::Robot<DOF> >(rcfg);
// 解析jointNames字符串按逗号分隔
joint_names_ = splitString(config.jointnames(), ",");
// 解析linkNames字符串按逗号分隔
link_names_ = splitString(config.linknames(), ",");
if (joint_names_.size() != dof_) {
throw runtime_error("joint names size mismatched with dof");
}
m_state_ = m_robot_->MakeState(link_names_, joint_names_);
m_cctrl_ = make_shared<ctrl::CartesianController<DOF> >(m_robot_);
upd_freq_ = config.updfreq();
CSP_buffer_ = make_shared<SPMCRingBuffer<JointPoint> >(config.buffersize());
CSV_buffer_ = make_shared<SPMCRingBuffer<JointVelocityCommand> >(config.buffersize());
CSC_buffer_ = make_shared<SPMCRingBuffer<JointCurrentCommand> >(config.buffersize());
upd_freq_ = 1000;
upd_timer_ = make_shared<FDTimer>();
upd_timer_->start(chrono::nanoseconds(1000 / upd_freq_ * 1000),
[this] { update_state_(); });
rsm_.store(ROBOT_READY);
} catch (exception &e) {
LOG(ERROR) << "HumanoidRobot init failed, id=" << id_;
throw runtime_error(e.what());
}
}
template<int DOF>
void HumanoidRobot<DOF>::init() {
motor_manager_ = MotorsInfo::getInstance()->getMotorManager();
@ -140,7 +59,7 @@ void HumanoidRobot<DOF>::init() {
std::vector<double>(7, 1.0));
ik_solver_ = std::make_shared<PinocchioDlsIKSolver>("/home/cmvr/Projects/cmvr-es/model/xiaoyan_description/dual_arm.urdf",
ik_solver_ = std::make_shared<PinocchioDlsIKSolver>("/home/lgv/cmvr/cmvr-es/model/xiaoyan_description/dual_arm.urdf",
"PELVIS_S",
"R_WRIST_R_S",
"R_FINGER_TIP_FIXED");

View File

@ -990,21 +990,3 @@ TEST(HumanoidRobotTest,IBVSWithRealRobotTrackedPoint) {
EXPECT_GT(ok_steps, 0) << "No successful tracked-point IBVS control steps.";
}
TEST(HumanoidRobotTest, EYouTest) {
auto& dmgr = DeviceManager::getInstance();
auto robot_abs = dmgr.getDevice<AbstractRobot>("ec_robot_01");
auto robot = std::dynamic_pointer_cast<HumanoidRobot<14>>(robot_abs);
ASSERT_NE(robot, nullptr) << "hc01 is not HumanoidRobot<14>";
std::vector<JointPoint> init_cmd = {
{"L_SHOULDER_P", 0.1}
};
// robot->moveJ(init_cmd, 0.1, 1.0);
// robot->calibrateZeroQ("L_SHOULDER_P");
robot->torqueOff("L_SHOULDER_P");
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}

View File

@ -9,7 +9,6 @@
#include <glog/logging.h>
#include "service/grpc/include/server_runner.h"
#include "utils/base/include/logger.h"
using namespace cmvr::service;
int main(int argc, char* argv[]) {
std::string config_path;

View File

@ -13,7 +13,6 @@
namespace cmvr::monitor{
class AbstractMonitor {
public:
AbstractMonitor() = default;
explicit AbstractMonitor(const XmlNode &cfg){
cfg_ = cfg;
freq_ = cfg_.getAttrDefault("freq", 1);

View File

@ -8,21 +8,17 @@
#include <condition_variable>
#include "../../abstract_monitor.h"
#include "cmvr/config/monitor_config/monitor_config.pb.h"
namespace cmvr::monitor {
class DiskMonitor final : public AbstractMonitor{
public:
explicit DiskMonitor(const XmlNode& config);
explicit DiskMonitor(const cmvr::config::DiskMonitorConfig& config); // 新增proto构造函数
~DiskMonitor();
protected:
bool check_() override;
bool execution_() override;
private:
void initFromProto(const cmvr::config::DiskMonitorConfig& config); // 新增初始化方法
std::unordered_map<std::string,int> folders_;
std::vector<std::string> dirsToClean_; // 需要清理的目录列表
mutable std::mutex mutex_; // 保护共享资源的互斥锁
@ -31,4 +27,6 @@ namespace cmvr::monitor {
};
}
#endif //FOLDER_MONITOR_H

View File

@ -14,6 +14,7 @@ using namespace cmvr::monitor;
namespace fs = std::filesystem;
using namespace std::chrono;
// 文件信息结构体
struct FileInfo {
std::string path;
@ -37,40 +38,51 @@ bool deleteOldestFile(const std::string& directoryPath) {
struct dirent* entry;
struct stat fileStat;
// 遍历目录中的每个条目
while ((entry = readdir(dir)) != nullptr) {
// 跳过 "." 和 ".."
if (std::string(entry->d_name) == "." || std::string(entry->d_name) == "..") {
continue;
}
// 构建完整路径
std::string filePath = directoryPath + "/" + entry->d_name;
// 获取文件状态信息
if (stat(filePath.c_str(), &fileStat) == -1) {
std::cerr << "Failed to get file status: " << filePath << std::endl;
continue;
}
// 只处理普通文件
if (S_ISREG(fileStat.st_mode)) {
FileInfo fileInfo;
fileInfo.path = filePath;
// 优先使用 st_birthtime (如果可用),否则使用 st_ctime
#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
fileInfo.creationTime = fileStat.st_birthtime;
#else
fileInfo.creationTime = fileStat.st_ctime;
#endif
files.push_back(fileInfo);
}
}
closedir(dir);
// 如果没有找到文件,返回失败
if (files.empty()) {
std::cout << "No files found in directory: " << directoryPath << std::endl;
return false;
}
// 按创建时间排序
std::sort(files.begin(), files.end(), compareByCreationTime);
std::string oldestFilePath = files[0].path;
// 删除最早创建的文件
std::string oldestFilePath = files[0].path;
if (unlink(oldestFilePath.c_str()) == -1) {
std::cerr << "Failed to delete file: " << oldestFilePath << std::endl;
return false;
@ -80,11 +92,11 @@ bool deleteOldestFile(const std::string& directoryPath) {
return true;
}
bool pathExists(const std::string& path) {
struct stat buffer;
return (stat(path.c_str(), &buffer) == 0);
}
int countFilesInDirectory(const std::string& path) {
DIR* dir = opendir(path.c_str());
if (!dir) {
@ -95,7 +107,9 @@ int countFilesInDirectory(const std::string& path) {
int count = 0;
struct dirent* entry;
// 遍历目录中的每个条目
while ((entry = readdir(dir)) != nullptr) {
// 跳过 "." 和 ".."
if (std::string(entry->d_name) != "." && std::string(entry->d_name) != "..") {
count++;
}
@ -105,8 +119,8 @@ int countFilesInDirectory(const std::string& path) {
return count;
}
// XML构造函数
DiskMonitor::DiskMonitor(const XmlNode& config) : AbstractMonitor(config){
try {
for (auto &node: config.getChildren()){
string fileDir = node.getAttrString("fileDir");
@ -124,42 +138,13 @@ DiskMonitor::DiskMonitor(const XmlNode& config) : AbstractMonitor(config){
throw runtime_error("[DiskMonitor] (DiskMonitor): Failed "+ string(e.what()));
}
}
// Proto构造函数
DiskMonitor::DiskMonitor(const cmvr::config::DiskMonitorConfig& config) : AbstractMonitor() {
try {
initFromProto(config);
is_initialized_ = true;
LOG(INFO) << "[DiskMonitor]: Init DiskMonitor from proto Success";
}
catch (const exception& e) {
LOG(ERROR) << "[DiskMonitor] (DiskMonitor): Failed " << e.what();
throw runtime_error("[DiskMonitor] (DiskMonitor): Failed " + string(e.what()));
}
}
// Proto初始化方法
void DiskMonitor::initFromProto(const cmvr::config::DiskMonitorConfig& config) {
// 设置监控ID和频率通过AbstractMonitor
// 假设AbstractMonitor有setId和setFreq方法如果没有需要添加
// 这里根据你的AbstractMonitor实现来调整
for (const auto& folder : config.folders()) {
string fileDir = folder.filedir();
if (!pathExists(fileDir)) {
throw runtime_error("[DiskMonitor] (initFromProto): path not exists: " + fileDir);
}
int maxVolume = folder.maxvolume();
folders_[fileDir] = maxVolume;
}
}
DiskMonitor::~DiskMonitor() {
folders_.clear();
}
bool DiskMonitor::check_() {
// 检查当前目录下的文件数量是否超过最大值
bool allOk = true;
// 遍历所有监控的文件夹
for (const auto& folder : folders_) {
const std::string& path = folder.first;
size_t maxFiles = folder.second;
@ -169,21 +154,28 @@ bool DiskMonitor::check_() {
continue;
}
int nFileCount = countFilesInDirectory(path);
if (nFileCount > maxFiles) {
if (nFileCount > maxFiles)
{
allOk = false;
dirsToClean_.push_back(path);
std::cout << "path need remove oldest file: " << path << std::endl;
}
} catch (const fs::filesystem_error& e) {
std::cerr << "Filesystem error: " << e.what() << '\n';
} catch (const std::exception& e) {
std::cerr << "Unexpected error: " << e.what() << '\n';
}
}
return allOk;
}
bool DiskMonitor::execution_() {
// 删除创建时间最早的文件
std::lock_guard<std::mutex> lock(mutex_);
bool success = true;
@ -191,6 +183,6 @@ bool DiskMonitor::execution_() {
deleteOldestFile(path);
}
dirsToClean_.clear();
dirsToClean_.clear(); // 清理完成后清空列表
return success;
}

View File

@ -5,8 +5,8 @@
#ifndef MONITOR_FACTORY_H
#define MONITOR_FACTORY_H
#include "monitor/abstract_monitor.h"
#include "cmvr/config/monitor_config/monitor_config.pb.h"
#include "../../monitor/abstract_monitor.h"
namespace cmvr::monitor
{
@ -14,17 +14,14 @@ namespace cmvr::monitor
{
public:
MonitorFactory() = default;
// 原有的XML方式
template <typename MonitorType>
std::shared_ptr<MonitorType> create(const XmlNode& cfg);
std::shared_ptr<AbstractMonitor> create(const XmlNode& cfg);
// 新增proto方式
template <typename MonitorType>
std::shared_ptr<MonitorType> create(const cmvr::config::DiskMonitorConfig& config);
std::shared_ptr<AbstractMonitor> create(const cmvr::config::DiskMonitorConfig& config);
};
}
#endif //MONITOR_FACTORY_H

View File

@ -15,38 +15,23 @@ namespace cmvr::monitor {
public:
MonitorManager(const MonitorManager&) = delete;
MonitorManager& operator=(const MonitorManager&) = delete;
// 原有的XML方式
static MonitorManager& getInstance(const XmlNode &cfg);
// 新增proto方式
static MonitorManager& getInstance(const cmvr::config::MonitorManagerConfig& config);
static MonitorManager& getInstance();
static void destroyInstance();
private:
// 原有的XML方式
explicit MonitorManager(const XmlNode &cfg);
// 新增proto方式
explicit MonitorManager(const cmvr::config::MonitorManagerConfig& config);
void init_monitors(); // XML方式
void init_monitors_from_proto(); // Proto方式
explicit MonitorManager (const XmlNode &cfg);
void init_monitors();
private:
static std::once_flag init_flag_;
static std::shared_ptr<MonitorManager> instance_;
// 两种配置方式,只有一个有效
bool use_proto_ = false;
XmlNode cfg_; // XML配置
cmvr::config::MonitorManagerConfig proto_cfg_; // Proto配置
XmlNode cfg_;
std::shared_ptr<MonitorFactory> monitor_factory_;
std::unordered_map<std::string, std::shared_ptr<AbstractMonitor>> monitors_;
};
}
#endif //MONITOR_MANAGER_H

View File

@ -3,12 +3,12 @@
//
#include "../include/monitor_factory.h"
#include "../../monitor/diskmonitor/include/disk_monitor.h"
using namespace std;
using namespace cmvr::monitor;
// XML方式的模板特化
template std::shared_ptr<DiskMonitor> MonitorFactory::create<DiskMonitor>(const XmlNode&);
template <typename MonitorType>
@ -17,30 +17,8 @@ std::shared_ptr<MonitorType> MonitorFactory::create(const XmlNode& cfg) {
return std::make_shared<DiskMonitor>(cfg);
}
else {
LOG(ERROR) << "[MonitorFactory]: Unsupported monitor type";
throw runtime_error("[MonitorFactory]: Unsupported monitor type");
LOG(ERROR) << "[DeviceFactory]: Unsupported device type";
throw runtime_error("[DeviceFactory]: Unsupported device type");
}
}
// Proto方式的模板特化
template std::shared_ptr<DiskMonitor> MonitorFactory::create<DiskMonitor>(const cmvr::config::DiskMonitorConfig&);
template <typename MonitorType>
std::shared_ptr<MonitorType> MonitorFactory::create(const cmvr::config::DiskMonitorConfig& config) {
if constexpr (std::is_same_v<MonitorType, DiskMonitor>) {
return std::make_shared<DiskMonitor>(config);
}
else {
LOG(ERROR) << "[MonitorFactory]: Unsupported monitor type";
throw runtime_error("[MonitorFactory]: Unsupported monitor type");
}
}
std::shared_ptr<AbstractMonitor> MonitorFactory::create(const XmlNode& cfg) {
// 保留原有实现
return nullptr;
}
std::shared_ptr<AbstractMonitor> MonitorFactory::create(const cmvr::config::DiskMonitorConfig& config) {
return std::make_shared<DiskMonitor>(config);
}

View File

@ -3,7 +3,8 @@
//
#include "../include/monitor_manager.h"
#include "monitor/diskmonitor/include/disk_monitor.h"
#include "../../monitor/diskmonitor/include/disk_monitor.h"
using namespace std;
using namespace cmvr::monitor;
@ -11,19 +12,11 @@ using namespace cmvr::monitor;
std::shared_ptr<MonitorManager> MonitorManager::instance_ = nullptr;
std::once_flag MonitorManager::init_flag_;
// XML方式构造函数
MonitorManager::MonitorManager(const XmlNode& cfg) : use_proto_(false), cfg_(cfg) {
MonitorManager::MonitorManager(const XmlNode& cfg) {
monitor_factory_ = make_shared<MonitorFactory>();
cfg_ = cfg;
init_monitors();
}
// Proto方式构造函数
MonitorManager::MonitorManager(const cmvr::config::MonitorManagerConfig& config) : use_proto_(true), proto_cfg_(config) {
monitor_factory_ = make_shared<MonitorFactory>();
init_monitors_from_proto();
}
// XML方式单例
MonitorManager& MonitorManager::getInstance(const XmlNode& cfg) {
std::call_once(init_flag_, [&cfg] {
instance_.reset(new MonitorManager(cfg));
@ -31,17 +24,9 @@ MonitorManager& MonitorManager::getInstance(const XmlNode& cfg) {
return *instance_;
}
// Proto方式单例
MonitorManager& MonitorManager::getInstance(const cmvr::config::MonitorManagerConfig& config) {
std::call_once(init_flag_, [&config] {
instance_.reset(new MonitorManager(config));
});
return *instance_;
}
MonitorManager& MonitorManager::getInstance() {
if (!instance_) {
throw std::runtime_error("[MonitorManager] (getInstance): MonitorManager not initialized. Call getInstance() first.");
throw std::runtime_error("[MonitorManager] (getInstance): MonitorManager not initialized. Call getInstance(const XmlNode&) first.");
}
return *instance_;
}
@ -50,41 +35,13 @@ void MonitorManager::destroyInstance() {
instance_.reset();
}
// XML方式初始化
void MonitorManager::init_monitors() {
try {
try{
auto diskmonitor_node = cfg_.getChild("DiskMonitor");
auto id = diskmonitor_node.getAttrString("id");
auto monitor = monitor_factory_->create<DiskMonitor>(diskmonitor_node);
if (monitor == nullptr) {
throw std::runtime_error("[MonitorManager]: Factory returned nullptr for monitor ID: " + id);
}
monitors_[id] = monitor;
}
catch (const exception& e) {
LOG(ERROR) << e.what();
throw runtime_error(e.what());
}
}
// Proto方式初始化
void MonitorManager::init_monitors_from_proto() {
try {
if (!proto_cfg_.has_disk_monitor()) {
LOG(WARNING) << "[MonitorManager]: No disk_monitor config found";
return;
}
const auto& disk_monitor_cfg = proto_cfg_.disk_monitor();
if (!disk_monitor_cfg.enable()) {
LOG(INFO) << "[MonitorManager]: Disk monitor is disabled";
return;
}
auto id = disk_monitor_cfg.id();
auto monitor = monitor_factory_->create<DiskMonitor>(disk_monitor_cfg);
if (monitor == nullptr) {
throw std::runtime_error("[MonitorManager]: Factory returned nullptr for monitor ID: " + id);
throw std::runtime_error("[DeviceManager]: Factory returned nullptr for device ID: " + id);
}
monitors_[id] = monitor;
}
@ -92,4 +49,5 @@ void MonitorManager::init_monitors_from_proto() {
LOG(ERROR) << e.what();
throw runtime_error(e.what());
}
}

View File

@ -9,7 +9,6 @@ add_library(service
grpc/src/grpc_humanoid_robot_service.cpp
grpc/src/grpc_hlc_service.cpp
grpc/src/server_runner.cpp
grpc/src/grpc_agv_service.cpp
)
target_include_directories(service PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

View File

@ -1,278 +0,0 @@
//
// Created by xtkuang on 2025/6/1.
//
/**
* @file grpc_agv_service.h
* @brief gRPC AGV
* api::AgvService::Service AGV RPC
* DeviceManager AGV AgvSrc1100
* @author xtkuang
* @date 2025-06-01
*/
#ifndef GRPC_AGV_SERVICE_H
#define GRPC_AGV_SERVICE_H
#include "cmvr/api/agv_service.grpc.pb.h"
#include "utils/base/include/grpc_utils.h"
#include "device_manager/include/device_manager.h"
namespace cmvr::service {
/**
* @brief gRPC AGV
* gRPC AGV
*/
class gRPCAGVServiceImpl final : public api::AgvService::Service {
public:
/**
* @brief DeviceManager
*/
gRPCAGVServiceImpl();
/**
* @brief
*/
~gRPCAGVServiceImpl() override = default;
// ===================== 基本状态查询接口 =====================
/**
* @brief AGV 1000
* @param context gRPC 使
* @param request IDheader.device_id
* @param response AGV IPMAC
* @return grpc::Status::OK response.header
*/
grpc::Status GetStatusInfo(grpc::ServerContext* context,
const api::GetAgvStatusInfoCommand_Request* request,
api::GetAgvStatusInfoCommand_Feedback* response) override;
/**
* @brief 1007
* @param context gRPC 使
* @param request ID simple
* @param response
* @return grpc::Status::OK response.header
*/
grpc::Status GetBatteryStatus(grpc::ServerContext* context,
const api::RobotStatusBatteryCommand_Request* request,
api::RobotStatusBatteryCommand_Feedback* response) override;
/**
* @brief 1004
* @param context gRPC 使
* @param request ID
* @param response
* @return grpc::Status::OK response.header
*/
grpc::Status GetRobotLocation(grpc::ServerContext* context,
const api::RobotStatusLocCommand_Request* request,
api::RobotStatusLocCommand_Feedback* response) override;
// ===================== 地图管理接口 =====================
/**
* @brief 4011
* @param context gRPC 使
* @param request ID
* @param response JSON
* @return grpc::Status::OK response.header
*/
grpc::Status RobotConfigDownloadMap(grpc::ServerContext* context,
const api::RobotConfigDownloadMapCommand_Request* request,
api::RobotConfigDownloadMapCommand_Feedback* response) override;
/**
* @brief 1300
* @param context gRPC 使
* @param request ID
* @param response
* @return grpc::Status::OK response.header
*/
grpc::Status GetMapStatus(grpc::ServerContext* context,
const api::RobotStatusMapCommand_Request* request,
api::RobotStatusMapCommand_Feedback* response) override;
/**
* @brief 4010
* @param context gRPC 使
* @param request ID JSON
* @param response ret_code
* @return grpc::Status::OK response.header
*/
grpc::Status RobotConfigUploadMap(grpc::ServerContext* context,
const api::RobotConfigUploadMapCommand_Request* request,
api::RobotConfigUploadMapCommand_Feedback* response) override;
// ===================== 控制权管理接口 =====================
/**
* @brief 4005
* @param context gRPC 使
* @param request ID
* @param response ret_code
* @return grpc::Status::OK response.header
*/
grpc::Status RobotConfigLock(grpc::ServerContext* context,
const api::RobotConfigLockCommand_Request* request,
api::RobotConfigLockCommand_Feedback* response) override;
/**
* @brief 1060
* @param context gRPC 使
* @param request ID
* @param response IP//
* @return grpc::Status::OK response.header
*/
grpc::Status GetCurrentLockStatus(grpc::ServerContext* context,
const api::RobotStatusCurrentLockCommand_Request* request,
api::RobotStatusCurrentLockCommand_Feedback* response) override;
// ===================== 运动控制接口 =====================
/**
* @brief 2010
* @param context gRPC 使
* @param request ID vx, vy, w, steer, duration
* @param response ret_code
* @note vx/vy/w
* @return grpc::Status::OK response.header
*/
grpc::Status RobotMotionControl(grpc::ServerContext* context,
const api::RobotMotionControlCommand_Request* request,
api::RobotMotionControlCommand_Feedback* response) override;
/**
* @brief 2022
* @param context gRPC 使
* @param request ID
* @param response ret_code
* @return grpc::Status::OK response.header
*/
grpc::Status RobotLoadMap(grpc::ServerContext* context,
const api::RobotLoadMapCommand_Request* request,
api::RobotLoadMapCommand_Feedback* response) override;
/**
* @brief 2000
* @param context gRPC 使
* @param request ID
* @param response ret_code
* @return grpc::Status::OK response.header
*/
grpc::Status RobotControlStop(grpc::ServerContext* context,
const api::RobotControlStopCommand::Request* request,
api::RobotControlStopCommand::Feedback* response) override;
// ===================== 导航任务接口 =====================
/**
* @brief 1022
* @param context gRPC 使
* @param request ID
* @param response loadmap_status0=, 1=, 2=
* @return grpc::Status::OK response.header
*/
grpc::Status QueryLoadMapStatus(grpc::ServerContext* context,
const api::RobotQueryLoadMapStatusCommand_Request* request,
api::RobotQueryLoadMapStatusCommand_Feedback* response) override;
/**
* @brief 1301
* @param context gRPC 使
* @param request ID
* @param response ID
* @return grpc::Status::OK response.header
*/
grpc::Status QueryStationList(grpc::ServerContext* context,
const api::QueryStationListCommand_Request* request,
api::QueryStationListCommand_Feedback* response) override;
/**
* @brief 3066
* @param context gRPC 使
* @param request ID move_task_list
* @param response ret_code=0
* @attention task_id, source_id, id
*
* @return grpc::Status::OK response.header
*/
grpc::Status RobotGoTargetList(grpc::ServerContext* context,
const api::RobotGoTargetListCommand_Request* request,
api::RobotGoTargetListCommand_Feedback* response) override;
/**
* @brief 1020
* @param context gRPC 使
* @param request ID simple
* @param response
* @return grpc::Status::OK response.header
*/
grpc::Status RobotStatusTaskCurrent(grpc::ServerContext* context,
const api::RobotStatusTaskCurrentCommand_Request* request,
api::RobotStatusTaskCurrentCommand_Feedback* response) override;
/**
* @brief 1110
* @param context gRPC 使
* @param request ID task_ids +
* @param response
* @return grpc::Status::OK response.header
*/
grpc::Status RobotStatusTaskPackage(grpc::ServerContext* context,
const api::RobotStatusTaskPackageCommand_Request* request,
api::RobotStatusTaskPackageCommand_Feedback* response) override;
/**
* @brief 3051
* @param context gRPC 使
* @param request ID PGV
* @param response ret_code=0
* @warning
* @return grpc::Status::OK response.header
*/
grpc::Status RobotGoTarget(grpc::ServerContext* context,
const api::RobotGoTargetCommand_Request* request,
api::RobotGoTargetCommand_Feedback* response) override;
/**
* @brief 3001
* @param context gRPC 使
* @param request ID
* @param response ret_code
* @return grpc::Status::OK response.header
*/
grpc::Status RobotTaskPause(grpc::ServerContext* context,
const api::RobotTaskPauseCommand::Request* request,
api::RobotTaskPauseCommand::Feedback* response) override;
/**
* @brief 3002
* @param context gRPC 使
* @param request ID
* @param response ret_code
* @return grpc::Status::OK response.header
*/
grpc::Status RobotTaskResume(grpc::ServerContext* context,
const api::RobotTaskResumeCommand::Request* request,
api::RobotTaskResumeCommand::Feedback* response) override;
/**
* @brief 3003
* @param context gRPC 使
* @param request ID
* @param response ret_code
* @return grpc::Status::OK response.header
*/
grpc::Status RobotTaskCancel(grpc::ServerContext* context,
const api::RobotTaskCancelCommand::Request* request,
api::RobotTaskCancelCommand::Feedback* response) override;
private:
device::DeviceManager& dmgr_; ///< 设备管理器引用,用于根据 device_id 获取 AGV 设备实例。
};
} // namespace cmvr::service
#endif // GRPC_AGV_SERVICE_H

View File

@ -11,7 +11,6 @@
#include <thread>
#include <grpcpp/grpcpp.h>
#include "rapidxml/xml_parser.h"
#include "cmvr/config/server_config/server_config.pb.h"
namespace cmvr::service {
@ -42,7 +41,6 @@ namespace cmvr::service {
std::thread worker_;
XmlNode cfg_;
cmvr::config::ServerConfig servercfg_;
std::unique_ptr<grpc::Server> server_;
std::string address_;

File diff suppressed because it is too large Load Diff

View File

@ -17,7 +17,7 @@ using google::protobuf::util::TimeUtil;
gRPCHumanoidRobotServiceImpl::gRPCHumanoidRobotServiceImpl():dmgr_(DeviceManager::getInstance())
{
pinocchio_ik_ = std::make_shared<PinocchioQpIKSolver>("/home/cmvr/Projects/cmvr-es/model/xiaoyan_description/dual_arm.urdf"
pinocchio_ik_ = std::make_shared<PinocchioQpIKSolver>("/home/linbo/cmvr/cmvr-es/model/xiaoyan_description/dual_arm.urdf"
,"PELVIS_S"
,"R_WRIST_R_S");
pinocchio_ik_->init();

View File

@ -22,8 +22,6 @@
#include "service/grpc/include/grpc_hlc_service.h"
#include "json/json.h"
#include <grpcpp/ext/proto_server_reflection_plugin.h>
#include "service/grpc/include/grpc_agv_service.h"
#include "common/utils/config_helper/include/config_helper.h"
using namespace cmvr::service;
ServerRunner::ServerRunner() = default;
@ -99,7 +97,9 @@ void ServerRunner::threadMain() {
using namespace cmvr::monitor;
try {
if (!cfg_.hasChild("DeviceManager")) {
throw std::runtime_error("Device Manager node not found");
}
static std::once_flag reflection_once;
std::call_once(reflection_once, []() {
@ -109,8 +109,13 @@ void ServerRunner::threadMain() {
auto dmgr_cfg = cfg_.getChild("DeviceManager");
DeviceManager::getInstance(dmgr_cfg);
cmvr::ConfigHelper::getServerConfig(servercfg_);
std::string port = servercfg_.grpc_server().port();
if (cfg_.hasChild("MonitorManager")) {
auto mmgr_cfg = cfg_.getChild("MonitorManager");
MonitorManager::getInstance(mmgr_cfg);
}
auto grpc_cfg = cfg_.getChild("gRPCServer");
std::string port = grpc_cfg.getAttrDefault("port", "50051");
std::string local_address = "0.0.0.0:" + port;
auto camera_service = std::make_unique<gRPCCameraServiceImpl>();
@ -121,7 +126,6 @@ void ServerRunner::threadMain() {
auto biohand_service = std::make_unique<gRPCMBioHeadServiceImpl>();
auto humanoid_robot_service = std::make_unique<gRPCHumanoidRobotServiceImpl>();
auto hlc_service = std::make_unique<gRPCHlcServiceImpl>();
auto agv_service = std::make_unique<gRPCAGVServiceImpl>();
grpc::ServerBuilder builder;
builder.AddListeningPort(local_address, grpc::InsecureServerCredentials());
@ -133,7 +137,6 @@ void ServerRunner::threadMain() {
builder.RegisterService(biohand_service.get());
builder.RegisterService(humanoid_robot_service.get());
builder.RegisterService(hlc_service.get());
builder.RegisterService(agv_service.get());
auto local_server = builder.BuildAndStart();
if (!local_server) {

View File

@ -1,42 +0,0 @@
/*
* This software is dual-licensed under GPLv3 and a commercial
* license. See the file LICENSE.md distributed with this software for
* full license information.
*/
/** \file
* \brief
* Headerfile for ec_base.c
*/
#ifndef _ec_base_
#define _ec_base_
#ifdef __cplusplus
extern "C" {
#endif
int ecx_setupdatagram(ecx_portt *port, void *frame, uint8 com, uint8 idx, uint16 ADP, uint16 ADO, uint16 length, void *data);
uint16 ecx_adddatagram(ecx_portt *port, void *frame, uint8 com, uint8 idx, boolean more, uint16 ADP, uint16 ADO, uint16 length, void *data);
int ecx_BWR(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout);
int ecx_BRD(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout);
int ecx_APRD(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout);
int ecx_ARMW(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout);
int ecx_FRMW(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout);
uint16 ecx_APRDw(ecx_portt *port, uint16 ADP, uint16 ADO, int timeout);
int ecx_FPRD(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout);
uint16 ecx_FPRDw(ecx_portt *port, uint16 ADP, uint16 ADO, int timeout);
int ecx_APWRw(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 data, int timeout);
int ecx_APWR(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout);
int ecx_FPWRw(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 data, int timeout);
int ecx_FPWR(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout);
int ecx_LRW(ecx_portt *port, uint32 LogAdr, uint16 length, void *data, int timeout);
int ecx_LRD(ecx_portt *port, uint32 LogAdr, uint16 length, void *data, int timeout);
int ecx_LWR(ecx_portt *port, uint32 LogAdr, uint16 length, void *data, int timeout);
int ecx_LRWDC(ecx_portt *port, uint32 LogAdr, uint16 length, void *data, uint16 DCrs, int64 *DCtime, int timeout);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,73 +0,0 @@
/*
* This software is dual-licensed under GPLv3 and a commercial
* license. See the file LICENSE.md distributed with this software for
* full license information.
*/
/** \file
* \brief
* Headerfile for ec_coe.c
*/
#ifndef _ec_coe_
#define _ec_coe_
#ifdef __cplusplus
extern "C" {
#endif
/* Storage for object description list */
typedef struct
{
/** slave number */
uint16 Slave;
/** number of entries in list */
uint16 Entries;
/** array of indexes */
uint16 Index[EC_MAXODLIST];
/** array of datatypes, see EtherCAT specification */
uint16 DataType[EC_MAXODLIST];
/** array of object codes, see EtherCAT specification */
uint8 ObjectCode[EC_MAXODLIST];
/** number of subindexes for each index */
uint8 MaxSub[EC_MAXODLIST];
/** textual description of each index */
char Name[EC_MAXODLIST][EC_MAXNAME + 1];
} ec_ODlistt;
/* storage for object list entry information */
typedef struct
{
/** number of entries in list */
uint16 Entries;
/** array of value infos, see EtherCAT specification */
uint8 ValueInfo[EC_MAXOELIST];
/** array of value infos, see EtherCAT specification */
uint16 DataType[EC_MAXOELIST];
/** array of bit lengths, see EtherCAT specification */
uint16 BitLength[EC_MAXOELIST];
/** array of object access bits, see EtherCAT specification */
uint16 ObjAccess[EC_MAXOELIST];
/** textual description of each index */
char Name[EC_MAXOELIST][EC_MAXNAME + 1];
} ec_OElistt;
void ecx_SDOerror(ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubIdx, int32 AbortCode);
int ecx_SDOread(ecx_contextt *context, uint16 slave, uint16 index, uint8 subindex,
boolean CA, int *psize, void *p, int timeout);
int ecx_SDOwrite(ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubIndex,
boolean CA, int psize, const void *p, int Timeout);
int ecx_RxPDO(ecx_contextt *context, uint16 Slave, uint16 RxPDOnumber, int psize, const void *p);
int ecx_TxPDO(ecx_contextt *context, uint16 slave, uint16 TxPDOnumber, int *psize, void *p, int timeout);
int ecx_readPDOmap(ecx_contextt *context, uint16 Slave, uint32 *Osize, uint32 *Isize);
int ecx_readPDOmapCA(ecx_contextt *context, uint16 Slave, int Thread_n, uint32 *Osize, uint32 *Isize);
int ecx_readODlist(ecx_contextt *context, uint16 Slave, ec_ODlistt *pODlist);
int ecx_readODdescription(ecx_contextt *context, uint16 Item, ec_ODlistt *pODlist);
int ecx_readOEsingle(ecx_contextt *context, uint16 Item, uint8 SubI, ec_ODlistt *pODlist, ec_OElistt *pOElist);
int ecx_readOE(ecx_contextt *context, uint16 Item, ec_ODlistt *pODlist, ec_OElistt *pOElist);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,31 +0,0 @@
/*
* This software is dual-licensed under GPLv3 and a commercial
* license. See the file LICENSE.md distributed with this software for
* full license information.
*/
/** \file
* \brief
* Headerfile for ec_config.c
*/
#ifndef _ec_config_
#define _ec_config_
#ifdef __cplusplus
extern "C" {
#endif
#define EC_NODEOFFSET 0x1000
#define EC_TEMPNODE 0xffff
int ecx_config_init(ecx_contextt *context);
int ecx_config_map_group(ecx_contextt *context, void *pIOmap, uint8 group);
int ecx_recover_slave(ecx_contextt *context, uint16 slave, int timeout);
int ecx_reconfig_slave(ecx_contextt *context, uint16 slave, int timeout);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,27 +0,0 @@
/*
* This software is dual-licensed under GPLv3 and a commercial
* license. See the file LICENSE.md distributed with this software for
* full license information.
*/
/** \file
* \brief
* Headerfile for ec_dc.c
*/
#ifndef _EC_ECATDC_H
#define _EC_ECATDC_H
#ifdef __cplusplus
extern "C" {
#endif
boolean ecx_configdc(ecx_contextt *context);
void ecx_dcsync0(ecx_contextt *context, uint16 slave, boolean act, uint32 CyclTime, int32 CyclShift);
void ecx_dcsync01(ecx_contextt *context, uint16 slave, boolean act, uint32 CyclTime0, uint32 CyclTime1, int32 CyclShift);
#ifdef __cplusplus
}
#endif
#endif /* _EC_ECATDC_H */

View File

@ -1,213 +0,0 @@
/*
* This software is dual-licensed under GPLv3 and a commercial
* license. See the file LICENSE.md distributed with this software for
* full license information.
*/
/** \file
* \brief
* Headerfile for ec_eoe.c
*/
#ifndef _ec_eoe_
#define _ec_eoe_
#ifdef __cplusplus
extern "C" {
#endif
#include "soem/soem.h"
/* use maximum size for EOE mailbox data - mbxheader and 2x frameinfo */
#define EC_MAXEOEDATA (EC_MAXMBX - (sizeof(ec_mbxheadert) + \
sizeof(uint16_t) + \
sizeof(uint16_t)))
/** DNS length according to ETG 1000.6 */
#define EOE_DNS_NAME_LENGTH 32
/** Ethernet address length not including VLAN */
#define EOE_ETHADDR_LENGTH 6
/** IPv4 address length */
#define EOE_IP4_LENGTH sizeof(uint32_t)
#define EOE_MAKEU32(a, b, c, d) (((uint32_t)((a) & 0xff) << 24) | \
((uint32_t)((b) & 0xff) << 16) | \
((uint32_t)((c) & 0xff) << 8) | \
(uint32_t)((d) & 0xff))
#if !defined(EC_BIG_ENDIAN) && defined(EC_LITTLE_ENDIAN)
#define EOE_HTONS(x) ((((x) & 0x00ffUL) << 8) | (((x) & 0xff00UL) >> 8))
#define EOE_NTOHS(x) EOE_HTONS(x)
#define EOE_HTONL(x) ((((x) & 0x000000ffUL) << 24) | \
(((x) & 0x0000ff00UL) << 8) | \
(((x) & 0x00ff0000UL) >> 8) | \
(((x) & 0xff000000UL) >> 24))
#define EOE_NTOHL(x) EOE_HTONL(x)
#else
#define EOE_HTONS(x) (x)
#define EOE_NTOHS(x) (x)
#define EOE_HTONL(x) (x)
#define EOE_NTOHL(x) (x)
#endif /* !defined(EC_BIG_ENDIAN) && defined(EC_LITTLE_ENDIAN) */
/** Get one byte from the 4-byte address */
#define eoe_ip4_addr1(ipaddr) (((const uint8_t *)(&(ipaddr)->addr))[0])
#define eoe_ip4_addr2(ipaddr) (((const uint8_t *)(&(ipaddr)->addr))[1])
#define eoe_ip4_addr3(ipaddr) (((const uint8_t *)(&(ipaddr)->addr))[2])
#define eoe_ip4_addr4(ipaddr) (((const uint8_t *)(&(ipaddr)->addr))[3])
/** Set an IP address given by the four byte-parts */
#define EOE_IP4_ADDR_TO_U32(ipaddr, a, b, c, d) \
(ipaddr)->addr = EOE_HTONL(EOE_MAKEU32(a, b, c, d))
/** Header frame info 1 */
#define EOE_HDR_FRAME_TYPE_OFFSET 0
#define EOE_HDR_FRAME_TYPE (0xF << 0)
#define EOE_HDR_FRAME_TYPE_SET(x) (((x) & 0xF) << 0)
#define EOE_HDR_FRAME_TYPE_GET(x) (((x) >> 0) & 0xF)
#define EOE_HDR_FRAME_PORT_OFFSET 4
#define EOE_HDR_FRAME_PORT (0xF << 4)
#define EOE_HDR_FRAME_PORT_SET(x) ((uint16)(((x) & 0xF) << 4))
#define EOE_HDR_FRAME_PORT_GET(x) (((x) >> 4) & 0xF)
#define EOE_HDR_LAST_FRAGMENT_OFFSET 8
#define EOE_HDR_LAST_FRAGMENT (0x1 << 8)
#define EOE_HDR_LAST_FRAGMENT_SET(x) (((x) & 0x1) << 8)
#define EOE_HDR_LAST_FRAGMENT_GET(x) (((x) >> 8) & 0x1)
#define EOE_HDR_TIME_APPEND_OFFSET 9
#define EOE_HDR_TIME_APPEND (0x1 << 9)
#define EOE_HDR_TIME_APPEND_SET(x) (((x) & 0x1) << 9)
#define EOE_HDR_TIME_APPEND_GET(x) (((x) >> 9) & 0x1)
#define EOE_HDR_TIME_REQUEST_OFFSET 10
#define EOE_HDR_TIME_REQUEST (0x1 << 10)
#define EOE_HDR_TIME_REQUEST_SET(x) (((x) & 0x1) << 10)
#define EOE_HDR_TIME_REQUEST_GET(x) (((x) >> 10) & 0x1)
/** Header frame info 2 */
#define EOE_HDR_FRAG_NO_OFFSET 0
#define EOE_HDR_FRAG_NO (0x3F << 0)
#define EOE_HDR_FRAG_NO_SET(x) ((uint16)(((x) & 0x3F) << 0))
#define EOE_HDR_FRAG_NO_GET(x) (((x) >> 0) & 0x3F)
#define EOE_HDR_FRAME_OFFSET_OFFSET 6
#define EOE_HDR_FRAME_OFFSET (0x3F << 6)
#define EOE_HDR_FRAME_OFFSET_SET(x) ((uint16)(((x) & 0x3F) << 6))
#define EOE_HDR_FRAME_OFFSET_GET(x) (((x) >> 6) & 0x3F)
#define EOE_HDR_FRAME_NO_OFFSET 12
#define EOE_HDR_FRAME_NO (0xF << 12)
#define EOE_HDR_FRAME_NO_SET(x) ((uint16)(((x) & 0xF) << 12))
#define EOE_HDR_FRAME_NO_GET(x) (((x) >> 12) & 0xF)
/** EOE param */
#define EOE_PARAM_OFFSET 4
#define EOE_PARAM_MAC_INCLUDE (0x1 << 0)
#define EOE_PARAM_IP_INCLUDE (0x1 << 1)
#define EOE_PARAM_SUBNET_IP_INCLUDE (0x1 << 2)
#define EOE_PARAM_DEFAULT_GATEWAY_INCLUDE (0x1 << 3)
#define EOE_PARAM_DNS_IP_INCLUDE (0x1 << 4)
#define EOE_PARAM_DNS_NAME_INCLUDE (0x1 << 5)
/** EoE frame types */
#define EOE_FRAG_DATA 0
#define EOE_INIT_RESP_TIMESTAMP 1
#define EOE_INIT_REQ 2 /* Spec SET IP REQ */
#define EOE_INIT_RESP 3 /* Spec SET IP RESP */
#define EOE_SET_ADDR_FILTER_REQ 4
#define EOE_SET_ADDR_FILTER_RESP 5
#define EOE_GET_IP_PARAM_REQ 6
#define EOE_GET_IP_PARAM_RESP 7
#define EOE_GET_ADDR_FILTER_REQ 8
#define EOE_GET_ADDR_FILTER_RESP 9
/** EoE parameter result codes */
#define EOE_RESULT_SUCCESS 0x0000
#define EOE_RESULT_UNSPECIFIED_ERROR 0x0001
#define EOE_RESULT_UNSUPPORTED_FRAME_TYPE 0x0002
#define EOE_RESULT_NO_IP_SUPPORT 0x0201
#define EOE_RESULT_NO_DHCP_SUPPORT 0x0202
#define EOE_RESULT_NO_FILTER_SUPPORT 0x0401
/** EOE ip4 address in network order */
typedef struct eoe_ip4_addr
{
uint32_t addr;
} eoe_ip4_addr_t;
/** EOE ethernet address */
OSAL_PACKED_BEGIN
typedef struct OSAL_PACKED eoe_ethaddr
{
uint8_t addr[EOE_ETHADDR_LENGTH];
} eoe_ethaddr_t;
OSAL_PACKED_END
/** EoE IP request structure, storage only, no need to pack */
typedef struct eoe_param
{
uint8_t mac_set : 1;
uint8_t ip_set : 1;
uint8_t subnet_set : 1;
uint8_t default_gateway_set : 1;
uint8_t dns_ip_set : 1;
uint8_t dns_name_set : 1;
eoe_ethaddr_t mac;
eoe_ip4_addr_t ip;
eoe_ip4_addr_t subnet;
eoe_ip4_addr_t default_gateway;
eoe_ip4_addr_t dns_ip;
char dns_name[EOE_DNS_NAME_LENGTH];
} eoe_param_t;
/** EOE structure.
* Used to interpret EoE mailbox packets.
*/
OSAL_PACKED_BEGIN
typedef struct OSAL_PACKED
{
ec_mbxheadert mbxheader;
uint16_t frameinfo1;
union
{
uint16_t frameinfo2;
uint16_t result;
};
uint8 data[EC_MAXEOEDATA];
} ec_EOEt;
OSAL_PACKED_END
int ecx_EOEdefinehook(ecx_contextt *context, void *hook);
int ecx_EOEsetIp(ecx_contextt *context,
uint16 slave,
uint8 port,
eoe_param_t *ipparam,
int timeout);
int ecx_EOEgetIp(ecx_contextt *context,
uint16 slave,
uint8 port,
eoe_param_t *ipparam,
int timeout);
int ecx_EOEsend(ecx_contextt *context,
uint16 slave,
uint8 port,
int psize,
void *p,
int timeout);
int ecx_EOErecv(ecx_contextt *context,
uint16 slave,
uint8 port,
int *psize,
void *p,
int timeout);
int ecx_EOEreadfragment(
ec_mbxbuft *MbxIn,
uint8 *rxfragmentno,
uint16 *rxframesize,
uint16 *rxframeoffset,
uint16 *rxframeno,
int *psize,
void *p);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,27 +0,0 @@
/*
* This software is dual-licensed under GPLv3 and a commercial
* license. See the file LICENSE.md distributed with this software for
* full license information.
*/
/** \file
* \brief
* Headerfile for ec_foe.c
*/
#ifndef _ec_foe_
#define _ec_foe_
#ifdef __cplusplus
extern "C" {
#endif
int ecx_FOEdefinehook(ecx_contextt *context, void *hook);
int ecx_FOEread(ecx_contextt *context, uint16 slave, char *filename, uint32 password, int *psize, void *p, int timeout);
int ecx_FOEwrite(ecx_contextt *context, uint16 slave, char *filename, uint32 password, int psize, void *p, int timeout);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,624 +0,0 @@
/*
* This software is dual-licensed under GPLv3 and a commercial
* license. See the file LICENSE.md distributed with this software for
* full license information.
*/
/** \file
* \brief
* Headerfile for ec_main.c
*/
#ifndef _ec_main_
#define _ec_main_
#ifdef __cplusplus
extern "C" {
#endif
#include "soem/ec_options.h"
typedef struct ec_adapter ec_adaptert;
struct ec_adapter
{
char name[EC_MAXLEN_ADAPTERNAME];
char desc[EC_MAXLEN_ADAPTERNAME];
ec_adaptert *next;
};
/** record for FMMU */
OSAL_PACKED_BEGIN
typedef struct OSAL_PACKED ec_fmmu
{
uint32 LogStart;
uint16 LogLength;
uint8 LogStartbit;
uint8 LogEndbit;
uint16 PhysStart;
uint8 PhysStartBit;
uint8 FMMUtype;
uint8 FMMUactive;
uint8 unused1;
uint16 unused2;
} ec_fmmut;
OSAL_PACKED_END
/** record for sync manager */
OSAL_PACKED_BEGIN
typedef struct OSAL_PACKED ec_sm
{
uint16 StartAddr;
uint16 SMlength;
uint32 SMflags;
} ec_smt;
OSAL_PACKED_END
OSAL_PACKED_BEGIN
typedef struct OSAL_PACKED ec_state_status
{
uint16 State;
uint16 Unused;
uint16 ALstatuscode;
} ec_state_status;
OSAL_PACKED_END
/** mailbox buffer array */
typedef uint8 ec_mbxbuft[EC_MAXMBX + 1];
#define EC_MBXINENABLE (uint8 *)1
typedef struct
{
int listhead, listtail, listcount;
int mbxemptylist[EC_MBXPOOLSIZE];
osal_mutext *mbxmutex;
ec_mbxbuft mbx[EC_MBXPOOLSIZE];
} ec_mbxpoolt;
#define EC_MBXQUEUESTATE_NONE 0
#define EC_MBXQUEUESTATE_REQ 1
#define EC_MBXQUEUESTATE_FAIL 2
#define EC_MBXQUEUESTATE_DONE 3
typedef struct
{
int listhead, listtail, listcount;
ec_mbxbuft *mbx[EC_MBXPOOLSIZE];
int mbxstate[EC_MBXPOOLSIZE];
int mbxremove[EC_MBXPOOLSIZE];
int mbxticket[EC_MBXPOOLSIZE];
uint16 mbxslave[EC_MBXPOOLSIZE];
osal_mutext *mbxmutex;
} ec_mbxqueuet;
#define ECT_MBXPROT_AOE 0x0001
#define ECT_MBXPROT_EOE 0x0002
#define ECT_MBXPROT_COE 0x0004
#define ECT_MBXPROT_FOE 0x0008
#define ECT_MBXPROT_SOE 0x0010
#define ECT_MBXPROT_VOE 0x0020
#define ECT_COEDET_SDO 0x01
#define ECT_COEDET_SDOINFO 0x02
#define ECT_COEDET_PDOASSIGN 0x04
#define ECT_COEDET_PDOCONFIG 0x08
#define ECT_COEDET_UPLOAD 0x10
#define ECT_COEDET_SDOCA 0x20
#define EC_SMENABLEMASK 0xfffeffff
typedef struct ecx_context ecx_contextt;
#define ECT_MBXH_NONE 0
#define ECT_MBXH_CYCLIC 1
#define ECT_MBXH_LOST 2
/** Slave state
* All slave information is put in this structure. Needed for most
* user interaction with slaves.
*/
typedef struct ec_slave
{
/** state of slave */
uint16 state;
/** AL status code */
uint16 ALstatuscode;
/** Configured address */
uint16 configadr;
/** Alias address */
uint16 aliasadr;
/** Manufacturer from EEprom */
uint32 eep_man;
/** ID from EEprom */
uint32 eep_id;
/** revision from EEprom */
uint32 eep_rev;
/** serial number from EEprom */
uint32 eep_ser;
/** Interface type */
uint16 Itype;
/** Device type */
uint16 Dtype;
/** output bits */
uint16 Obits;
/** output bytes, if Obits < 8 then Obytes = 0 */
uint32 Obytes;
/** output pointer in IOmap buffer */
uint8 *outputs;
/** output offset in IOmap buffer */
uint32 Ooffset;
/** startbit in first output byte */
uint8 Ostartbit;
/** input bits */
uint16 Ibits;
/** input bytes, if Ibits < 8 then Ibytes = 0 */
uint32 Ibytes;
/** input pointer in IOmap buffer */
uint8 *inputs;
/** input offset in IOmap buffer */
uint32 Ioffset;
/** startbit in first input byte */
uint8 Istartbit;
/** SM structure */
ec_smt SM[EC_MAXSM];
/** SM type 0=unused 1=MbxWr 2=MbxRd 3=Outputs 4=Inputs */
uint8 SMtype[EC_MAXSM];
/** FMMU structure */
ec_fmmut FMMU[EC_MAXFMMU];
/** FMMU0 function 0=unused 1=outputs 2=inputs 3=SM status*/
uint8 FMMU0func;
/** FMMU1 function */
uint8 FMMU1func;
/** FMMU2 function */
uint8 FMMU2func;
/** FMMU3 function */
uint8 FMMU3func;
/** length of write mailbox in bytes, if no mailbox then 0 */
uint16 mbx_l;
/** mailbox write offset */
uint16 mbx_wo;
/** length of read mailbox in bytes */
uint16 mbx_rl;
/** mailbox read offset */
uint16 mbx_ro;
/** mailbox supported protocols */
uint16 mbx_proto;
/** Counter value of mailbox link layer protocol 1..7 */
uint8 mbx_cnt;
/** has DC capability */
boolean hasdc;
/** Physical type; Ebus, EtherNet combinations */
uint8 ptype;
/** topology: 1 to 3 links */
uint8 topology;
/** active ports bitmap : ....3210 , set if respective port is active **/
uint8 activeports;
/** consumed ports bitmap : ....3210, used for internal delay measurement **/
uint8 consumedports;
/** slave number for parent, 0=master */
uint16 parent;
/** port number on parent this slave is connected to **/
uint8 parentport;
/** port number on this slave the parent is connected to **/
uint8 entryport;
/** DC receivetimes on port A */
int32 DCrtA;
/** DC receivetimes on port B */
int32 DCrtB;
/** DC receivetimes on port C */
int32 DCrtC;
/** DC receivetimes on port D */
int32 DCrtD;
/** propagation delay */
int32 pdelay;
/** next DC slave */
uint16 DCnext;
/** previous DC slave */
uint16 DCprevious;
/** DC cycle time in ns */
int32 DCcycle;
/** DC shift from clock modulus boundary */
int32 DCshift;
/** DC sync activation, 0=off, 1=on */
uint8 DCactive;
/** link to SII config */
uint16 SIIindex;
/** 1 = 8 bytes per read, 0 = 4 bytes per read */
uint8 eep_8byte;
/** 0 = eeprom to master , 1 = eeprom to PDI */
uint8 eep_pdi;
/** CoE details */
uint8 CoEdetails;
/** FoE details */
uint8 FoEdetails;
/** EoE details */
uint8 EoEdetails;
/** SoE details */
uint8 SoEdetails;
/** E-bus current */
int16 Ebuscurrent;
/** if >0 block use of LRW in processdata */
uint8 blockLRW;
/** group */
uint8 group;
/** first unused FMMU */
uint8 FMMUunused;
/** Boolean for tracking whether the slave is (not) responding, not used/set by the SOEM library */
boolean islost;
/** registered configuration function PO->SO */
int (*PO2SOconfig)(ecx_contextt *context, uint16 slave);
/** mailbox handler state, 0 = no handler, 1 = cyclic task mbx handler, 2 = slave lost */
int mbxhandlerstate;
/** mailbox handler robust mailbox protocol state */
int mbxrmpstate;
/** mailbox handler RMP extended mbx in state */
uint16 mbxinstateex;
/** pointer to CoE mailbox in buffer */
uint8 *coembxin;
/** CoE mailbox in flag, true = mailbox full */
boolean coembxinfull;
/** CoE mailbox in overrun counter */
int coembxoverrun;
/** pointer to SoE mailbox in buffer */
uint8 *soembxin;
/** SoE mailbox in flag, true = mailbox full */
boolean soembxinfull;
/** SoE mailbox in overrun counter */
int soembxoverrun;
/** pointer to FoE mailbox in buffer */
uint8 *foembxin;
/** FoE mailbox in flag, true = mailbox full */
boolean foembxinfull;
/** FoE mailbox in overrun counter */
int foembxoverrun;
/** pointer to EoE mailbox in buffer */
uint8 *eoembxin;
/** EoE mailbox in flag, true = mailbox full */
boolean eoembxinfull;
/** EoE mailbox in overrun counter */
int eoembxoverrun;
/** pointer to VoE mailbox in buffer */
uint8 *voembxin;
/** VoE mailbox in flag, true = mailbox full */
boolean voembxinfull;
/** VoE mailbox in overrun counter */
int voembxoverrun;
/** pointer to AoE mailbox in buffer */
uint8 *aoembxin;
/** AoE mailbox in flag, true = mailbox full */
boolean aoembxinfull;
/** AoE mailbox in overrun counter */
int aoembxoverrun;
/** pointer to out mailbox status register buffer */
uint8 *mbxstatus;
/** readable name */
char name[EC_MAXNAME + 1];
} ec_slavet;
/** for list of ethercat slave groups */
typedef struct ec_group
{
/** logical start address for this group */
uint32 logstartaddr;
/** output bytes, if Obits < 8 then Obytes = 0 */
uint32 Obytes;
/** output pointer in IOmap buffer */
uint8 *outputs;
/** input bytes, if Ibits < 8 then Ibytes = 0 */
uint32 Ibytes;
/** input pointer in IOmap buffer */
uint8 *inputs;
/** has DC capability */
boolean hasdc;
/** next DC slave */
uint16 DCnext;
/** E-bus current */
int16 Ebuscurrent;
/** if >0 block use of LRW in processdata */
uint8 blockLRW;
/** IO segments used */
uint16 nsegments;
/** 1st input segment */
uint16 Isegment;
/** Offset in input segment */
uint16 Ioffset;
/** Expected workcounter outputs */
uint16 outputsWKC;
/** Expected workcounter inputs */
uint16 inputsWKC;
/** check slave states */
boolean docheckstate;
/** IO segmentation list. Datagrams must not break SM in two. */
uint32 IOsegment[EC_MAXIOSEGMENTS];
/** pointer to out mailbox status register buffer */
uint8 *mbxstatus;
/** mailbox status register buffer length */
int32 mbxstatuslength;
/** mailbox status lookup table */
uint16 mbxstatuslookup[EC_MAXSLAVE];
/** mailbox last handled in mxbhandler */
uint16 lastmbxpos;
/** mailbox transmit queue struct */
ec_mbxqueuet mbxtxqueue;
} ec_groupt;
#define ECT_ESMTRANS_IP 0x0001
#define ECT_ESMTRANS_PS 0x0002
#define ECT_ESMTRANS_PI 0x0004
#define ECT_ESMTRANS_SP 0x0008
#define ECT_ESMTRANS_SO 0x0010
#define ECT_ESMTRANS_SI 0x0020
#define ECT_ESMTRANS_OS 0x0040
#define ECT_ESMTRANS_OP 0x0080
#define ECT_ESMTRANS_OI 0x0100
#define ECT_ESMTRANS_IB 0x0200
#define ECT_ESMTRANS_BI 0x0400
#define ECT_ESMTRANS_II 0x0800
#define ECT_ESMTRANS_PP 0x1000
#define ECT_ESMTRANS_SS 0x2000
/** ENI CoE command structure */
typedef struct ec_enicoecmd
{
/** transition(s) during which command should be sent */
uint16 Transition;
/** complete access flag */
boolean CA;
/** ccs (1 = read, 2 = write) */
uint8 Ccs;
/** object index */
uint16 Index;
/** object subindex */
uint8 SubIdx;
/** timeout in us */
int Timeout;
/** size in bytes of parameter buffer */
int DataSize;
/** pointer to parameter buffer */
void *Data;
} ec_enicoecmdt;
/** ENI slave structure */
typedef struct ec_enislave
{
uint16 Slave;
uint32 VendorId;
uint32 ProductCode;
uint32 RevisionNo;
ec_enicoecmdt *CoECmds;
int CoECmdCount;
} ec_enislavet;
/** ENI structure */
typedef struct ec_eni
{
ec_enislavet *slave;
int slavecount;
} ec_enit;
/** SII FMMU structure */
typedef struct ec_eepromFMMU
{
uint16 Startpos;
uint8 nFMMU;
uint8 FMMU0;
uint8 FMMU1;
uint8 FMMU2;
uint8 FMMU3;
} ec_eepromFMMUt;
/** SII SM structure */
typedef struct ec_eepromSM
{
uint16 Startpos;
uint8 nSM;
uint16 PhStart;
uint16 Plength;
uint8 Creg;
uint8 Sreg; /* don't care */
uint8 Activate;
uint8 PDIctrl; /* don't care */
} ec_eepromSMt;
/** record to store rxPDO and txPDO table from eeprom */
typedef struct ec_eepromPDO
{
uint16 Startpos;
uint16 Length;
uint16 nPDO;
uint16 Index[EC_MAXEEPDO];
uint16 SyncM[EC_MAXEEPDO];
uint16 BitSize[EC_MAXEEPDO];
uint16 SMbitsize[EC_MAXSM];
} ec_eepromPDOt;
/** standard ethercat mailbox header */
OSAL_PACKED_BEGIN
typedef struct OSAL_PACKED ec_mbxheader
{
uint16 length;
uint16 address;
uint8 priority;
uint8 mbxtype;
} ec_mbxheadert;
OSAL_PACKED_END
/** ALstatus and ALstatus code */
OSAL_PACKED_BEGIN
typedef struct OSAL_PACKED ec_alstatus
{
uint16 alstatus;
uint16 unused;
uint16 alstatuscode;
} ec_alstatust;
OSAL_PACKED_END
/** stack structure to store segmented LRD/LWR/LRW constructs */
typedef struct ec_idxstack
{
uint8 pushed;
uint8 pulled;
uint8 idx[EC_MAXBUF];
void *data[EC_MAXBUF];
uint16 length[EC_MAXBUF];
uint16 dcoffset[EC_MAXBUF];
uint8 type[EC_MAXBUF];
} ec_idxstackT;
/** ringbuf for error storage */
typedef struct ec_ering
{
int16 head;
int16 tail;
ec_errort Error[EC_MAXELIST + 1];
} ec_eringt;
/** SyncManager Communication Type structure for CA */
OSAL_PACKED_BEGIN
typedef struct OSAL_PACKED ec_SMcommtype
{
uint8 n;
uint8 nu1;
uint8 SMtype[EC_MAXSM];
} ec_SMcommtypet;
OSAL_PACKED_END
/** SDO assign structure for CA */
OSAL_PACKED_BEGIN
typedef struct OSAL_PACKED ec_PDOassign
{
uint8 n;
uint8 nu1;
uint16 index[256];
} ec_PDOassignt;
OSAL_PACKED_END
/** SDO description structure for CA */
OSAL_PACKED_BEGIN
typedef struct OSAL_PACKED ec_PDOdesc
{
uint8 n;
uint8 nu1;
uint32 PDO[256];
} ec_PDOdesct;
OSAL_PACKED_END
/** Context structure, referenced by all ecx functions*/
struct ecx_context
{
/** @publicsection */
/* Network state */
/** port, may include red_port */
ecx_portt port;
/** list of detected slaves */
ec_slavet slavelist[EC_MAXSLAVE];
/** number of slaves found in configuration */
int slavecount;
/** list of groups */
ec_groupt grouplist[EC_MAXGROUP];
/** ecaterror state */
boolean ecaterror;
/** last DC time from slaves */
int64 DCtime;
/** @privatesection */
/* Internal state */
/** internal, eeprom cache buffer */
uint8 esibuf[EC_MAXEEPBUF];
/** internal, eeprom cache map */
uint32 esimap[EC_MAXEEPBITMAP];
/** internal, current slave for eeprom cache */
uint16 esislave;
/** internal, error list */
ec_eringt elist;
/** internal, processdata stack buffer info */
ec_idxstackT idxstack;
/** internal, SM buffer */
ec_SMcommtypet SMcommtype[EC_MAX_MAPT];
/** internal, PDO assign list */
ec_PDOassignt PDOassign[EC_MAX_MAPT];
/** internal, PDO description list */
ec_PDOdesct PDOdesc[EC_MAX_MAPT];
/** internal, SM list from eeprom */
ec_eepromSMt eepSM;
/** internal, FMMU list from eeprom */
ec_eepromFMMUt eepFMMU;
/** internal, mailbox pool */
ec_mbxpoolt mbxpool;
/** @publicsection */
/* Configurable settings */
/** network information hook */
ec_enit *ENI;
/** registered FoE hook */
int (*FOEhook)(uint16 slave, int packetnumber, int datasize);
/** registered EoE hook */
int (*EOEhook)(ecx_contextt *context, uint16 slave, void *eoembx);
/** flag to control legacy automatic state change or manual state change */
int manualstatechange;
/** opaque pointer to application userdata, never used by SOEM. */
void *userdata;
/** In overlapped mode, inputs will replace outputs in the incoming
* frame. Use this mode for TI ESC:s. Processdata is always aligned
* on a byte boundary. */
boolean overlappedMode;
/** Do not map each slave on a byte boundary. May result in smaller
* frame sizes. Has no effect in overlapped mode. */
boolean packedMode;
};
ec_adaptert *ec_find_adapters(void);
void ec_free_adapters(ec_adaptert *adapter);
uint8 ec_nextmbxcnt(uint8 cnt);
void ec_clearmbx(ec_mbxbuft *Mbx);
void ecx_pusherror(ecx_contextt *context, const ec_errort *Ec);
boolean ecx_poperror(ecx_contextt *context, ec_errort *Ec);
boolean ecx_iserror(ecx_contextt *context);
void ecx_packeterror(ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubIdx, uint16 ErrorCode);
int ecx_init(ecx_contextt *context, const char *ifname);
int ecx_init_redundant(ecx_contextt *context, ecx_redportt *redport, const char *ifname, char *if2name);
void ecx_close(ecx_contextt *context);
uint8 ecx_siigetbyte(ecx_contextt *context, uint16 slave, uint16 address);
int16 ecx_siifind(ecx_contextt *context, uint16 slave, uint16 cat);
void ecx_siistring(ecx_contextt *context, char *str, uint16 slave, uint16 Sn);
uint16 ecx_siiFMMU(ecx_contextt *context, uint16 slave, ec_eepromFMMUt *FMMU);
uint16 ecx_siiSM(ecx_contextt *context, uint16 slave, ec_eepromSMt *SM);
uint16 ecx_siiSMnext(ecx_contextt *context, uint16 slave, ec_eepromSMt *SM, uint16 n);
uint32 ecx_siiPDO(ecx_contextt *context, uint16 slave, ec_eepromPDOt *PDO, uint8 t);
int ecx_readstate(ecx_contextt *context);
int ecx_writestate(ecx_contextt *context, uint16 slave);
uint16 ecx_statecheck(ecx_contextt *context, uint16 slave, uint16 reqstate, int timeout);
int ecx_mbxhandler(ecx_contextt *context, uint8 group, int limit);
int ecx_mbxempty(ecx_contextt *context, uint16 slave, int timeout);
int ecx_mbxsend(ecx_contextt *context, uint16 slave, ec_mbxbuft *mbx, int timeout);
int ecx_mbxreceive(ecx_contextt *context, uint16 slave, ec_mbxbuft **mbx, int timeout);
int ecx_mbxENIinitcmds(ecx_contextt *context, uint16 slave, uint16_t transition);
void ecx_esidump(ecx_contextt *context, uint16 slave, uint8 *esibuf);
uint32 ecx_readeeprom(ecx_contextt *context, uint16 slave, uint16 eeproma, int timeout);
int ecx_writeeeprom(ecx_contextt *context, uint16 slave, uint16 eeproma, uint16 data, int timeout);
int ecx_eeprom2master(ecx_contextt *context, uint16 slave);
int ecx_eeprom2pdi(ecx_contextt *context, uint16 slave);
uint64 ecx_readeepromAP(ecx_contextt *context, uint16 aiadr, uint16 eeproma, int timeout);
int ecx_writeeepromAP(ecx_contextt *context, uint16 aiadr, uint16 eeproma, uint16 data, int timeout);
uint64 ecx_readeepromFP(ecx_contextt *context, uint16 configadr, uint16 eeproma, int timeout);
int ecx_writeeepromFP(ecx_contextt *context, uint16 configadr, uint16 eeproma, uint16 data, int timeout);
void ecx_readeeprom1(ecx_contextt *context, uint16 slave, uint16 eeproma);
uint32 ecx_readeeprom2(ecx_contextt *context, uint16 slave, int timeout);
int ecx_receive_processdata_group(ecx_contextt *context, uint8 group, int timeout);
int ecx_send_processdata(ecx_contextt *context);
int ecx_receive_processdata(ecx_contextt *context, int timeout);
int ecx_send_processdata_group(ecx_contextt *context, uint8 group);
ec_mbxbuft *ecx_getmbx(ecx_contextt *context);
int ecx_dropmbx(ecx_contextt *context, ec_mbxbuft *mbx);
int ecx_initmbxpool(ecx_contextt *context);
int ecx_initmbxqueue(ecx_contextt *context, uint8 group);
int ecx_slavembxcyclic(ecx_contextt *context, uint16 slave);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,128 +0,0 @@
/*
* This software is dual-licensed under GPLv3 and a commercial
* license. See the file LICENSE.md distributed with this software for
* full license information.
*/
/** \file
* \brief
* Build options for SOEM
*/
#ifndef _ec_options_
#define _ec_options_
#ifdef __cplusplus
extern "C" {
#endif
/* Max sizes */
/** standard frame buffer size in bytes */
#define EC_BUFSIZE (EC_MAXECATFRAME)
/** number of frame buffers per channel (tx, rx1 rx2) */
#define EC_MAXBUF (16)
/** size of EEPROM bitmap cache */
#define EC_MAXEEPBITMAP (128)
/** size of EEPROM cache buffer */
#define EC_MAXEEPBUF (EC_MAXEEPBITMAP << 5)
/** default group size in 2^x */
#define EC_LOGGROUPOFFSET (16)
/** max. entries in EtherCAT error list */
#define EC_MAXELIST (64)
/** max. length of readable name in slavelist and Object Description List */
#define EC_MAXNAME (40)
/** max. number of slaves in array */
#define EC_MAXSLAVE (200)
/** max. number of groups */
#define EC_MAXGROUP (2)
/** max. number of IO segments per group */
#define EC_MAXIOSEGMENTS (64)
/** max. mailbox size */
#define EC_MAXMBX (1486)
/** number of mailboxes in pool */
#define EC_MBXPOOLSIZE (32)
/** max. eeprom PDO entries */
#define EC_MAXEEPDO (0x200)
/** max. SM used */
#define EC_MAXSM (8)
/** max. FMMU used */
#define EC_MAXFMMU (4)
/** max. adapter name length */
#define EC_MAXLEN_ADAPTERNAME (128)
/** define maximum number of concurrent threads in mapping */
#define EC_MAX_MAPT (1)
/** max entries in Object Description list */
#define EC_MAXODLIST (1024)
/** max entries in Object Entry list */
#define EC_MAXOELIST (256)
/** max. length of readable SoE name */
#define EC_SOE_MAXNAME (60)
/** max. number of SoE mappings */
#define EC_SOE_MAXMAPPING (64)
/* Timeouts and retries */
/** timeout value in us for tx frame to return to rx */
#define EC_TIMEOUTRET (2000)
/** timeout value in us for safe data transfer, max. triple retry */
#define EC_TIMEOUTRET3 (EC_TIMEOUTRET * 3)
/** timeout value in us for return "safe" variant (f.e. wireless) */
#define EC_TIMEOUTSAFE (20000)
/** timeout value in us for EEPROM access */
#define EC_TIMEOUTEEP (20000)
/** timeout value in us for tx mailbox cycle */
#define EC_TIMEOUTTXM (20000)
/** timeout value in us for rx mailbox cycle */
#define EC_TIMEOUTRXM (700000)
/** timeout value in us for check statechange */
#define EC_TIMEOUTSTATE (2000000)
/** default number of retries if wkc <= 0 */
#define EC_DEFAULTRETRIES (3)
/* MAC addresses */
/** Primary source MAC address used for EtherCAT.
*
* This address is not the MAC address used from the NIC. EtherCAT
* does not care about MAC addressing, but it is used here to
* differentiate the route the packet traverses through the EtherCAT
* segment. This is needed to find out the packet flow in redundant
* configurations. */
#define EC_PRIMARY_MAC_ARRAY {0x0101, 0x0101, 0x0101}
/** Secondary source MAC address used for EtherCAT. */
#define EC_SECONDARY_MAC_ARRAY {0x0404, 0x0404, 0x0404}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,30 +0,0 @@
/*
* This software is dual-licensed under GPLv3 and a commercial
* license. See the file LICENSE.md distributed with this software for
* full license information.
*/
/** \file
* \brief
* Headerfile for ec_print.c
*/
#ifndef _ec_print_
#define _ec_print_
#ifdef __cplusplus
extern "C" {
#endif
const char *ec_sdoerror2string(uint32 sdoerrorcode);
char *ec_ALstatuscode2string(uint16 ALstatuscode);
char *ec_soeerror2string(uint16 errorcode);
char *ec_mbxerror2string(uint16 errorcode);
char *ecx_err2string(const ec_errort Ec);
char *ecx_elist2string(ecx_contextt *context);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,121 +0,0 @@
/*
* This software is dual-licensed under GPLv3 and a commercial
* license. See the file LICENSE.md distributed with this software for
* full license information.
*/
/** \file
* \brief
* Headerfile for ec_soe.c
*/
#ifndef _ec_soe_
#define _ec_soe_
#ifdef __cplusplus
extern "C" {
#endif
#define EC_SOE_DATASTATE_B 0x01
#define EC_SOE_NAME_B 0x02
#define EC_SOE_ATTRIBUTE_B 0x04
#define EC_SOE_UNIT_B 0x08
#define EC_SOE_MIN_B 0x10
#define EC_SOE_MAX_B 0x20
#define EC_SOE_VALUE_B 0x40
#define EC_SOE_DEFAULT_B 0x80
#define EC_IDN_MDTCONFIG 24
#define EC_IDN_ATCONFIG 16
/** SoE name structure */
OSAL_PACKED_BEGIN
typedef struct OSAL_PACKED
{
/** current length in bytes of list */
uint16 currentlength;
/** maximum length in bytes of list */
uint16 maxlength;
char name[EC_SOE_MAXNAME];
} ec_SoEnamet;
OSAL_PACKED_END
/** SoE list structure */
OSAL_PACKED_BEGIN
typedef struct OSAL_PACKED
{
/** current length in bytes of list */
uint16 currentlength;
/** maximum length in bytes of list */
uint16 maxlength;
union
{
uint8 byte[8];
uint16 word[4];
uint32 dword[2];
uint64 lword[1];
};
} ec_SoElistt;
OSAL_PACKED_END
/** SoE IDN mapping structure */
OSAL_PACKED_BEGIN
typedef struct OSAL_PACKED
{
/** current length in bytes of list */
uint16 currentlength;
/** maximum length in bytes of list */
uint16 maxlength;
uint16 idn[EC_SOE_MAXMAPPING];
} ec_SoEmappingt;
OSAL_PACKED_END
#define EC_SOE_LENGTH_1 0x00
#define EC_SOE_LENGTH_2 0x01
#define EC_SOE_LENGTH_4 0x02
#define EC_SOE_LENGTH_8 0x03
#define EC_SOE_TYPE_BINARY 0x00
#define EC_SOE_TYPE_UINT 0x01
#define EC_SOE_TYPE_INT 0x02
#define EC_SOE_TYPE_HEX 0x03
#define EC_SOE_TYPE_STRING 0x04
#define EC_SOE_TYPE_IDN 0x05
#define EC_SOE_TYPE_FLOAT 0x06
#define EC_SOE_TYPE_PARAMETER 0x07
/** SoE attribute structure */
OSAL_PACKED_BEGIN
typedef struct OSAL_PACKED
{
/** evaluation factor for display purposes */
uint32 evafactor : 16;
/** length of IDN element(s) */
uint32 length : 2;
/** IDN is list */
uint32 list : 1;
/** IDN is command */
uint32 command : 1;
/** datatype */
uint32 datatype : 3;
uint32 reserved1 : 1;
/** decimals to display if float datatype */
uint32 decimals : 4;
/** write protected in pre-op */
uint32 wppreop : 1;
/** write protected in safe-op */
uint32 wpsafeop : 1;
/** write protected in op */
uint32 wpop : 1;
uint32 reserved2 : 1;
} ec_SoEattributet;
OSAL_PACKED_END
int ecx_SoEread(ecx_contextt *context, uint16 slave, uint8 driveNo, uint8 elementflags, uint16 idn, int *psize, void *p, int timeout);
int ecx_SoEwrite(ecx_contextt *context, uint16 slave, uint8 driveNo, uint8 elementflags, uint16 idn, int psize, void *p, int timeout);
int ecx_readIDNmap(ecx_contextt *context, uint16 slave, uint32 *Osize, uint32 *Isize);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,551 +0,0 @@
/*
* This software is dual-licensed under GPLv3 and a commercial
* license. See the file LICENSE.md distributed with this software for
* full license information.
*/
/** \file
* \brief
* General typedefs and defines for EtherCAT.
*
* Defines that could need optimisation for specific applications
* are the EC_TIMEOUTxxx. Assumptions for the standard settings are a
* standard linux PC or laptop and a wired connection to maximal 100 slaves.
* For use with wireless connections or lots of slaves the timeouts need
* increasing. For fast systems running Xenomai and RT-net or alike the
* timeouts need to be shorter.
*/
#ifndef _EC_TYPE_H
#define _EC_TYPE_H
#ifdef __cplusplus
extern "C" {
#endif
#include "osal.h"
#include "soem/ec_options.h"
/* Endianness */
/** Define little endian target by default if no endian is set */
#if !defined(EC_LITTLE_ENDIAN) && !defined(EC_BIG_ENDIAN)
#define EC_LITTLE_ENDIAN
#endif
/* Error codes */
/** return value no frame returned */
#define EC_NOFRAME -1
/** return value unknown frame received */
#define EC_OTHERFRAME -2
/** return value general error */
#define EC_ERROR -3
/** return value too many slaves */
#define EC_SLAVECOUNTEXCEEDED -4
/** return value request timeout */
#define EC_TIMEOUT -5
/* Constants */
/** maximum EtherCAT frame length in bytes */
#define EC_MAXECATFRAME 1518
/** size of DC datagram used in first LRW frame */
#define EC_FIRSTDCDATAGRAM 20
/** datagram type EtherCAT */
#define EC_ECATTYPE 0x1000
/** maximum EtherCAT LRW frame length in bytes */
/* MTU - Ethernet header - length - datagram header - WCK - FCS */
#define EC_MAXLRWDATA (EC_MAXECATFRAME - 14 - 2 - 10 - 2 - 4)
/** definition for frame buffers */
typedef uint8 ec_bufT[EC_BUFSIZE];
/** ethernet header definition */
OSAL_PACKED_BEGIN
typedef struct OSAL_PACKED
{
/** destination MAC */
uint16 da0, da1, da2;
/** source MAC */
uint16 sa0, sa1, sa2;
/** ethernet type */
uint16 etype;
} ec_etherheadert;
OSAL_PACKED_END
/** ethernet header size */
#define ETH_HEADERSIZE sizeof(ec_etherheadert)
/** EtherCAT datagram header definition */
OSAL_PACKED_BEGIN
typedef struct OSAL_PACKED
{
/** length of EtherCAT datagram */
uint16 elength;
/** EtherCAT command, see ec_cmdtype */
uint8 command;
/** index, used in SOEM for Tx to Rx recombination */
uint8 index;
/** ADP */
uint16 ADP;
/** ADO */
uint16 ADO;
/** length of data portion in datagram */
uint16 dlength;
/** interrupt, currently unused */
uint16 irpt;
} ec_comt;
OSAL_PACKED_END
/** EtherCAT header size */
#define EC_HEADERSIZE sizeof(ec_comt)
/** size of ec_comt.elength item in EtherCAT header */
#define EC_ELENGTHSIZE sizeof(uint16)
/** offset position of command in EtherCAT header */
#define EC_CMDOFFSET EC_ELENGTHSIZE
/** size of workcounter item in EtherCAT datagram */
#define EC_WKCSIZE sizeof(uint16)
/** definition of datagram follows bit in ec_comt.dlength */
#define EC_DATAGRAMFOLLOWS (1 << 15)
/** Possible error codes returned. */
typedef enum
{
/** No error */
EC_ERR_OK = 0,
/** Library already initialized. */
EC_ERR_ALREADY_INITIALIZED,
/** Library not initialized. */
EC_ERR_NOT_INITIALIZED,
/** Timeout occurred during execution of the function. */
EC_ERR_TIMEOUT,
/** No slaves were found. */
EC_ERR_NO_SLAVES,
/** Function failed. */
EC_ERR_NOK
} ec_err;
/** Possible EtherCAT slave states */
typedef enum
{
/** No valid state. */
EC_STATE_NONE = 0x00,
/** Init state*/
EC_STATE_INIT = 0x01,
/** Pre-operational. */
EC_STATE_PRE_OP = 0x02,
/** Boot state*/
EC_STATE_BOOT = 0x03,
/** Safe-operational. */
EC_STATE_SAFE_OP = 0x04,
/** Operational */
EC_STATE_OPERATIONAL = 0x08,
/** Error or ACK error */
EC_STATE_ACK = 0x10,
EC_STATE_ERROR = 0x10
} ec_state;
/** Possible buffer states */
typedef enum
{
/** Empty */
EC_BUF_EMPTY = 0x00,
/** Allocated, but not filled */
EC_BUF_ALLOC = 0x01,
/** Transmitted */
EC_BUF_TX = 0x02,
/** Received, but not consumed */
EC_BUF_RCVD = 0x03,
/** Cycle completed */
EC_BUF_COMPLETE = 0x04
} ec_bufstate;
/** Ethercat data types */
typedef enum
{
ECT_BOOLEAN = 0x0001,
ECT_INTEGER8 = 0x0002,
ECT_INTEGER16 = 0x0003,
ECT_INTEGER32 = 0x0004,
ECT_UNSIGNED8 = 0x0005,
ECT_UNSIGNED16 = 0x0006,
ECT_UNSIGNED32 = 0x0007,
ECT_REAL32 = 0x0008,
ECT_VISIBLE_STRING = 0x0009,
ECT_OCTET_STRING = 0x000A,
ECT_UNICODE_STRING = 0x000B,
ECT_TIME_OF_DAY = 0x000C,
ECT_TIME_DIFFERENCE = 0x000D,
ECT_DOMAIN = 0x000F,
ECT_INTEGER24 = 0x0010,
ECT_REAL64 = 0x0011,
ECT_INTEGER64 = 0x0015,
ECT_UNSIGNED24 = 0x0016,
ECT_UNSIGNED64 = 0x001B,
ECT_BIT1 = 0x0030,
ECT_BIT2 = 0x0031,
ECT_BIT3 = 0x0032,
ECT_BIT4 = 0x0033,
ECT_BIT5 = 0x0034,
ECT_BIT6 = 0x0035,
ECT_BIT7 = 0x0036,
ECT_BIT8 = 0x0037
} ec_datatype;
/** Ethercat command types */
typedef enum
{
/** No operation */
EC_CMD_NOP = 0x00,
/** Auto Increment Read */
EC_CMD_APRD,
/** Auto Increment Write */
EC_CMD_APWR,
/** Auto Increment Read Write */
EC_CMD_APRW,
/** Configured Address Read */
EC_CMD_FPRD,
/** Configured Address Write */
EC_CMD_FPWR,
/** Configured Address Read Write */
EC_CMD_FPRW,
/** Broadcast Read */
EC_CMD_BRD,
/** Broadcast Write */
EC_CMD_BWR,
/** Broadcast Read Write */
EC_CMD_BRW,
/** Logical Memory Read */
EC_CMD_LRD,
/** Logical Memory Write */
EC_CMD_LWR,
/** Logical Memory Read Write */
EC_CMD_LRW,
/** Auto Increment Read Multiple Write */
EC_CMD_ARMW,
/** Configured Read Multiple Write */
EC_CMD_FRMW
/** Reserved */
} ec_cmdtype;
/** Ethercat EEprom command types */
typedef enum
{
/** No operation */
EC_ECMD_NOP = 0x0000,
/** Read */
EC_ECMD_READ = 0x0100,
/** Write */
EC_ECMD_WRITE = 0x0201,
/** Reload */
EC_ECMD_RELOAD = 0x0300
} ec_ecmdtype;
/** EEprom state machine read size */
#define EC_ESTAT_R64 0x0040
/** EEprom state machine busy flag */
#define EC_ESTAT_BUSY 0x8000
/** EEprom state machine error flag mask */
#define EC_ESTAT_EMASK 0x7800
/** EEprom state machine error acknowledge */
#define EC_ESTAT_NACK 0x2000
/* Ethercat SSI (Slave Information Interface) */
/** Start address SII sections in Eeprom */
#define ECT_SII_START 0x0040
enum
{
/** SII category strings */
ECT_SII_STRING = 10,
/** SII category general */
ECT_SII_GENERAL = 30,
/** SII category FMMU */
ECT_SII_FMMU = 40,
/** SII category SM */
ECT_SII_SM = 41,
/** SII category PDO */
ECT_SII_PDO = 50
};
/** Item offsets in SII general section */
enum
{
ECT_SII_MANUF = 0x0008,
ECT_SII_ID = 0x000a,
ECT_SII_REV = 0x000c,
ECT_SII_SER = 0x000e,
ECT_SII_BOOTRXMBX = 0x0014,
ECT_SII_BOOTTXMBX = 0x0016,
ECT_SII_MBXSIZE = 0x0019,
ECT_SII_TXMBXADR = 0x001a,
ECT_SII_RXMBXADR = 0x0018,
ECT_SII_MBXPROTO = 0x001c
};
/** Mailbox types definitions */
enum
{
/** Error mailbox type */
ECT_MBXT_ERR = 0x00,
/** ADS over EtherCAT mailbox type */
ECT_MBXT_AOE,
/** Ethernet over EtherCAT mailbox type */
ECT_MBXT_EOE,
/** CANopen over EtherCAT mailbox type */
ECT_MBXT_COE,
/** File over EtherCAT mailbox type */
ECT_MBXT_FOE,
/** Servo over EtherCAT mailbox type */
ECT_MBXT_SOE,
/** Vendor over EtherCAT mailbox type */
ECT_MBXT_VOE = 0x0f
};
/** CoE mailbox types */
enum
{
ECT_COES_EMERGENCY = 0x01,
ECT_COES_SDOREQ,
ECT_COES_SDORES,
ECT_COES_TXPDO,
ECT_COES_RXPDO,
ECT_COES_TXPDO_RR,
ECT_COES_RXPDO_RR,
ECT_COES_SDOINFO
};
/** CoE SDO commands */
enum
{
ECT_SDO_DOWN_INIT = 0x21,
ECT_SDO_DOWN_EXP = 0x23,
ECT_SDO_DOWN_INIT_CA = 0x31,
ECT_SDO_UP_REQ = 0x40,
ECT_SDO_UP_REQ_CA = 0x50,
ECT_SDO_SEG_UP_REQ = 0x60,
ECT_SDO_ABORT = 0x80
};
/** CoE Object Description commands */
enum
{
ECT_GET_ODLIST_REQ = 0x01,
ECT_GET_ODLIST_RES = 0x02,
ECT_GET_OD_REQ = 0x03,
ECT_GET_OD_RES = 0x04,
ECT_GET_OE_REQ = 0x05,
ECT_GET_OE_RES = 0x06,
ECT_SDOINFO_ERROR = 0x07
};
/** FoE opcodes */
enum
{
ECT_FOE_READ = 0x01,
ECT_FOE_WRITE,
ECT_FOE_DATA,
ECT_FOE_ACK,
ECT_FOE_ERROR,
ECT_FOE_BUSY
};
/** SoE opcodes */
enum
{
ECT_SOE_READREQ = 0x01,
ECT_SOE_READRES,
ECT_SOE_WRITEREQ,
ECT_SOE_WRITERES,
ECT_SOE_NOTIFICATION,
ECT_SOE_EMERGENCY
};
/** Ethercat registers */
enum
{
ECT_REG_TYPE = 0x0000,
ECT_REG_PORTDES = 0x0007,
ECT_REG_ESCSUP = 0x0008,
ECT_REG_STADR = 0x0010,
ECT_REG_ALIAS = 0x0012,
ECT_REG_DLCTL = 0x0100,
ECT_REG_DLPORT = 0x0101,
ECT_REG_DLALIAS = 0x0103,
ECT_REG_DLSTAT = 0x0110,
ECT_REG_ALCTL = 0x0120,
ECT_REG_ALSTAT = 0x0130,
ECT_REG_ALSTATCODE = 0x0134,
ECT_REG_PDICTL = 0x0140,
ECT_REG_IRQMASK = 0x0200,
ECT_REG_RXERR = 0x0300,
ECT_REG_FRXERR = 0x0308,
ECT_REG_EPUECNT = 0x030C,
ECT_REG_PECNT = 0x030D,
ECT_REG_PECODE = 0x030E,
ECT_REG_LLCNT = 0x0310,
ECT_REG_WDCNT = 0x0442,
ECT_REG_EEPCFG = 0x0500,
ECT_REG_EEPCTL = 0x0502,
ECT_REG_EEPSTAT = 0x0502,
ECT_REG_EEPADR = 0x0504,
ECT_REG_EEPDAT = 0x0508,
ECT_REG_FMMU0 = 0x0600,
ECT_REG_FMMU1 = ECT_REG_FMMU0 + 0x10,
ECT_REG_FMMU2 = ECT_REG_FMMU1 + 0x10,
ECT_REG_FMMU3 = ECT_REG_FMMU2 + 0x10,
ECT_REG_SM0 = 0x0800,
ECT_REG_SM1 = ECT_REG_SM0 + 0x08,
ECT_REG_SM2 = ECT_REG_SM1 + 0x08,
ECT_REG_SM3 = ECT_REG_SM2 + 0x08,
ECT_REG_SM0STAT = ECT_REG_SM0 + 0x05,
ECT_REG_SM1STAT = ECT_REG_SM1 + 0x05,
ECT_REG_SM1ACT = ECT_REG_SM1 + 0x06,
ECT_REG_SM1CONTR = ECT_REG_SM1 + 0x07,
ECT_REG_DCTIME0 = 0x0900,
ECT_REG_DCTIME1 = 0x0904,
ECT_REG_DCTIME2 = 0x0908,
ECT_REG_DCTIME3 = 0x090C,
ECT_REG_DCSYSTIME = 0x0910,
ECT_REG_DCSOF = 0x0918,
ECT_REG_DCSYSOFFSET = 0x0920,
ECT_REG_DCSYSDELAY = 0x0928,
ECT_REG_DCSYSDIFF = 0x092C,
ECT_REG_DCSPEEDCNT = 0x0930,
ECT_REG_DCTIMEFILT = 0x0934,
ECT_REG_DCCUC = 0x0980,
ECT_REG_DCSYNCACT = 0x0981,
ECT_REG_DCSTART0 = 0x0990,
ECT_REG_DCCYCLE0 = 0x09A0,
ECT_REG_DCCYCLE1 = 0x09A4
};
/** standard SDO Sync Manager Communication Type */
#define ECT_SDO_SMCOMMTYPE 0x1c00
/** standard SDO PDO assignment */
#define ECT_SDO_PDOASSIGN 0x1c10
/** standard SDO RxPDO assignment */
#define ECT_SDO_RXPDOASSIGN 0x1c12
/** standard SDO TxPDO assignment */
#define ECT_SDO_TXPDOASSIGN 0x1c13
/** Ethercat packet type */
#define ETH_P_ECAT 0x88A4
/** Error types */
typedef enum
{
EC_ERR_TYPE_SDO_ERROR = 0,
EC_ERR_TYPE_EMERGENCY = 1,
EC_ERR_TYPE_PACKET_ERROR = 3,
EC_ERR_TYPE_SDOINFO_ERROR = 4,
EC_ERR_TYPE_FOE_ERROR = 5,
EC_ERR_TYPE_FOE_BUF2SMALL = 6,
EC_ERR_TYPE_FOE_PACKETNUMBER = 7,
EC_ERR_TYPE_SOE_ERROR = 8,
EC_ERR_TYPE_MBX_ERROR = 9,
EC_ERR_TYPE_FOE_FILE_NOTFOUND = 10,
EC_ERR_TYPE_EOE_INVALID_RX_DATA = 11
} ec_err_type;
/** Struct to retrieve errors. */
typedef struct
{
/** Time at which the error was generated. */
ec_timet Time;
/** Signal bit, error set but not read */
boolean Signal;
/** Slave number that generated the error */
uint16 Slave;
/** CoE SDO index that generated the error */
uint16 Index;
/** CoE SDO subindex that generated the error */
uint8 SubIdx;
/** Type of error */
ec_err_type Etype;
union
{
/** General abortcode */
int32 AbortCode;
/** Specific error for Emergency mailbox */
struct
{
uint16 ErrorCode;
uint8 ErrorReg;
uint8 b1;
uint16 w1;
uint16 w2;
};
};
} ec_errort;
/** Helper macros */
/** Set the count value in the Mailbox header */
#define MBX_HDR_SET_CNT(cnt) ((uint8)((cnt) << 4))
/** Macro to make a word from 2 bytes */
#define MK_WORD(msb, lsb) ((((uint16)(msb)) << 8) | (lsb))
/** Macro to get hi byte of a word */
#define HI_BYTE(w) ((w) >> 8)
/** Macro to get low byte of a word */
#define LO_BYTE(w) ((w) & 0x00ff)
/** Macro to swap hi and low byte of a word */
#define SWAP(w) ((((w) & 0xff00) >> 8) | (((w) & 0x00ff) << 8))
/** Macro to get hi word of a dword */
#define LO_WORD(l) ((l) & 0xffff)
/** Macro to get hi word of a dword */
#define HI_WORD(l) ((l) >> 16)
#define get_unaligned(ptr) \
({ __typeof__(*(ptr)) __tmp; memcpy(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
#define put_unaligned32(val, ptr) \
(memcpy((ptr), &(val), 4))
#define put_unaligned64(val, ptr) \
(memcpy((ptr), &(val), 8))
#if !defined(EC_BIG_ENDIAN) && defined(EC_LITTLE_ENDIAN)
#define htoes(A) (A)
#define htoel(A) (A)
#define htoell(A) (A)
#define etohs(A) (A)
#define etohl(A) (A)
#define etohll(A) (A)
#elif !defined(EC_LITTLE_ENDIAN) && defined(EC_BIG_ENDIAN)
#define htoes(A) ((((uint16)(A) & 0xff00) >> 8) | \
(((uint16)(A) & 0x00ff) << 8))
#define htoel(A) ((((uint32)(A) & 0xff000000) >> 24) | \
(((uint32)(A) & 0x00ff0000) >> 8) | \
(((uint32)(A) & 0x0000ff00) << 8) | \
(((uint32)(A) & 0x000000ff) << 24))
#define htoell(A) ((((uint64)(A) & (uint64)0xff00000000000000ULL) >> 56) | \
(((uint64)(A) & (uint64)0x00ff000000000000ULL) >> 40) | \
(((uint64)(A) & (uint64)0x0000ff0000000000ULL) >> 24) | \
(((uint64)(A) & (uint64)0x000000ff00000000ULL) >> 8) | \
(((uint64)(A) & (uint64)0x00000000ff000000ULL) << 8) | \
(((uint64)(A) & (uint64)0x0000000000ff0000ULL) << 24) | \
(((uint64)(A) & (uint64)0x000000000000ff00ULL) << 40) | \
(((uint64)(A) & (uint64)0x00000000000000ffULL) << 56))
#define etohs htoes
#define etohl htoel
#define etohll htoell
#else
#error "Must define one of EC_BIG_ENDIAN or EC_LITTLE_ENDIAN"
#endif
#ifdef __cplusplus
}
#endif
#endif /* _EC_TYPE_H */

View File

@ -1,108 +0,0 @@
/*
* This software is dual-licensed under GPLv3 and a commercial
* license. See the file LICENSE.md distributed with this software for
* full license information.
*/
/** \file
* \brief
* Headerfile for nicdrv.c
*/
#ifndef _nicdrvh_
#define _nicdrvh_
#ifdef __cplusplus
extern "C" {
#endif
#include <pthread.h>
/** pointer structure to Tx and Rx stacks */
typedef struct
{
/** socket connection used */
int *sock;
/** tx buffer */
ec_bufT (*txbuf)[EC_MAXBUF];
/** tx buffer lengths */
int (*txbuflength)[EC_MAXBUF];
/** temporary receive buffer */
ec_bufT *tempbuf;
/** rx buffers */
ec_bufT (*rxbuf)[EC_MAXBUF];
/** rx buffer status fields */
int (*rxbufstat)[EC_MAXBUF];
/** received MAC source address (middle word) */
int (*rxsa)[EC_MAXBUF];
/** number of received frames */
uint64 rxcnt;
} ec_stackT;
/** pointer structure to buffers for redundant port */
typedef struct
{
ec_stackT stack;
int sockhandle;
/** rx buffers */
ec_bufT rxbuf[EC_MAXBUF];
/** rx buffer status */
int rxbufstat[EC_MAXBUF];
/** rx MAC source address */
int rxsa[EC_MAXBUF];
/** temporary rx buffer */
ec_bufT tempinbuf;
} ecx_redportt;
/** pointer structure to buffers, vars and mutexes for port instantiation */
typedef struct
{
ec_stackT stack;
int sockhandle;
/** rx buffers */
ec_bufT rxbuf[EC_MAXBUF];
/** rx buffer status */
int rxbufstat[EC_MAXBUF];
/** rx MAC source address */
int rxsa[EC_MAXBUF];
/** temporary rx buffer */
ec_bufT tempinbuf;
/** temporary rx buffer status */
int tempinbufs;
/** transmit buffers */
ec_bufT txbuf[EC_MAXBUF];
/** transmit buffer lengths */
int txbuflength[EC_MAXBUF];
/** temporary tx buffer */
ec_bufT txbuf2;
/** temporary tx buffer length */
int txbuflength2;
/** last used frame index */
uint8 lastidx;
/** current redundancy state */
int redstate;
/** pointer to redundancy port and buffers */
ecx_redportt *redport;
pthread_mutex_t getindex_mutex;
pthread_mutex_t tx_mutex;
pthread_mutex_t rx_mutex;
} ecx_portt;
extern const uint16 priMAC[3];
extern const uint16 secMAC[3];
void ec_setupheader(void *p);
int ecx_setupnic(ecx_portt *port, const char *ifname, int secondary);
int ecx_closenic(ecx_portt *port);
void ecx_setbufstat(ecx_portt *port, uint8 idx, int bufstat);
uint8 ecx_getindex(ecx_portt *port);
int ecx_outframe(ecx_portt *port, uint8 idx, int sock);
int ecx_outframe_red(ecx_portt *port, uint8 idx);
int ecx_waitinframe(ecx_portt *port, uint8 idx, int timeout);
int ecx_srconfirm(ecx_portt *port, uint8 idx, int timeout);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,222 +0,0 @@
/*
* This software is dual-licensed under GPLv3 and a commercial
* license. See the file LICENSE.md distributed with this software for
* full license information.
*/
#ifndef _osal_
#define _osal_
#ifdef __cplusplus
extern "C" {
#endif
#include "osal_defs.h"
#include <stdint.h>
#include <stddef.h>
/* General types */
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
typedef uint8_t boolean;
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef int64_t int64;
typedef uint64_t uint64;
typedef float float32;
typedef double float64;
typedef struct osal_timer
{
ec_timet stop_time;
} osal_timert;
/**
* @brief Returns monotonic time from some unspecified moment in the
* past.
*
* This time must be strictly increasing. It is used for time
* intervals measurement.
*
* @param ts Pointer to an ec_timet structure where the time will be
* stored.
*/
void osal_get_monotonic_time(ec_timet *ts);
/**
* @brief Returns the current time.
*
* This time is used to set the initial EtherCAT network DC time and
* for logging purposes.
*
* @return ec_timet containing the current time.
*/
ec_timet osal_current_time(void);
/**
* @brief Calculates the difference between two timestamps.
*
* @param start Pointer to the start timestamp.
* @param end Pointer to the end timestamp.
* @param diff Pointer to an ec_timet structure where the difference
* will be stored.
*/
void osal_time_diff(ec_timet *start, ec_timet *end, ec_timet *diff);
/**
* @brief Starts the timer with a specified timeout.
*
* @param self Pointer to the timer object.
* @param timeout_usec Timeout in microseconds.
*/
void osal_timer_start(osal_timert *self, uint32 timeout_usec);
/**
* @brief Checks if the timer has expired.
*
* @param self Pointer to the timer object.
* @return True if the timer is expired, false otherwise.
*/
boolean osal_timer_is_expired(osal_timert *self);
/**
* @brief Sleeps for a specified duration in microseconds.
*
* @param usec Duration in microseconds.
* @return 0 on success, -1 on failure.
*/
int osal_usleep(uint32 usec);
/**
* @brief Sleeps until the specified monotonic time.
*
* @param ts Pointer to an ec_timet structure representing the
* absolute time to sleep until.
* @return 0 on success, -1 on failure.
*/
int osal_monotonic_sleep(ec_timet *ts);
/**
* @brief Allocates memory of the specified size.
*
* @param size Size in bytes to allocate.
* @return Pointer to the allocated memory or NULL on failure.
*/
void *osal_malloc(size_t size);
/**
* @brief Frees the allocated memory.
*
* @param ptr Pointer to the memory to free.
*/
void osal_free(void *ptr);
/**
* @brief Creates a new thread.
*
* @param thandle Pointer to the thread handle which will store the
* thread ID.
* @param stacksize Size of the stack for the new thread.
* @param func Pointer to the function to execute in the new thread.
* @param param Pointer to parameters to pass to the thread function.
* @return 1 on success, 0 on failure.
*/
int osal_thread_create(void *thandle, int stacksize, void *func, void *param);
/**
* @brief Creates a new real-time thread.
*
* @param thandle Pointer to the thread handle which will store the
* thread ID.
* @param stacksize Size of the stack for the new thread.
* @param func Pointer to the function to execute in the new thread.
* @param param Pointer to parameters to pass to the thread function.
* @return 1 on success, 0 on failure.
*/
int osal_thread_create_rt(void *thandle, int stacksize, void *func, void *param);
/**
* @brief Creates a mutex.
*
* @return Pointer to the created mutex or NULL on failure.
*/
void *osal_mutex_create(void);
/**
* @brief Destroys a mutex.
*
* @param mutex Pointer to the mutex to destroy.
*/
void osal_mutex_destroy(void *mutex);
/**
* @brief Locks the mutex.
*
* @param mutex Pointer to the mutex to lock.
*/
void osal_mutex_lock(void *mutex);
/**
* @brief Unlocks the mutex.
*
* @param mutex Pointer to the mutex to unlock.
*/
void osal_mutex_unlock(void *mutex);
#ifndef osal_timespec_from_usec
#define osal_timespec_from_usec(usec, result) \
do \
{ \
(result)->tv_sec = usec / 1000000; \
(result)->tv_nsec = (usec % 1000000) * 1000; \
} while (0)
#endif
#ifndef osal_timespeccmp
#define osal_timespeccmp(a, b, CMP) \
(((a)->tv_sec == (b)->tv_sec) \
? ((a)->tv_nsec CMP(b)->tv_nsec) \
: ((a)->tv_sec CMP(b)->tv_sec))
#endif
#ifndef osal_timespecadd
#define osal_timespecadd(a, b, result) \
do \
{ \
(result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
(result)->tv_nsec = (a)->tv_nsec + (b)->tv_nsec; \
if ((result)->tv_nsec >= 1000000000) \
{ \
++(result)->tv_sec; \
(result)->tv_nsec -= 1000000000; \
} \
} while (0)
#endif
#ifndef osal_timespecsub
#define osal_timespecsub(a, b, result) \
do \
{ \
(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
(result)->tv_nsec = (a)->tv_nsec - (b)->tv_nsec; \
if ((result)->tv_nsec < 0) \
{ \
--(result)->tv_sec; \
(result)->tv_nsec += 1000000000; \
} \
} while (0)
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,46 +0,0 @@
/*
* This software is dual-licensed under GPLv3 and a commercial
* license. See the file LICENSE.md distributed with this software for
* full license information.
*/
#ifndef _osal_defs_
#define _osal_defs_
#ifdef __cplusplus
extern "C" {
#endif
#include <pthread.h>
#include <sys/time.h>
// define if debug printf is needed
#ifdef EC_DEBUG
#include <stdio.h>
#define EC_PRINT printf
#else
#define EC_PRINT(...) \
do \
{ \
} while (0)
#endif
#ifndef OSAL_PACKED
#define OSAL_PACKED_BEGIN
#define OSAL_PACKED __attribute__((__packed__))
#define OSAL_PACKED_END
#endif
#define ec_timet struct timespec
#define OSAL_THREAD_HANDLE pthread_t *
#define OSAL_THREAD_FUNC void
#define OSAL_THREAD_FUNC_RT void
#define osal_mutext pthread_mutex_t
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,28 +0,0 @@
/*
* This software is dual-licensed under GPLv3 and a commercial
* license. See the file LICENSE.md distributed with this software for
* full license information.
*/
/** \file
* \brief
* SOEM main include file
*/
#ifndef _SOEM_H
#define _SOEM_H
#include "soem/ec_options.h"
#include "soem/ec_type.h"
#include "nicdrv.h"
#include "soem/ec_base.h"
#include "soem/ec_main.h"
#include "soem/ec_dc.h"
#include "soem/ec_coe.h"
#include "soem/ec_foe.h"
#include "soem/ec_soe.h"
#include "soem/ec_eoe.h"
#include "soem/ec_config.h"
#include "soem/ec_print.h"
#endif /* _SOEM_H */

Binary file not shown.

View File

@ -1,906 +0,0 @@
/**
* @file agv_command.proto
* @brief AGV Protobuf
* SeerSRC API
*
* @note gRPC AgvService
*/
syntax = "proto3";
import "cmvr/api/common.proto";
package cmvr.api;
// ============================================================================
// 1. 1000, 0x03E8
// ============================================================================
/**
* @brief AGV
* @note API 10000x03E8
*/
message AgvStatusInfo {
optional string id = 1; ///< AGV ID
optional string vehicle_id = 2; ///< "agv_001"
optional string version = 3; ///<
optional string model = 4; ///< "SRC-1100"
optional string dsp_version = 5; ///< DSP
optional string current_ip = 6; ///< IP
optional string mac = 7; ///< MAC
optional int32 rssi = 8; ///< Wi-Fi 0~100
optional int32 ret_code = 9; ///< 0
optional string err_msg = 10; ///<
}
/**
* @brief AGV /
* @note IDheader.device_id AgvStatusInfo
*/
message GetAgvStatusInfoCommand {
message Request {
CommandHeader.Request header = 1; ///< device_id
}
message Feedback {
CommandHeader.Feedback header = 1; ///< success/error_message/timestamp
AgvStatusInfo status = 2; ///< AGV
}
}
// ============================================================================
// 2. 1007, 0x03EF
// ============================================================================
/**
* @brief
* @note API 10070x03EF/
*/
message AgvBatteryStatus {
optional double battery_level = 1; ///< 0~1 0%~100%
optional double battery_temp = 2; ///<
optional bool charging = 3; ///<
optional double voltage = 4; ///< V
optional double current = 5; ///< A
optional double max_charge_voltage = 6; ///< -1
optional double max_charge_current = 7; ///< -1
optional bool manual_charge = 8; ///< SRC-2000
optional bool auto_charge = 9; ///< SRC-2000
optional int32 battery_cycle = 10; ///< BMS
optional string battery_user_data = 11; ///<
optional string extra = 12; ///<
optional int32 ret_code = 13; ///< 0
optional string create_on = 14; ///< ISO 8601
optional string err_msg = 15; ///<
}
/**
* @brief
*/
message RobotStatusBatteryRequestData {
optional bool simple = 1; ///< true=false= false
}
/**
* @brief
*/
message RobotStatusBatteryCommand {
message Request {
CommandHeader.Request header = 1; ///<
RobotStatusBatteryRequestData data = 2; ///<
}
message Feedback {
CommandHeader.Feedback header = 1; ///<
AgvBatteryStatus status = 2; ///<
}
}
// ============================================================================
// 3. 1004, 0x03EC
// ============================================================================
/**
* @brief
* @note API 10040x03EC姿
*/
message AgvRobotLocation {
optional double x = 1; ///< X
optional double y = 2; ///< Y
optional double angle = 3; ///<
optional double confidence = 4; ///< 0~1
optional string current_station = 5; ///< ID
optional string last_station = 6; ///< ID
optional int32 loc_method = 7; ///< 0=, 1=, 2=, 3=...
optional int32 ret_code = 8; ///< 0
optional string create_on = 9; ///<
optional string err_msg = 10; ///<
}
/**
* @brief
*/
message RobotStatusLocCommand {
message Request {
CommandHeader.Request header = 1; ///<
}
message Feedback {
CommandHeader.Feedback header = 1; ///<
AgvRobotLocation status = 2; ///<
}
}
// ============================================================================
// 4. 4011, 0x0FAB
// ============================================================================
/**
* @brief
*/
message RobotConfigDownloadMapRequestData {
optional string map_name = 1; ///<
}
/**
* @brief
*/
message AgvDownloadMapResult {
optional int32 ret_code = 1; ///< 0
optional string create_on = 2; ///<
optional string err_msg = 3; ///<
optional string map_content = 4; ///< JSON
}
/**
* @brief
*/
message RobotConfigDownloadMapCommand {
message Request {
CommandHeader.Request header = 1;
RobotConfigDownloadMapRequestData data = 2;
}
message Feedback {
CommandHeader.Feedback header = 1;
AgvDownloadMapResult status = 2;
}
}
// ============================================================================
// 5. 1300, 0x0514
// ============================================================================
/**
* @brief
*/
message MapFileInfo {
optional string name = 1; ///<
optional string modified = 2; ///<
optional int64 size = 3; ///<
}
/**
* @brief
* @note API 13000x0514
*/
message AgvMapStatus {
optional string current_map = 1; ///<
optional string current_map_md5 = 2; ///< MD5
repeated string maps = 3; ///<
repeated MapFileInfo map_files_info = 4; ///<
optional int32 ret_code = 5; ///< 0
optional string create_on = 6; ///<
optional string err_msg = 7; ///<
}
/**
* @brief
*/
message RobotStatusMapCommand {
message Request {
CommandHeader.Request header = 1;
}
message Feedback {
CommandHeader.Feedback header = 1;
AgvMapStatus status = 2;
}
}
// ============================================================================
// 6. 4010, 0x0FAA
// ============================================================================
/**
* @brief
*/
message RobotConfigUploadMapRequestData {
optional string map_content = 1; ///< JSON
}
/**
* @brief
*/
message AgvUploadMapResult {
optional int32 ret_code = 1; ///< 0
optional string create_on = 2; ///<
optional string err_msg = 3; ///<
}
/**
* @brief
*/
message RobotConfigUploadMapCommand {
message Request {
CommandHeader.Request header = 1;
RobotConfigUploadMapRequestData data = 2;
}
message Feedback {
CommandHeader.Feedback header = 1;
AgvUploadMapResult status = 2;
}
}
// ============================================================================
// 7. 4005, 0x0FA5
// ============================================================================
/**
* @brief
*/
message RobotConfigLockRequestData {
optional string nick_name = 1; ///< /
}
/**
* @brief
*/
message AgvLockResult {
optional int32 ret_code = 1; ///< 0
optional string create_on = 2; ///<
optional string err_msg = 3; ///<
}
/**
* @brief
*/
message RobotConfigLockCommand {
message Request {
CommandHeader.Request header = 1;
RobotConfigLockRequestData data = 2;
}
message Feedback {
CommandHeader.Feedback header = 1;
AgvLockResult status = 2;
}
}
// ============================================================================
// 8. 1060, 0x0424
// ============================================================================
/**
* @brief
* @note API 10600x0424
*/
message AgvCurrentLockStatus {
optional bool locked = 1; ///<
optional string ip = 2; ///< IP
optional int32 port = 3; ///<
optional uint32 type = 4; ///< 0=default, 2=roboshop, 0xDD=srd
optional string nick_name = 5; ///<
optional int64 time_t = 6; ///< Unix
optional string desc = 7; ///<
optional int32 ret_code = 8; ///< 0
optional string create_on = 9; ///<
optional string err_msg = 10; ///<
}
/**
* @brief
*/
message RobotStatusCurrentLockCommand {
message Request {
CommandHeader.Request header = 1;
}
message Feedback {
CommandHeader.Feedback header = 1;
AgvCurrentLockStatus status = 2;
}
}
// ============================================================================
// 9. 2010, 0x07DA
// ============================================================================
/**
* @brief
* @note 20100x07DA
* vx/vy/w steer/real_steer
* duration = -1
*/
message RobotMotionControlRequestData {
optional double vx = 1; ///< X 线m/s
optional double vy = 2; ///< Y 线m/s
optional double w = 3; ///< rad/s
optional double steer = 4; ///< rad
optional double real_steer = 5; ///< steer
optional int64 duration = 6; ///< ms-1
}
/**
* @brief
*/
message RobotMotionControlResult {
optional int32 ret_code = 1; ///< 0
optional string create_on = 2; ///<
optional string err_msg = 3; ///<
}
/**
* @brief
*/
message RobotMotionControlCommand {
message Request {
CommandHeader.Request header = 1;
RobotMotionControlRequestData data = 2;
}
message Feedback {
CommandHeader.Feedback header = 1;
RobotMotionControlResult status = 2;
}
}
// ============================================================================
// 10. 2022, 0x07E6
// ============================================================================
/**
* @brief
* @note 20220x07E6
*/
message RobotLoadMapRequestData {
optional string map_name = 1; ///< -_
}
/**
* @brief
*/
message RobotLoadMapResult {
optional int32 ret_code = 1; ///< 0
optional string create_on = 2; ///<
optional string err_msg = 3; ///<
}
/**
* @brief
*/
message RobotLoadMapCommand {
message Request {
CommandHeader.Request header = 1;
RobotLoadMapRequestData data = 2;
}
message Feedback {
CommandHeader.Feedback header = 1;
RobotLoadMapResult status = 2;
}
}
// ============================================================================
// 11. 1022, 0x03FE
// ============================================================================
/**
* @brief
* @note 10220x03FEloadmap_status: 0=, 1=, 2=
* 2
*/
message RobotQueryLoadMapStatusResult {
optional int32 loadmap_status = 1; ///< 0=, 1=, 2=
optional int32 ret_code = 2; ///< 0
optional string create_on = 3; ///<
optional string err_msg = 4; ///<
}
/**
* @brief
*/
message RobotQueryLoadMapStatusCommand {
message Request {
CommandHeader.Request header = 1;
}
message Feedback {
CommandHeader.Feedback header = 1;
RobotQueryLoadMapStatusResult status = 2;
}
}
// ============================================================================
// 12. 1301, 0x0515
// ============================================================================
/**
* @brief
*/
message StationItem {
optional string id = 1; ///< ID
optional string type = 2; ///< "LocationMark", "ChargePoint"
optional double x = 3; ///< X
optional double y = 4; ///< Y
optional double r = 5; ///<
optional string desc = 6; ///<
optional string executor = 7; ///<
optional string prepoint = 8; ///< ID
optional string recfile = 9; ///<
optional bool spin = 10; ///<
optional bool use_down_pgv = 11; ///< 使 PGV
}
/**
* @brief
*/
message QueryStationListResult {
repeated StationItem stations = 1; ///<
optional int32 ret_code = 2; ///< 0
optional string create_on = 3; ///<
optional string err_msg = 4; ///<
}
/**
* @brief
*/
message QueryStationListCommand {
message Request {
CommandHeader.Request header = 1;
}
message Feedback {
CommandHeader.Feedback header = 1;
QueryStationListResult status = 2;
}
}
// ============================================================================
// 13. 3066, 0x0BFA
// ============================================================================
/**
* @brief
* @note 3066 move_task_list
* source_id id
*/
message MoveTaskItem {
optional string task_id = 1; ///< ID
optional string source_id = 2; ///< ID
optional string id = 3; ///< ID
optional string operation = 4; ///< "JackLoad"
optional double jack_height = 5; ///<
}
/**
* @brief
*/
message RobotGoTargetListRequestData {
repeated MoveTaskItem move_task_list = 1; ///<
}
/**
* @brief
* @note ret_code=0
*/
message RobotGoTargetListResult {
optional int32 ret_code = 1; ///< 0
optional string create_on = 2; ///<
optional string err_msg = 3; ///<
}
/**
* @brief
*/
message RobotGoTargetListCommand {
message Request {
CommandHeader.Request header = 1;
RobotGoTargetListRequestData data = 2;
}
message Feedback {
CommandHeader.Feedback header = 1;
RobotGoTargetListResult status = 2;
}
}
// ============================================================================
// 14. 1020, 0x03FC
// ============================================================================
/**
* @brief 1020
*/
message RobotStatusTaskReqData {
optional bool simple = 1; ///< true= task_statusfalse=
}
/**
* @brief
*/
message NavContainerItem {
optional string container_name = 1; ///<
optional string desc = 2; ///<
optional string goods_id = 3; ///< ID
optional bool has_goods = 4; ///<
}
/**
* @brief 1020
*/
message RobotStatusTaskResData {
optional int32 task_status = 1; ///< 0=NONE, 1=WAITING, 2=RUNNING, 3=SUSPENDED, 4=COMPLETED, 5=FAILED, 6=CANCELED
optional int32 task_type = 2; ///< 0=, 1=, 2=, 3=, 7=
optional string target_id = 3; ///< IDtask_type 2/3
repeated double target_point = 4; ///< [x, y, r]task_type 1
repeated string finished_path = 5; ///<
repeated string unfinished_path = 6; ///<
optional string move_status_info = 7; ///<
repeated NavContainerItem containers = 8; ///<
optional int32 ret_code = 9; ///< 0
optional string create_on = 10; ///<
optional string err_msg = 11; ///<
}
/**
* @brief
*/
message RobotStatusTaskCurrentCommand {
message Request {
CommandHeader.Request header = 1;
RobotStatusTaskReqData data = 2;
}
message Feedback {
CommandHeader.Feedback header = 1;
RobotStatusTaskResData data = 2;
}
}
// ============================================================================
// 15. 1110, 0x0456
// ============================================================================
/**
* @brief 1110
*/
message QueryTaskStatusPackageReqData {
repeated string task_ids = 1; ///< ID +
}
/**
* @brief
*/
message SingleTaskStatusItem {
optional string task_id = 1; ///< ID
optional int32 status = 2; ///< task_status
optional int32 type = 3; ///< task_type
}
/**
* @brief
*/
message TaskStatusPackage {
optional string closest_target = 1; ///< ID
optional string source_name = 2; ///<
optional string target_name = 3; ///<
optional double percentage = 4; ///< 0~100
optional double distance = 5; ///<
optional string info = 6; ///<
repeated SingleTaskStatusItem task_status_list = 7; ///<
}
/**
* @brief 1110
*/
message QueryTaskStatusPackageResData {
optional TaskStatusPackage task_status_package = 1; ///<
optional int32 ret_code = 2; ///< 0
optional string create_on = 3; ///<
optional string err_msg = 4; ///<
}
/**
* @brief
*/
message RobotStatusTaskPackageCommand {
message Request {
CommandHeader.Request header = 1;
QueryTaskStatusPackageReqData data = 2;
}
message Feedback {
CommandHeader.Feedback header = 1;
QueryTaskStatusPackageResData data = 2;
}
}
// ============================================================================
// 16. 3051, 0x0BEB
// ============================================================================
/**
* @brief DI
*/
message DIItem {
int32 id = 1; ///< DI
bool status = 2; ///< true=, false=
}
/**
* @brief DO
*/
message DOItem {
int32 id = 1; ///< DO
bool status = 2; ///< true=, false=
}
/**
* @brief
*/
message SoundArgs {
optional string name = 1; ///<
optional int32 loop = 2; ///< 0=, 1=
optional int32 stop = 3; ///< 1=
}
/**
* @brief WaitDI
*/
message WaitDIArgs {
repeated DIItem DI = 1; ///< DI
optional double timeout = 2; ///< 0
}
/**
* @brief SetDO
*/
message SetDOArgs {
repeated DOItem do_list = 1; ///< DO
}
/**
* @brief PGV
*/
message PgvParam {
optional bool use_pgv = 1; ///< 使 PGV
optional bool use_down_pgv = 2; ///< 使 PGV
optional double pgv_adjust_dist = 3; ///<
optional double pgv_adjust_cx = 4; ///< X
optional double pgv_adjust_cy = 5; ///< Y
optional double pgv_x_adjust = 6; ///< X
}
/**
* @brief +
*/
message FreeGoPoint {
double x = 1; ///< X
double y = 2; ///< Y
double theta = 3; ///<
}
/**
* @brief
*/
message ScriptArgs {
map<string, string> str_kv = 1; ///<
map<string, double> num_kv = 2; ///<
repeated DOItem do_list = 3; ///< DO
repeated DIItem di_list = 4; ///< DI
}
/**
* @brief 3051
* @warning /
*
* warning/error
* freego
*/
message RobotGoTargetReqData {
// -------- --------
string source_id = 1; ///< ID"SELF_POSITION"
string id = 2; ///< ID"SELF_POSITION" operation
optional string task_id = 3; ///< ID
// -------- --------
optional double angle = 4; ///<
optional string method = 5; ///< "forward" "backward"
optional double max_speed = 6; ///< 线m/s0 使
optional double max_wspeed = 7; ///< rad/s
optional double max_acc = 8; ///< m/s²
optional double max_wacc = 9; ///< rad/s²
optional int64 duration = 10; ///<
optional int32 orientation = 11; ///< 使
optional bool spin = 12; ///<
optional int64 delay = 13; ///< 0
optional int32 start_rot_dir = 14; ///< -1=, 0=, 1=
optional int32 end_rot_dir = 15; ///< -1=, 0=, 1=
optional double reach_dist = 16; ///<
optional double reach_angle = 17; ///<
optional string skill_name = 18; ///< "Action" "GotoSpecifiedPose"
// -------- PGV --------
optional PgvParam pgv = 19; ///<
// -------- --------
optional string operation = 20; ///< JackLoad/ForkUnload/RollerLoad/HookLoad/WaitDI/SetDO/sound/Script
optional double jack_height = 21; ///<
optional double start_height = 22; ///<
optional double end_height = 23; ///<
optional double fork_mid_height = 24; ///<
optional double fork_dist = 25; ///<
optional string direction = 26; ///< "left"/"right"/"front"/"back"
optional bool recognize = 27; ///<
optional string recfile = 28; ///< "shelf/s0002.shelf"
// -------- --------
optional SoundArgs sounds_args = 29; ///<
// -------- WaitDI / SetDO --------
optional WaitDIArgs wait_di_args = 30; ///< WaitDI
optional SetDOArgs set_do_args = 31; ///< SetDO
// -------- --------
optional string script_name = 32; ///<
optional ScriptArgs script_args = 33; ///<
optional int32 script_stage = 34; ///< 0=, 1=, 2=, 3=
// -------- GoByOdometer --------
optional double move_angle = 35; ///<
optional double speed_w = 36; ///< rad/s
optional int32 loc_mode = 37; ///< 1=, 0=
// -------- --------
optional FreeGoPoint freego = 38; ///< id
}
/**
* @brief 3051
*/
message RobotGoTargetResData {
optional int32 ret_code = 1; ///< 0
optional string create_on = 2; ///<
optional string err_msg = 3; ///<
}
/**
* @brief
*/
message RobotGoTargetCommand {
message Request {
CommandHeader.Request header = 1;
RobotGoTargetReqData data = 2;
}
message Feedback {
CommandHeader.Feedback header = 1;
RobotGoTargetResData data = 2;
}
}
// ============================================================================
// 17. 2000, 0x07D0
// ============================================================================
/**
* @brief
* @note 20000x07D0
*/
message RobotControlStopRequestData
{
}
/**
* @brief
*/
message RobotControlStopResult
{
optional int32 ret_code = 1; ///< 0
optional string create_on = 2; ///<
optional string err_msg = 3; ///<
}
/**
* @brief
*/
message RobotControlStopCommand
{
message Request
{
CommandHeader.Request header = 1;
RobotControlStopRequestData data = 2;
}
message Feedback
{
CommandHeader.Feedback header = 1;
RobotControlStopResult status = 2;
}
}
// ============================================================================
// 18. // 3001/3002/3003
// ============================================================================
/**
* @brief 3001, 0x0BB9
* @note
*/
message RobotTaskPauseCommand {
message Request {
CommandHeader.Request header = 1;
// data
}
message Feedback {
CommandHeader.Feedback header = 1;
/**
* @brief
*/
message Result {
optional int32 ret_code = 1; ///< 0
optional string create_on = 2; ///<
optional string err_msg = 3; ///<
}
Result status = 2;
}
}
/**
* @brief 3002, 0x0BBA
* @note
*/
message RobotTaskResumeCommand {
message Request {
CommandHeader.Request header = 1;
// data
}
message Feedback {
CommandHeader.Feedback header = 1;
/**
* @brief
*/
message Result {
optional int32 ret_code = 1; ///< 0
optional string create_on = 2; ///<
optional string err_msg = 3; ///<
}
Result status = 2;
}
}
/**
* @brief 3003, 0x0BBB
* @note
*/
message RobotTaskCancelCommand {
message Request {
CommandHeader.Request header = 1;
// data
}
message Feedback {
CommandHeader.Feedback header = 1;
/**
* @brief
*/
message Result {
optional int32 ret_code = 1; ///< 0
optional string create_on = 2; ///<
optional string err_msg = 3; ///<
}
Result status = 2;
}
}

View File

@ -1,74 +0,0 @@
/**
* @file agv_service.proto
* @brief AGV服务的gRPC接口AGV相关命令
* gRPCAGVServiceImpl
*/
syntax = "proto3";
import "cmvr/api/agv_command.proto";
package cmvr.api;
service AgvService {
//
rpc GetStatusInfo(GetAgvStatusInfoCommand.Request) returns (GetAgvStatusInfoCommand.Feedback);
rpc GetBatteryStatus(RobotStatusBatteryCommand.Request) returns (RobotStatusBatteryCommand.Feedback);
rpc GetRobotLocation(RobotStatusLocCommand.Request) returns (RobotStatusLocCommand.Feedback);
rpc RobotConfigDownloadMap(RobotConfigDownloadMapCommand.Request) returns (RobotConfigDownloadMapCommand.Feedback);
rpc GetMapStatus(RobotStatusMapCommand.Request) returns (RobotStatusMapCommand.Feedback);
rpc RobotConfigUploadMap(RobotConfigUploadMapCommand.Request) returns (RobotConfigUploadMapCommand.Feedback);
//
rpc RobotConfigLock(RobotConfigLockCommand.Request) returns (RobotConfigLockCommand.Feedback);
//
rpc GetCurrentLockStatus(RobotStatusCurrentLockCommand.Request) returns (RobotStatusCurrentLockCommand.Feedback);
//
rpc RobotMotionControl(RobotMotionControlCommand.Request) returns (RobotMotionControlCommand.Feedback);
// 2022
rpc RobotLoadMap(RobotLoadMapCommand.Request) returns (RobotLoadMapCommand.Feedback);
// 1022
rpc QueryLoadMapStatus(RobotQueryLoadMapStatusCommand.Request) returns (RobotQueryLoadMapStatusCommand.Feedback);
// 1301
rpc QueryStationList(QueryStationListCommand.Request) returns (QueryStationListCommand.Feedback);
// 3066
rpc RobotGoTargetList(RobotGoTargetListCommand.Request) returns (RobotGoTargetListCommand.Feedback);
// 1020 robot_status_task_req
// 1020 robot_status_task_req
rpc RobotStatusTaskCurrent(RobotStatusTaskCurrentCommand.Request) returns (RobotStatusTaskCurrentCommand.Feedback);
// 1110 robot_status_task_status_package_req
rpc RobotStatusTaskPackage(RobotStatusTaskPackageCommand.Request) returns (RobotStatusTaskPackageCommand.Feedback);
// 3051 robot_task_gotarget_req 0x0BEB
rpc RobotGoTarget(RobotGoTargetCommand.Request) returns (RobotGoTargetCommand.Feedback);
// 0x07D0
rpc RobotControlStop(RobotControlStopCommand.Request) returns (RobotControlStopCommand.Feedback);
// 3001 (0x0BB9)
rpc RobotTaskPause(RobotTaskPauseCommand.Request) returns (RobotTaskPauseCommand.Feedback);
// 3002 (0x0BBA)
rpc RobotTaskResume(RobotTaskResumeCommand.Request) returns (RobotTaskResumeCommand.Feedback);
// 3003 (0x0BBB)
rpc RobotTaskCancel(RobotTaskCancelCommand.Request) returns (RobotTaskCancelCommand.Feedback);
}

View File

@ -1,20 +0,0 @@
// camera_config.proto -
syntax = "proto3";
package cmvr.config;
message AGVsrc1100Config{
string id = 1;
string ip = 2;
bool enable = 3;
int32 port_status = 4; // 19204
int32 port_control = 5; // 19205 API
int32 port_nav = 6; // 19206 API
int32 port_config = 7; // 19207 API
int32 port_other = 8; // 19210 API
int32 port_push = 9; // 19301 API
}
message AGVConfig{
repeated AGVsrc1100Config src1100_agvs = 1;
}

View File

@ -1,44 +0,0 @@
// biohead.proto
syntax = "proto3";
package cmvr.config;
//
message EyeBrowConfig {
string serial = 1; // "64:0~3"
string offest = 2; // "90 90 90 90"
string jLmtUp = 3; // "90 170 155 110"
string jLmtLow = 4; // "20 77 90 20"
}
//
message EyeConfig {
string serial = 1; // "64:4~9"
string offest = 2; // "90 90 90 90 90 90"
string jLmtUp = 3; // "90 150 165 90 120 115"
string jLmtLow = 4; // "20 90 90 25 70 75"
}
//
message MouthConfig {
string serial = 1; // "65:0~9"
string offest = 2; // "90 90 90 90 90 90 90 90 90 90"
string jLmtUp = 3; // "150 110 130 140 100 105 110 125 90 95"
string jLmtLow = 4; // "70 30 80 80 65 55 45 80 85 90"
}
// BioHead配置
message BioHeadConfig {
string id = 1; // ID "bio_head"
string serial = 2; // "/dev/ttyUSB0"
int32 ctrlFreq = 3; // 50
EyeBrowConfig eyebrow = 4; //
EyeConfig eye = 5; //
MouthConfig mouth = 6; //
bool enable = 7; //
}
message HeadConfig {
repeated BioHeadConfig bioheads = 3;
}

View File

@ -1,22 +0,0 @@
syntax = "proto3";
package cmvr.config;
//
message FolderConfig {
string fileDir = 1; //
int32 maxVolume = 2; // MB
}
//
message DiskMonitorConfig {
string id = 1; // ID "file_monitor"
int32 freq = 2; // Hz
repeated FolderConfig folders = 3; //
bool enable = 4; //
}
//
message MonitorManagerConfig {
DiskMonitorConfig disk_monitor = 1; //
}

View File

@ -1,88 +0,0 @@
syntax = "proto3";
package cmvr.config;
//
message MotorConfig {
int32 id = 1; // ID
string jointName = 2; //
float limitQLb = 3; //
float limitQUb = 4; //
float limitQd = 5; //
}
// CAN设备配置
message CanDeviceConfig {
string id = 1; // CAN ID
string devId = 2; // ID
int32 channelId = 3; // ID
bool enable = 4; //
string toolFrame = 5; // /
repeated MotorConfig motors = 6; //
}
// CAN管理器配置
message CanManagerConfig {
string id = 1; // CAN管理器ID
string devId = 2; // ID
CanDeviceConfig left_arm = 3; // CAN
CanDeviceConfig right_arm = 4; // CAN
CanDeviceConfig head = 5; // CAN
CanDeviceConfig waist = 6; // CAN
}
//
message HumanRobotConfig {
string id = 1; // ID "hc01"
int32 dof = 2; // 14
string urdf = 3; // URDF文件路径
string baseLink = 4; // link名称 "PELVIS_S"
string jointNames = 5; //
string linkNames = 6; // link名称列表
int32 bufferSize = 7; // 50
bool verbose = 8; //
int32 updFreq = 9; // 500
CanManagerConfig can_manager = 10; // CAN管理器配置
bool enable = 11; //
}
// EtherCAT主站配置
message EthercatMasterConfig {
string interface = 1; // "eth0"
int32 cycle_time_us = 2; // 1000
bool enable = 3; //
}
// EtherCAT电机驱动配置
message EthercatMotorConfig {
int32 slave = 1; // ID
string jointName = 2; //
float limitQLb = 3; //
float limitQUb = 4; //
float limitQd = 5; //
}
// EtherCAT机器人配置
message EthercatRobotConfig {
string id = 1; // ID
int32 dof = 2; //
string urdf = 3; // URDF文件路径
string baseLink = 4; // link名称
string jointNames = 5; //
string linkNames = 6; // link名称列表
int32 bufferSize = 7; //
bool verbose = 8; //
int32 updFreq = 9; // Hz
bool enable = 10; //
EthercatMasterConfig master = 11; // EtherCAT主站配置
repeated EthercatMotorConfig motors = 12; //
}
//
message RobotConfig {
repeated HumanRobotConfig humanrobots = 1;
repeated EthercatRobotConfig ethercat_robots = 2; // EtherCAT机器人
}

View File

@ -1,10 +0,0 @@
syntax = "proto3";
package cmvr.config;
message GrpcServerConfig{
string port = 1;
}
message ServerConfig{
GrpcServerConfig grpc_server = 1;
}

View File

@ -33,6 +33,5 @@ third_party/modbus/3.1.11
third_party/visp/3.7.0
third_party/mainif/0.0.5
third_party/matplotplusplus/1.2.0
third_party/soem