Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Odom topic in python #1172

Open
r0n1tr opened this issue Jun 7, 2024 · 1 comment
Open

Odom topic in python #1172

r0n1tr opened this issue Jun 7, 2024 · 1 comment

Comments

@r0n1tr
Copy link

r0n1tr commented Jun 7, 2024

Hi sir,

We are using a python script to overlay odometry feed from a cloud generated environment (.ply) that is converted into a 2d occupancy grid for autonomous navigation, it seems to be that there's a significant difference in latency between the odom feed in rtab_map and then using it in python. Additionally, when we do "reset odometry" in rtabmap, the odometry shown in rtabmap corrects itself once localised, but the odometry topic in python is not corrected, and becomes very incorrect. I was wondering if there was a specific reason or a severe oversight on our part. Thank you for your time.

Here is our code for extra context:

import os
import threading
import rospy
import open3d as o3d
import numpy as np
import matplotlib.pyplot as plt
from sensor_msgs.msg import PointCloud2
from nav_msgs.msg import Odometry
import sensor_msgs.point_cloud2 as pc2

class OccupancyMapNode:
    def _init_(self, resolution=0.01):
        self.resolution = resolution
        self.occupancy_grid = None
        self.odometry_x = 0.0
        self.odometry_y = 0.0
        self.odometry_yaw = 0.0
        self.robot_height = None
        self.lock = threading.Lock()
        self.height_threshold_lower = 0.1  # Exclude points below this height
        
        # Set the environment variables
        local_ip = "172.17.0.2"
        remote_pi_ip = "192.168.137.26"
        os.environ['ROS_IP'] = local_ip
        os.environ['ROS_MASTER_URI'] = f"http://{remote_pi_ip}:11311"
        
        rospy.init_node('occupancy_map_node', anonymous=True)
        
        # Subscribe to the point cloud and odometry topics
        point_cloud_topic = "/rtabmap/cloud_obstacles"
        odometry_topic = "/rtabmap/odom"
        self.point_cloud_subscriber = rospy.Subscriber(point_cloud_topic, PointCloud2, self.point_cloud_callback)
        self.odometry_subscriber = rospy.Subscriber(odometry_topic, Odometry, self.odometry_callback)

        # Start ROS thread
        self.ros_thread = threading.Thread(target=self.ros_spin)
        self.ros_thread.start()

        plt.ion()
        self.fig, self.ax = plt.subplots()

    def ros_spin(self):
        rospy.spin()

    def point_cloud_callback(self, msg):
        points = []
        for p in pc2.read_points(msg, field_names=("x", "y", "z"), skip_nans=True):
            points.append([p[0], p[1], p[2]])
        points = np.array(points)
        
        if len(points) == 0:
            print("No points found in the point cloud :(")
            return

        with self.lock:
            self.occupancy_grid = points

    def odometry_callback(self, msg):
        position = msg.pose.pose.position
        orientation = msg.pose.pose.orientation
        with self.lock:
            self.odometry_x = position.x
            self.odometry_y = position.y
            quaternion = (orientation.x, orientation.y, orientation.z, orientation.w)
            euler = self.quaternion_to_euler(quaternion)
            self.odometry_yaw = euler[2]  # Yaw is the third element

    def quaternion_to_euler(self, quaternion):
        # Convert quaternion to euler angles (roll, pitch, yaw)
        x, y, z, w = quaternion
        t0 = +2.0 * (w * x + y * z)
        t1 = +1.0 - 2.0 * (x * x + y * y)
        roll = np.arctan2(t0, t1)
        
        t2 = +2.0 * (w * y - z * x)
        t2 = +1.0 if t2 > +1.0 else t2
        t2 = -1.0 if t2 < -1.0 else t2
        pitch = np.arcsin(t2)
        
        t3 = +2.0 * (w * z + x * y)
        t4 = +1.0 - 2.0 * (y * y + z * z)
        yaw = np.arctan2(t3, t4)
        
        return roll, pitch, yaw

    def display_occupancy_map(self):
        with self.lock:
            if self.occupancy_grid is None:
                return
            
            # Dynamically determine the ceiling height threshold based on the 90th percentile
            height_threshold_upper = np.percentile(self.occupancy_grid[:, 2], 50)
            
            # Filter points based on height thresholds
            filtered_points = self.occupancy_grid[(self.occupancy_grid[:, 2] > self.height_threshold_lower) &
                                                  (self.occupancy_grid[:, 2] < height_threshold_upper)]
            
            self.ax.clear()
            self.ax.scatter(filtered_points[:, 0], filtered_points[:, 1], s=1)  # Display occupancy grid
            
            # Plot odometry position as a red dot
            self.ax.scatter(self.odometry_x, self.odometry_y, color='red')  
            
            self.ax.set_xlabel('X')
            self.ax.set_ylabel('Y')
            self.ax.set_title('Occupancy Map with Odometry Path')
            
            plt.draw()
            plt.gcf().canvas.flush_events()

node = OccupancyMapNode(resolution=0.01)

try:
    while not rospy.is_shutdown():
        node.display_occupancy_map()
        plt.pause(0.1)
except (KeyboardInterrupt, SystemExit):
    print("Shutting down")
    rospy.signal_shutdown('Exiting...')
@matlabbe
Copy link
Member

For the odometry latency, do you mean there is more latency on python code or rtabmap's odometry?

For the odometry correctly, either you use TF to get map->odom transform to correct the received odometry, or subscribe to /rtabmap/mapGraph and read mapToOdom transform to correct the odometry afterwards.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants