Skip to content

Commit dcd39c4

Browse files
authored
Fixed resetting joint states when performing mode switches (#11)
* Fixed resetting joint states when performing mode switches * Improved Logging in rest goal state * Logging Improvement Mode Switching to None * Disabled respawning of controller manager
1 parent 62971a3 commit dcd39c4

File tree

4 files changed

+68
-26
lines changed

4 files changed

+68
-26
lines changed

dynamixel_ros_control/include/dynamixel_ros_control/joint.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class Joint
3737
bool addActiveCommandInterface(const std::string& interface_name);
3838
bool removeActiveCommandInterface(const std::string& interface_name);
3939
bool updateControlMode();
40+
bool readControlMode();
4041
bool controlModeChanged() const;
4142
void resetControlModeChanged();
4243

dynamixel_ros_control/launch/controller_manager.launch.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ launch:
3030
name: "joint_state_broadcaster_spawner"
3131
output: "screen"
3232
args: "joint_state_broadcaster"
33-
respawn: "true"
34-
respawn_delay: 5.0
33+
#respawn: "true"
34+
# respawn_delay: 5.0
3535

3636
- node:
3737
pkg: "controller_manager"

dynamixel_ros_control/src/dynamixel_hardware_interface.cpp

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ DynamixelHardwareInterface::on_init(const hardware_interface::HardwareInfo& hard
139139
set_torque_service_ = node_->create_service<std_srvs::srv::SetBool>(
140140
"~/set_torque", [this](const std::shared_ptr<std_srvs::srv::SetBool::Request> request,
141141
const std::shared_ptr<std_srvs::srv::SetBool::Response> response) {
142+
if (lifecycle_state_.label() != hardware_interface::lifecycle_state_names::ACTIVE) {
143+
response->success = false;
144+
response->message = "Hardware Interface must be in 'active' state to set torque";
145+
return;
146+
}
142147
DXL_LOG_INFO("Request to set torque to " << (request->data ? "ON" : "OFF") << " received.");
143148
response->success = setTorque(request->data);
144149
response->message = response->success ? "Torque set successfully" : "Failed to set torque";
@@ -152,8 +157,13 @@ DynamixelHardwareInterface::on_init(const hardware_interface::HardwareInfo& hard
152157

153158
// set up e-stop subscription
154159
soft_e_stop_subscription_ = node_->create_subscription<std_msgs::msg::Bool>(
155-
"~/soft_e_stop", rclcpp::SystemDefaultsQoS(),
156-
[this](const std_msgs::msg::Bool::SharedPtr msg) { setEStop(msg->data); });
160+
"~/soft_e_stop", rclcpp::SystemDefaultsQoS(), [this](const std_msgs::msg::Bool::SharedPtr msg) {
161+
if (lifecycle_state_.label() != hardware_interface::lifecycle_state_names::ACTIVE) {
162+
DXL_LOG_WARN("E-Stop message received but hardware interface is not in 'active' state.");
163+
return;
164+
}
165+
setEStop(msg->data);
166+
});
157167
// Transmissions
158168
if (!loadTransmissionConfiguration()) {
159169
return hardware_interface::CallbackReturn::ERROR;
@@ -242,7 +252,14 @@ hardware_interface::CallbackReturn DynamixelHardwareInterface::on_activate(const
242252
DXL_LOG_ERROR("Failed to set torque on activation to " << (torque_on_startup_ ? "ON" : "OFF"));
243253
return hardware_interface::CallbackReturn::ERROR;
244254
}
245-
is_torqued_ = torque_on_startup_; // TODO: check if successful
255+
// make sure position control mode is active (safer than leaving it in whatever mode it was before)
256+
// imagine, torque on startup but actuator from last shutdown in current mode & no controller running
257+
for (auto& [name, joint] : joints_) {
258+
if (!joint.readControlMode() || !joint.updateControlMode()) {
259+
return CallbackReturn::ERROR;
260+
}
261+
}
262+
is_torqued_ = torque_on_startup_;
246263
if (!resetGoalStateAndVerify()) {
247264
return CallbackReturn::ERROR;
248265
}
@@ -384,6 +401,9 @@ DynamixelHardwareInterface::perform_command_mode_switch(const std::vector<std::s
384401
return hardware_interface::return_type::ERROR;
385402
}
386403
}
404+
405+
first_read_successful_ = false; // force second reset in read
406+
387407
mode_switch_failed_ = false; // mark as successful
388408
return hardware_interface::return_type::OK;
389409
}
@@ -743,7 +763,7 @@ bool DynamixelHardwareInterface::resetGoalStateAndVerify()
743763
{
744764
// Read current values (positions, velocities, etc.) before enabling torque
745765
if (!read_manager_.read() || !read_manager_.isOk() || !isHardwareOk()) {
746-
DXL_LOG_ERROR("Failed to read current positions before enabling torque. Cannot enable torque.");
766+
DXL_LOG_ERROR("[resetGoalStateAndVerify] Failed to read current values from actuators.");
747767
return false;
748768
}
749769

@@ -754,29 +774,30 @@ bool DynamixelHardwareInterface::resetGoalStateAndVerify()
754774

755775
// Write goal positions (will only write for the values belonging to the active command interfaces!)
756776
if (!control_write_manager_.write() || !control_write_manager_.isOk() || !isHardwareOk()) {
757-
DXL_LOG_ERROR("Failed to write goal positions before enabling torque. Cannot enable torque.");
777+
DXL_LOG_ERROR("[resetGoalStateAndVerify] Failed to write reset goal values.");
758778
return false;
759779
}
760780

761781
// Re-read goal values for verification
762782
if (!cmd_read_manager_.read() || !cmd_read_manager_.isOk()) {
763-
DXL_LOG_ERROR("Failed to re-read goal positions before enabling torque. Cannot verify goal positions.");
783+
DXL_LOG_ERROR("[resetGoalStateAndVerify] Failed to re-read goal.");
764784
return false;
765785
}
766786

767787
// Verify goal command values match the read values (for active command interfaces)
768788
for (auto& [name, joint] : joints_) {
769789
for (const auto& interface_name : joint.getAvailableCommandInterfaces()) {
770790
if (joint.read_goal_values_.count(interface_name) == 0) {
771-
DXL_LOG_ERROR("Cannot verify cmd values from motor " << name << "!");
791+
DXL_LOG_ERROR("[resetGoalStateAndVerify] Cannot verify cmd values from motor " << name << "!");
772792
return false;
773793
}
774794
const auto& interface_value = joint.read_goal_values_.at(interface_name);
775795
if (std::abs(interface_value - joint.getActuatorState().goal[interface_name]) > 1e-2) {
776-
DXL_LOG_ERROR("Joint '" << name << "' goal " << interface_name
777-
<< " does not match read goal position before enabling torque. "
778-
<< "(Current: " << joint.getActuatorState().goal[interface_name]
779-
<< ", Read Goal Position: " << interface_value << ")");
796+
DXL_LOG_ERROR("[resetGoalStateAndVerify] Joint '"
797+
<< name << "' goal " << interface_name
798+
<< " does not match read goal value before enabling torque. "
799+
<< "(Current: " << joint.getActuatorState().goal[interface_name]
800+
<< ", Read Goal Value: " << interface_value << ")");
780801
return false;
781802
}
782803
}

dynamixel_ros_control/src/joint.cpp

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,25 @@ bool Joint::removeActiveCommandInterface(const std::string& interface_name)
166166
return true;
167167
}
168168

169+
bool Joint::readControlMode()
170+
{
171+
int32_t mode = UNDEFINED;
172+
if (!dynamixel->readRegister(DXL_REGISTER_CONTROL_MODE, mode)) {
173+
return false;
174+
}
175+
control_mode_ = static_cast<ControlMode>(mode);
176+
return true;
177+
}
178+
169179
bool Joint::updateControlMode()
170180
{
171181
if (active_command_interfaces_.empty()) {
172-
// Do nothing if no command interface is active
182+
// Switch to position mode if no interface is active
183+
if (control_mode_ != POSITION && control_mode_ != EXTENDED_POSITION && control_mode_ != CURRENT_BASED_POSITION) {
184+
control_mode_ = preferred_position_control_mode_;
185+
DXL_LOG_DEBUG("No controller active for joint '" << name << "'. Switching to position control mode.");
186+
return dynamixel->writeControlMode(preferred_position_control_mode_, true); // at startup torque is unknown
187+
}
173188
return true;
174189
}
175190
// determine required control mode
@@ -214,6 +229,7 @@ std::string Joint::interfaceToLimitRegisterName(const std::string& interface_nam
214229
void Joint::resetGoalState(const std::string& interface_name)
215230
{
216231
double& value = getActuatorState().goal.at(interface_name); // This should exist
232+
ControlMode next_control_mode = getControlModeFromInterfaces(active_command_interfaces_);
217233

218234
// Special handling for position
219235
if (interface_name == hardware_interface::HW_IF_POSITION) {
@@ -227,18 +243,22 @@ void Joint::resetGoalState(const std::string& interface_name)
227243
"goal field. Add a position state interface to this joint to resolve this problem.");
228244
value = 0;
229245
}
230-
} else {
231-
if (std::find(active_command_interfaces_.begin(), active_command_interfaces_.end(), interface_name) !=
232-
active_command_interfaces_.end() ||
233-
active_command_interfaces_.empty()) {
234-
// if no command interface is set (or known), reset to zero ( motor might be in velocity or current mode)
235-
// also reset to zero if in velocity / effort mode
246+
} else if (interface_name == hardware_interface::HW_IF_VELOCITY) {
247+
if (control_mode_ == VELOCITY || next_control_mode == VELOCITY) {
236248
value = 0.0;
237249
} else {
238-
// Default value, e.g. as velocity limit in position mode
239-
value = default_goal_values_.at(interface_name); // This should exist
250+
value = default_goal_values_.at(hardware_interface::HW_IF_VELOCITY);
251+
}
252+
} else if (interface_name == hardware_interface::HW_IF_EFFORT || interface_name == hardware_interface::HW_IF_CURRENT) {
253+
if (control_mode_ == CURRENT || next_control_mode == CURRENT) {
254+
value = 0.0; // controller must immediately write gravity compensating value !!
255+
} else {
256+
value = default_goal_values_.at(interface_name);
240257
}
241258
}
259+
DXL_LOG_DEBUG("Resetting goal value of interface '" << interface_name << "' for joint '" << name << "' to " << value);
260+
DXL_LOG_DEBUG("Active command interfaces for joint '" << name << "': " << iterableToString(active_command_interfaces_)
261+
<< ", control mode: " << control_mode_);
242262
if (command_transmission) {
243263
command_transmission->actuator_to_joint(); // Unfortunately, there is no interface for single interface handles
244264
}
@@ -278,10 +298,10 @@ ControlMode Joint::getControlModeFromInterfaces(const std::vector<std::string>&
278298

279299
return CURRENT;
280300
}
281-
DXL_LOG_WARN("None out of the command interfaces "
282-
<< hardware_interface::HW_IF_POSITION << ", " << hardware_interface::HW_IF_VELOCITY << ", "
283-
<< hardware_interface::HW_IF_EFFORT << " have been requested. Defaulting to "
284-
<< hardware_interface::HW_IF_POSITION << " mode");
301+
DXL_LOG_DEBUG("None out of the command interfaces "
302+
<< hardware_interface::HW_IF_POSITION << ", " << hardware_interface::HW_IF_VELOCITY << ", "
303+
<< hardware_interface::HW_IF_EFFORT << " have been requested. Defaulting to "
304+
<< hardware_interface::HW_IF_POSITION << " mode");
285305
return POSITION;
286306
}
287307

0 commit comments

Comments
 (0)