Add torque_disabled context
This commit is contained in:
parent
9afc4b771c
commit
2bb73ac431
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
import abc
|
import abc
|
||||||
import logging
|
import logging
|
||||||
|
from contextlib import contextmanager
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
|
@ -463,6 +464,14 @@ class MotorsBus(abc.ABC):
|
||||||
def enable_torque(self, motors: str | list[str] | None = None, num_retry: int = 0) -> None:
|
def enable_torque(self, motors: str | list[str] | None = None, num_retry: int = 0) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def torque_disabled(self):
|
||||||
|
self.disable_torque()
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
self.enable_torque()
|
||||||
|
|
||||||
def set_timeout(self, timeout_ms: int | None = None):
|
def set_timeout(self, timeout_ms: int | None = None):
|
||||||
timeout_ms = timeout_ms if timeout_ms is not None else self.default_timeout
|
timeout_ms = timeout_ms if timeout_ms is not None else self.default_timeout
|
||||||
self.port_handler.setPacketTimeoutMillis(timeout_ms)
|
self.port_handler.setPacketTimeoutMillis(timeout_ms)
|
||||||
|
|
|
@ -146,29 +146,28 @@ class KochFollower(Robot):
|
||||||
logger.info(f"Calibration saved to {self.calibration_fpath}")
|
logger.info(f"Calibration saved to {self.calibration_fpath}")
|
||||||
|
|
||||||
def configure(self) -> None:
|
def configure(self) -> None:
|
||||||
self.arm.disable_torque()
|
with self.arm.torque_disabled():
|
||||||
self.arm.configure_motors()
|
self.arm.configure_motors()
|
||||||
# Use 'extended position mode' for all motors except gripper, because in joint mode the servos
|
# Use 'extended position mode' for all motors except gripper, because in joint mode the servos
|
||||||
# can't rotate more than 360 degrees (from 0 to 4095) And some mistake can happen while
|
# can't rotate more than 360 degrees (from 0 to 4095) And some mistake can happen while assembling
|
||||||
# assembling the arm, you could end up with a servo with a position 0 or 4095 at a crucial
|
# the arm, you could end up with a servo with a position 0 or 4095 at a crucial point
|
||||||
# point
|
for name in self.arm.names:
|
||||||
for name in self.arm.names:
|
if name != "gripper":
|
||||||
if name != "gripper":
|
self.arm.write("Operating_Mode", name, OperatingMode.EXTENDED_POSITION.value)
|
||||||
self.arm.write("Operating_Mode", name, OperatingMode.EXTENDED_POSITION.value)
|
|
||||||
|
|
||||||
# Use 'position control current based' for gripper to be limited by the limit of the current.
|
# Use 'position control current based' for gripper to be limited by the limit of the current. For
|
||||||
# For the follower gripper, it means it can grasp an object without forcing too much even tho,
|
# the follower gripper, it means it can grasp an object without forcing too much even tho, its
|
||||||
# its goal position is a complete grasp (both gripper fingers are ordered to join and reach a touch).
|
# goal position is a complete grasp (both gripper fingers are ordered to join and reach a touch).
|
||||||
# For the leader gripper, it means we can use it as a physical trigger, since we can force with our finger
|
# For the leader gripper, it means we can use it as a physical trigger, since we can force with
|
||||||
# to make it move, and it will move back to its original target position when we release the force.
|
# our finger to make it move, and it will move back to its original target position when we
|
||||||
self.arm.write("Operating_Mode", "gripper", OperatingMode.CURRENT_POSITION.value)
|
# release the force.
|
||||||
|
self.arm.write("Operating_Mode", "gripper", OperatingMode.CURRENT_POSITION.value)
|
||||||
|
|
||||||
# Set better PID values to close the gap between recorded states and actions
|
# Set better PID values to close the gap between recorded states and actions
|
||||||
# TODO(rcadene): Implement an automatic procedure to set optimal PID values for each motor
|
# TODO(rcadene): Implement an automatic procedure to set optimal PID values for each motor
|
||||||
self.arm.write("Position_P_Gain", "elbow_flex", 1500)
|
self.arm.write("Position_P_Gain", "elbow_flex", 1500)
|
||||||
self.arm.write("Position_I_Gain", "elbow_flex", 0)
|
self.arm.write("Position_I_Gain", "elbow_flex", 0)
|
||||||
self.arm.write("Position_D_Gain", "elbow_flex", 600)
|
self.arm.write("Position_D_Gain", "elbow_flex", 600)
|
||||||
self.arm.enable_torque()
|
|
||||||
|
|
||||||
def get_observation(self) -> dict[str, Any]:
|
def get_observation(self) -> dict[str, Any]:
|
||||||
if not self.is_connected:
|
if not self.is_connected:
|
||||||
|
|
|
@ -144,17 +144,15 @@ class SO100Follower(Robot):
|
||||||
print("Calibration saved to", self.calibration_fpath)
|
print("Calibration saved to", self.calibration_fpath)
|
||||||
|
|
||||||
def configure(self) -> None:
|
def configure(self) -> None:
|
||||||
self.arm.disable_torque()
|
with self.arm.torque_disabled():
|
||||||
self.arm.configure_motors()
|
self.arm.configure_motors()
|
||||||
for name in self.arm.names:
|
for name in self.arm.names:
|
||||||
self.arm.write("Operating_Mode", name, OperatingMode.POSITION.value)
|
self.arm.write("Operating_Mode", name, OperatingMode.POSITION.value)
|
||||||
# Set P_Coefficient to lower value to avoid shakiness (Default is 32)
|
# Set P_Coefficient to lower value to avoid shakiness (Default is 32)
|
||||||
self.arm.write("P_Coefficient", name, 16)
|
self.arm.write("P_Coefficient", name, 16)
|
||||||
# Set I_Coefficient and D_Coefficient to default value 0 and 32
|
# Set I_Coefficient and D_Coefficient to default value 0 and 32
|
||||||
self.arm.write("I_Coefficient", name, 0)
|
self.arm.write("I_Coefficient", name, 0)
|
||||||
self.arm.write("D_Coefficient", name, 32)
|
self.arm.write("D_Coefficient", name, 32)
|
||||||
|
|
||||||
self.arm.enable_torque()
|
|
||||||
|
|
||||||
def get_observation(self) -> dict[str, Any]:
|
def get_observation(self) -> dict[str, Any]:
|
||||||
if not self.is_connected:
|
if not self.is_connected:
|
||||||
|
|
|
@ -141,32 +141,31 @@ class ViperX(Robot):
|
||||||
logger.info(f"Calibration saved to {self.calibration_fpath}")
|
logger.info(f"Calibration saved to {self.calibration_fpath}")
|
||||||
|
|
||||||
def configure(self) -> None:
|
def configure(self) -> None:
|
||||||
self.arm.disable_torque()
|
with self.arm.torque_disabled():
|
||||||
self.arm.configure_motors()
|
self.arm.configure_motors()
|
||||||
|
|
||||||
# Set secondary/shadow ID for shoulder and elbow. These joints have two motors.
|
# Set secondary/shadow ID for shoulder and elbow. These joints have two motors.
|
||||||
# As a result, if only one of them is required to move to a certain position,
|
# As a result, if only one of them is required to move to a certain position,
|
||||||
# the other will follow. This is to avoid breaking the motors.
|
# the other will follow. This is to avoid breaking the motors.
|
||||||
self.arm.write("Secondary_ID", "shoulder_shadow", 2)
|
self.arm.write("Secondary_ID", "shoulder_shadow", 2)
|
||||||
self.arm.write("Secondary_ID", "elbow_shadow", 4)
|
self.arm.write("Secondary_ID", "elbow_shadow", 4)
|
||||||
|
|
||||||
# Set a velocity limit of 131 as advised by Trossen Robotics
|
# Set a velocity limit of 131 as advised by Trossen Robotics
|
||||||
# TODO(aliberts): remove as it's actually useless in position control
|
# TODO(aliberts): remove as it's actually useless in position control
|
||||||
self.arm.write("Velocity_Limit", 131)
|
self.arm.write("Velocity_Limit", 131)
|
||||||
|
|
||||||
# Use 'extended position mode' for all motors except gripper, because in joint mode the servos can't
|
# Use 'extended position mode' for all motors except gripper, because in joint mode the servos
|
||||||
# rotate more than 360 degrees (from 0 to 4095) And some mistake can happen while assembling the arm,
|
# can't rotate more than 360 degrees (from 0 to 4095) And some mistake can happen while assembling
|
||||||
# you could end up with a servo with a position 0 or 4095 at a crucial point. See:
|
# the arm, you could end up with a servo with a position 0 or 4095 at a crucial point.
|
||||||
# https://emanual.robotis.com/docs/en/dxl/x/x_series/#operating-mode11
|
# See: https://emanual.robotis.com/docs/en/dxl/x/x_series/#operating-mode11
|
||||||
for name in self.arm.names:
|
for name in self.arm.names:
|
||||||
if name != "gripper":
|
if name != "gripper":
|
||||||
self.arm.write("Operating_Mode", name, OperatingMode.EXTENDED_POSITION.value)
|
self.arm.write("Operating_Mode", name, OperatingMode.EXTENDED_POSITION.value)
|
||||||
|
|
||||||
# Use 'position control current based' for follower gripper to be limited by the limit of the current.
|
# Use 'position control current based' for follower gripper to be limited by the limit of the
|
||||||
# It can grasp an object without forcing too much even tho, it's goal position is a complete grasp
|
# current. It can grasp an object without forcing too much even tho, it's goal position is a
|
||||||
# (both gripper fingers are ordered to join and reach a touch).
|
# complete grasp (both gripper fingers are ordered to join and reach a touch).
|
||||||
self.arm.write("Operating_Mode", "gripper", OperatingMode.CURRENT_POSITION.value)
|
self.arm.write("Operating_Mode", "gripper", OperatingMode.CURRENT_POSITION.value)
|
||||||
self.arm.enable_torque()
|
|
||||||
|
|
||||||
def get_observation(self) -> dict[str, Any]:
|
def get_observation(self) -> dict[str, Any]:
|
||||||
"""The returned observations do not have a batch dimension."""
|
"""The returned observations do not have a batch dimension."""
|
||||||
|
|
Loading…
Reference in New Issue