|
- """Module for configuring and setting up the SO100 robot hardware.
-
- This module provides functionality for initializing and configuring the SO100 robot's
- servo motors and other hardware components.
-
- The program will:
- 1. Disable all torque motors of provided SO100.
- 2. Ask the user to move the SO100 to the position 1 (see CONFIGURING.md for more details).
- 3. Record the position of the SO100.
- 4. Ask the user to move the SO100 to the position 2 (see CONFIGURING.md for more details).
- 5. Record the position of the SO100.
- 8. Calculate the offset and inverted mode of the SO100.
- 9. Let the user verify in real time that the SO100 is working properly.
-
- It will also enable all appropriate operating modes for the SO100.
- """
-
- import argparse
- import json
- import time
-
- import pyarrow as pa
- from bus import FeetechBus, 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."""
- input("Press Enter to continue...")
-
-
- def configure_servos(bus: FeetechBus):
- """Configure the servos with default settings.
-
- Args:
- bus: The FeetechBus instance to configure.
-
- """
- bus.write_torque_enable(
- wrap_joints_and_values(FULL_ARM, [TorqueMode.DISABLED.value] * 6),
- )
-
- bus.write_operating_mode(
- wrap_joints_and_values(FULL_ARM, [OperatingMode.ONE_TURN.value] * 6),
- )
-
- bus.write_max_angle_limit(
- wrap_joints_and_values(FULL_ARM, [pa.scalar(0, pa.uint32())] * 6),
- )
-
- bus.write_min_angle_limit(
- wrap_joints_and_values(FULL_ARM, [pa.scalar(0, pa.uint32())] * 6),
- )
-
-
- def main():
- """Run the servo configuration process."""
- parser = argparse.ArgumentParser(
- description="SO100 Auto Configure: This program is used to automatically configure the Low Cost Robot (SO100) "
- "for the user.",
- )
-
- parser.add_argument(
- "--port", type=str, required=True, help="The port of the SO100.",
- )
- parser.add_argument(
- "--right",
- action="store_true",
- help="If the SO100 is on the right side of the user.",
- )
- parser.add_argument(
- "--left",
- action="store_true",
- help="If the SO100 is on the left side of the user.",
- )
-
- args = parser.parse_args()
-
- if args.right and args.left:
- raise ValueError("You cannot specify both --right and --left.")
-
- args = parser.parse_args()
-
- 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 = FeetechBus(
- args.port,
- {
- "shoulder_pan": (1, "st3215"),
- "shoulder_lift": (2, "st3215"),
- "elbow_flex": (3, "st3215"),
- "wrist_flex": (4, "st3215"),
- "wrist_roll": (5, "st3215"),
- "gripper": (6, "st3215"),
- },
- )
-
- configure_servos(arm)
-
- print("Please move the SO100 to the first position.")
- pause()
- pwm_position_1 = arm.read_position(FULL_ARM)["values"].values
-
- print("Please move the SO100 to the second position.")
- pause()
- pwm_position_2 = arm.read_position(FULL_ARM)["values"].values
-
- 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)):
- control_table_json[FULL_ARM[i].as_py()] = {
- "id": i + 1,
- "model": "sts3215",
- "torque": True,
- "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()],
- }
-
- left = "left" if args.left else "right"
- path = (
- input(
- f"Please enter the path of the configuration file (default is ./examples/so100/configs/follower.{left}.json): ",
- )
- or f"./examples/so100/configs/follower.{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()
|