from arbotix_python.arbotix import ArbotiX SERVO_IDS = [1, 2, 3, 4, 5, 6] arbotix = ArbotiX('/dev/ttyUSB0') err = arbotix.syncWrite(14, [[servo_id, 255, 1] for servo_id in SERVO_IDS]) if err != -1: print('Successfully reconfigured servos') else: print( 'Error writing to servos -- make sure start.sh is not running in the background' )
class WidowXController(RobotController): def __init__(self, robot_name, print_debug, email_cred_file='', log_file='', control_rate=100, gripper_attached='default'): super(WidowXController, self).__init__(robot_name, print_debug, email_cred_file, log_file, control_rate, gripper_attached) self._redist_rate = rospy.Rate(50) self._arbotix = ArbotiX('/dev/ttyUSB0') assert self._arbotix.syncWrite(MAX_TORQUE_L, [[servo_id, 255, 0] for servo_id in SERVO_IDS]) != -1, "failure during servo configuring" assert self._arbotix.syncWrite(TORQUE_LIMIT, [[servo_id, 255, 0] for servo_id in SERVO_IDS]) != -1, "failure during servo configuring" self._joint_lock = Lock() self._angles, self._velocities = {}, {} rospy.Subscriber("/joint_states", JointState, self._joint_callback) time.sleep(1) self._joint_pubs = [rospy.Publisher('/{}/command'.format(name), Float64, queue_size=1) for name in JOINT_NAMES[:-1]] self._gripper_pub = rospy.Publisher('/gripper_prismatic_joint/command', Float64, queue_size=1) p.connect(p.DIRECT) widow_x_urdf = '/'.join(__file__.split('/')[:-1]) + '/widowx/widowx.urdf' self._armID = p.loadURDF(widow_x_urdf, useFixedBase=True) p.resetBasePositionAndOrientation(self._armID, [0, 0, 0], p.getQuaternionFromEuler([np.pi, np.pi, np.pi])) self._n_errors = 0 def _init_gripper(self, gripper_attached): assert gripper_attached == 'default', 'widow_x only supports its default gripper at the moment' def _joint_callback(self, msg): with self._joint_lock: for name, position, velocity in zip(msg.name, msg.position, msg.velocity): self._angles[name] = position self._velocities[name] = velocity def _move_to_target_joints(self, joint_values): for value, pub in zip(joint_values, self._joint_pubs): pub.publish(Float64(value)) def move_to_neutral(self, duration=2): self._n_errors = 0 self._lerp_joints(np.array(NEUTRAL_VALUES), duration) self._gripper_pub.publish(Float64(GRIPPER_DROP[0])) time.sleep(GRIPPER_WAIT) def _reset_pybullet(self): for i, angle in enumerate(self.get_joint_angles()): p.resetJointState(self._armID, i, angle) def _lerp_joints(self, target_joint_pos, duration): start_t, start_joints = rospy.get_time(), self.get_joint_angles() self._control_rate.sleep() cur_joints = self.get_joint_angles() while rospy.get_time() - start_t < 1.2 * duration and not np.isclose(target_joint_pos[:5], cur_joints[:5], atol=CONTROL_TOL).all(): t = min(1.0, (rospy.get_time() - start_t) / duration) target_joints = (1 - t) * start_joints[:5] + t * target_joint_pos[:5] self._move_to_target_joints(target_joints) self._control_rate.sleep() cur_joints = self.get_joint_angles() logging.getLogger('robot_logger').debug('Lerped for {} seconds'.format(rospy.get_time() - start_t)) self._reset_pybullet() delta = np.linalg.norm(target_joints[:5] - cur_joints[:5]) if delta > MAX_FINAL_ERR: assert self._arbotix.syncWrite(TORQUE_LIMIT, [[servo_id, 255, 0] for servo_id in SERVO_IDS]) != -1, "failure during servo configuring" self._n_errors += 1 if self._n_errors > MAX_ERRORS: logging.getLogger('robot_logger').error('More than {} errors! WidowX probably crashed.'.format(MAX_ERRORS)) raise Environment_Exception logging.getLogger('robot_logger').debug('Delta at end of lerp is {}'.format(delta)) def move_to_eep(self, target_pose, duration=1.5): """ :param target_pose: Cartesian pose (x,y,z, quat). :param duration: Total time trajectory will take before ending """ target_joint_pos = self._calculate_ik(target_pose[:3], target_pose[3:])[0] target_joint_pos = np.clip(np.array(target_joint_pos)[:6], JOINT_MIN, JOINT_MAX) self._lerp_joints(target_joint_pos, duration) def move_to_ja(self, waypoints, duration=1.5): """ :param waypoints: List of joint angle arrays. If len(waypoints) == 1: then go directly to point. Otherwise: take trajectory that ends at waypoints[-1] and passes through each intermediate waypoint :param duration: Total time trajectory will take before ending """ for waypoint in waypoints: # Move to each waypoint in sequence. See move_to_target_joint_position # in controller.py self._move_to_target_joints(waypoint) def redistribute_objects(self): """ Play pre-recorded trajectory that sweeps objects into center of bin """ logging.getLogger('robot_logger').info('redistribute...') file = '/'.join(str.split(robot_envs.__file__, "/")[ :-1]) + '/recorded_trajectories/pushback_traj_{}.pkl'.format(self._robot_name) joint_pos = pkl.load(open(file, "rb")) self._redist_rate.sleep() for joint_t in joint_pos: print(joint_t) self._move_to_target_joints(joint_t) self._redist_rate.sleep() def get_joint_angles(self): #returns current joint angles with self._joint_lock: joints_ret = ['joint_1', 'joint_2', 'joint_3', 'joint_4', 'joint_5', 'gripper_revolute_joint'] try: return np.array([self._angles[k] for k in joints_ret]) except KeyError: return None def get_joint_angles_velocity(self): #returns current joint angles #No velocities for widowx? :( with self._joint_lock: joints_ret = ['joint_1', 'joint_2', 'joint_3', 'joint_4', 'joint_5', 'gripper_revolute_joint'] try: return np.array([self._velocities[k] for k in joints_ret]) except KeyError: return None def get_cartesian_pose(self): #Returns cartesian end-effector pose self._reset_pybullet() position, quat = p.getLinkState(self._armID, 5, computeForwardKinematics=1)[4:6] return np.array(list(position) + list(quat)) def quat_2_euler(self, quat): roll, pitch, yaw = Quaternion(quat).yaw_pitch_roll return np.pi - yaw, pitch, roll def euler_2_quat(self, yaw=0.0, pitch=np.pi, roll=0.0): roll_matrix = np.array([[np.cos(roll), -np.sin(roll), 0.0],[np.sin(roll), np.cos(roll), 0.0], [0, 0, 1.0]]) pitch_matrix = np.array([[np.cos(pitch), 0., np.sin(pitch)], [0.0, 1.0, 0.0], [-np.sin(pitch), 0, np.cos(pitch)]]) yaw_matrix = np.array([[1.0, 0, 0], [0, np.cos(yaw), -np.sin(yaw)], [0, np.sin(yaw), np.cos(yaw)]]) rot_mat = roll_matrix.dot(pitch_matrix.dot(yaw_matrix)) return Quaternion(matrix=rot_mat).elements def get_gripper_state(self, integrate_force=False): # returns gripper joint angle, force reading (none if no force) with self._joint_lock: joint_angle = self._angles['gripper_prismatic_joint_1'] return joint_angle, None def open_gripper(self, wait = False): # should likely wrap separate gripper control class for max re-usability self._gripper_pub.publish(Float64(self.GRIPPER_OPEN)) time.sleep(GRIPPER_WAIT) def close_gripper(self, wait = False): # should likely wrap separate gripper control class for max re-usability self._gripper_pub.publish(Float64(self.GRIPPER_CLOSE)) time.sleep(GRIPPER_WAIT) @property def GRIPPER_CLOSE(self): return GRIPPER_CLOSED[0] @property def GRIPPER_OPEN(self): return GRIPPER_OPEN[1] def _calculate_ik(self, targetPos, targetQuat, threshold=1e-5, maxIter=1000, nJoints=6): closeEnough = False iter_count = 0 dist2 = None best_ret, best_dist = None, float('inf') while (not closeEnough and iter_count < maxIter): jointPoses = list(p.calculateInverseKinematics(self._armID, 5, targetPos, targetQuat, JOINT_MIN, JOINT_MAX)) for i in range(nJoints): jointPoses[i] = max(min(jointPoses[i], JOINT_MAX[i]), JOINT_MIN[i]) p.resetJointState(self._armID, i, jointPoses[i]) ls = p.getLinkState(self._armID, 5, computeForwardKinematics=1) newPos, newQuat = ls[4], ls[5] dist2 = sum([(targetPos[i] - newPos[i]) ** 2 for i in range(3)]) closeEnough = dist2 < threshold iter_count += 1 if dist2 < best_dist: best_ret, best_dist = (jointPoses, newPos, newQuat), dist2 return best_ret