Skip to content

Commit af9d156

Browse files
author
Shota Aoki
authored
電流制御機能とサンプルの追加 (#7)
* 電流制御機能の実装。X7の電流制御サンプルの実装 * 電流制限機能を実装 * set_currentsの修正。current_limitが0以上の値になるように修正 * load_config_file内で変更後のposition_limitとcurrent_limitを表示する * コンフィグファイルの調整 * コンフィグファイル読み込み時に、current writeとposition readの設定をチェックする * S17のwrite_currentサンプル追加 * READMEに電流制御の説明を追記 * README修正 * READMEの微修正 * Jointのcurrent_limitをcurrent_limit_when_position_exceeds_limitに変更 * current limitに到達したら制限電流値を表示する * READMEを微修正
1 parent cce15c5 commit af9d156

File tree

14 files changed

+560
-10
lines changed

14 files changed

+560
-10
lines changed

rt_manipulators_lib/include/hardware.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ class Hardware {
6666
bool set_velocity(const uint8_t id, const double velocity);
6767
bool set_velocity(const std::string& joint_name, const double velocity);
6868
bool set_velocities(const std::string& group_name, std::vector<double>& velocities);
69+
bool set_current(const uint8_t id, const double current);
70+
bool set_current(const std::string& joint_name, const double current);
71+
bool set_currents(const std::string& group_name, std::vector<double>& currents);
6972
bool write_max_acceleration_to_group(const std::string& group_name,
7073
const double acceleration_rpss);
7174
bool write_max_velocity_to_group(const std::string& group_name, const double velocity_rps);
@@ -94,6 +97,7 @@ class Hardware {
9497
bool parse_config_file(const std::string& config_yaml);
9598
bool write_operating_mode(const std::string& group_name);
9699
bool limit_goal_velocity_by_present_position(const std::string& group_name);
100+
bool limit_goal_current_by_present_position(const std::string& group_name);
97101
bool create_sync_read_group(const std::string& group_name);
98102
bool create_sync_write_group(const std::string& group_name);
99103
bool set_indirect_address(const std::string& group_name, const uint16_t addr_indirect_start,
@@ -106,6 +110,7 @@ class Hardware {
106110
double dxl_voltage_to_volt(const int16_t voltage) const;
107111
uint32_t radian_to_dxl_pos(const double position);
108112
uint32_t to_dxl_velocity(const double velocity_rps);
113+
uint16_t to_dxl_current(const double current_ampere);
109114
uint32_t to_dxl_acceleration(const double acceleration_rpss);
110115
uint32_t to_dxl_profile_velocity(const double velocity_rps);
111116

rt_manipulators_lib/include/hardware_communicator.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class Communicator{
6464
bool write_double_word_data(const dxl_id_t & id, const dxl_address_t & address,
6565
const dxl_double_word_t & write_data);
6666
bool read_byte_data(const dxl_id_t & id, const dxl_address_t & address, dxl_byte_t & read_data);
67+
bool read_word_data(const dxl_id_t & id, const dxl_address_t & address, dxl_word_t & read_data);
6768
bool read_double_word_data(const dxl_id_t & id, const dxl_address_t & address,
6869
dxl_double_word_t & read_data);
6970

rt_manipulators_lib/include/hardware_joints.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ class Joints{
7070
bool set_velocity(const dxl_id_t & id, const velocity_t & velocity);
7171
bool set_velocity(const joint_name_t & joint_name, const velocity_t & velocity);
7272
bool set_velocities(const group_name_t & group_name, const std::vector<velocity_t>& velocities);
73+
bool set_current(const dxl_id_t & id, const current_t & current);
74+
bool set_current(const joint_name_t & joint_name, const current_t & current);
75+
bool set_currents(const group_name_t & group_name, const std::vector<current_t>& currents);
7376

7477
private:
7578
group_map_t joint_groups_;

rt_manipulators_lib/include/joint.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@ namespace joint {
2424
class Joint {
2525
public:
2626
Joint(const uint8_t id, const uint8_t operating_mode,
27-
const double max_position_limit, const double min_position_limit);
27+
const double max_position_limit, const double min_position_limit,
28+
const double current_limit_when_position_exceeds_limit);
2829
uint8_t id() const;
2930
uint8_t operating_mode() const;
3031
double max_position_limit() const;
3132
double min_position_limit() const;
33+
double current_limit_when_position_exceeds_limit() const;
3234
void set_present_position(const double position_radian);
3335
void set_present_velocity(const double velocity_rps);
3436
void set_present_current(const double current_ampere);
@@ -41,21 +43,25 @@ class Joint {
4143
int8_t get_present_temperature() const;
4244
void set_goal_position(const double position_radian);
4345
void set_goal_velocity(const double velocity_rps);
46+
void set_goal_current(const double current_ampere);
4447
double get_goal_position() const;
4548
double get_goal_velocity() const;
49+
double get_goal_current() const;
4650

4751
private:
4852
uint8_t id_;
4953
uint8_t operating_mode_;
5054
double max_position_limit_;
5155
double min_position_limit_;
56+
double current_limit_when_position_exceeds_limit_;
5257
double present_position_;
5358
double present_velocity_;
5459
double present_current_;
5560
double present_voltage_;
5661
int8_t present_temperature_;
5762
double goal_position_;
5863
double goal_velocity_;
64+
double goal_current_;
5965
};
6066

6167
class JointGroup {

rt_manipulators_lib/src/hardware.cpp

Lines changed: 127 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,12 @@ const double TO_ACCELERATION_TO_RAD_PER_SS = TO_ACCELERATION_TO_RAD_PER_MM / 360
3939
const double DXL_ACCELERATION_FROM_RAD_PER_SS = 1.0 / TO_ACCELERATION_TO_RAD_PER_SS;
4040
const int DXL_MAX_ACCELERATION = 32767;
4141
const double TO_CURRENT_AMPERE = 0.00269;
42+
const double TO_DXL_CURRENT = 1.0 / TO_CURRENT_AMPERE;
4243
const double TO_VOLTAGE_VOLT = 0.1;
4344

4445
// Dynamixel XM Series address table
4546
const uint16_t ADDR_OPERATING_MODE = 11;
47+
const uint16_t ADDR_CURRENT_LIMIT = 38;
4648
const uint16_t ADDR_MAX_POSITION_LIMIT = 48;
4749
const uint16_t ADDR_MIN_POSITION_LIMIT = 52;
4850
const uint16_t ADDR_TORQUE_ENABLE = 64;
@@ -100,6 +102,12 @@ bool Hardware::load_config_file(const std::string& config_yaml) {
100102
std::cerr << "positionもsync_readするようにコンフィグファイルを修正して下さい." << std::endl;
101103
return false;
102104
}
105+
if (group->sync_write_current_enabled() && !group->sync_read_position_enabled()) {
106+
std::cerr << group_name << "グループはcurrentをsync_writeしますが, ";
107+
std::cerr << "positionをsync_readしません." << std::endl;
108+
std::cerr << "positionもsync_readするようにコンフィグファイルを修正して下さい." << std::endl;
109+
return false;
110+
}
103111
}
104112

105113
std::cout << "Config file '" << config_yaml << "' loaded." << std::endl;
@@ -109,6 +117,12 @@ bool Hardware::load_config_file(const std::string& config_yaml) {
109117
std::cout << "\t" << joint_name;
110118
std::cout << ", id:" << std::to_string(joints_.joint(joint_name)->id());
111119
std::cout << ", mode:" << std::to_string(joints_.joint(joint_name)->operating_mode());
120+
std::cout << ", modified max_position_limit:" << std::to_string(
121+
joints_.joint(joint_name)->max_position_limit());
122+
std::cout << ", modified min_position_limit:" << std::to_string(
123+
joints_.joint(joint_name)->min_position_limit());
124+
std::cout << ", current_limit_when_position_exceeds_limit:" << std::to_string(
125+
joints_.joint(joint_name)->current_limit_when_position_exceeds_limit());
112126
std::cout << std::endl;
113127
}
114128
}
@@ -129,8 +143,8 @@ void Hardware::disconnect() {
129143
return;
130144
}
131145

132-
// 速度指示モードの場合は、goal_velocityを0にする
133146
for (const auto& [group_name, group] : joints_.groups()) {
147+
// 速度指示モードの場合は、goal_velocityを0にする
134148
if (group->sync_write_velocity_enabled()) {
135149
std::cout << group_name << "グループにはvelocityのsync_writeが設定されています." << std::endl;
136150
std::cout << "安全のため, disconnect()関数内で目標速度 0 rad/sを書き込みます." << std::endl;
@@ -139,6 +153,15 @@ void Hardware::disconnect() {
139153
}
140154
sync_write(group_name);
141155
}
156+
// 電流指示モードの場合は、goal_currentを0にする
157+
if (group->sync_write_current_enabled()) {
158+
std::cout << group_name << "グループにはcurrentのsync_writeが設定されています." << std::endl;
159+
std::cout << "安全のため, disconnect()関数内で目標速度 0 Aを書き込みます." << std::endl;
160+
for (const auto & joint_name : group->joint_names()) {
161+
joints_.joint(joint_name)->set_goal_current(0);
162+
}
163+
sync_write(group_name);
164+
}
142165
}
143166

144167
comm_->disconnect();
@@ -282,6 +305,12 @@ bool Hardware::sync_write(const std::string& group_name) {
282305
write_data.push_back(DXL_HIBYTE(DXL_HIWORD(goal_velocity)));
283306
}
284307

308+
if (joints_.group(group_name)->sync_write_current_enabled()) {
309+
uint16_t goal_current = to_dxl_current(joints_.joint(joint_name)->get_goal_current());
310+
write_data.push_back(DXL_LOBYTE(goal_current));
311+
write_data.push_back(DXL_HIBYTE(goal_current));
312+
}
313+
285314
auto id = joints_.joint(joint_name)->id();
286315
if (!comm_->set_sync_write_data(group_name, id, write_data)) {
287316
return false;
@@ -335,8 +364,8 @@ bool Hardware::stop_thread() {
335364
// リソースを解放
336365
read_write_thread_.reset();
337366

338-
// 速度指示モードの場合は、goal_velocityを0にする
339367
for (const auto& [group_name, group] : joints_.groups()) {
368+
// 速度指示モードの場合は、goal_velocityを0にする
340369
if (group->sync_write_velocity_enabled()) {
341370
std::cout << group_name << "グループにはvelocityのsync_writeが設定されています." << std::endl;
342371
std::cout << "安全のため, stop_thread()関数内で目標速度 0 rad/sを書き込みます." << std::endl;
@@ -345,6 +374,15 @@ bool Hardware::stop_thread() {
345374
}
346375
sync_write(group_name);
347376
}
377+
// 電流指示モードの場合は、goal_currentを0にする
378+
if (group->sync_write_current_enabled()) {
379+
std::cout << group_name << "グループにはcurrentのsync_writeが設定されています." << std::endl;
380+
std::cout << "安全のため, stop_thread()関数内で目標電流 0 Aを書き込みます." << std::endl;
381+
for (const auto & joint_name : group->joint_names()) {
382+
joints_.joint(joint_name)->set_goal_current(0);
383+
}
384+
sync_write(group_name);
385+
}
348386
}
349387

350388
return true;
@@ -452,6 +490,36 @@ bool Hardware::set_velocities(const std::string& group_name, std::vector<double>
452490
return joints_.set_velocities(group_name, velocities);
453491
}
454492

493+
bool Hardware::set_current(const uint8_t id, const double current) {
494+
if (!thread_enable_) {
495+
std::cerr << "目標電流を書き込む場合は、";
496+
std::cerr << "安全のためstart_thread()を実行してください." << std::endl;
497+
return false;
498+
}
499+
500+
return joints_.set_current(id, current);
501+
}
502+
503+
bool Hardware::set_current(const std::string& joint_name, const double current) {
504+
if (!thread_enable_) {
505+
std::cerr << "目標電流を書き込む場合は、";
506+
std::cerr << "安全のためstart_thread()を実行してください." << std::endl;
507+
return false;
508+
}
509+
510+
return joints_.set_current(joint_name, current);
511+
}
512+
513+
bool Hardware::set_currents(const std::string& group_name, std::vector<double>& currents) {
514+
if (!thread_enable_) {
515+
std::cerr << "目標電流を書き込む場合は、";
516+
std::cerr << "安全のためstart_thread()を実行してください." << std::endl;
517+
return false;
518+
}
519+
520+
return joints_.set_currents(group_name, currents);
521+
}
522+
455523
bool Hardware::write_max_acceleration_to_group(const std::string& group_name,
456524
const double acceleration_rpss) {
457525
// 指定されたグループ内のサーボモータの最大動作加速度(radian / s^2)を設定する
@@ -703,6 +771,7 @@ bool Hardware::parse_config_file(const std::string& config_yaml) {
703771

704772
uint32_t dxl_max_pos_limit = 0;
705773
uint32_t dxl_min_pos_limit = 0;
774+
uint16_t dxl_current_limit = 0;
706775
if (!comm_->read_double_word_data(joint_id, ADDR_MAX_POSITION_LIMIT, dxl_max_pos_limit)) {
707776
std::cerr << joint_name << "のMax Position Limitの読み取りに失敗しました." << std::endl;
708777
return false;
@@ -711,6 +780,10 @@ bool Hardware::parse_config_file(const std::string& config_yaml) {
711780
std::cerr << joint_name << "のMin Position Limitの読み取りに失敗しました." << std::endl;
712781
return false;
713782
}
783+
if (!comm_->read_word_data(joint_id, ADDR_CURRENT_LIMIT, dxl_current_limit)) {
784+
std::cerr << joint_name << "のCurrent Limitの読み取りに失敗しました." << std::endl;
785+
return false;
786+
}
714787

715788
// 角度リミット値をラジアンに変換
716789
double max_position_limit = dxl_pos_to_radian(static_cast<int32_t>(dxl_max_pos_limit));
@@ -722,7 +795,18 @@ bool Hardware::parse_config_file(const std::string& config_yaml) {
722795
min_position_limit += config[joint_name]["pos_limit_margin"].as<double>();
723796
}
724797

725-
auto joint = joint::Joint(joint_id, ope_mode, max_position_limit, min_position_limit);
798+
// 電流リミット値をアンペアに変換
799+
double current_limit = dxl_current_to_ampere(dxl_current_limit);
800+
// 電流リミット値にマージンを加算する
801+
if (config[joint_name]["current_limit_margin"]) {
802+
// current_limitは0以上の値にする
803+
current_limit = std::max(
804+
current_limit - config[joint_name]["current_limit_margin"].as<double>(),
805+
0.0);
806+
}
807+
808+
auto joint = joint::Joint(
809+
joint_id, ope_mode, max_position_limit, min_position_limit, current_limit);
726810
joints_.append_joint(joint_name, joint);
727811
}
728812
std::vector<std::string> sync_read_targets;
@@ -815,6 +899,33 @@ bool Hardware::limit_goal_velocity_by_present_position(const std::string& group_
815899
return retval;
816900
}
817901

902+
bool Hardware::limit_goal_current_by_present_position(const std::string& group_name) {
903+
// ジョイントの現在角度がmax/min position limit を超えた場合、
904+
// goal_currentをcurrent limitに制限する
905+
bool retval = true;
906+
for (const auto & joint_name : joints_.group(group_name)->joint_names()) {
907+
auto max_position_limit = joints_.joint(joint_name)->max_position_limit();
908+
auto min_position_limit = joints_.joint(joint_name)->min_position_limit();
909+
auto current_limit = joints_.joint(joint_name)->current_limit_when_position_exceeds_limit();
910+
auto present_position = joints_.joint(joint_name)->get_present_position();
911+
auto goal_current = joints_.joint(joint_name)->get_goal_current();
912+
bool has_exceeded_max_pos_limit = present_position > max_position_limit &&
913+
goal_current > current_limit;
914+
bool has_exceeded_min_pos_limit = present_position < min_position_limit &&
915+
goal_current < -current_limit;
916+
917+
if (has_exceeded_max_pos_limit || has_exceeded_min_pos_limit) {
918+
std::cout << joint_name << "ジョイントの現在角度が限界角度に到達しました、";
919+
std::cout << "goal_currentを" << current_limit << " Aに制限します." << std::endl;
920+
auto limited_current = std::clamp(goal_current, -current_limit, current_limit);
921+
joints_.joint(joint_name)->set_goal_current(limited_current);
922+
retval = false;
923+
}
924+
}
925+
926+
return retval;
927+
}
928+
818929
bool Hardware::create_sync_read_group(const std::string& group_name) {
819930
// HardwareCommunicatorに、指定されたデータを読むSyncReadGroupを追加する
820931
// できるだけ多くのデータをSyncReadで読み取るため、インダイレクトアドレスを活用する
@@ -909,6 +1020,12 @@ bool Hardware::create_sync_write_group(const std::string& group_name) {
9091020
}
9101021
}
9111022

1023+
if (joints_.group(group_name)->sync_write_current_enabled()) {
1024+
if (!append(ADDR_GOAL_CURRENT, LEN_GOAL_CURRENT, "goal_current")) {
1025+
return false;
1026+
}
1027+
}
1028+
9121029
comm_->make_sync_write_group(group_name, ADDR_INDIRECT_DATA_29, total_length);
9131030

9141031
std::vector<uint8_t> init_data(total_length, 0);
@@ -957,6 +1074,9 @@ void Hardware::read_write_thread(const std::vector<std::string>& group_names,
9571074
if (joints_.group(group_name)->sync_write_velocity_enabled()) {
9581075
limit_goal_velocity_by_present_position(group_name);
9591076
}
1077+
if (joints_.group(group_name)->sync_write_current_enabled()) {
1078+
limit_goal_current_by_present_position(group_name);
1079+
}
9601080
sync_write(group_name);
9611081
}
9621082

@@ -988,6 +1108,10 @@ uint32_t Hardware::to_dxl_velocity(const double velocity_rps) {
9881108
return velocity_rps * DXL_VELOCITY_FROM_RAD_PER_SEC;
9891109
}
9901110

1111+
uint16_t Hardware::to_dxl_current(const double current_ampere) {
1112+
return current_ampere * TO_DXL_CURRENT;
1113+
}
1114+
9911115
uint32_t Hardware::to_dxl_acceleration(const double acceleration_rpss) {
9921116
// 加速度 rad/s^2をDYNAMIXELのデータに変換する
9931117

rt_manipulators_lib/src/hardware_communicator.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,20 @@ bool Communicator::read_byte_data(
194194
return true;
195195
}
196196

197+
bool Communicator::read_word_data(
198+
const dxl_id_t & id, const dxl_address_t & address, dxl_word_t & read_data) {
199+
dxl_error_t dxl_error = 0;
200+
dxl_word_t data = 0;
201+
dxl_result_t dxl_result =
202+
packet_handler_->read2ByteTxRx(port_handler_.get(), id, address, &data, &dxl_error);
203+
204+
if (!parse_dxl_error(std::string(__func__), id, address, dxl_result, dxl_error)) {
205+
return false;
206+
}
207+
read_data = data;
208+
return true;
209+
}
210+
197211
bool Communicator::read_double_word_data(
198212
const dxl_id_t & id, const dxl_address_t & address, dxl_double_word_t & read_data) {
199213
dxl_error_t dxl_error = 0;

rt_manipulators_lib/src/hardware_joints.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,4 +291,44 @@ bool Joints::set_velocities(
291291
return true;
292292
}
293293

294+
bool Joints::set_current(const dxl_id_t & id, const current_t & current) {
295+
if (!has_joint(id)) {
296+
std::cerr << "ID:" << std::to_string(id) << "のジョイントは存在しません." << std::endl;
297+
return false;
298+
}
299+
300+
joint(id)->set_goal_current(current);
301+
return true;
302+
}
303+
304+
bool Joints::set_current(const joint_name_t & joint_name, const current_t & current) {
305+
if (!has_joint(joint_name)) {
306+
std::cerr << joint_name << "ジョイントは存在しません." << std::endl;
307+
return false;
308+
}
309+
310+
joint(joint_name)->set_goal_current(current);
311+
return true;
312+
}
313+
314+
bool Joints::set_currents(const group_name_t & group_name, const std::vector<current_t>& currents) {
315+
if (!has_group(group_name)) {
316+
std::cerr << group_name << "はjoint_groupsに存在しません." << std::endl;
317+
return false;
318+
}
319+
320+
if (joint_groups_.at(group_name)->joint_names().size() != currents.size()) {
321+
std::cerr << "目標値のサイズ:" << currents.size();
322+
std::cerr << "がジョイント数:" << joint_groups_.at(group_name)->joint_names().size();
323+
std::cerr << "と一致しません." << std::endl;
324+
return false;
325+
}
326+
327+
for (size_t i = 0; i < currents.size(); i++) {
328+
auto joint_name = joint_groups_.at(group_name)->joint_names()[i];
329+
joint(joint_name)->set_goal_current(currents[i]);
330+
}
331+
return true;
332+
}
333+
294334
} // namespace hardware_joints

0 commit comments

Comments
 (0)