@@ -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 }
0 commit comments