diff --git a/cmvr-es/applications/src/touch_screen_app_test.cpp b/cmvr-es/applications/src/touch_screen_app_test.cpp
index b2c178fe..08aa560e 100644
--- a/cmvr-es/applications/src/touch_screen_app_test.cpp
+++ b/cmvr-es/applications/src/touch_screen_app_test.cpp
@@ -21,7 +21,7 @@ void run_touch_once(int u, int v) {
const XmlNode config(kConfigPath);
// auto& dm = cmvr::device::DeviceManager::getInstance();
- cmvr::device::DeviceManager::getInstance(config.getChild("DeviceManager"));
+ cmvr::device::DeviceManager::getInstance();
// cmvr::service::ServerRunner runner;
diff --git a/cmvr-es/common/config/biohead_config/biohead_config.pb.txt b/cmvr-es/common/config/biohead_config/biohead_config.pb.txt
new file mode 100644
index 00000000..b2880e64
--- /dev/null
+++ b/cmvr-es/common/config/biohead_config/biohead_config.pb.txt
@@ -0,0 +1,27 @@
+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"
+ }
+}
\ No newline at end of file
diff --git a/cmvr-es/common/config/cabin_robot.xml b/cmvr-es/common/config/cabin_robot.xml
index d67dffac..e69de29b 100644
--- a/cmvr-es/common/config/cabin_robot.xml
+++ b/cmvr-es/common/config/cabin_robot.xml
@@ -1,152 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/cmvr-es/common/config/camera_config/camera_config.pb.txt b/cmvr-es/common/config/camera_config/camera_config.pb.txt
index 18b02c30..f35f4018 100644
--- a/cmvr-es/common/config/camera_config/camera_config.pb.txt
+++ b/cmvr-es/common/config/camera_config/camera_config.pb.txt
@@ -27,7 +27,7 @@ realsense_cameras {
align_mode: ALIGN_MODE_COLOR
buffer_size: 30
sync: false
- enable: true
+ enable: false
}
realsense_cameras {
diff --git a/cmvr-es/common/config/dexhand_config/dexhand_config.pb.txt b/cmvr-es/common/config/dexhand_config/dexhand_config.pb.txt
index e6783dd2..6adf262b 100644
--- a/cmvr-es/common/config/dexhand_config/dexhand_config.pb.txt
+++ b/cmvr-es/common/config/dexhand_config/dexhand_config.pb.txt
@@ -1,6 +1,6 @@
rh56dftp_dexhands {
id: "hand1"
- ip: "192.168.1.213"
+ ip: "192.168.1.223"
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: true
+ enable: false
}
px_6ax_gen3 {
diff --git a/cmvr-es/common/config/monitor_config/monitor_config.pb.txt b/cmvr-es/common/config/monitor_config/monitor_config.pb.txt
new file mode 100644
index 00000000..d5350f3c
--- /dev/null
+++ b/cmvr-es/common/config/monitor_config/monitor_config.pb.txt
@@ -0,0 +1,25 @@
+# 监控管理器配置
+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
+ }
+ }
+}
\ No newline at end of file
diff --git a/cmvr-es/common/config/robot_config/robot_config.pb.txt b/cmvr-es/common/config/robot_config/robot_config.pb.txt
new file mode 100644
index 00000000..cfbd4cd5
--- /dev/null
+++ b/cmvr-es/common/config/robot_config/robot_config.pb.txt
@@ -0,0 +1,212 @@
+# HumanRobot配置
+humanrobots {
+ id: "hc01"
+ dof: 14
+ 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: 50
+ verbose: false
+ enable: false
+
+ can_manager {
+ id: ""
+ devId: ""
+
+ left_arm {
+ id: ""
+ devId: ""
+ channelId: 0
+ enable: false
+ toolFrame: "L_FINGER_TIP"
+ motors {
+ id: 23
+ jointName: "L_SHOULDER_P"
+ limitQLb: 3.14
+ limitQUb: 3.14
+ limitQd: 3.0
+ }
+ motors {
+ id: 24
+ jointName: "L_SHOULDER_R"
+ limitQLb: 3.14
+ limitQUb: 3.14
+ limitQd: 3.0
+ }
+ motors {
+ id: 25
+ jointName: "L_SHOULDER_Y"
+ limitQLb: 3.14
+ limitQUb: 3.14
+ limitQd: 3.0
+ }
+ motors {
+ id: 26
+ jointName: "L_ELBOW_R"
+ limitQLb: 3.14
+ limitQUb: 3.14
+ limitQd: 3.0
+ }
+ motors {
+ id: 27
+ jointName: "L_WRIST_P"
+ limitQLb: 3.14
+ limitQUb: 3.14
+ limitQd: 3.0
+ }
+ motors {
+ id: 28
+ jointName: "L_WRIST_Y"
+ limitQLb: 3.14
+ limitQUb: 3.14
+ limitQd: 3.0
+ }
+ motors {
+ id: 29
+ jointName: "L_WRIST_R"
+ limitQLb: 3.14
+ limitQUb: 3.14
+ limitQd: 3.0
+ }
+ }
+
+ right_arm {
+ id: ""
+ devId: ""
+ channelId: 1
+ enable: true
+ toolFrame: "R_FINGER_TIP"
+ motors {
+ id: 16
+ jointName: "R_SHOULDER_P"
+ limitQLb: 3.14
+ limitQUb: 3.14
+ limitQd: 3.0
+ }
+ motors {
+ id: 17
+ jointName: "R_SHOULDER_R"
+ limitQLb: 3.14
+ limitQUb: 3.14
+ limitQd: 3.0
+ }
+ motors {
+ id: 18
+ jointName: "R_SHOULDER_Y"
+ limitQLb: 3.14
+ limitQUb: 3.14
+ limitQd: 3.0
+ }
+ motors {
+ id: 19
+ jointName: "R_ELBOW_R"
+ limitQLb: 3.14
+ limitQUb: 3.14
+ limitQd: 3.0
+ }
+ motors {
+ id: 20
+ jointName: "R_WRIST_P"
+ limitQLb: -3.14
+ limitQUb: 3.14
+ limitQd: 3.0
+ }
+ motors {
+ id: 21
+ jointName: "R_WRIST_Y"
+ limitQLb: -1.102
+ limitQUb: 1.02
+ limitQd: 3.0
+ }
+ motors {
+ id: 22
+ jointName: "R_WRIST_R"
+ limitQLb: -0.293
+ limitQUb: 1.57079
+ limitQd: 3.0
+ }
+ }
+
+ head {
+ id: ""
+ devId: ""
+ channelId: 2
+ enable: true
+ motors {
+ id: 32
+ jointName: "HEAD_Y"
+ limitQLb: 3.14
+ limitQUb: 3.14
+ limitQd: 3.0
+ }
+ motors {
+ id: 30
+ jointName: "HEAD_P"
+ limitQLb: 3.14
+ limitQUb: 3.14
+ limitQd: 3.0
+ }
+ motors {
+ id: 31
+ jointName: "HEAD_R"
+ limitQLb: 3.14
+ limitQUb: 3.14
+ limitQd: 3.0
+ }
+ }
+
+ waist {
+ id: ""
+ devId: ""
+ channelId: 3
+ enable: false
+ motors {
+ id: 4
+ jointName: "WAIST_Y"
+ limitQLb: 3.14
+ limitQUb: 3.14
+ limitQd: 3.0
+ }
+ motors {
+ id: 15
+ jointName: "WAIST_P"
+ limitQLb: 3.14
+ limitQUb: 3.14
+ limitQd: 3.0
+ }
+ }
+ }
+}
+
+
+
+# EtherCAT机器人配置
+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
+ }
+}
\ No newline at end of file
diff --git a/cmvr-es/common/config/server_config/server_config.pb.txt b/cmvr-es/common/config/server_config/server_config.pb.txt
new file mode 100644
index 00000000..78599a06
--- /dev/null
+++ b/cmvr-es/common/config/server_config/server_config.pb.txt
@@ -0,0 +1,3 @@
+grpc_server {
+ port: "50052"
+}
\ No newline at end of file
diff --git a/cmvr-es/common/utils/config_helper/include/config_helper.h b/cmvr-es/common/utils/config_helper/include/config_helper.h
index 7d189128..445af379 100644
--- a/cmvr-es/common/utils/config_helper/include/config_helper.h
+++ b/cmvr-es/common/utils/config_helper/include/config_helper.h
@@ -10,6 +10,9 @@
#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/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 { \
@@ -82,6 +85,20 @@ namespace cmvr
return SET_CONFIG(config, touch_screen_app_config_file);
}
+ 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
diff --git a/cmvr-es/common/utils/config_helper/include/config_setting.h b/cmvr-es/common/utils/config_helper/include/config_setting.h
index 5d58fb9e..caedf533 100644
--- a/cmvr-es/common/utils/config_helper/include/config_setting.h
+++ b/cmvr-es/common/utils/config_helper/include/config_setting.h
@@ -6,3 +6,6 @@ DECLARE_string(dexhand_config_file);
DECLARE_string(microphone_config_file);
DECLARE_string(speaker_config_file);
DECLARE_string(touch_screen_app_config_file);
+DECLARE_string(biohead_config_file);
+DECLARE_string(robot_config_file);
+DECLARE_string(server_config_file);
diff --git a/cmvr-es/common/utils/config_helper/src/config_setting.cpp b/cmvr-es/common/utils/config_helper/src/config_setting.cpp
index 9e44092d..528819f5 100644
--- a/cmvr-es/common/utils/config_helper/src/config_setting.cpp
+++ b/cmvr-es/common/utils/config_helper/src/config_setting.cpp
@@ -88,3 +88,15 @@ 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(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");
diff --git a/cmvr-es/data_center/CMakeLists.txt b/cmvr-es/data_center/CMakeLists.txt
index d0fda580..ff66818d 100644
--- a/cmvr-es/data_center/CMakeLists.txt
+++ b/cmvr-es/data_center/CMakeLists.txt
@@ -11,6 +11,7 @@ target_link_libraries(data_center PRIVATE
cmvr_es::utils
cmvr_es::device::canbus
cmvr_es::device::ti5motor
+ cmvr_es::device::eyoumotor
protobuf
glog
)
diff --git a/cmvr-es/data_center/include/motors_info.h b/cmvr-es/data_center/include/motors_info.h
index 56c2de04..4c86ce00 100644
--- a/cmvr-es/data_center/include/motors_info.h
+++ b/cmvr-es/data_center/include/motors_info.h
@@ -23,8 +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;
diff --git a/cmvr-es/data_center/src/motors_info.cpp b/cmvr-es/data_center/src/motors_info.cpp
index 4b6a087c..c1eafea6 100644
--- a/cmvr-es/data_center/src/motors_info.cpp
+++ b/cmvr-es/data_center/src/motors_info.cpp
@@ -3,6 +3,8 @@
//
#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"
@@ -12,99 +14,95 @@ using namespace cmvr::device;
MotorsInfo::MotorsInfo() {
}
-void MotorsInfo::init(const XmlNode &cfg) {
- // 定义 lambda 函数,用于读取 XML 节点 enable 属性
- auto readEnable = [](const XmlNode &node) -> bool {
- std::string enable_str = node.getAttrString("enable"); // 默认 false
- return (enable_str == "true" || enable_str == "1");
- };
- auto can_cfg = cfg.getChild("CanManger");
+void MotorsInfo::init(const cmvr::config::HumanRobotConfig& config) {
+ const auto& can_manager = config.can_manager();
- auto l_can_cfg = can_cfg.getChild("LeftArmCan");
- left_arm_enabled_ = readEnable(l_can_cfg);
+ // 读取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 l_motors_cfg;
+ std::vector r_motors_cfg;
+ std::vector waist_motors_cfg;
+ std::vector head_motors_cfg;
+
+ // 左臂
if (left_arm_enabled_) {
- l_motors_cfg_ = l_can_cfg.getChildren("Motor");
- l_can_client_ = std::make_shared(l_can_cfg);
- l_can_sender_ = std::make_shared >();
- l_can_receiver_ = std::make_shared >();
- l_message_manager_ = std::make_shared >();
+ 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(left_arm);
+ l_can_sender_ = std::make_shared>();
+ l_can_receiver_ = std::make_shared>();
+ l_message_manager_ = std::make_shared>();
}
-
- auto r_can_cfg = can_cfg.getChild("RightArmCan");
- right_arm_enabled_ = readEnable(r_can_cfg);
+ // 右臂
if (right_arm_enabled_) {
- r_motors_cfg_ = r_can_cfg.getChildren("Motor");
- r_can_client_ = std::make_shared(r_can_cfg);
- r_can_sender_ = std::make_shared >();
- r_can_receiver_ = std::make_shared >();
- r_message_manager_ = std::make_shared >();
+ 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(right_arm);
+ r_can_sender_ = std::make_shared>();
+ r_can_receiver_ = std::make_shared>();
+ r_message_manager_ = std::make_shared>();
}
-
- auto waist_can_cfg = can_cfg.getChild("WaistCan");
- waist_enabled_ = readEnable(waist_can_cfg);
+ // 腰部
if (waist_enabled_) {
- waist_motors_cfg_ = waist_can_cfg.getChildren("Motor");
- waist_can_client_ = std::make_shared(waist_can_cfg);
- waist_can_sender_ = std::make_shared >();
- waist_can_receiver_ = std::make_shared >();
- waist_message_manager_ = std::make_shared >();
+ const auto& waist = can_manager.waist();
+ for (const auto& motor : waist.motors()) {
+ waist_motors_cfg.push_back(motor);
+ }
+ waist_can_client_ = std::make_shared(waist);
+ waist_can_sender_ = std::make_shared>();
+ waist_can_receiver_ = std::make_shared>();
+ waist_message_manager_ = std::make_shared>();
}
- auto head_can_cfg = can_cfg.getChild("HeadCan");
- head_enabled_ = readEnable(head_can_cfg);
+ // 头部
if (head_enabled_) {
- head_motors_cfg_ = head_can_cfg.getChildren("Motor");
- head_can_client_ = std::make_shared(head_can_cfg);
- head_can_sender_ = std::make_shared >();
- head_can_receiver_ = std::make_shared >();
- head_message_manager_ = std::make_shared >();
+ const auto& head = can_manager.head();
+ for (const auto& motor : head.motors()) {
+ head_motors_cfg.push_back(motor);
+ }
+ head_can_client_ = std::make_shared(head);
+ head_can_sender_ = std::make_shared>();
+ head_can_receiver_ = std::make_shared>();
+ head_message_manager_ = std::make_shared>();
}
- // 开始初始化
+ // 初始化 limbs
struct Limb {
std::string name;
bool enabled;
std::shared_ptr client;
- std::shared_ptr > sender;
- std::shared_ptr > receiver;
- std::shared_ptr > message_manager;
- std::vector motor_cfgs;
+ std::shared_ptr> sender;
+ std::shared_ptr> receiver;
+ std::shared_ptr> message_manager;
+ std::vector motor_cfgs;
};
std::vector 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_
- }
+ {"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}
};
- // 创建 MotorManager
motor_manager_ = std::make_shared();
+ std::vector> tasks;
- std::vector > tasks;
-
- for (auto &limb: limbs) {
+ for (auto &limb : limbs) {
if (!limb.enabled) continue;
-
if (limb.client) limb.client->init();
- // 2. 初始化 Sender / Receiver(如果有)
if (limb.sender && limb.receiver && limb.client) {
auto ret = limb.sender->Init(limb.client.get(), false);
if (ret != ErrorCode::OK)
@@ -124,19 +122,16 @@ void MotorsInfo::init(const XmlNode &cfg) {
LOG(ERROR) << "Failed to start " << limb.name << " CAN receiver.";
}
- // 3. 创建协议(如果有CAN)
std::shared_ptr protocol = nullptr;
if (limb.sender && limb.message_manager) {
protocol = std::make_shared(limb.sender, limb.message_manager);
}
- // 4. 并行初始化电机
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 &cfg: limb.motor_cfgs) {
- auto motor = std::make_shared(cfg);
+ 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(motor_cfg);
if (protocol) motor->setProtocol(protocol);
motor->init();
motor_manager_->addMotor(motor);
@@ -145,12 +140,26 @@ void MotorsInfo::init(const XmlNode &cfg) {
}
}
- // 等待所有任务完成
- for (auto &task: tasks) task.get();
-
+ 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();
+ }
+ auto protocol = std::make_shared(config.master().interface());
+ for (const auto& motor_cfg : config.motors()) {
+ auto motor = std::make_shared(motor_cfg);
+ if (protocol) motor->setProtocol(protocol);
+ motor->init();
+ motor_manager_->addMotor(motor);
+ }
+}
+
bool MotorsInfo::getJointsQ(const std::vector &joints_name,
std::unordered_map &joint_qs) const {
auto res{true};
diff --git a/cmvr-es/device_manager/include/device_factory.h b/cmvr-es/device_manager/include/device_factory.h
index 1fcce739..096664a0 100644
--- a/cmvr-es/device_manager/include/device_factory.h
+++ b/cmvr-es/device_manager/include/device_factory.h
@@ -28,15 +28,7 @@ namespace cmvr::device {
template
std::shared_ptr createFromConfig(const ConfigType& cfg);
private:
- std::shared_ptr create_agv_(const XmlNode& cfg);
- std::shared_ptr create_battery_(const XmlNode& cfg);
- std::shared_ptr create_camera_(const XmlNode& cfg);
- std::shared_ptr create_dexhand_(const XmlNode& cfg);
- std::shared_ptr create_gripper_(const XmlNode& cfg);
- std::shared_ptr create_mic_(const XmlNode& cfg);
- std::shared_ptr create_robot_(const XmlNode& cfg);
- std::shared_ptr create_speaker_(const XmlNode& cfg);
- std::shared_ptr create_biohead_(const XmlNode& cfg);
+
};
}
diff --git a/cmvr-es/device_manager/include/device_manager.h b/cmvr-es/device_manager/include/device_manager.h
index ee782e5d..865d1104 100644
--- a/cmvr-es/device_manager/include/device_manager.h
+++ b/cmvr-es/device_manager/include/device_manager.h
@@ -41,7 +41,6 @@ namespace cmvr::device {
DeviceManager(const DeviceManager&) = delete;
DeviceManager& operator=(const DeviceManager&) = delete;
- static DeviceManager& getInstance(const XmlNode &cfg);
static DeviceManager& getInstance();
static void destroyInstance();
@@ -68,7 +67,7 @@ namespace cmvr::device {
std::unique_ptr dev_factory_;
std::unique_ptr sys_monitor_;
- explicit DeviceManager(const XmlNode &cfg);
+ explicit DeviceManager();
void init_devices_();
void get_os_info_();
};
diff --git a/cmvr-es/device_manager/src/device_factory.cpp b/cmvr-es/device_manager/src/device_factory.cpp
index fba92e51..f80e53f4 100644
--- a/cmvr-es/device_manager/src/device_factory.cpp
+++ b/cmvr-es/device_manager/src/device_factory.cpp
@@ -18,172 +18,16 @@
//#include "devices/robot/aubo_robot/include/aubo_robot.h"
using namespace std;
using namespace cmvr::device;
-
-
-template std::shared_ptr DeviceFactory::create(const XmlNode&);
-template std::shared_ptr DeviceFactory::create(const XmlNode&);
-template std::shared_ptr DeviceFactory::create(const XmlNode&);
-template std::shared_ptr DeviceFactory::create(const XmlNode&);
-template std::shared_ptr DeviceFactory::create(const XmlNode&);
-template std::shared_ptr DeviceFactory::create(const XmlNode&);
-template std::shared_ptr DeviceFactory::create(const XmlNode&);
-template std::shared_ptr DeviceFactory::create(const XmlNode&);
-template std::shared_ptr DeviceFactory::create(const XmlNode&);
-
-template
-std::shared_ptr DeviceFactory::create(const XmlNode& cfg) {
- if constexpr (std::is_same_v) {
- return create_agv_(cfg);
- } else if constexpr (std::is_same_v) {
- return create_battery_(cfg);
- } else if constexpr (std::is_same_v) {
- return create_camera_(cfg);
- } else if constexpr (std::is_same_v) {
- return create_dexhand_(cfg);
- } else if constexpr (std::is_same_v) {
- return create_gripper_(cfg);
- } else if constexpr (std::is_same_v) {
- return create_mic_(cfg);
- } else if constexpr (std::is_same_v) {
- return create_robot_(cfg);
- } else if constexpr (std::is_same_v) {
- return create_speaker_(cfg);
- }else if constexpr (std::is_same_v){
- return create_biohead_(cfg);
- }
- else {
- LOG(ERROR) << "[DeviceFactory]: Unsupported device type";
- throw runtime_error("[DeviceFactory]: Unsupported device type");
- }
-}
-
-std::shared_ptr DeviceFactory::create_agv_(const XmlNode& cfg) {
- return nullptr;
-}
-
-std::shared_ptr DeviceFactory::create_battery_(const XmlNode& cfg) {
- return nullptr;
-}
-
-std::shared_ptr DeviceFactory::create_camera_(const XmlNode& cfg) {
- try {
- if (cfg.getNodeName() == "UVCCamera") {
- return std::make_shared(cfg);
- }
- else if (cfg.getNodeName() == "MechMind") {
- //return std::make_shared(cfg);
- LOG(ERROR) << "[DeviceFactory]: Unsupported device type " << cfg.getNodeName();
- return nullptr;
- }
- else if (cfg.getNodeName() == "RealsenseCamera") {
- return std::make_shared(cfg);
- }
- else {
- LOG(ERROR) << "[DeviceFactory]: Unsupported device type " << cfg.getNodeName();
- return nullptr;
- }
- }
- catch (const exception &e) {
- return nullptr;
- }
-}
-
-std::shared_ptr DeviceFactory::create_dexhand_(const XmlNode& cfg) {
- try {
- if (cfg.getNodeName() == "RH56DFTP") {
- return std::make_shared(cfg);
- }
- else if (cfg.getNodeName() == "PX6AXGen3") {
- return std::make_shared(cfg);
- }
- else {
- LOG(ERROR) << "[DeviceFactory]: Unsupported device type " << cfg.getNodeName();
- return nullptr;
- }
- }
- catch (const exception &e) {
- return nullptr;
- }
-}
-
-std::shared_ptr DeviceFactory::create_gripper_(const XmlNode& cfg) {
- return nullptr;
-}
-
-std::shared_ptr DeviceFactory::create_mic_(const XmlNode& cfg) {
- try {
- if (cfg.getNodeName() == "ffmpegMicPhone") {
- return std::make_shared(cfg);
- }
- else {
- LOG(ERROR) << "[DeviceFactory]: Unsupported device type " << cfg.getNodeName();
- return nullptr;
- }
- }
- catch (const exception &e) {
- return nullptr;
- }
- return nullptr;
-}
-
-std::shared_ptr DeviceFactory::create_robot_(const XmlNode& cfg) {
- try {
- if (cfg.getNodeName() == "Humanoid") {
- auto motos_info = MotorsInfo::getInstance();
- motos_info->init(cfg);
- return std::make_shared>(cfg);
- }
- else if (cfg.getNodeName() == "AuboRobot") {
- //return std::make_shared>(cfg);
- LOG(ERROR) << "[DeviceFactory]: Unsupported device type " << cfg.getNodeName();
- return nullptr;
- }
- else {
- LOG(ERROR) << "[DeviceFactory]: Unsupported device type " << cfg.getNodeName();
- return nullptr;
- }
- }
- catch (const exception &e) {
- return nullptr;
- }
-}
-
-std::shared_ptrDeviceFactory::create_biohead_(const XmlNode& cfg) {
- try {
- if (cfg.getNodeName() == "esp32") {
- return std::make_shared(cfg);
- }
- else {
- LOG(ERROR) << "[DeviceFactory]: Unsupported device type " << cfg.getNodeName();
- return nullptr;
- }
- }
- catch (const exception &e) {
- return nullptr;
- }
-}
-
-std::shared_ptr DeviceFactory::create_speaker_(const XmlNode& cfg) {
- try {
- if (cfg.getNodeName() == "ffmpegSpeaker") {
- return std::make_shared(cfg);
- }
- else {
- LOG(ERROR) << "[DeviceFactory]: Unsupported device type " << cfg.getNodeName();
- return nullptr;
- }
- }
- catch (const exception &e) {
- return nullptr;
- }
-}
-
template std::shared_ptr DeviceFactory::createFromConfig(const config::UVCCameraConfig& cfg);
template std::shared_ptr DeviceFactory::createFromConfig(const config::RealSenseCameraConfig& cfg);
template std::shared_ptr DeviceFactory::createFromConfig(const config::RH56DFTPDexHandConfig& cfg);
template std::shared_ptr DeviceFactory::createFromConfig(const config::PX6AXGen3& cfg);
template std::shared_ptr DeviceFactory::createFromConfig(const config::FFMpegMicroPhoneConfig& cfg);
template std::shared_ptr DeviceFactory::createFromConfig(const config::FFMpegSpeakerConfig& cfg);
+template std::shared_ptr DeviceFactory::createFromConfig(const config::BioHeadConfig& cfg);
+template std::shared_ptr DeviceFactory::createFromConfig(const config::HumanRobotConfig& cfg);
+template std::shared_ptr DeviceFactory::createFromConfig(const config::EthercatRobotConfig& cfg);
+
template
std::shared_ptr DeviceFactory::createFromConfig(const ConfigType& cfg)
{
@@ -244,6 +88,38 @@ std::shared_ptr DeviceFactory::createFromConfig(const ConfigType& cf
throw runtime_error("[DeviceFactory]: Unsupported microphone device type");
}
}
+ else if constexpr (std::is_same_v)
+ {
+ if constexpr (std::is_same_v)
+ {
+ return std::make_shared(cfg);
+ }
+ else
+ {
+ LOG(ERROR) << "[DeviceFactory]: Unsupported microphone device type ";
+ throw runtime_error("[DeviceFactory]: Unsupported microphone device type");
+ }
+ }
+ else if constexpr (std::is_same_v)
+ {
+ if constexpr (std::is_same_v)
+ {
+ auto motos_info = MotorsInfo::getInstance();
+ motos_info->init(cfg);
+ return std::make_shared>(cfg);
+ }
+ else if constexpr (std::is_same_v)
+ {
+ auto motos_info = MotorsInfo::getInstance();
+ motos_info->init(cfg);
+ return std::make_shared>(cfg);
+ }
+ else
+ {
+ LOG(ERROR) << "[DeviceFactory]: Unsupported microphone device type ";
+ throw runtime_error("[DeviceFactory]: Unsupported microphone device type");
+ }
+ }
else {
LOG(ERROR) << "[DeviceFactory]: Unsupported device type";
throw runtime_error("[DeviceFactory]: Unsupported device type");
@@ -253,3 +129,4 @@ std::shared_ptr DeviceFactory::createFromConfig(const ConfigType& cf
return nullptr;
}
}
+
diff --git a/cmvr-es/device_manager/src/device_manager.cpp b/cmvr-es/device_manager/src/device_manager.cpp
index 805516f9..93ff9534 100644
--- a/cmvr-es/device_manager/src/device_manager.cpp
+++ b/cmvr-es/device_manager/src/device_manager.cpp
@@ -24,12 +24,9 @@ std::shared_ptr DeviceManager::instance_ = nullptr;
std::once_flag DeviceManager::init_flag_;
-DeviceManager::DeviceManager(const XmlNode& cfg) {
+DeviceManager::DeviceManager() {
try {
- cfg_ = cfg;
- info_.version = cfg_.getAttrDefault("ver", "1.0");
- info_.name = cfg_.getAttrDefault("name", "cmvr_es");
- info_.description = cfg_.getAttrDefault("description", "empty");
+
get_os_info_();
dev_factory_ = std::make_unique();
@@ -42,17 +39,12 @@ DeviceManager::DeviceManager(const XmlNode& cfg) {
}
}
-DeviceManager& DeviceManager::getInstance(const XmlNode& cfg) {
- std::call_once(init_flag_, [&cfg] {
- instance_.reset(new DeviceManager(cfg));
- });
- return *instance_;
-}
-
DeviceManager& DeviceManager::getInstance() {
- if (!instance_) {
- throw std::runtime_error("[DeviceManager] (getInstance): DeviceManager not initialized. Call getInstance(const XmlNode&) first.");
- }
+ if (!instance_)
+ std::call_once(init_flag_, [&] {
+ instance_.reset(new DeviceManager());
+ });
+
return *instance_;
}
@@ -199,38 +191,38 @@ void DeviceManager::getSystemStatus(SystemStatus& status) const {
void DeviceManager::init_devices_() {
try{
- auto dmgr_node = cfg_.getChild("Devices");
- auto battery_node = dmgr_node.getChild("Battery");
- for (auto &node: battery_node.getChildren()){
- string id = node.getAttrString("id");
- if (devices_.count(id)) {
- LOG(ERROR) << "[DeviceManager]: Duplicate Battery Device ID " << id;
- throw runtime_error("[DeviceManager]: Duplicate Battery Device ID " + id);
- }
- auto device = dev_factory_->create(node);
- if (device == nullptr) {
- throw std::runtime_error("[DeviceManager]: Factory returned nullptr for device ID: " + id);
- }
- devices_[id] = device;
- std::get>(devices_[id])->init();
- LOG(INFO) << "[DeviceManager]: Init Battery " << id << " Success";
- }
+ // auto dmgr_node = cfg_.getChild("Devices");
+ // auto battery_node = dmgr_node.getChild("Battery");
+ // for (auto &node: battery_node.getChildren()){
+ // string id = node.getAttrString("id");
+ // if (devices_.count(id)) {
+ // LOG(ERROR) << "[DeviceManager]: Duplicate Battery Device ID " << id;
+ // throw runtime_error("[DeviceManager]: Duplicate Battery Device ID " + id);
+ // }
+ // auto device = dev_factory_->create(node);
+ // if (device == nullptr) {
+ // throw std::runtime_error("[DeviceManager]: Factory returned nullptr for device ID: " + id);
+ // }
+ // devices_[id] = device;
+ // std::get>(devices_[id])->init();
+ // LOG(INFO) << "[DeviceManager]: Init Battery " << id << " Success";
+ // }
- auto agv_node = dmgr_node.getChild("AGV");
- for (auto &node: agv_node.getChildren()){
- string id = node.getAttrString("id");
- if (devices_.count(id)) {
- LOG(ERROR) << "[DeviceManager]: Duplicate AGV Device ID" << id;
- throw runtime_error("[DeviceManager]: Duplicate AGV Device ID" + id);
- }
- auto device = dev_factory_->create(node);
- if (device == nullptr) {
- throw std::runtime_error("[DeviceManager]: Factory returned nullptr for device ID: " + id);
- }
- devices_[id] = device;
- std::get>(devices_[id])->init();
- LOG(INFO) << "[DeviceManager]: Init AGV " << id << " Success";
- }
+ // auto agv_node = dmgr_node.getChild("AGV");
+ // for (auto &node: agv_node.getChildren()){
+ // string id = node.getAttrString("id");
+ // if (devices_.count(id)) {
+ // LOG(ERROR) << "[DeviceManager]: Duplicate AGV Device ID" << id;
+ // throw runtime_error("[DeviceManager]: Duplicate AGV Device ID" + id);
+ // }
+ // auto device = dev_factory_->create(node);
+ // if (device == nullptr) {
+ // throw std::runtime_error("[DeviceManager]: Factory returned nullptr for device ID: " + id);
+ // }
+ // devices_[id] = device;
+ // std::get>(devices_[id])->init();
+ // LOG(INFO) << "[DeviceManager]: Init AGV " << id << " Success";
+ // }
config::CameraConfig camera_config;
ConfigHelper::getCamerasConfig(camera_config);
@@ -296,20 +288,36 @@ void DeviceManager::init_devices_() {
std::get>(devices_[id])->init();
}
- auto robot_node = dmgr_node.getChild("Robot");
- for (auto &node: robot_node.getChildren()){
- string id = node.getAttrString("id");
+ config::RobotConfig robot_config;
+ ConfigHelper::getRobotConfig(robot_config);
+ for (int i = 0; i < robot_config.humanrobots().size(); i++) {
+ auto robot = robot_config.humanrobots(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);
- }
- auto device = dev_factory_->create(node);
- if (device == nullptr) {
- throw std::runtime_error("[DeviceManager]: Factory returned nullptr for device ID: " + 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(robot);
+ devices_[id] = device;
+ std::get>(devices_[id])->init();
+ }
+
+ 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(robot);
devices_[id] = device;
std::get>(devices_[id])->init();
- LOG(INFO) << "[DeviceManager]: Init Robot " << id << " Success";
}
config::MicroPhoneConfig micro_phone_config;
@@ -346,22 +354,21 @@ void DeviceManager::init_devices_() {
std::get>(devices_[id])->init();
}
-
- 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(node);
- if (device == nullptr){
- throw std::runtime_error("[DeviceManager]: Factory returned nullptr for device ID: " + id);
+ 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);
}
+ std::cout << "Biohead[" << i << "]: " << id << std::endl;
+ auto device = dev_factory_->createFromConfig(head);
devices_[id] = device;
std::get>(devices_[id])->init();
- LOG(INFO) << "[BioHead]: Init biohead " << id << " Success";
-
}
}
catch (const exception& e) {
diff --git a/cmvr-es/devices/biohead/abstract_biohead.h b/cmvr-es/devices/biohead/abstract_biohead.h
index 93e0eb20..09b774ff 100644
--- a/cmvr-es/devices/biohead/abstract_biohead.h
+++ b/cmvr-es/devices/biohead/abstract_biohead.h
@@ -58,6 +58,7 @@ namespace cmvr::device {
// 抽象头部类
class AbstractBiohead : public AbstractDevice {
public:
+ AbstractBiohead() = default;
explicit AbstractBiohead(const XmlNode &config) : AbstractDevice(config) {}
~AbstractBiohead() override = default;
diff --git a/cmvr-es/devices/biohead/biohead_esp32/include/biohead_esp32.h b/cmvr-es/devices/biohead/biohead_esp32/include/biohead_esp32.h
index 52b34d5d..08c0953f 100644
--- a/cmvr-es/devices/biohead/biohead_esp32/include/biohead_esp32.h
+++ b/cmvr-es/devices/biohead/biohead_esp32/include/biohead_esp32.h
@@ -7,7 +7,7 @@
#include
#include
#include
-
+#include "cmvr/config/biohead_config/biohead_config.pb.h"
namespace cmvr::device {
struct ServoChannel {
@@ -18,6 +18,7 @@ namespace cmvr::device {
class BioHeadRobot : public AbstractBiohead {
public:
explicit BioHeadRobot(const XmlNode &config);
+ BioHeadRobot(const cmvr::config::BioHeadConfig& config);
~BioHeadRobot() override = default;
// 接口实现
@@ -66,7 +67,7 @@ namespace cmvr::device {
std::shared_ptr speak_thread_;
std::atomic speak_running_{false};
-
+ cmvr::config::BioHeadConfig config_;
};
diff --git a/cmvr-es/devices/biohead/biohead_esp32/src/biohead_esp32.cpp b/cmvr-es/devices/biohead/biohead_esp32/src/biohead_esp32.cpp
index c3b67887..8ff9e3b3 100644
--- a/cmvr-es/devices/biohead/biohead_esp32/src/biohead_esp32.cpp
+++ b/cmvr-es/devices/biohead/biohead_esp32/src/biohead_esp32.cpp
@@ -26,6 +26,219 @@ 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();
+ 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 offsets;
+ std::istringstream oss(offset_str);
+ double val;
+ while (oss >> val) offsets.push_back(val);
+
+ // 解析角度限制
+ std::vector 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 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(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 offsets;
+ std::istringstream oss(offset_str);
+ double val;
+ while (oss >> val) offsets.push_back(val);
+
+ // 解析角度限制
+ std::vector 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 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(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 offsets;
+ std::istringstream oss(offset_str);
+ double val;
+ while (oss >> val) offsets.push_back(val);
+
+ // 解析角度限制
+ std::vector 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 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(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) {
diff --git a/cmvr-es/devices/camera/realsense_camera/src/realsense_camera_test.cpp b/cmvr-es/devices/camera/realsense_camera/src/realsense_camera_test.cpp
index 803ee75a..6fdaa099 100644
--- a/cmvr-es/devices/camera/realsense_camera/src/realsense_camera_test.cpp
+++ b/cmvr-es/devices/camera/realsense_camera/src/realsense_camera_test.cpp
@@ -21,7 +21,7 @@ TEST(RealsenseCameraRealDeviceTest, SaveFrames) {
return;
}
auto dmgr_cfg = config.getChild("DeviceManager");
- auto &dmgr = DeviceManager::getInstance(dmgr_cfg);
+ auto &dmgr = DeviceManager::getInstance();
auto cam = dmgr.getDevice("cam4");
cam->start();
diff --git a/cmvr-es/devices/canbus/abstract_canbus.h b/cmvr-es/devices/canbus/abstract_canbus.h
index ca0399d0..6fce7f5e 100644
--- a/cmvr-es/devices/canbus/abstract_canbus.h
+++ b/cmvr-es/devices/canbus/abstract_canbus.h
@@ -54,6 +54,7 @@ namespace cmvr::device {
class AbstractCanbus : public AbstractDevice {
public:
+ AbstractCanbus() = default;
AbstractCanbus(const XmlNode &cfg) : AbstractDevice(cfg) {}
~AbstractCanbus() {}
/**
diff --git a/cmvr-es/devices/canbus/can_client/socket/socket_can_client_raw.cc b/cmvr-es/devices/canbus/can_client/socket/socket_can_client_raw.cc
index aef0af2c..28779a06 100644
--- a/cmvr-es/devices/canbus/can_client/socket/socket_can_client_raw.cc
+++ b/cmvr-es/devices/canbus/can_client/socket/socket_can_client_raw.cc
@@ -35,6 +35,17 @@ 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(channel_id);
+ interface_ = CANCardParameter::NATIVE;
+
+ enable_can_err_check_ = false;
+
+
+ }
+
void SocketCanClientRaw::init() {
// if (!parameter.has_channel_id()) {
diff --git a/cmvr-es/devices/canbus/can_client/socket/socket_can_client_raw.h b/cmvr-es/devices/canbus/can_client/socket/socket_can_client_raw.h
index 3de5b42c..04d57c86 100644
--- a/cmvr-es/devices/canbus/can_client/socket/socket_can_client_raw.h
+++ b/cmvr-es/devices/canbus/can_client/socket/socket_can_client_raw.h
@@ -26,6 +26,7 @@
#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 {
@@ -36,6 +37,7 @@ 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;
@@ -73,6 +75,8 @@ namespace cmvr {
//
bool enable_can_err_check_{false};
+
+ cmvr::config::CanDeviceConfig config_;
};
}
}
diff --git a/cmvr-es/devices/motor/CMakeLists.txt b/cmvr-es/devices/motor/CMakeLists.txt
index 532924d2..3b7669c9 100644
--- a/cmvr-es/devices/motor/CMakeLists.txt
+++ b/cmvr-es/devices/motor/CMakeLists.txt
@@ -1,5 +1,5 @@
add_subdirectory(ti5_motor)
-
+add_subdirectory(eyou_motor)
# --------------------------------------------------------
# Unit test
# --------------------------------------------------------
diff --git a/cmvr-es/devices/motor/abstract_motor.h b/cmvr-es/devices/motor/abstract_motor.h
index 710f88d2..bb89a415 100644
--- a/cmvr-es/devices/motor/abstract_motor.h
+++ b/cmvr-es/devices/motor/abstract_motor.h
@@ -41,6 +41,7 @@ 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;
diff --git a/cmvr-es/devices/motor/eyou_motor/CMakeLists.txt b/cmvr-es/devices/motor/eyou_motor/CMakeLists.txt
new file mode 100644
index 00000000..abb62da2
--- /dev/null
+++ b/cmvr-es/devices/motor/eyou_motor/CMakeLists.txt
@@ -0,0 +1,19 @@
+add_library(eyoumotor SHARED
+ ${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
+ eu_ethercat
+ protobuf
+ glog
+)
+
+install(TARGETS eyoumotor LIBRARY DESTINATION lib)
\ No newline at end of file
diff --git a/cmvr-es/devices/motor/eyou_motor/ethercat/eyou_motor_ethercat_protocol.cpp b/cmvr-es/devices/motor/eyou_motor/ethercat/eyou_motor_ethercat_protocol.cpp
new file mode 100644
index 00000000..4e5edace
--- /dev/null
+++ b/cmvr-es/devices/motor/eyou_motor/ethercat/eyou_motor_ethercat_protocol.cpp
@@ -0,0 +1,652 @@
+//
+// 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
+#include
+#include
+
+using namespace cmvr::device;
+using namespace cmvr::msgs;
+
+// 构造函数
+EYouEthercatProtocol::EYouEthercatProtocol(std::string ifName)
+ : interface_name_(ifName), initialized_(false), slave_count_(0) {
+ comm_proto = CommProto::ETHERCAT;
+
+ try {
+ // 初始化message_manager
+ message_manager_ = std::make_shared>();
+
+ // 初始化eu sdk
+ int ms = 1;
+ if (ETH_SUCCESS != eth_initDLL(interface_name_.c_str(), ms, &slave_count_)) {
+ LOG(ERROR) << "[EYouEthercatProtocol] eth_initDLL failed for interface: " << interface_name_;
+ eth_freeDLL();
+ throw std::runtime_error("[EYouEthercatProtocol] eth_initDLL failed");
+ }
+
+ initialized_ = true;
+ LOG(INFO) << "[EYouEthercatProtocol] Initialized successfully, found " << slave_count_ << " slaves";
+
+ // 初始化从站状态
+ for (int i = 0; i < slave_count_; i++) {
+ eth_State state;
+ if (eth_getSlaveState(i, &state) == ETH_SUCCESS) {
+ LOG(INFO) << "[EYouEthercatProtocol] Slave " << i << " state: " << state;
+ }
+ node_states_[i] = NodeState();
+ }
+
+ } catch (const std::exception& e) {
+ LOG(ERROR) << "[EYouEthercatProtocol] Constructor failed: " << e.what();
+ throw std::runtime_error(e.what());
+ }
+}
+
+// 析构函数
+EYouEthercatProtocol::~EYouEthercatProtocol() {
+ // 失能所有电机
+ // for (auto& node : node_states_) {
+ // if (node.second.enabled) {
+ // eth_disable(node.first);
+ // LOG(INFO) << "[EYouEthercatProtocol] Disabled motor " << node.first;
+ // }
+ // }
+
+ if (initialized_) {
+ eth_freeDLL();
+ LOG(INFO) << "[EYouEthercatProtocol] SDK freed successfully";
+ }
+}
+
+// 初始化节点
+bool EYouEthercatProtocol::initNode(uint8_t node_id) {
+ try {
+ int ret = 0;
+ if (node_id > slave_count_) {
+ LOG(ERROR) << "[EYouEthercatProtocol] Node " << node_id << " out of range (max: " << slave_count_ - 1 << ")";
+ return false;
+ }
+
+ // 初始化节点状态
+ node_states_[node_id].initialized = true;
+
+ // 设置初始操作模式为轮廓位置模式
+ if (eth_setOperateMode(node_id, eth_OperateMode_ProfilePosition) != ETH_SUCCESS) {
+ LOG(ERROR) << "[EYouEthercatProtocol] Failed to set operate mode for node " << node_id;
+ return false;
+ }
+
+ // 等待模式切换完成
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+
+ // 使能电机
+ ret = eth_enable(node_id);
+ if (ret != ETH_SUCCESS) {
+ LOG(ERROR) << "[EYouEthercatProtocol] Failed to enable motor " << node_id << ",error: " << ret;
+ return false;
+ }
+
+ node_states_[node_id].enabled = true;
+ node_states_[node_id].current_mode = RUN_MODE_PROFILE_POSITION;
+
+ // 添加NMT响应协议
+ message_manager_->AddRecvProtocolData, false>(node_id);
+
+ 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, RunMode mode) {
+ eth_OperateMode eth_mode;
+
+ switch (mode) {
+ case RUN_MODE_PROFILE_POSITION:
+ eth_mode = eth_OperateMode_ProfilePosition;
+ break;
+ case RUN_MODE_VELOCITY:
+ eth_mode = eth_OperateMode_Velocity;
+ break;
+ case RUN_MODE_PROFILE_VELOCITY:
+ eth_mode = eth_OperateMode_ProfileVelocity;
+ break;
+ case RUN_MODE_TORQUE:
+ eth_mode = eth_OperateMode_ProfileTorque;
+ break;
+ case RUN_MODE_HOMING:
+ eth_mode = eth_OperateMode_Homing;
+ break;
+ case RUN_MODE_INTERPOLATED_POSITION:
+ eth_mode = eth_OperateMode_InterpolatedPosition;
+ break;
+ case RUN_MODE_CYCLIC_SYNC_POSITION:
+ eth_mode = eth_OperateMode_CyclicSyncPosition;
+ break;
+ case RUN_MODE_CYCLIC_SYNC_VELOCITY:
+ eth_mode = eth_OperateMode_CyclicSyncVelocity;
+ break;
+ case RUN_MODE_CYCLIC_SYNC_CURRENT:
+ eth_mode = eth_OperateMode_CyclicSyncTorque;
+ break;
+ default:
+ LOG(ERROR) << "[EYouEthercatProtocol] Unknown mode " << mode << " for node " << node_id;
+ return;
+ }
+
+ if (eth_setOperateMode(node_id, eth_mode) == ETH_SUCCESS) {
+ node_states_[node_id].current_mode = mode;
+ LOG(INFO) << "[EYouEthercatProtocol] Node " << node_id << " mode set to " << mode;
+ } else {
+ LOG(ERROR) << "[EYouEthercatProtocol] Failed to set mode for node " << node_id;
+ }
+}
+
+// 设置目标位置和速度
+void EYouEthercatProtocol::setTarget(uint8_t node_id, double angle_rad, double vel) {
+ auto pos_cmd = angleToPos(angle_rad);
+ auto speed = static_cast(std::abs(velToSpeed(vel)));
+
+ msgs::RunMode current_mode = getMode(node_id);
+
+ switch (current_mode) {
+ case RUN_MODE_PROFILE_POSITION: {
+ // 先设置轮廓速度
+ eth_setProfileVelocity(node_id, speed);
+ // 设置目标位置
+ eth_setTargetPosition(node_id, pos_cmd);
+
+ // 构建控制字:使能状态 + 立即更新标志
+ uint16_t ctlword = 0x0F | 0x20; // 0x0F使能, 0x20立即更新
+
+ // 触发位置更新
+ eth_setControlWord(node_id, ctlword);
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+
+ // 启动新位置命令
+ eth_setControlWord(node_id, ctlword | 0x10);
+ break;
+ }
+ case RUN_MODE_CYCLIC_SYNC_POSITION:
+ eth_setTargetPosition(node_id, 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(velToSpeed(vel));
+
+ msgs::RunMode current_mode = getMode(node_id);
+
+ switch (current_mode) {
+ case RUN_MODE_VELOCITY:
+ case RUN_MODE_PROFILE_VELOCITY:
+ case RUN_MODE_CYCLIC_SYNC_VELOCITY:
+ eth_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 RUN_MODE_CYCLIC_SYNC_POSITION:
+ {
+ eth_setTargetPosition(node_id, pos_cmd);
+ break;
+ }
+ case RUN_MODE_PROFILE_POSITION:
+ {
+ // 1. 设置目标位置
+ eth_setTargetPosition(node_id, pos_cmd);
+
+ // 2. 构建控制字:使能状态 + 立即更新标志
+ uint16_t ctlword = 0x0F | 0x20; // 0x0F使能, 0x20立即更新
+
+ // 3. 触发位置更新
+ eth_setControlWord(node_id, ctlword);
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+
+ // 4. 启动新位置命令
+ eth_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);
+ // 开启软件位置限制
+ hint32 limitEnable = 0x4c494d54;
+ if (eth_writeSDO(node_id, 0x2003, 0x00, &limitEnable, eth_DataType_int32, 100) != ETH_SUCCESS) {
+ LOG(ERROR) << "[EYouEthercatProtocol] Failed to enable software position limit for node " << node_id;
+ }
+
+ // 设置软件位置限制
+ if (eth_writeSDO(node_id, 0x607D, 0x01, &lb_val, eth_DataType_int32, 100) != ETH_SUCCESS) {
+ LOG(ERROR) << "[EYouEthercatProtocol] Failed to set lower position limit for node " << node_id;
+ }
+
+ if (eth_writeSDO(node_id, 0x607D, 0x02, &ub_val, eth_DataType_int32, 100) != ETH_SUCCESS) {
+ LOG(ERROR) << "[EYouEthercatProtocol] Failed to set upper position limit for node " << node_id;
+ }
+}
+
+// 设置速度限制
+void EYouEthercatProtocol::setLimitQd(uint8_t node_id, double qd) {
+ auto speed = static_cast(std::abs(velToSpeed(qd)));
+
+ // 设置最大速度限制
+ if (eth_writeSDO(node_id, 0x607F, 0x00, &speed, eth_DataType_uint32, 100) != ETH_SUCCESS) {
+ LOG(ERROR) << "[EYouEthercatProtocol] Failed to set max speed limit for node " << node_id;
+ }
+
+ if (eth_writeSDO(node_id, 0x6081, 0x00, &speed, eth_DataType_uint32, 100) != ETH_SUCCESS) {
+ LOG(ERROR) << "[EYouEthercatProtocol] Failed to set profile speed for node " << node_id;
+ }
+}
+
+// 设置加速度限制
+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((std::abs(u_qdd) / (2.0 * M_PI)) * GearRatio * PULSE_PER_REV);
+ auto decel = static_cast((std::abs(l_qdd) / (2.0 * M_PI)) * GearRatio * PULSE_PER_REV);
+
+ // 通过SDO写入加速度和减速度限制
+ if (eth_writeSDO(node_id, 0x6083, 0x00, &accel, eth_DataType_uint32, 100) != ETH_SUCCESS) {
+ LOG(ERROR) << "[EYouEthercatProtocol] Failed to set acceleration limit for node " << node_id;
+ }
+
+ if (eth_writeSDO(node_id, 0x6084, 0x00, &decel, eth_DataType_uint32, 100) != ETH_SUCCESS) {
+ LOG(ERROR) << "[EYouEthercatProtocol] Failed to set deceleration limit for node " << node_id;
+ }
+}
+
+// 零位校准
+bool EYouEthercatProtocol::calibrateZeroQ(uint8_t node_id) {
+ try {
+ hint32 pos;
+ hint32 offset = 0;
+ hint32 rev = 0;
+
+ //读取当前位置
+ int iRet = eth_readSDO(node_id,0x6064,0x00,&pos,eth_DataType_uint32,20000);
+ if (iRet != ETH_SUCCESS)
+ {
+ std::cout <<"read actualPos last failed: "< temp || pos < -temp)
+ {
+ pos = pos % r;
+ if (pos > temp || pos < -temp)
+ {
+ if (pos > temp)
+ {
+ pos = pos -r;
+ }
+ else if(pos < -temp)
+ {
+ pos = pos + r;
+ }
+ }
+ std::cout <<"分辨率超过编码器范围,电机重新上电后变为零点" << std::endl;
+
+ }
+ ////
+
+ //写home offset偏移
+ offset = -pos;
+ iRet = eth_writeSDO(node_id,0x607c,0x00,&offset,eth_DataType_uint32,20000);
+ if (iRet != ETH_SUCCESS)
+ {
+ std::cout <<"writeSdo offset -pos failed: "<(std::abs(velToSpeed(qd)));
+
+ msgs::RunMode current_mode = getMode(node_id);
+
+ switch (current_mode) {
+ case RUN_MODE_CYCLIC_SYNC_POSITION:
+ case RUN_MODE_PROFILE_POSITION:
+ eth_setProfileVelocity(node_id, speed);
+ last_Qd_[node_id] = speed;
+ break;
+ case RUN_MODE_PROFILE_VELOCITY:
+ case RUN_MODE_CYCLIC_SYNC_VELOCITY:
+ eth_setTargetVelocity(node_id, static_cast(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² (加速度)
+ // 转换为电机加速度(脉冲/秒²)
+ // 圈数/秒² = qdd / 2π
+ // 脉冲/秒² = 圈数/秒² * GearRatio * PULSE_PER_REV
+ uint32_t accel = static_cast((std::abs(qdd) / (2.0 * M_PI)) * GearRatio * PULSE_PER_REV);
+
+ if (last_Qdd_[node_id] != accel) {
+ eth_setProfileAcceleration(node_id, accel);
+ eth_setProfileDeceleration(node_id, accel);
+ last_Qdd_[node_id] = accel;
+ }
+}
+
+// 力矩关闭
+void EYouEthercatProtocol::torqueOff(uint8_t node_id) {
+ auto ret = eth_disable(node_id);
+ LOG(INFO) << "[EYouEthercatProtocol] Torque off for motor " << node_id << ", ret = " << ret;
+}
+
+// 获取运行模式
+RunMode EYouEthercatProtocol::getMode(uint8_t node_id) {
+ eth_OperateMode mode;
+ if (eth_getOperateMode(node_id, &mode) != ETH_SUCCESS) {
+ LOG(ERROR) << "[EYouEthercatProtocol] Failed to read mode for node " << node_id;
+ return node_states_[node_id].current_mode;
+ }
+
+ // 将SDK的操作模式转换为内部运行模式
+ switch (mode) {
+ case eth_OperateMode_ProfilePosition:
+ return RUN_MODE_PROFILE_POSITION;
+ case eth_OperateMode_Velocity:
+ return RUN_MODE_VELOCITY;
+ case eth_OperateMode_ProfileVelocity:
+ return RUN_MODE_PROFILE_VELOCITY;
+ case eth_OperateMode_ProfileTorque:
+ return RUN_MODE_TORQUE;
+ case eth_OperateMode_Homing:
+ return RUN_MODE_HOMING;
+ case eth_OperateMode_InterpolatedPosition:
+ return RUN_MODE_INTERPOLATED_POSITION;
+ case eth_OperateMode_CyclicSyncPosition:
+ return RUN_MODE_CYCLIC_SYNC_POSITION;
+ case eth_OperateMode_CyclicSyncVelocity:
+ return RUN_MODE_CYCLIC_SYNC_VELOCITY;
+ case eth_OperateMode_CyclicSyncTorque:
+ return RUN_MODE_CYCLIC_SYNC_CURRENT;
+ default:
+ return RUN_MODE_UNSPECIFIED;
+ }
+}
+
+// 配置轮廓参数
+void EYouEthercatProtocol::configProfile(uint8_t node_id, uint32_t speed, uint32_t accel, uint32_t decel) {
+ eth_setProfileVelocity(node_id, speed);
+ eth_setProfileAcceleration(node_id, accel);
+ eth_setProfileDeceleration(node_id, decel);
+}
+
+// 获取力矩
+double EYouEthercatProtocol::getTorque(uint8_t node_id) {
+ int16_t torque = 0;
+ if (eth_getActualTorque(node_id, &torque) != ETH_SUCCESS) {
+ LOG(ERROR) << "[EYouEthercatProtocol] Failed to read torque for node " << node_id;
+ return 0.0;
+ }
+ return torque / 1000.0; // 转换为实际力矩值(额定力矩的倍数)
+}
+
+// 获取状态字
+uint16_t EYouEthercatProtocol::getStatusWord(uint8_t node_id) {
+ uint16_t status_word = 0;
+ if (eth_getStatusWord(node_id, &status_word) == ETH_SUCCESS) {
+ 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; // bit 3 为1表示故障
+}
+
+// 故障复位
+void EYouEthercatProtocol::faultReset(uint8_t node_id) {
+ if (isFault(node_id)) {
+ if (eth_faultReset(node_id) == ETH_SUCCESS) {
+ 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 EYouEthercatProtocol::GetRobotDetail() {
+ if (message_manager_) {
+ auto data_ptr = std::make_unique();
+ message_manager_->GetSensorData(data_ptr.get());
+ return data_ptr;
+ }
+ return std::make_unique();
+}
+
+// 辅助函数实现(弧度制版本)
+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((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 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) {
+ // 更新状态字
+ eth_getStatusWord(node_id, &node_states_[node_id].status_word);
+ // 可以根据需要更新其他状态信息
+}
\ No newline at end of file
diff --git a/cmvr-es/devices/motor/eyou_motor/ethercat/eyou_motor_ethercat_protocol.h b/cmvr-es/devices/motor/eyou_motor/ethercat/eyou_motor_ethercat_protocol.h
new file mode 100644
index 00000000..11401e97
--- /dev/null
+++ b/cmvr-es/devices/motor/eyou_motor/ethercat/eyou_motor_ethercat_protocol.h
@@ -0,0 +1,106 @@
+//
+// 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"
+
+#include "eyou_ethercat/include/eu_ethercat.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+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; // 位置偏置值
+ };
+
+ class EYouEthercatProtocol : public MotorProtocolInterface {
+ public:
+ explicit EYouEthercatProtocol(std::string ifName);
+ ~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 GetRobotDetail();
+
+ 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 condition, int timeout_ms);
+ void updateNodeState(uint8_t node_id); // 更新节点状态
+
+ // 成员变量
+ std::unordered_map node_states_; // 节点状态映射
+ std::unordered_map last_Qd_; // 上次设置的速度
+ std::unordered_map last_Qdd_; // 上次设置的加速度
+
+ std::shared_ptr> can_sender_;
+ std::shared_ptr> message_manager_;
+
+ std::string interface_name_; // 网卡接口名
+ bool initialized_; // 是否已初始化SDK
+ int slave_count_; // 从站数量
+ };
+
+ } // namespace device
+} // namespace cmvr
\ No newline at end of file
diff --git a/cmvr-es/devices/motor/eyou_motor/eyou_motor.cpp b/cmvr-es/devices/motor/eyou_motor/eyou_motor.cpp
new file mode 100644
index 00000000..d9e2f043
--- /dev/null
+++ b/cmvr-es/devices/motor/eyou_motor/eyou_motor.cpp
@@ -0,0 +1,5 @@
+//
+// Created by cmvr on 2026/3/30.
+//
+
+#include "eyou_motor.h"
\ No newline at end of file
diff --git a/cmvr-es/devices/motor/eyou_motor/eyou_motor.h b/cmvr-es/devices/motor/eyou_motor/eyou_motor.h
new file mode 100644
index 00000000..e94979e9
--- /dev/null
+++ b/cmvr-es/devices/motor/eyou_motor/eyou_motor.h
@@ -0,0 +1,51 @@
+//
+// 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 canopen_protocol = std::dynamic_pointer_cast(protocol_);
+ // canopen_protocol->setMode(node_id_,msgs::RUN_MODE_CYCLIC_SYNC_POSITION);
+ // canopen_protocol->seedSdoRequest(node_id_, msgs::CS_WRITE_TWO_BYTES, msgs::CONTROL_WORD_6040, msgs::SUB_INDEX_0, 0x06,15);
+ // canopen_protocol->seedSdoRequest(node_id_, msgs::CS_WRITE_TWO_BYTES, msgs::CONTROL_WORD_6040, msgs::SUB_INDEX_0, 0x0F,15);
+ // canopen_protocol->setLimitQd(node_id_,5.0);
+ // canopen_protocol->setLimitQdd(node_id_,10.0,-10.0);
+
+ // canopen_protocol->torqueOff(node_id_);
+ }
+ }
+ };
+
+
+ }
+}
diff --git a/cmvr-es/devices/motor/motor_protocol_interface.h b/cmvr-es/devices/motor/motor_protocol_interface.h
index 634a715c..6b49aa06 100644
--- a/cmvr-es/devices/motor/motor_protocol_interface.h
+++ b/cmvr-es/devices/motor/motor_protocol_interface.h
@@ -15,7 +15,8 @@ namespace cmvr {
public:
enum class CommProto : uint8_t {
CANOPEN = 1,
- CUSTOM = 2
+ ETHERCAT = 2,
+ CUSTOM = 3
};
virtual ~MotorProtocolInterface() = default;
diff --git a/cmvr-es/devices/motor/ti5_motor/ti5_motor.h b/cmvr-es/devices/motor/ti5_motor/ti5_motor.h
index cfc9bde9..65f44ddc 100644
--- a/cmvr-es/devices/motor/ti5_motor/ti5_motor.h
+++ b/cmvr-es/devices/motor/ti5_motor/ti5_motor.h
@@ -1,11 +1,12 @@
//
// 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 中完成
*/
@@ -22,6 +23,15 @@ 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;
+ }
+
+
/**
* 电机初始化在具体的类中完成
*/
diff --git a/cmvr-es/devices/robot/abstract_robot.h b/cmvr-es/devices/robot/abstract_robot.h
index 5759c3af..91daf0ae 100644
--- a/cmvr-es/devices/robot/abstract_robot.h
+++ b/cmvr-es/devices/robot/abstract_robot.h
@@ -41,6 +41,7 @@ namespace cmvr::device{
class AbstractRobot: public AbstractDevice {
public:
+ AbstractRobot() = default;
explicit AbstractRobot(const XmlNode &config): AbstractDevice(config) {}
~AbstractRobot() override=default;
diff --git a/cmvr-es/devices/robot/humanoid_robot/include/humanoid_robot.h b/cmvr-es/devices/robot/humanoid_robot/include/humanoid_robot.h
index 7770997b..9cd2d11d 100644
--- a/cmvr-es/devices/robot/humanoid_robot/include/humanoid_robot.h
+++ b/cmvr-es/devices/robot/humanoid_robot/include/humanoid_robot.h
@@ -35,6 +35,8 @@
#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{
@@ -49,12 +51,10 @@ 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,6 +232,7 @@ namespace cmvr::device{
std::atomic is_head_busy_{false}, is_waist_busy_{false};
+ std::string urdf_path_ = "";
};
diff --git a/cmvr-es/devices/robot/humanoid_robot/src/humanoid_robot.cpp b/cmvr-es/devices/robot/humanoid_robot/src/humanoid_robot.cpp
index 0146c053..56c7542b 100644
--- a/cmvr-es/devices/robot/humanoid_robot/src/humanoid_robot.cpp
+++ b/cmvr-es/devices/robot/humanoid_robot/src/humanoid_robot.cpp
@@ -16,7 +16,7 @@ template
HumanoidRobot::HumanoidRobot(const XmlNode &cfg) : AbstractRobot(cfg) {
try {
id_ = cfg.getAttrString("id");
-
+ urdf_path_ = cfg.getAttrString("urdf");
dof_ = DOF;
if (!pathExists(cfg.getAttrString("urdf"))) {
throw runtime_error("urdf file does not exist");
@@ -49,6 +49,87 @@ HumanoidRobot::HumanoidRobot(const XmlNode &cfg) : AbstractRobot(cfg) {
}
}
+
+template
+HumanoidRobot::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 >(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 >(m_robot_);
+ upd_freq_ = config.updfreq();
+ CSP_buffer_ = make_shared >(config.buffersize());
+ CSV_buffer_ = make_shared >(config.buffersize());
+ CSC_buffer_ = make_shared >(config.buffersize());
+
+ upd_freq_ = 1000;
+ upd_timer_ = make_shared();
+ 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
+HumanoidRobot::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 >(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 >(m_robot_);
+ upd_freq_ = config.updfreq();
+ CSP_buffer_ = make_shared >(config.buffersize());
+ CSV_buffer_ = make_shared >(config.buffersize());
+ CSC_buffer_ = make_shared >(config.buffersize());
+
+ upd_freq_ = 1000;
+ upd_timer_ = make_shared();
+ 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
void HumanoidRobot::init() {
motor_manager_ = MotorsInfo::getInstance()->getMotorManager();
@@ -59,7 +140,7 @@ void HumanoidRobot::init() {
std::vector(7, 1.0));
- ik_solver_ = std::make_shared("/home/lgv/cmvr/cmvr-es/model/xiaoyan_description/dual_arm.urdf",
+ ik_solver_ = std::make_shared(urdf_path_,
"PELVIS_S",
"R_WRIST_R_S",
"R_FINGER_TIP_FIXED");
diff --git a/cmvr-es/devices/robot/humanoid_robot/src/humanoid_robot_test.cpp b/cmvr-es/devices/robot/humanoid_robot/src/humanoid_robot_test.cpp
index d1b47e4e..1fba8212 100644
--- a/cmvr-es/devices/robot/humanoid_robot/src/humanoid_robot_test.cpp
+++ b/cmvr-es/devices/robot/humanoid_robot/src/humanoid_robot_test.cpp
@@ -112,7 +112,7 @@ TEST(HumanoidRobotTest, speedLSmokeTest) {
const XmlNode config("/home/lgv/cmvr/cmvr-es/cmvr-es/common/config/cabin_robot.xml");
ASSERT_TRUE(config.hasChild("DeviceManager")) << "DeviceManager node not found";
auto dmgr_cfg = config.getChild("DeviceManager");
- auto& dmgr = DeviceManager::getInstance(dmgr_cfg);
+ auto& dmgr = DeviceManager::getInstance();
auto robot_abs = dmgr.getDevice("hc01");
auto robot = std::dynamic_pointer_cast>(robot_abs);
@@ -231,7 +231,7 @@ TEST(HumanoidRobotTest, moveLSCurveLocalRealRobot) {
const XmlNode config("/home/lgv/cmvr/cmvr-es/cmvr-es/common/config/cabin_robot.xml");
ASSERT_TRUE(config.hasChild("DeviceManager")) << "DeviceManager node not found";
auto dmgr_cfg = config.getChild("DeviceManager");
- auto& dmgr = DeviceManager::getInstance(dmgr_cfg);
+ auto& dmgr = DeviceManager::getInstance();
auto robot_abs = dmgr.getDevice("hc01");
auto robot = std::dynamic_pointer_cast>(robot_abs);
@@ -368,7 +368,7 @@ TEST(HumanoidRobotTest, moveLRealRobot) {
const XmlNode config("/home/lgv/cmvr/cmvr-es/cmvr-es/common/config/cabin_robot.xml");
ASSERT_TRUE(config.hasChild("DeviceManager")) << "DeviceManager node not found";
auto dmgr_cfg = config.getChild("DeviceManager");
- auto& dmgr = DeviceManager::getInstance(dmgr_cfg);
+ auto& dmgr = DeviceManager::getInstance();
auto robot_abs = dmgr.getDevice("hc01");
auto robot = std::dynamic_pointer_cast