You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

robot.py 6.5 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. import numpy as np
  2. from dynamixel import Dynamixel, OperatingMode, ReadAttribute
  3. import time
  4. from dynamixel_sdk import (
  5. GroupSyncRead,
  6. GroupSyncWrite,
  7. DXL_LOBYTE,
  8. DXL_HIBYTE,
  9. DXL_LOWORD,
  10. DXL_HIWORD,
  11. )
  12. from enum import Enum, auto
  13. from typing import Union
  14. class MotorControlType(Enum):
  15. PWM = auto()
  16. POSITION_CONTROL = auto()
  17. DISABLED = auto()
  18. UNKNOWN = auto()
  19. class Robot:
  20. # def __init__(self, device_name: str, baudrate=1_000_000, servo_ids=[1, 2, 3, 4, 5]):
  21. def __init__(self, dynamixel, baudrate=1_000_000, servo_ids=[1, 2, 3, 4, 5]):
  22. self.servo_ids = servo_ids
  23. self.dynamixel = dynamixel
  24. # self.dynamixel = Dynamixel.Config(baudrate=baudrate, device_name=device_name).instantiate()
  25. self.position_reader = GroupSyncRead(
  26. self.dynamixel.portHandler,
  27. self.dynamixel.packetHandler,
  28. ReadAttribute.POSITION.value,
  29. 4,
  30. )
  31. for id in self.servo_ids:
  32. self.position_reader.addParam(id)
  33. self.velocity_reader = GroupSyncRead(
  34. self.dynamixel.portHandler,
  35. self.dynamixel.packetHandler,
  36. ReadAttribute.VELOCITY.value,
  37. 4,
  38. )
  39. for id in self.servo_ids:
  40. self.velocity_reader.addParam(id)
  41. self.pos_writer = GroupSyncWrite(
  42. self.dynamixel.portHandler,
  43. self.dynamixel.packetHandler,
  44. self.dynamixel.ADDR_GOAL_POSITION,
  45. 4,
  46. )
  47. for id in self.servo_ids:
  48. self.pos_writer.addParam(id, [2048])
  49. self.pwm_writer = GroupSyncWrite(
  50. self.dynamixel.portHandler,
  51. self.dynamixel.packetHandler,
  52. self.dynamixel.ADDR_GOAL_PWM,
  53. 2,
  54. )
  55. for id in self.servo_ids:
  56. self.pwm_writer.addParam(id, [2048])
  57. self._disable_torque()
  58. self.motor_control_state = MotorControlType.DISABLED
  59. def read_position(self, tries=2):
  60. """
  61. Reads the joint positions of the robot. 2048 is the center position. 0 and 4096 are 180 degrees in each direction.
  62. :param tries: maximum number of tries to read the position
  63. :return: list of joint positions in range [0, 4096]
  64. """
  65. result = self.position_reader.txRxPacket()
  66. if result != 0:
  67. if tries > 0:
  68. return self.read_position(tries=tries - 1)
  69. else:
  70. print(f"failed to read position!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
  71. positions = []
  72. for id in self.servo_ids:
  73. position = self.position_reader.getData(id, ReadAttribute.POSITION.value, 4)
  74. if position > 2**31:
  75. position -= 2**32
  76. positions.append(position)
  77. return positions
  78. def read_velocity(self):
  79. """
  80. Reads the joint velocities of the robot.
  81. :return: list of joint velocities,
  82. """
  83. self.velocity_reader.txRxPacket()
  84. velocties = []
  85. for id in self.servo_ids:
  86. velocity = self.velocity_reader.getData(id, ReadAttribute.VELOCITY.value, 4)
  87. if velocity > 2**31:
  88. velocity -= 2**32
  89. velocties.append(velocity)
  90. return velocties
  91. def set_goal_pos(self, action):
  92. """
  93. :param action: list or numpy array of target joint positions in range [0, 4096]
  94. """
  95. if not self.motor_control_state is MotorControlType.POSITION_CONTROL:
  96. self._set_position_control()
  97. for i, motor_id in enumerate(self.servo_ids):
  98. data_write = [
  99. DXL_LOBYTE(DXL_LOWORD(action[i])),
  100. DXL_HIBYTE(DXL_LOWORD(action[i])),
  101. DXL_LOBYTE(DXL_HIWORD(action[i])),
  102. DXL_HIBYTE(DXL_HIWORD(action[i])),
  103. ]
  104. self.pos_writer.changeParam(motor_id, data_write)
  105. self.pos_writer.txPacket()
  106. def set_pwm(self, action):
  107. """
  108. Sets the pwm values for the servos.
  109. :param action: list or numpy array of pwm values in range [0, 885]
  110. """
  111. if not self.motor_control_state is MotorControlType.PWM:
  112. self._set_pwm_control()
  113. for i, motor_id in enumerate(self.servo_ids):
  114. data_write = [
  115. DXL_LOBYTE(DXL_LOWORD(action[i])),
  116. DXL_HIBYTE(DXL_LOWORD(action[i])),
  117. ]
  118. self.pwm_writer.changeParam(motor_id, data_write)
  119. self.pwm_writer.txPacket()
  120. def set_trigger_torque(self):
  121. """
  122. Sets a constant torque torque for the last servo in the chain. This is useful for the trigger of the leader arm
  123. """
  124. self.dynamixel._enable_torque(self.servo_ids[-1])
  125. self.dynamixel.set_pwm_value(self.servo_ids[-1], 200)
  126. def limit_pwm(self, limit: Union[int, list, np.ndarray]):
  127. """
  128. Limits the pwm values for the servos in for position control
  129. @param limit: 0 ~ 885
  130. @return:
  131. """
  132. if isinstance(limit, int):
  133. limits = [
  134. limit,
  135. ] * 5
  136. else:
  137. limits = limit
  138. self._disable_torque()
  139. for motor_id, limit in zip(self.servo_ids, limits):
  140. self.dynamixel.set_pwm_limit(motor_id, limit)
  141. self._enable_torque()
  142. def _disable_torque(self):
  143. print(f"disabling torque for servos {self.servo_ids}")
  144. for motor_id in self.servo_ids:
  145. self.dynamixel._disable_torque(motor_id)
  146. def _enable_torque(self):
  147. print(f"enabling torque for servos {self.servo_ids}")
  148. for motor_id in self.servo_ids:
  149. self.dynamixel._enable_torque(motor_id)
  150. def _set_pwm_control(self):
  151. self._disable_torque()
  152. for motor_id in self.servo_ids:
  153. self.dynamixel.set_operating_mode(motor_id, OperatingMode.PWM)
  154. self._enable_torque()
  155. self.motor_control_state = MotorControlType.PWM
  156. def _set_position_control(self):
  157. self._disable_torque()
  158. for motor_id in self.servo_ids:
  159. self.dynamixel.set_operating_mode(motor_id, OperatingMode.POSITION)
  160. self._enable_torque()
  161. self.motor_control_state = MotorControlType.POSITION_CONTROL
  162. if __name__ == "__main__":
  163. robot = Robot(device_name="/dev/tty.usbmodem57380045631")
  164. robot._disable_torque()
  165. for _ in range(10000):
  166. s = time.time()
  167. pos = robot.read_position()
  168. elapsed = time.time() - s
  169. print(f"read took {elapsed} pos {pos}")