diff --git a/Progress_Documentation/rosgraph.png b/Progress_Documentation/rosgraph.png new file mode 100644 index 0000000000000000000000000000000000000000..ff23c1e3b964eda6a6300045131a5f90dabb3da8 Binary files /dev/null and b/Progress_Documentation/rosgraph.png differ diff --git a/workspaces/COLCON_WS/src/Universal_Robots_ROS2_Gazebo_Simulation b/workspaces/COLCON_WS/src/Universal_Robots_ROS2_Gazebo_Simulation new file mode 160000 index 0000000000000000000000000000000000000000..93b25c6aae7efd4845633cd01f45403a2cc592e6 --- /dev/null +++ b/workspaces/COLCON_WS/src/Universal_Robots_ROS2_Gazebo_Simulation @@ -0,0 +1 @@ +Subproject commit 93b25c6aae7efd4845633cd01f45403a2cc592e6 diff --git a/workspaces/COLCON_WS/src/serial_to_pcl/serial_to_pcl/moveit_stop.py b/workspaces/COLCON_WS/src/serial_to_pcl/serial_to_pcl/moveit_stop.py new file mode 100644 index 0000000000000000000000000000000000000000..5d94cbb331a0ea6fcff667b96a3c2a8c15402483 --- /dev/null +++ b/workspaces/COLCON_WS/src/serial_to_pcl/serial_to_pcl/moveit_stop.py @@ -0,0 +1,113 @@ +import rclpy +from rclpy.node import Node +from sensor_msgs.msg import PointCloud2 +from tf2_ros import TransformListener, Buffer +import numpy as np +import trimesh +from std_msgs.msg import String +import sensor_msgs_py.point_cloud2 as pc2 + +class PointCloudProcessor(Node): + def __init__(self): + super().__init__('pointcloud_processor') + + self.subscription = self.create_subscription( + PointCloud2, + 'valid_from_perspective', + self.pointcloud_callback, + 10) + + self.cancellation_pub = self.create_publisher( + String, "/trajectory_execution_event", 1 + ) + + self.tf_buffer = Buffer() + self.tf_listener = TransformListener(self.tf_buffer, self) + + # Create meshes 5cm larger than the original example + self.meshes_static = [ + trimesh.creation.cylinder(radius=0.2, height=1.0), # Cylinder for upper_arm_link + trimesh.creation.cylinder(radius=0.2, height=1.05) # Cylinder for forearm_link + ] + + # Rotate cylinders 90 degrees around the y-axis + rotation_matrix = trimesh.transformations.rotation_matrix( + angle=np.pi / 2, # 90 degrees in radians + direction=[0, 1, 0] # Rotation around the y-axis + ) + for mesh in self.meshes_static: + mesh.apply_transform(rotation_matrix) + + # Translate cylinders 35cm in the negative x direction + translation_matrix_x = trimesh.transformations.translation_matrix([-0.35, 0, 0]) + for mesh in self.meshes_static: + mesh.apply_transform(translation_matrix_x) + + # Move the upper_arm_link cylinder 10cm in the positive x direction + translation_matrix_upper_arm = trimesh.transformations.translation_matrix([0.1, 0, 0]) + self.meshes_static[0].apply_transform(translation_matrix_upper_arm) + + # Move the forearm_link cylinder 5cm in the negative x direction + translation_matrix_forearm = trimesh.transformations.translation_matrix([-0.05, 0, 0]) + self.meshes_static[1].apply_transform(translation_matrix_forearm) + + # Move cylinders 10cm in the positive z direction + translation_matrix_z = trimesh.transformations.translation_matrix([0, 0, 0.1]) + for mesh in self.meshes_static: + mesh.apply_transform(translation_matrix_z) + + # Threshold for stopping the trajectory + self.point_threshold = 33 # Adjust as needed + + def pointcloud_callback(self, msg): + self.perspective_frame = 'vl53l7cx_link' + try: + now = rclpy.time.Time() + transforms = { + 'shoulder': self.tf_buffer.lookup_transform(self.perspective_frame, 'upper_arm_link', now), + 'forearm': self.tf_buffer.lookup_transform(self.perspective_frame, 'forearm_link', now) + } + except Exception as e: + self.get_logger().error(f'Error in looking up transform: {e}') + return + + transformed_meshes = [] + for i, transform in enumerate(transforms.values()): + transformed_meshes.append(self.transform_mesh(transform, self.meshes_static[i])) + + points = np.array([(point['x'], point['y'], point['z']) for point in pc2.read_points(msg, field_names=("x", "y", "z"), skip_nans=True)], dtype=np.float64) + + inside_robot = np.logical_or.reduce([mesh.contains(points) for mesh in transformed_meshes]) + points_inside_robot = points[inside_robot] + + self.get_logger().info(f'Number of points inside robot: {len(points_inside_robot)}') + + if len(points_inside_robot) > self.point_threshold: + self.stop_trajectory() + + def transform_mesh(self, transform, mesh_static): + translation = transform.transform.translation + rotation = transform.transform.rotation + + translation_matrix = trimesh.transformations.translation_matrix([translation.x, translation.y, translation.z]) + rotation_matrix = trimesh.transformations.quaternion_matrix([rotation.w, rotation.x, rotation.y, rotation.z]) + transformation_matrix = np.dot(translation_matrix, rotation_matrix) + + transformed_mesh = mesh_static.copy() + transformed_mesh.apply_transform(transformation_matrix) + return transformed_mesh + + def stop_trajectory(self): + cancel_string = String() + cancel_string.data = "stop" + self.cancellation_pub.publish(cancel_string) + +def main(args=None): + rclpy.init(args=args) + pointcloud_processor = PointCloudProcessor() + rclpy.spin(pointcloud_processor) + pointcloud_processor.destroy_node() + rclpy.shutdown() + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/workspaces/COLCON_WS/src/serial_to_pcl/serial_to_pcl/random_pcl.py b/workspaces/COLCON_WS/src/serial_to_pcl/serial_to_pcl/random_pcl.py new file mode 100644 index 0000000000000000000000000000000000000000..5f34bcd7fec830053cba991488e89cccda31d22f --- /dev/null +++ b/workspaces/COLCON_WS/src/serial_to_pcl/serial_to_pcl/random_pcl.py @@ -0,0 +1,66 @@ +import rclpy +from rclpy.node import Node +from sensor_msgs.msg import PointCloud2, PointField +from std_msgs.msg import Header +import numpy as np +import random + +#!/usr/bin/env python3 + + +class RandomPointCloudPublisher(Node): + def __init__(self): + super().__init__('random_pointcloud_publisher') + self.publisher_ = self.create_publisher(PointCloud2, 'pcl', 10) + self.timer = self.create_timer(0.1, self.publish_pointcloud) # Publish every second + self.get_logger().info("Random PointCloud Publisher Node has been started.") + + def generate_random_pointcloud(self, num_points=4800): + points = np.random.uniform(-1.1, 1.1, (num_points, 3)) # Generate random points as a NumPy array + return points + + def create_point_cloud(self, points, parent_frame): + """ + Create a PointCloud2 message from the 3D points. + """ + ros_dtype = PointField.FLOAT32 # ROS 2 data type for floating-point numbers + dtype = np.float32 # NumPy data type for floating-point numbers + itemsize = np.dtype(dtype).itemsize # Size of each data item in bytes + + data = points.astype(dtype).tobytes() # Convert points to binary data + + fields = [PointField(name=n, offset=i * itemsize, datatype=ros_dtype, count=1) + for i, n in enumerate('xyz')] # Define the fields for x, y, and z + + header = Header(frame_id=parent_frame) # Create a header with the parent frame + return PointCloud2( + header=header, + height=1, # Single row of points + width=points.shape[0], # Number of points + is_dense=True, # Allow for invalid points + is_bigendian=False, # Data is in little-endian format + fields=fields, # Fields for x, y, and z + point_step=(itemsize * 3), # Size of each point in bytes + row_step=(itemsize * 3 * points.shape[0]), # Size of each row in bytes + data=data # Binary data for the points + ) + + def publish_pointcloud(self): + points = self.generate_random_pointcloud() + pointcloud_msg = self.create_point_cloud(points, 'vl53l7cx_link') + self.publisher_.publish(pointcloud_msg) + self.get_logger().info("Published random point cloud.") + +def main(args=None): + rclpy.init(args=args) + node = RandomPointCloudPublisher() + try: + rclpy.spin(node) + except KeyboardInterrupt: + pass + finally: + node.destroy_node() + rclpy.shutdown() + +if __name__ == '__main__': + main() diff --git a/workspaces/COLCON_WS/src/serial_to_pcl/serial_to_pcl/test_transform.py b/workspaces/COLCON_WS/src/serial_to_pcl/serial_to_pcl/test_transform.py index 4277d0d8936e38e024e00e4495ebe17519932360..064c3b8fe562eeb75db8ebdc97e0ad3c317cb34b 100644 --- a/workspaces/COLCON_WS/src/serial_to_pcl/serial_to_pcl/test_transform.py +++ b/workspaces/COLCON_WS/src/serial_to_pcl/serial_to_pcl/test_transform.py @@ -5,10 +5,6 @@ from tf2_ros import TransformListener, Buffer import numpy as np import trimesh from std_msgs.msg import Header -# Removed unused import -import os - -# Removed unused import import sensor_msgs.msg as sensor_msgs import sensor_msgs_py.point_cloud2 as pc2 @@ -17,7 +13,7 @@ class PointCloudProcessor(Node): super().__init__('pointcloud_processor') self.subscription = self.create_subscription( PointCloud2, - 'pcd', + 'pcl', self.pointcloud_callback, 10) self.publisher_valid = self.create_publisher(PointCloud2, '/valid_from_perspective', 10) @@ -26,23 +22,37 @@ class PointCloudProcessor(Node): self.tf_buffer = Buffer() self.tf_listener = TransformListener(self.tf_buffer, self) - base_path = os.path.join(os.path.expanduser('~'), 'robot-sensor', 'workspaces', 'COLCON_WS', 'src', 'ur_description', 'meshes', 'ur10', 'collision_custom') + # Create cylinders self.meshes_static = [ - trimesh.load_mesh(os.path.join(base_path, 'shoulder.stl')), - trimesh.load_mesh(os.path.join(base_path, 'forearm.stl')), - trimesh.load_mesh(os.path.join(base_path, 'upperarm.stl')), - trimesh.load_mesh(os.path.join(base_path, 'wrist1.stl')), - trimesh.load_mesh(os.path.join(base_path, 'wrist2.stl')), - trimesh.load_mesh(os.path.join(base_path, 'wrist3.stl')) + trimesh.creation.cylinder(radius=0.18, height=0.9), # Cylinder for upper_arm_link (10 cm shorter) + trimesh.creation.cylinder(radius=0.18, height=1.0) # Cylinder for forearm_link ] - base_path_collision = os.path.join(os.path.expanduser('~'), 'robot-sensor', 'workspaces', 'COLCON_WS', 'src', 'ur_description', 'meshes', 'ur10', 'collision') - self.meshes_static.append(trimesh.load_mesh(os.path.join(base_path_collision, 'base.stl'))) + # Rotate cylinders 90 degrees around the y-axis + rotation_matrix = trimesh.transformations.rotation_matrix( + angle=np.pi / 2, # 90 degrees in radians + direction=[0, 1, 0] # Rotation around the y-axis + ) + for mesh in self.meshes_static: + mesh.apply_transform(rotation_matrix) + + # Translate cylinders 35cm in the negative x direction + translation_matrix_x = trimesh.transformations.translation_matrix([-0.35, 0, 0]) + for mesh in self.meshes_static: + mesh.apply_transform(translation_matrix_x) + + # Move the upper_arm_link cylinder 10cm in the positive x direction + translation_matrix_upper_arm = trimesh.transformations.translation_matrix([0.1, 0, 0]) + self.meshes_static[0].apply_transform(translation_matrix_upper_arm) + + # Move the upper_arm_link cylinder 10cm in the positive x direction + translation_matrix_upper_arm = trimesh.transformations.translation_matrix([-0.05, 0, 0]) + self.meshes_static[1].apply_transform(translation_matrix_upper_arm) - scale_factor = 1.5 - scale_matrix = trimesh.transformations.scale_matrix(scale_factor) + # Move cylinders 10cm in the positive z direction + translation_matrix_z = trimesh.transformations.translation_matrix([0, 0, 0.1]) for mesh in self.meshes_static: - mesh.apply_transform(scale_matrix) + mesh.apply_transform(translation_matrix_z) def visualize_meshes(self, meshes): if meshes: # Check if there are meshes to visualize @@ -58,26 +68,18 @@ class PointCloudProcessor(Node): try: now = rclpy.time.Time() transforms = { - 'base': self.tf_buffer.lookup_transform(self.perspective_frame, 'world', now), - 'shoulder': self.tf_buffer.lookup_transform(self.perspective_frame, 'shoulder_link', now), - 'upperarm': self.tf_buffer.lookup_transform(self.perspective_frame, 'upper_arm_link', now), - 'forearm': self.tf_buffer.lookup_transform(self.perspective_frame, 'forearm_link', now), - 'wrist1': self.tf_buffer.lookup_transform(self.perspective_frame, 'wrist_1_link', now), - 'wrist2': self.tf_buffer.lookup_transform(self.perspective_frame, 'wrist_2_link', now), - 'wrist3': self.tf_buffer.lookup_transform(self.perspective_frame, 'wrist_3_link', now) + 'shoulder': self.tf_buffer.lookup_transform(self.perspective_frame, 'upper_arm_link', now), + 'forearm': self.tf_buffer.lookup_transform(self.perspective_frame, 'forearm_link', now) } except Exception as e: self.get_logger().error(f'Error in looking up transform: {e}') + return + transformed_meshes = [] - for i, transform in enumerate(transforms.values()): # Removed unused 'key' + for i, transform in enumerate(transforms.values()): transformed_meshes.append(self.transform_mesh(transform, self.meshes_static[i])) - for i, (key, transform) in enumerate(transforms.items()): - transformed_meshes.append(self.transform_mesh(transform, self.meshes_static[i])) - - translation_matrix_forearm = trimesh.transformations.translation_matrix([0, 0, -0.05]) - transformed_meshes[3].apply_transform(translation_matrix_forearm) - self.visualize_meshes(transformed_meshes) + #self.visualize_meshes(transformed_meshes) points = np.array([(point['x'], point['y'], point['z']) for point in pc2.read_points(msg, field_names=("x", "y", "z"), skip_nans=True)], dtype=np.float64) @@ -104,6 +106,7 @@ class PointCloudProcessor(Node): return transformed_mesh def publish_point_cloud(self, points_valid, points_invalid): + self.get_logger().info(f'Publishing {len(points_valid)} valid points.') self.publisher_valid.publish(self.point_cloud(points_valid, self.perspective_frame)) self.publisher_invalid.publish(self.point_cloud(points_invalid, self.perspective_frame)) @@ -136,4 +139,4 @@ def main(args=None): rclpy.shutdown() if __name__ == '__main__': - main() \ No newline at end of file + main() diff --git a/workspaces/COLCON_WS/src/serial_to_pcl/setup.py b/workspaces/COLCON_WS/src/serial_to_pcl/setup.py index 621d049a65dc8fd17e70cfabeb1b12c54b92dc9f..5daa3e48ddd38861e5ab9398bec8ee1ca28e1efc 100755 --- a/workspaces/COLCON_WS/src/serial_to_pcl/setup.py +++ b/workspaces/COLCON_WS/src/serial_to_pcl/setup.py @@ -23,6 +23,7 @@ setup( 'serial_to_pcl_node = serial_to_pcl.serial_to_pcl_node:main', 'pcl_rob_node = serial_to_pcl.pcl_rob_node:main', 'pcl_rob_v2_node = serial_to_pcl.pcl_rob_v2_node:main', + 'random_pcl_node = serial_to_pcl.random_pcl:main', ], }, ) diff --git a/workspaces/pymoveit2_ws/src/pymoveit2 b/workspaces/pymoveit2_ws/src/pymoveit2 new file mode 160000 index 0000000000000000000000000000000000000000..4797ed5b0b89e602f184459b99f08257f78f319d --- /dev/null +++ b/workspaces/pymoveit2_ws/src/pymoveit2 @@ -0,0 +1 @@ +Subproject commit 4797ed5b0b89e602f184459b99f08257f78f319d