Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance DXL item initialization by prioritizing 'Limit' parameters. #5

Merged
merged 1 commit into from
Jan 17, 2025

Conversation

Woojin-Crive
Copy link
Contributor

Changes

This PR enhances the Dynamixel parameter initialization sequence by implementing a priority-based approach for limit parameters:

  1. Two-Phase Parameter Initialization

    • Previously: All parameters were written in a single pass without priority
    • Now: Implemented a two-phase initialization process
    • Phase 1: Writes all "Limit" parameters first
    • Phase 2: Writes remaining operational parameters
  2. Implementation Details

    • Added parameter name filtering using string search for "Limit"

Why

  • Items like "Profile Velocity" should be within the range of the defined limits. Thus, setting the limits first ensures these parameters remain valid during initialization.

Technical Details

  • Uses string search (find("Limit")) to identify limit-related parameters
  • Maintains identical write operations and error checking in both phases
  • Preserves existing parameter validation and type conversion

Copy link
Member

@HPaper HPaper left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that prioritizing the processing of "Limit" items over other parameters is a necessary feature considering the functionality of Dynamixel. Adding this feature is a very positive improvement. With a few additional code changes, it could be even better.

}

// Then write the remaining items
for (auto it : gpio.parameters) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current implementation separates the processing of "Limit" items and other items into two loops. While this approach works, it can be optimized by combining the loops into one. By doing so, we reduce the number of iterations over gpio.parameters, making the code simpler and slightly more efficient. Additionally, separating the conditions for "Limit" items and others within the loop maintains the existing logic while improving readability and maintainability.

Here’s a suggested implementation:

bool DynamixelHardware::InitDxlItems()
{
  RCLCPP_INFO_STREAM(logger_, "$$$$$ Init Dxl Items");

  for (const hardware_interface::ComponentInfo & gpio : info_.gpios) {
    uint8_t id = static_cast<uint8_t>(stoi(gpio.parameters.at("ID")));

    // Single loop to handle all parameters
    for (auto it : gpio.parameters) {
      if (it.first == "ID" || it.first == "type") {
        continue; // Skip ID and type
      }

      // Write "Limit" items first
      if (it.first.find("Limit") != std::string::npos) {
        if (dxl_comm_->WriteItem(
            id, it.first,
            static_cast<uint32_t>(stoi(it.second))) != DxlError::OK)
        {
          RCLCPP_ERROR_STREAM(logger_, "[ID:" << std::to_string(id) << "] Write Item error (Limit)");
          return false;
        }
        RCLCPP_INFO_STREAM(
          logger_,
          "[ID:" << std::to_string(id) << "] (Limit) item_name:" << it.first.c_str() << "\tdata:" <<
            stoi(it.second));
      } else {
        // Write other items
        if (dxl_comm_->WriteItem(
            id, it.first,
            static_cast<uint32_t>(stoi(it.second))) != DxlError::OK)
        {
          RCLCPP_ERROR_STREAM(logger_, "[ID:" << std::to_string(id) << "] Write Item error");
          return false;
        }
        RCLCPP_INFO_STREAM(
          logger_,
          "[ID:" << std::to_string(id) << "] item_name:" << it.first.c_str() << "\tdata:" <<
            stoi(it.second));
      }
    }
  }
  return true;
}

Key Benefits:

Efficiency: The parameters are iterated only once.
Maintainability: Combining the loops reduces redundancy, and separating conditions ("Limit" vs. others) within the loop improves clarity.
Logic Preservation: The "Limit" items are still processed before others, maintaining the intended behavior.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your suggestion to combine the limit parameters and other parameters into a single loop. However, the original code explicitly ensures that all limit parameters are written before any other parameters. This two-phase approach is critical because it guarantees that subsequent parameter writes will fall within valid, pre-established limits.

When we merge everything into a single loop, we lose that strict ordering. Although the if (it.first.find("Limit") ... ) check is present, we can’t guarantee all limit parameters will be handled first in a single pass—especially in containers where iteration order can be non-deterministic. That means some non-limit parameters might get set before the corresponding limit parameters, which could lead to invalid configurations.

I do appreciate the goal of reducing loops and simplifying the code, but preserving the limit-first logic is paramount for reliable initialization. If you have any other ideas on how to keep this guarantee while simplifying the loops, I am open to further discussion!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your detailed explanation and for pointing out the importance of preserving the strict ordering of limit parameters before other parameters. You are absolutely correct that combining everything into a single loop could break the intended logic by potentially allowing non-limit parameters to be set before their corresponding limits, especially in cases where the iteration order of the container is non-deterministic.

Additionally, I considered an alternative approach where the first loop processes and removes limit parameters from the container, reducing the number of iterations required in the second loop. However, as this would involve modifying the container during iteration, it might not yield significant efficiency improvements and could introduce unnecessary complexity.

Given these points, I agree that your proposed two-phase approach is the most reliable way to ensure the initialization process remains robust and predictable. Thank you again for the clarification, and I’m happy to proceed with your method. If any further ideas come to mind, I’ll be sure to share them! 😊

}

// Then write the remaining items
for (auto it : gpio.parameters) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your detailed explanation and for pointing out the importance of preserving the strict ordering of limit parameters before other parameters. You are absolutely correct that combining everything into a single loop could break the intended logic by potentially allowing non-limit parameters to be set before their corresponding limits, especially in cases where the iteration order of the container is non-deterministic.

Additionally, I considered an alternative approach where the first loop processes and removes limit parameters from the container, reducing the number of iterations required in the second loop. However, as this would involve modifying the container during iteration, it might not yield significant efficiency improvements and could introduce unnecessary complexity.

Given these points, I agree that your proposed two-phase approach is the most reliable way to ensure the initialization process remains robust and predictable. Thank you again for the clarification, and I’m happy to proceed with your method. If any further ideas come to mind, I’ll be sure to share them! 😊

Copy link
Collaborator

@sunghowoo sunghowoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@sunghowoo sunghowoo merged commit 5df2f56 into ROBOTIS-GIT:main Jan 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants