|
- """Module for configuring and setting up the Low Cost Robot (LCR) hardware.
-
- This module provides functionality for initializing and configuring the LCR robot's
- servo motors and other hardware components.
-
- The program will:
- 1. Disable all torque motors of provided LCR.
- 2. Ask the user to move the LCR to the position 1 (see CONFIGURING.md for more details).
- 3. Record the position of the LCR.
- 4. Ask the user to move the LCR to the position 2 (see CONFIGURING.md for more details).
- 5. Record the position of the LCR.
- 8. Calculate interpolation functions.
- 9. Let the user verify in real time that the LCR is working properly.
-
- It will also enable all appropriate operating modes for the LCR.
- """
-
- import argparse
- import json
- import time
-
- import pyarrow as pa
- from bus import DynamixelBus, OperatingMode, TorqueMode
- from pwm_position_control.functions import construct_control_table
- from pwm_position_control.tables import (
- construct_logical_to_pwm_conversion_table_arrow,
- construct_pwm_to_logical_conversion_table_arrow,
- )
- from pwm_position_control.transform import pwm_to_logical_arrow, wrap_joints_and_values
-
- FULL_ARM = pa.array(
- [
- "shoulder_pan",
- "shoulder_lift",
- "elbow_flex",
- "wrist_flex",
- "wrist_roll",
- "gripper",
- ],
- type=pa.string(),
- )
-
- ARM_WITHOUT_GRIPPER = pa.array(
- ["shoulder_pan", "shoulder_lift", "elbow_flex", "wrist_flex", "wrist_roll"],
- type=pa.string(),
- )
-
- GRIPPER = pa.array(["gripper"], type=pa.string())
-
-
- def pause():
- """Pause execution and wait for user input to continue."""
- input("Press Enter to continue...")
-
-
- def configure_servos(bus: DynamixelBus):
- """Configure servo motors with appropriate settings.
-
- Args:
- bus: DynamixelBus instance for servo communication
-
- """
- bus.write_torque_enable(
- wrap_joints_and_values(FULL_ARM, [TorqueMode.DISABLED.value] * 6),
- )
-
- bus.write_operating_mode(
- wrap_joints_and_values(
- ARM_WITHOUT_GRIPPER, [OperatingMode.EXTENDED_POSITION.value] * 5,
- ),
- )
-
- bus.write_operating_mode(
- wrap_joints_and_values(
- GRIPPER, [OperatingMode.CURRENT_CONTROLLED_POSITION.value],
- ),
- )
-
-
- def main():
- """Initialize and configure the LCR robot hardware components."""
- parser = argparse.ArgumentParser(
- description="LCR Auto Configure: This program is used to automatically configure the Low Cost Robot (LCR) for "
- "the user.",
- )
-
- parser.add_argument("--port", type=str, required=True, help="The port of the LCR.")
- parser.add_argument(
- "--right",
- action="store_true",
- help="If the LCR is on the right side of the user.",
- )
- parser.add_argument(
- "--left",
- action="store_true",
- help="If the LCR is on the left side of the user.",
- )
- parser.add_argument(
- "--follower",
- action="store_true",
- help="If the LCR is the follower of the user.",
- )
- parser.add_argument(
- "--leader", action="store_true", help="If the LCR is the leader of the user.",
- )
-
- args = parser.parse_args()
-
- if args.right and args.left:
- raise ValueError("You cannot specify both --right and --left.")
-
- if args.follower and args.leader:
- raise ValueError("You cannot specify both --follower and --leader.")
-
- targets = (
- wrap_joints_and_values(FULL_ARM, [0, -90, 90, 0, -90, 0]),
- wrap_joints_and_values(FULL_ARM, [90, 0, 0, 90, 0, -90]),
- )
-
- arm = DynamixelBus(
- args.port,
- {
- "shoulder_pan": (1, "x_series"),
- "shoulder_lift": (2, "x_series"),
- "elbow_flex": (3, "x_series"),
- "wrist_flex": (4, "x_series"),
- "wrist_roll": (5, "x_series"),
- "gripper": (6, "x_series"),
- },
- )
-
- configure_servos(arm)
-
- print("Please move the LCR to the first position.")
- pause()
- pwm_position_1 = arm.read_position(FULL_ARM)
-
- print("Please move the LCR to the second position.")
- pause()
- pwm_position_2 = arm.read_position(FULL_ARM)
-
- print("Configuration completed.")
-
- pwm_positions = (pwm_position_1, pwm_position_2)
-
- pwm_to_logical_conversion_table = construct_pwm_to_logical_conversion_table_arrow(
- pwm_positions, targets,
- )
- logical_to_pwm_conversion_table = construct_logical_to_pwm_conversion_table_arrow(
- pwm_positions, targets,
- )
-
- control_table_json = {}
- for i in range(len(FULL_ARM)):
- model = (
- "xl430-w250"
- if i <= 1 and args.follower
- else "xl330-m288" if args.follower else "xl330-m077"
- )
-
- control_table_json[FULL_ARM[i].as_py()] = {
- "id": i + 1,
- "model": model,
- "torque": (
- True if args.follower else True if args.leader and i == 5 else False
- ),
- "goal_current": (
- 500
- if args.follower and i == 5
- else 40 if args.leader and i == 5 else None
- ),
- "goal_position": -40.0 if args.leader and i == 5 else None,
- "pwm_to_logical": pwm_to_logical_conversion_table[FULL_ARM[i].as_py()],
- "logical_to_pwm": logical_to_pwm_conversion_table[FULL_ARM[i].as_py()],
- "P": (
- 640
- if model == "xl430-w250"
- else 1500 if model == "xl330-m288" and i != 5 else 250
- ),
- "I": 0,
- "D": 3600 if model == "xl430-w250" else 600,
- }
-
- left = "left" if args.left else "right"
- leader = "leader" if args.leader else "follower"
-
- path = (
- input(
- f"Please enter the path of the configuration file (default is ./examples/alexk-lcr/configs/{leader}.{left}.json): ",
- )
- or f"./examples/alexk-lcr/configs/{leader}.{left}.json"
- )
-
- with open(path, "w") as file:
- json.dump(control_table_json, file)
-
- control_table = construct_control_table(
- pwm_to_logical_conversion_table, logical_to_pwm_conversion_table,
- )
-
- while True:
- try:
- pwm_position = arm.read_position(FULL_ARM)
- logical_position = pwm_to_logical_arrow(
- pwm_position, control_table, ranged=True,
- ).field("values")
-
- print(f"Logical Position: {logical_position}")
-
- except ConnectionError:
- print(
- "Connection error occurred. Please check the connection and try again.",
- )
-
- time.sleep(0.5)
-
-
- if __name__ == "__main__":
- main()
|