fix(ti5 motors):can send & rec bug
This commit is contained in:
parent
f768960ff2
commit
29a899b305
@ -149,4 +149,155 @@ arm {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
robot_arms {
|
||||
id: "left_arm"
|
||||
|
||||
motor {
|
||||
motor_system_id: "left_arm_can_motors"
|
||||
motor_group_ids: "left_arm_can_motors"
|
||||
dof: 7
|
||||
joint_names: "L_SHOULDER_P"
|
||||
joint_names: "L_SHOULDER_R"
|
||||
joint_names: "L_SHOULDER_Y"
|
||||
joint_names: "L_ELBOW_R"
|
||||
joint_names: "L_WRIST_P"
|
||||
joint_names: "L_WRIST_Y"
|
||||
joint_names: "L_WRIST_R"
|
||||
upd_freq: 1000
|
||||
buffer_size: 50
|
||||
default_vel: 1.0
|
||||
default_acc: 2.0
|
||||
}
|
||||
|
||||
kinematics {
|
||||
pinocchio_dls_ik_solver {
|
||||
urdf_path: "model/xiaoyan_description/dual_arm.urdf"
|
||||
base_frame_name: "PELVIS_S"
|
||||
flange_frame_name: "L_WRIST_R_S"
|
||||
tcp_frame_name: "L_FINGER_TIP_FIXED"
|
||||
max_iters: 100
|
||||
pos_eps: 1e-6
|
||||
rot_eps: 1e-6
|
||||
damping: 1e-6
|
||||
joint_limit_policy {
|
||||
limits {
|
||||
enable: true
|
||||
source: JOINT_LIMIT_SOURCE_CUSTOM
|
||||
joints { joint_name: "L_SHOULDER_P" q_lb: -3.14 q_ub: 3.14 qd: 5.0 qdd: 10.0 }
|
||||
joints { joint_name: "L_SHOULDER_R" q_lb: -0.78 q_ub: 1.57 qd: 5.0 qdd: 10.0 }
|
||||
joints { joint_name: "L_SHOULDER_Y" q_lb: -3.14 q_ub: 3.14 qd: 5.0 qdd: 10.0 }
|
||||
joints { joint_name: "L_ELBOW_R" q_lb: 0 q_ub: 2.05 qd: 5.0 qdd: 10.0 }
|
||||
joints { joint_name: "L_WRIST_P" q_lb: -3.14 q_ub: 3.14 qd: 5.0 qdd: 10.0 }
|
||||
joints { joint_name: "L_WRIST_Y" q_lb: -0.78 q_ub: 0.78 qd: 5.0 qdd: 10.0 }
|
||||
joints { joint_name: "L_WRIST_R" q_lb: -0.57 q_ub: 1.57 qd: 5.0 qdd: 10.0 }
|
||||
}
|
||||
soft_limit {
|
||||
enable: true
|
||||
margin_ratio: 0.01
|
||||
min_margin_rad: 0.01
|
||||
}
|
||||
avoidance {
|
||||
enable: false
|
||||
gain: 0.2
|
||||
margin_ratio: 0.15
|
||||
max_push: 0.25
|
||||
weight: 0.05
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
motion {
|
||||
move_j {
|
||||
toppra_joint_motion_planner {
|
||||
path_type: TOPPRA_PATH_TYPE_QUINTIC
|
||||
sample_period_s: 0.001
|
||||
grid_size: 150
|
||||
high_grid_size: 300
|
||||
}
|
||||
}
|
||||
|
||||
move_l {
|
||||
pinocchio_cartesian_motion_planner {
|
||||
sample_period_s: 0.001
|
||||
position_gain: 4.0
|
||||
rotation_gain: 4.0
|
||||
line_deviation_check {
|
||||
enable: true
|
||||
line_deviation_warn_m: 0.01
|
||||
line_deviation_stop_m: 0.03
|
||||
line_direction_warn_deg: 20.0
|
||||
line_direction_stop_deg: 45.0
|
||||
line_direction_reset_deg: 10.0
|
||||
line_check_min_distance_m: 0.01
|
||||
}
|
||||
joint_continuity_check {
|
||||
enable: true
|
||||
max_joint_delta_rad: 0.05
|
||||
max_joint_velocity_rad_s: 10.0
|
||||
max_joint_acceleration_rad_s2: 5000.0
|
||||
}
|
||||
cartesian_step_feasibility_check {
|
||||
enable: true
|
||||
min_linear_speed_ratio: 0.2
|
||||
max_linear_direction_deviation_deg: 45.0
|
||||
min_angular_speed_ratio: 0.2
|
||||
max_angular_direction_deviation_deg: 45.0
|
||||
min_desired_linear_speed: 1e-4
|
||||
min_desired_angular_speed: 1e-4
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
speed_l {
|
||||
pinocchio_cartesian_motion_planner {
|
||||
linear_velocity_max: 0.55
|
||||
linear_acceleration_max: 5.0
|
||||
linear_jerk_max: 10.0
|
||||
angular_velocity_max: 1.0
|
||||
angular_acceleration_max: 5.0
|
||||
angular_jerk_max: 12.0
|
||||
linear_target_replan_threshold: 1e-4
|
||||
angular_target_replan_threshold: 1e-4
|
||||
linear_reverse_cos_threshold: -0.8660254037844386
|
||||
linear_reverse_switch_speed_threshold: 1e-3
|
||||
enforce_joint_acceleration_limits: true
|
||||
line_deviation_check {
|
||||
enable: true
|
||||
line_deviation_warn_m: 0.01
|
||||
line_deviation_stop_m: 0.03
|
||||
line_direction_warn_deg: 20.0
|
||||
line_direction_stop_deg: 45.0
|
||||
line_direction_reset_deg: 10.0
|
||||
line_check_min_distance_m: 0.01
|
||||
}
|
||||
joint_velocity_check {
|
||||
enable: true
|
||||
max_joint_velocity_rad_s: 30.0
|
||||
max_joint_acceleration_rad_s2: 10000.0
|
||||
}
|
||||
cartesian_velocity_feasibility_check {
|
||||
enable: true
|
||||
min_linear_speed_ratio: 0.2
|
||||
max_linear_direction_deviation_deg: 5.0
|
||||
min_angular_speed_ratio: 0.2
|
||||
max_angular_direction_deviation_deg: 5.0
|
||||
min_desired_linear_speed: 1e-4
|
||||
min_desired_angular_speed: 1e-4
|
||||
}
|
||||
}
|
||||
|
||||
speed_l_controller {
|
||||
cartesian_velocity_controller {
|
||||
control_period_s: 0.001
|
||||
stop_twist_norm: 1e-9
|
||||
stop_command_velocity_norm: 1e-3
|
||||
stop_measured_velocity_norm: 1e-2
|
||||
stop_acceleration: 10
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ dexhand {
|
||||
dexhands {
|
||||
id: "hand1"
|
||||
rh56dftp {
|
||||
ip: "192.168.1.213"
|
||||
ip: "192.168.1.223"
|
||||
port: 6000
|
||||
poll_interval_ms: 10
|
||||
}
|
||||
|
||||
@ -6,35 +6,35 @@ device_manager {
|
||||
id: "mujoco_world"
|
||||
type: DEVICE_TYPE_MUJOCO_WORLD
|
||||
config_file: "devices/mujoco/mujoco_world.pb.txt"
|
||||
enable: true
|
||||
enable: false
|
||||
}
|
||||
|
||||
devices {
|
||||
id: "right_arm_mujoco_motors"
|
||||
type: DEVICE_TYPE_MOTOR_SYSTEM
|
||||
config_file: "devices/motor/mujoco_motors.pb.txt"
|
||||
enable: true
|
||||
enable: false
|
||||
}
|
||||
|
||||
devices {
|
||||
id: "mujoco_right_arm"
|
||||
type: DEVICE_TYPE_ROBOT_ARM
|
||||
config_file: "devices/arm/arm_mujoco_qp.pb.txt"
|
||||
enable: true
|
||||
enable: false
|
||||
}
|
||||
|
||||
devices {
|
||||
id: "mujoco_viewer"
|
||||
type: DEVICE_TYPE_MUJOCO_VIEWER
|
||||
config_file: "devices/mujoco/mujoco_viewer.pb.txt"
|
||||
enable: true
|
||||
enable: false
|
||||
}
|
||||
|
||||
devices {
|
||||
id: "mujoco_hand_cam"
|
||||
type: DEVICE_TYPE_CAMERA
|
||||
config_file: "devices/camera/camera.pb.txt"
|
||||
enable: true
|
||||
enable: false
|
||||
}
|
||||
|
||||
devices {
|
||||
@ -52,11 +52,18 @@ device_manager {
|
||||
}
|
||||
|
||||
|
||||
devices {
|
||||
id: "hand1"
|
||||
type: DEVICE_TYPE_DEXHAND
|
||||
config_file: "devices/dexhand/dexhand.pb.txt"
|
||||
enable: true
|
||||
}
|
||||
|
||||
devices {
|
||||
id: "hand2"
|
||||
type: DEVICE_TYPE_DEXHAND
|
||||
config_file: "devices/dexhand/dexhand.pb.txt"
|
||||
enable: false
|
||||
enable: true
|
||||
}
|
||||
|
||||
devices {
|
||||
@ -70,7 +77,7 @@ device_manager {
|
||||
id: "mujoco_zero_touch_dexhand"
|
||||
type: DEVICE_TYPE_DEXHAND
|
||||
config_file: "devices/dexhand/dexhand.pb.txt"
|
||||
enable: true
|
||||
enable: false
|
||||
}
|
||||
|
||||
devices {
|
||||
@ -84,7 +91,7 @@ device_manager {
|
||||
id: "right_arm_can_motors"
|
||||
type: DEVICE_TYPE_MOTOR_SYSTEM
|
||||
config_file: "devices/motor/ti5_motors.pb.txt"
|
||||
enable: false
|
||||
enable: true
|
||||
}
|
||||
|
||||
devices {
|
||||
@ -112,6 +119,13 @@ device_manager {
|
||||
id: "right_arm"
|
||||
type: DEVICE_TYPE_ROBOT_ARM
|
||||
config_file: "devices/arm/arm.pb.txt"
|
||||
enable: true
|
||||
}
|
||||
|
||||
devices {
|
||||
id: "left_arm"
|
||||
type: DEVICE_TYPE_ROBOT_ARM
|
||||
config_file: "devices/arm/arm.pb.txt"
|
||||
enable: false
|
||||
}
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ task_manager {
|
||||
run_mode: TASK_RUN_MODE_PERIODIC_STEP
|
||||
control_period_s: 0.001
|
||||
config_file: "tasks/touch_screen_task/touch_screen_task_mujoco.pb.txt"
|
||||
enable: true
|
||||
enable: false
|
||||
}
|
||||
tasks {
|
||||
id: "grpc_server"
|
||||
|
||||
@ -247,6 +247,9 @@ namespace cmvr {
|
||||
curr_period_ = period_;
|
||||
|
||||
Update();
|
||||
if (send_with_once_) {
|
||||
has_sent_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename SensorType>
|
||||
|
||||
@ -77,6 +77,19 @@ namespace cmvr {
|
||||
sensor_data->enable = (bytes[2] != 0);
|
||||
}
|
||||
|
||||
TEST(CanSenderTest, OneShotMessageWaitsForExplicitUpdate) {
|
||||
MyProtocol protocol;
|
||||
SenderMessage<MySensorData> message(MyProtocol::ID, &protocol, true);
|
||||
|
||||
EXPECT_TRUE(message.has_sent());
|
||||
|
||||
protocol.SetSpeed(12.3);
|
||||
protocol.SetEnable(true);
|
||||
message.Update();
|
||||
|
||||
EXPECT_FALSE(message.has_sent());
|
||||
}
|
||||
|
||||
|
||||
TEST(CanSenderTest, OneRunCase) {
|
||||
cmvr::config::SocketCanConfig cfg;
|
||||
|
||||
@ -214,14 +214,14 @@ namespace cmvr::device{
|
||||
|
||||
|
||||
// 使用的通讯协议
|
||||
virtual void setProtocol(std::shared_ptr<MotorProtocolInterface> protocol) {
|
||||
virtual bool setProtocol(std::shared_ptr<MotorProtocolInterface> protocol) {
|
||||
std::scoped_lock lock(mtx_);
|
||||
protocol_ = std::move(protocol);
|
||||
if (!protocol_) {
|
||||
CMVR_LOG(ERROR) << "Protocol not set for motor";
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
protocol_->initNode(node_id_);
|
||||
return protocol_->initNode(node_id_);
|
||||
}
|
||||
|
||||
uint8_t id() const {
|
||||
|
||||
@ -68,16 +68,16 @@ bool CanMotorBusRuntime::start()
|
||||
return false;
|
||||
}
|
||||
|
||||
auto ret = sender_->Start();
|
||||
auto ret = receiver_->Start();
|
||||
if (ret != ErrorCode::OK) {
|
||||
CMVR_LOG(ERROR) << "[CanMotorBusRuntime] failed to start CAN sender: " << id_;
|
||||
CMVR_LOG(ERROR) << "[CanMotorBusRuntime] failed to start CAN receiver: " << id_;
|
||||
stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = receiver_->Start();
|
||||
ret = sender_->Start();
|
||||
if (ret != ErrorCode::OK) {
|
||||
CMVR_LOG(ERROR) << "[CanMotorBusRuntime] failed to start CAN receiver: " << id_;
|
||||
CMVR_LOG(ERROR) << "[CanMotorBusRuntime] failed to start CAN sender: " << id_;
|
||||
stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -59,7 +59,12 @@ namespace cmvr {
|
||||
// canopen_protocol->configProfile(node_id_,4000,8000,8000);
|
||||
canopen_protocol->seedNmtRequest(node_id_,msgs::NMT_ENTER_PRE_OPERATIONAL);
|
||||
canopen_protocol->seedNmtRequest(node_id_,msgs::NMT_START_REMOTE_NODE);
|
||||
canopen_protocol->setMode(node_id_,msgs::RUN_MODE_CYCLIC_SYNC_POSITION);
|
||||
if (!canopen_protocol->setMode(
|
||||
node_id_, msgs::RUN_MODE_CYCLIC_SYNC_POSITION)) {
|
||||
CMVR_LOG(ERROR) << "[Ti5Motor] failed to initialize operation mode: "
|
||||
<< info_.joint_name;
|
||||
return false;
|
||||
}
|
||||
// canopen_protocol->seedSdoRequest(node_id_, msgs::CS_WRITE_TWO_BYTES, msgs::CIA402_CONTROL_WORD_6040, msgs::SUB_INDEX_0, 0x06,15);
|
||||
// canopen_protocol->seedSdoRequest(node_id_, msgs::CS_WRITE_TWO_BYTES, msgs::CIA402_CONTROL_WORD_6040, msgs::SUB_INDEX_0, 0x0F,15);
|
||||
canopen_protocol->setLimitQ(node_id_, info_.limit_q_ub, info_.limit_q_lb);
|
||||
|
||||
@ -74,12 +74,7 @@ namespace cmvr {
|
||||
return data_ptr;
|
||||
}
|
||||
|
||||
msgs::RunMode getMode(uint8_t node_id) override {
|
||||
return GetRobotDetail()->motors().at(node_id).run_mode();
|
||||
// cur_mode_[node_id] = feed_mode;
|
||||
// return feed_mode;
|
||||
// return cur_mode_[node_id];
|
||||
}
|
||||
msgs::RunMode getMode(uint8_t node_id) override;
|
||||
|
||||
|
||||
private:
|
||||
@ -113,6 +108,7 @@ namespace cmvr {
|
||||
std::map<uint8_t, motor::Ti5MotorRPDO1 *> rpdo1_commands_{};
|
||||
std::map<uint8_t, motor::Ti5MotorRPDO2 *> rpdo2_commands_{};
|
||||
|
||||
bool getMotorStatus(uint8_t node_id, msgs::MotorStatus* status) const;
|
||||
void writeProfilePositionTargetBySdo(uint8_t node_id, int32_t pos);
|
||||
|
||||
|
||||
|
||||
@ -67,7 +67,7 @@ bool Ti5MotorCanopenProtocol::initNode(uint8_t node_id) {
|
||||
|
||||
if (sdo_commands_[node_id] == nullptr) {
|
||||
CMVR_LOG(ERROR) << "Ti5 Motor SDO Request Protocol does not exist in the MessageManager!";
|
||||
return ErrorCode::CANBUS_ERROR;
|
||||
return false;
|
||||
}
|
||||
can_sender_->AddMessage(sdo_commands_[node_id]->ID(), sdo_commands_[node_id], true);
|
||||
|
||||
@ -78,7 +78,7 @@ bool Ti5MotorCanopenProtocol::initNode(uint8_t node_id) {
|
||||
|
||||
if (rpdo1_commands_[node_id] == nullptr) {
|
||||
CMVR_LOG(ERROR) << "Ti5 Motor RPDO1 Protocol does not exist in the MessageManager!";
|
||||
return ErrorCode::CANBUS_ERROR;
|
||||
return false;
|
||||
}
|
||||
can_sender_->AddMessage(rpdo1_commands_[node_id]->ID(), rpdo1_commands_[node_id], true);
|
||||
|
||||
@ -88,11 +88,38 @@ bool Ti5MotorCanopenProtocol::initNode(uint8_t node_id) {
|
||||
|
||||
if (rpdo2_commands_[node_id] == nullptr) {
|
||||
CMVR_LOG(ERROR) << "Ti5 Motor RPDO2 Protocol does not exist in the MessageManager!";
|
||||
return ErrorCode::CANBUS_ERROR;
|
||||
return false;
|
||||
}
|
||||
can_sender_->AddMessage(rpdo2_commands_[node_id]->ID(), rpdo2_commands_[node_id], true);
|
||||
|
||||
return ErrorCode::OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Ti5MotorCanopenProtocol::getMotorStatus(
|
||||
const uint8_t node_id,
|
||||
msgs::MotorStatus* const status) const {
|
||||
if (!message_manager_ || !status) {
|
||||
return false;
|
||||
}
|
||||
|
||||
msgs::RobotDetail robot_detail;
|
||||
if (message_manager_->GetSensorData(&robot_detail) != ErrorCode::OK) {
|
||||
return false;
|
||||
}
|
||||
const auto it = robot_detail.motors().find(node_id);
|
||||
if (it == robot_detail.motors().end()) {
|
||||
return false;
|
||||
}
|
||||
status->CopyFrom(it->second);
|
||||
return true;
|
||||
}
|
||||
|
||||
cmvr::msgs::RunMode Ti5MotorCanopenProtocol::getMode(const uint8_t node_id) {
|
||||
msgs::MotorStatus status;
|
||||
if (!getMotorStatus(node_id, &status)) {
|
||||
return msgs::RUN_MODE_UNSPECIFIED;
|
||||
}
|
||||
return status.run_mode();
|
||||
}
|
||||
|
||||
void Ti5MotorCanopenProtocol::setMotorConversion(
|
||||
@ -286,12 +313,28 @@ bool Ti5MotorCanopenProtocol::setMode(uint8_t node_id, msgs::RunMode mode) {
|
||||
cw.enable_operation = 1;
|
||||
seedSdoRequest(node_id, CS_WRITE_TWO_BYTES, CIA402_CONTROL_WORD_6040, SUB_INDEX_0, cw.value, 20);
|
||||
|
||||
int32_t current_position = 0;
|
||||
if (mode == RUN_MODE_PROFILE_POSITION || mode == RUN_MODE_CYCLIC_SYNC_POSITION) {
|
||||
seedSdoRequest(node_id, CS_READ_REQUEST, CIA402_ACTUAL_POSITION_6064, SUB_INDEX_0, 0, 20);
|
||||
msgs::MotorStatus status;
|
||||
if (!waitUntil([&]() {
|
||||
return getMotorStatus(node_id, &status) &&
|
||||
status.has_sdo_response() &&
|
||||
status.sdo_response().index() == CIA402_ACTUAL_POSITION_6064;
|
||||
}, 500)) {
|
||||
CMVR_LOG(ERROR) << "motor " << static_cast<int>(node_id)
|
||||
<< ": actual-position feedback timed out";
|
||||
return false;
|
||||
}
|
||||
current_position = status.position();
|
||||
}
|
||||
|
||||
|
||||
switch (mode) {
|
||||
case RUN_MODE_PROFILE_POSITION: {
|
||||
// 4 : 设置目标位置(为当前位置)
|
||||
auto cur_pos = GetRobotDetail()->motors().at(node_id).position();
|
||||
seedSdoRequest(node_id, CS_WRITE_FOUR_BYTES, CIA402_TARGET_POSITION_607A, SUB_INDEX_0, cur_pos);
|
||||
seedSdoRequest(node_id, CS_WRITE_FOUR_BYTES, CIA402_TARGET_POSITION_607A,
|
||||
SUB_INDEX_0, current_position);
|
||||
|
||||
|
||||
// 5 : 触发位置运动(new_set_point 翻转)
|
||||
@ -308,8 +351,8 @@ bool Ti5MotorCanopenProtocol::setMode(uint8_t node_id, msgs::RunMode mode) {
|
||||
case RUN_MODE_CYCLIC_SYNC_POSITION: {
|
||||
// configRPDO1(node_id, true);
|
||||
// 设置目标位置为当前位置
|
||||
auto cur_pos = GetRobotDetail()->motors().at(node_id).position();
|
||||
seedSdoRequest(node_id, CS_WRITE_FOUR_BYTES, CIA402_TARGET_POSITION_607A, SUB_INDEX_0, cur_pos);
|
||||
seedSdoRequest(node_id, CS_WRITE_FOUR_BYTES, CIA402_TARGET_POSITION_607A,
|
||||
SUB_INDEX_0, current_position);
|
||||
|
||||
//3 : 使能 15
|
||||
cw.enable_operation = 1;
|
||||
@ -541,7 +584,11 @@ bool Ti5MotorCanopenProtocol::calibrateZeroQ(uint8_t node_id) {
|
||||
// 2: 等待确认清除成功
|
||||
seedSdoRequest(node_id, CS_READ_REQUEST, CANOPEN_POSITION_OFFSET_2008, SUB_INDEX_0, 0);
|
||||
if (!waitUntil([&]() {
|
||||
return GetRobotDetail()->motors().at(node_id).position_offset() == 0;
|
||||
msgs::MotorStatus status;
|
||||
return getMotorStatus(node_id, &status) &&
|
||||
status.has_sdo_response() &&
|
||||
status.sdo_response().index() == CANOPEN_POSITION_OFFSET_2008 &&
|
||||
status.position_offset() == 0;
|
||||
}, 1000)) {
|
||||
CMVR_LOG(ERROR) << "motor " << node_id << ": 0x2008 set zero failed";
|
||||
return false;
|
||||
@ -549,7 +596,17 @@ bool Ti5MotorCanopenProtocol::calibrateZeroQ(uint8_t node_id) {
|
||||
|
||||
// 3: 读取当前位置 0x6064
|
||||
seedSdoRequest(node_id, CS_READ_REQUEST, CIA402_ACTUAL_POSITION_6064, SUB_INDEX_0, 0, 20);
|
||||
auto cur_pos = GetRobotDetail()->motors().at(node_id).position();
|
||||
msgs::MotorStatus status;
|
||||
if (!waitUntil([&]() {
|
||||
return getMotorStatus(node_id, &status) &&
|
||||
status.has_sdo_response() &&
|
||||
status.sdo_response().index() == CIA402_ACTUAL_POSITION_6064;
|
||||
}, 500)) {
|
||||
CMVR_LOG(ERROR) << "motor " << static_cast<int>(node_id)
|
||||
<< ": actual-position feedback timed out during calibration";
|
||||
return false;
|
||||
}
|
||||
const auto cur_pos = status.position();
|
||||
|
||||
// 4: 将当前位置写入偏置寄存器
|
||||
seedSdoRequest(node_id, CS_WRITE_FOUR_BYTES, CANOPEN_POSITION_OFFSET_2008, SUB_INDEX_0, cur_pos);
|
||||
@ -561,10 +618,14 @@ bool Ti5MotorCanopenProtocol::calibrateZeroQ(uint8_t node_id) {
|
||||
// 6: 确认写入成功
|
||||
seedSdoRequest(node_id, CS_READ_REQUEST, CANOPEN_POSITION_OFFSET_2008, SUB_INDEX_0, 0, 20);
|
||||
if (!waitUntil([&]() {
|
||||
return GetRobotDetail()->motors().at(node_id).position_offset() == cur_pos;
|
||||
msgs::MotorStatus latest_status;
|
||||
return getMotorStatus(node_id, &latest_status) &&
|
||||
latest_status.has_sdo_response() &&
|
||||
latest_status.sdo_response().index() == CANOPEN_POSITION_OFFSET_2008 &&
|
||||
latest_status.position_offset() == cur_pos;
|
||||
}, 500)) {
|
||||
return false;
|
||||
CMVR_LOG(ERROR) << "motor " << node_id << ": 0x2008 set current position failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -575,9 +636,10 @@ bool Ti5MotorCanopenProtocol::torqueOn(uint8_t node_id) {
|
||||
}
|
||||
|
||||
bool Ti5MotorCanopenProtocol::brakeRelease(uint8_t node_id) {
|
||||
(void)node_id;
|
||||
CMVR_LOG(ERROR) << "[Ti5MotorCanopenProtocol] brakeRelease is not implemented";
|
||||
return false;
|
||||
// (void)node_id;
|
||||
// CMVR_LOG(ERROR) << "[Ti5MotorCanopenProtocol] brakeRelease is not implemented";
|
||||
torqueOff(node_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Ti5MotorCanopenProtocol::quickStop(uint8_t node_id) {
|
||||
@ -594,8 +656,12 @@ bool Ti5MotorCanopenProtocol::quickStop(uint8_t node_id) {
|
||||
}
|
||||
|
||||
bool Ti5MotorCanopenProtocol::reachedTargetQ(uint8_t node_id) {
|
||||
msgs::MotorStatus motor_status;
|
||||
if (!getMotorStatus(node_id, &motor_status)) {
|
||||
return false;
|
||||
}
|
||||
statusword_t st{};
|
||||
st.value = GetRobotDetail()->motors().at(node_id).status_word();
|
||||
st.value = motor_status.status_word();
|
||||
return st.target_reached == 1;
|
||||
}
|
||||
|
||||
@ -617,9 +683,11 @@ double Ti5MotorCanopenProtocol::getQ(uint8_t node_id) {
|
||||
if (!conversion) {
|
||||
return 0.0;
|
||||
}
|
||||
auto data_ptr = std::make_unique<msgs::RobotDetail>();
|
||||
message_manager_->GetSensorData(data_ptr.get());
|
||||
auto cnt = data_ptr->motors().at(node_id).position();
|
||||
msgs::MotorStatus motor_status;
|
||||
if (!getMotorStatus(node_id, &motor_status)) {
|
||||
return 0.0;
|
||||
}
|
||||
const auto cnt = motor_status.position();
|
||||
return countsToRad(cnt, *conversion);
|
||||
}
|
||||
|
||||
@ -628,8 +696,10 @@ double Ti5MotorCanopenProtocol::getQd(uint8_t node_id) {
|
||||
if (!conversion) {
|
||||
return 0.0;
|
||||
}
|
||||
auto data_ptr = std::make_unique<msgs::RobotDetail>();
|
||||
message_manager_->GetSensorData(data_ptr.get());
|
||||
auto cnt = data_ptr->motors().at(node_id).speed();
|
||||
msgs::MotorStatus motor_status;
|
||||
if (!getMotorStatus(node_id, &motor_status)) {
|
||||
return 0.0;
|
||||
}
|
||||
const auto cnt = motor_status.speed();
|
||||
return velocityRawToRadPerSec(cnt, *conversion);
|
||||
}
|
||||
|
||||
@ -105,14 +105,14 @@ bool MotorManager::init()
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool start_before_motor_init =
|
||||
const bool start_before_motor_creation =
|
||||
motor_group_cfg.bus_type() == config::MOTOR_BUS_ETHERCAT;
|
||||
if (start_before_motor_init && !bus_runtime->start()) {
|
||||
if (start_before_motor_creation && !bus_runtime->start()) {
|
||||
bus_runtime->stop();
|
||||
all_ok = false;
|
||||
continue;
|
||||
}
|
||||
if (start_before_motor_init) {
|
||||
if (start_before_motor_creation) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
}
|
||||
|
||||
@ -123,19 +123,36 @@ bool MotorManager::init()
|
||||
all_ok = false;
|
||||
continue;
|
||||
}
|
||||
if (!start_before_motor_creation && !bus_runtime->start()) {
|
||||
bus_runtime->stop();
|
||||
all_ok = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool group_ok = true;
|
||||
if (motor_group_cfg.bus_type() == config::MOTOR_BUS_CAN) {
|
||||
for (auto& motor : motors) {
|
||||
if (!addMotor(motor)) {
|
||||
if (!motor->init()) {
|
||||
CMVR_LOG(ERROR) << "[MotorManager] failed to initialize CAN motor: "
|
||||
<< motor->jointName();
|
||||
group_ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!group_ok) {
|
||||
bus_runtime->stop();
|
||||
all_ok = false;
|
||||
continue;
|
||||
}
|
||||
if (!start_before_motor_init && !bus_runtime->start()) {
|
||||
|
||||
for (auto& motor : motors) {
|
||||
if (!addMotor(motor)) {
|
||||
group_ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!group_ok) {
|
||||
bus_runtime->stop();
|
||||
all_ok = false;
|
||||
continue;
|
||||
@ -268,6 +285,26 @@ bool MotorManager::commandCyclicPositionsAtomic(
|
||||
if (std::dynamic_pointer_cast<MujocoMotor>(motors.front())) {
|
||||
return MujocoMotor::commandCyclicPositionsAtomic(motors, positions, velocities);
|
||||
}
|
||||
if (std::dynamic_pointer_cast<Ti5Motor>(motors.front())) {
|
||||
// TI5 currently exposes only a per-motor RPDO command. Keep the
|
||||
// fallback here so callers retain one manager-level entry point.
|
||||
static std::once_flag ti5_non_atomic_warning;
|
||||
std::call_once(ti5_non_atomic_warning, []() {
|
||||
CMVR_LOG(WARNING)
|
||||
<< "[MotorManager] TI5 motors use non-atomic cyclic position commands";
|
||||
});
|
||||
for (std::size_t i = 0; i < motors.size(); ++i) {
|
||||
if (!std::dynamic_pointer_cast<Ti5Motor>(motors[i])) {
|
||||
CMVR_LOG(ERROR) << "[MotorManager] mixed motor types in cyclic position command";
|
||||
return false;
|
||||
}
|
||||
if (!motors[i]->commandCyclicPosition(positions[i], velocities[i])) {
|
||||
CMVR_LOG(ERROR) << "[MotorManager] failed to command TI5 motor at index " << i;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
CMVR_LOG(ERROR) << "[MotorManager] atomic cyclic position is unsupported for motor type: "
|
||||
<< motors.front()->typeName();
|
||||
@ -483,9 +520,8 @@ std::vector<std::shared_ptr<AbstractMotor>> MotorManager::createCanMotors_(
|
||||
motors.reserve(motor_cfgs.size());
|
||||
for (const auto& cfg : motor_cfgs) {
|
||||
auto motor = std::make_shared<Ti5Motor>(cfg);
|
||||
motor->setProtocol(protocol);
|
||||
if (!motor->init()) {
|
||||
CMVR_LOG(ERROR) << "[MotorManager] failed to init TI5 motor: "
|
||||
if (!motor->setProtocol(protocol)) {
|
||||
CMVR_LOG(ERROR) << "[MotorManager] failed to register TI5 motor protocols: "
|
||||
<< cfg.joint_name();
|
||||
return {};
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user