using System.Collections; using System.Linq; using RosMessageTypes.NiryoMoveit; using UnityEngine; using Unity.Robotics.ROSTCPConnector; using Unity.Robotics.ROSTCPConnector.ROSGeometry; using RosMessageTypes.Geometry; public class TrajectoryPlanner : MonoBehaviour { // ROS Connector private ROSConnection ros; // Hardcoded variables private int numRobotJoints = 6; private readonly float jointAssignmentWait = 0.1f; private readonly float poseAssignmentWait = 0.5f; private readonly Vector3 pickPoseOffset = Vector3.up * 0.1f; // Assures that the gripper is always positioned above the target cube before grasping. private readonly Quaternion pickOrientation = Quaternion.Euler(90, 90, 0); // Variables required for ROS communication public string rosServiceName = "niryo_moveit"; public GameObject niryoOne; public GameObject target; public GameObject targetPlacement; // Articulation Bodies private ArticulationBody[] jointArticulationBodies; private ArticulationBody leftGripper; private ArticulationBody rightGripper; private Transform gripperBase; private Transform leftGripperGameObject; private Transform rightGripperGameObject; private enum Poses { PreGrasp, Grasp, PickUp, Place }; /// /// Close the gripper /// private void CloseGripper() { var leftDrive = leftGripper.xDrive; var rightDrive = rightGripper.xDrive; leftDrive.target = -0.01f; rightDrive.target = 0.01f; leftGripper.xDrive = leftDrive; rightGripper.xDrive = rightDrive; } /// /// Open the gripper /// private void OpenGripper() { var leftDrive = leftGripper.xDrive; var rightDrive = rightGripper.xDrive; leftDrive.target = 0.01f; rightDrive.target = -0.01f; leftGripper.xDrive = leftDrive; rightGripper.xDrive = rightDrive; } /// /// Get the current values of the robot's joint angles. /// /// NiryoMoveitJoints MNiryoMoveitJoints CurrentJointConfig() { MNiryoMoveitJoints joints = new MNiryoMoveitJoints(); joints.joint_00 = jointArticulationBodies[0].xDrive.target; joints.joint_01 = jointArticulationBodies[1].xDrive.target; joints.joint_02 = jointArticulationBodies[2].xDrive.target; joints.joint_03 = jointArticulationBodies[3].xDrive.target; joints.joint_04 = jointArticulationBodies[4].xDrive.target; joints.joint_05 = jointArticulationBodies[5].xDrive.target; return joints; } /// /// Create a new MoverServiceRequest with the current values of the robot's joint angles, /// the target cube's current position and rotation, and the targetPlacement position and rotation. /// /// Call the MoverService using the ROSConnection and if a trajectory is successfully planned, /// execute the trajectories in a coroutine. /// public void PublishJoints() { MMoverServiceRequest request = new MMoverServiceRequest(); request.joints_input = CurrentJointConfig(); // Pick Pose request.pick_pose = new MPose { position = (target.transform.position + pickPoseOffset).To(), // The hardcoded x/z angles assure that the gripper is always positioned above the target cube before grasping. orientation = Quaternion.Euler(90, target.transform.eulerAngles.y, 0).To() }; // Place Pose request.place_pose = new MPose { position = (targetPlacement.transform.position + pickPoseOffset).To(), orientation = pickOrientation.To() }; ros.SendServiceMessage(rosServiceName, request, TrajectoryResponse); } void TrajectoryResponse(MMoverServiceResponse response) { if (response.trajectories.Length > 0) { Debug.Log("Trajectory returned."); StartCoroutine(ExecuteTrajectories(response)); } else { Debug.LogError("No trajectory returned from MoverService."); } } /// /// Execute the returned trajectories from the MoverService. /// /// The expectation is that the MoverService will return four trajectory plans, /// PreGrasp, Grasp, PickUp, and Place, /// where each plan is an array of robot poses. A robot pose is the joint angle values /// of the six robot joints. /// /// Executing a single trajectory will iterate through every robot pose in the array while updating the /// joint values on the robot. /// /// /// MoverServiceResponse received from niryo_moveit mover service running in ROS /// private IEnumerator ExecuteTrajectories(MMoverServiceResponse response) { if (response.trajectories != null) { // For every trajectory plan returned for (int poseIndex = 0 ; poseIndex < response.trajectories.Length; poseIndex++) { // For every robot pose in trajectory plan for (int jointConfigIndex = 0 ; jointConfigIndex < response.trajectories[poseIndex].joint_trajectory.points.Length; jointConfigIndex++) { var jointPositions = response.trajectories[poseIndex].joint_trajectory.points[jointConfigIndex].positions; float[] result = jointPositions.Select(r=> (float)r * Mathf.Rad2Deg).ToArray(); // Set the joint values for every joint for (int joint = 0; joint < jointArticulationBodies.Length; joint++) { var joint1XDrive = jointArticulationBodies[joint].xDrive; joint1XDrive.target = result[joint]; jointArticulationBodies[joint].xDrive = joint1XDrive; } // Wait for robot to achieve pose for all joint assignments yield return new WaitForSeconds(jointAssignmentWait); } // Close the gripper if completed executing the trajectory for the Grasp pose if (poseIndex == (int)Poses.Grasp) CloseGripper(); // Wait for the robot to achieve the final pose from joint assignment yield return new WaitForSeconds(poseAssignmentWait); } // All trajectories have been executed, open the gripper to place the target cube OpenGripper(); } } /// /// Find all robot joints in Awake() and add them to the jointArticulationBodies array. /// Find left and right finger joints and assign them to their respective articulation body objects. /// void Start() { // Get ROS connection static instance ros = ROSConnection.instance; jointArticulationBodies = new ArticulationBody[numRobotJoints]; string shoulder_link = "world/base_link/shoulder_link"; jointArticulationBodies[0] = niryoOne.transform.Find(shoulder_link).GetComponent(); string arm_link = shoulder_link + "/arm_link"; jointArticulationBodies[1] = niryoOne.transform.Find(arm_link).GetComponent(); string elbow_link = arm_link + "/elbow_link"; jointArticulationBodies[2] = niryoOne.transform.Find(elbow_link).GetComponent(); string forearm_link = elbow_link + "/forearm_link"; jointArticulationBodies[3] = niryoOne.transform.Find(forearm_link).GetComponent(); string wrist_link = forearm_link + "/wrist_link"; jointArticulationBodies[4] = niryoOne.transform.Find(wrist_link).GetComponent(); string hand_link = wrist_link + "/hand_link"; jointArticulationBodies[5] = niryoOne.transform.Find(hand_link).GetComponent(); // Find left and right fingers string right_gripper = hand_link + "/tool_link/gripper_base/servo_head/control_rod_right/right_gripper"; string left_gripper = hand_link + "/tool_link/gripper_base/servo_head/control_rod_left/left_gripper"; string gripper_base = hand_link + "/tool_link/gripper_base/Collisions/unnamed"; gripperBase = niryoOne.transform.Find(gripper_base); leftGripperGameObject = niryoOne.transform.Find(left_gripper); rightGripperGameObject = niryoOne.transform.Find(right_gripper); rightGripper = rightGripperGameObject.GetComponent(); leftGripper = leftGripperGameObject.GetComponent(); } }