Real Robot Project Part 2

Hello Team,

I hope everyone is doing well.

I am currently facing an issue in the Real Robot Lab, specifically in the course “ROS2 BASICS IN 5 DAYS (PYTHON).” My challenge arises in Part 2, under the ‘services’ section. I was tasked with creating a service server that aligns the robot’s right side to the wall. This alignment should then trigger the wall-following behavior.

While my code executes flawlessly in simulation, it doesn’t seem to function as intended in the Real Robot Lab. I’m unsure where the discrepancy lies. I will provide my code for your reference:

from rclpy.qos import ReliabilityPolicy, QoSProfile
from rclpy.callback_groups import ReentrantCallbackGroup
from rclpy.executors import MultiThreadedExecutor
from sensor_msgs.msg import LaserScan
from geometry_msgs.msg import Twist
from custom_interfaces.srv import FindWall
import rclpy
from rclpy.node import Node
import time
import math

class WallFinderServer(Node):
    def __init__(self):
        super().__init__('wall_finder_server')

        self.group = ReentrantCallbackGroup()

        self.wall_aligned = False  # Flag to indicate if the wall is aligned

        self.wall_finder_srv = self.create_service(
            FindWall, 
            'find_wall', 
            self.find_wall_callback)

        self.twist_publisher = self.create_publisher(
            Twist, 
            '/cmd_vel',
            10)

        self.sub_laser = self.create_subscription(
            LaserScan,
            "/scan",
            self.laser_callback,
            QoSProfile(depth=10, reliability=ReliabilityPolicy.BEST_EFFORT),
            callback_group=self.group
        )

        self.initial_configuration = False
        self.turn_sign = +1
        self.laser_min_idx = 0
        self.laser_min = -1.0
        self.angle_to_rotate = 0.0
        self.laser_front = 0.0
        self.n_ranges = 0
        self.front_laser_idx = 0
        self.right_laser_idx = 0

        self.dist_tol = 0.03
        self.laser_idx_tol = 6

        self.vel_angular_z = 0.2
        self.vel_linear_x = 0.05

        self.first_turn_finished = False
        self.second_turn_finished = False

    def laser_callback(self, msg):
        if not self.initial_configuration:
            self.n_ranges = len(msg.ranges)
            self.front_laser_idx = int(self.n_ranges / 2)
            # Calculate the right laser index based on the front laser index
            self.right_laser_idx = (self.front_laser_idx + int(self.n_ranges / 4)) % self.n_ranges
            self.initial_configuration = True
            self.get_logger().info('Front laser idx: "%s"' % str(self.front_laser_idx))
            self.get_logger().info('Right laser idx: "%s"' % str(self.right_laser_idx))

        self.laser_min = min(msg.ranges)
        self.laser_min_idx = msg.ranges.index(self.laser_min)
        min_range_angle = (2 * math.pi * (self.laser_min_idx + 1)) / self.n_ranges

        if not self.first_turn_finished:
            self.angle_to_rotate = min_range_angle - math.pi
            if self.angle_to_rotate < 0:
                self.turn_sign = -1
            self.get_logger().info('Angle to rotate: "%s"' % str(self.angle_to_rotate * 180 / math.pi))
        elif not self.second_turn_finished:
            self.angle_to_rotate = min_range_angle - (3 * math.pi / 2)
            self.get_logger().info('Angle to rotate 2: "%s"' % str(self.angle_to_rotate * 180 / math.pi))

        self.laser_front = msg.ranges[self.front_laser_idx]

    def move_robot(self, linear_x, angular_z, duration):
        # Move the robot with the given velocities for the specified duration
        msg = Twist()
        msg.linear.x = linear_x
        msg.angular.z = angular_z

        start_time = time.time()
        while time.time() - start_time < duration:
            self.twist_publisher.publish(msg)
            time.sleep(0.1)
        msg.linear.x = 0.0
        msg.angular.z = 0.0
        self.twist_publisher.publish(msg)

    def find_wall_callback(self, request, response):
        while self.laser_min < 0:
            self.get_logger().info('WAITING FOR IDENTIFYING THE NEAREST WALL')
            time.sleep(0.5)

        while abs(self.laser_min_idx - self.front_laser_idx) > self.laser_idx_tol:
            turn_sign = self.turn_sign
            self.move_robot(0.0, turn_sign * self.vel_angular_z, 0.5)
            self.get_logger().info('FIRST TURN')

        self.first_turn_finished = True
        self.move_robot(0.0, 0.0, 0.5)
        self.get_logger().info('First turn finished, the robot is looking at the nearest wall')

        linear_x_sign = 1 if self.laser_front < 0.3 else -1
        while abs(self.laser_front - 0.3) > self.dist_tol:
            self.move_robot(linear_x_sign * self.vel_linear_x, 0.0, 0.5)
            self.get_logger().info('LINEAR MOTION')

        self.move_robot(0.0, 0.0, 0.5)
        self.get_logger().info('The robot is 30 cm away from the wall')

        while abs(self.laser_min_idx - self.right_laser_idx) > self.laser_idx_tol:
            self.move_robot(0.0, self.vel_angular_z, 0.5)
            self.get_logger().info('SECOND TURN')

        self.second_turn_finished = True
        self.move_robot(0.0, 0.0, 0.5)
        self.get_logger().info('The robot is aligned with the right wall')

        self.wall_aligned = True
        response.wallfound = True
        return response


def main(args=None):
    # initialize the ROS communication
    rclpy.init(args=args)
    wall_finder_node = WallFinderServer()
    # Create a MultiThreadedExecutor with 3 threads
    executor = MultiThreadedExecutor(num_threads=3)
    # Add the node to the executor
    executor.add_node(wall_finder_node)
    try:
        # Spin the executor
        executor.spin()
    finally:
        # Shutdown the executor
        executor.shutdown()
        wall_finder_node.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()

I would greatly appreciate any assistance you can offer.

I hope you can help me as fast as you can :blush:

@girishkumar.kannan

Dear Girish,

I apologize if I seem persistent, but as a student with summer vacation ending soon, I am quite anxious. I have been working diligently on this for two months, aiming to grasp the content thoroughly. As you may understand at my age, when I want to truly understand something, I tend to repeat it multiple times :sweat_smile:.

I genuinely respect your expertise in ROS, and you’ve become our master in this subject. I am reaching out in the hope that you might assist me in resolving my issues so I can earn the certificate before school resumes.

Thank you very much for understanding, and I apologize once again if this feels like an imposition.

Best regards,

Ghassan

Hi @ghassan11 ,

No problem, I understand that.

Again, no problem, I understand. But please don’t tag me directly. When I am unavailable, someone else can help with your issues. If you tag me directly, then others may not help you and think that you need a response only from me.
And, again, I am not a master in ROS, but I do like to help students who are new to ROS and are truly interested in pursuing robotics.

I cannot look into your code and find the bug if you cannot explain what is happening.
For me to help you better please explain your problem.

  1. What is happening?
  2. What is not happening?
  3. What is happening instead?

Regards,
Girish

@girishkumar.kannan

Hello Girish,

what is Happening : The find wall logic is working well in the simulation but do not work in the real robot lab

What is not Happening : Is that the robot dose not aligns to the wall by its right side in the Real robot Lab but it aligns in Simulation

Thanks

Hi @ghassan11 ,

This explanation still does not convey the actual problem. Could you upload some video? I need to understand what is happening so I can give you some suggestions.
If your program works correctly in the simulation and it does not work correctly in the real robot, I cannot find a bug in your program. Because this is a behavior related issue. Even if I spend hours trying to understand your code, I will not be able to fix a behavior issue just be looking at your error-free code.
I need to understand the actual situation to make fail-safes or workarounds or fixes.

So if possible, explain me in detail what is happening in the real robot situation, or share a video. That will help a lot.
I hope you understand this.

Regards,
Girish

@girishkumar.kannan

Hello Girish Thanks for the respond,

Yes sure I will provide you 2 videos one video shows what happens in the simulation and the other shows what is happening in the Real robot Lab

This Video shows what is happening In the Simulation when I run the code :

This Video shows what is happening In the Real Robot Lab When I Run the code :

I hope this videos helps you to understand My issue,

If you need more information’s I am free

Thanks,

Ghassan

Hi @ghassan11 ,

Saw your two videos.

You could have actually said that the “Robot keeps rotating and does not find the wall”, instead of saying that the program worked in simulation and not working in real robot.

The fix is very simple. You just have to revise your rotate logic and scanning logic.
The problem is right here, in your rotation logic:

So what you are doing is:

while (laser index difference > laser index tolerance):
   set turn sign
   rotate the robot

This is basically a scan->rotate loop. The problem is you are not stopping the robot.

The fix is to add a stop after every scan rotate loop.

while (laser index difference > laser index tolerance):
   set turn sign
   rotate for a few seconds, in your case 0.5 secs
   stop for a few seconds, preferably 0.25 secs

This way, you implement a scan->rotate->stop loop (also known as stop->scan->rotate loop).
Now the robot will definitely stop when it has found the wall, instead of rotating forever.

The key point here is that you NEED to send the robot a stop signal (which is all zeros in Twist command). Otherwise the robot will endlessly rotate in a loop.
Yes, it works in simulation, because the simulation does not have the exact 100% match of the real robot. Simulation has only minimal features that makes the robot move. Real robot has lot more features, so you need to factor those into your program.

This fix should help you get rid of your problem.

Regards,
Girish

@girishkumar.kannan

Sorry Girish,

I tried to solve it I tried to fix the code but the same issue can you please check the code I fixed it with your advice and tell me what I did wrong or why it is the same issue only rotates

Also this code which I tried to fix it runs well in simulation but not in real robot lab

this is my code with your advice :

from rclpy.qos import ReliabilityPolicy, QoSProfile
from rclpy.callback_groups import ReentrantCallbackGroup
from rclpy.executors import MultiThreadedExecutor
from sensor_msgs.msg import LaserScan
from geometry_msgs.msg import Twist
from custom_interfaces.srv import FindWall
import rclpy
from rclpy.node import Node
import time
import math

class WallFinderServer(Node):
    def __init__(self):
        super().__init__('wall_finder_server')

        self.group = ReentrantCallbackGroup()

        self.wall_aligned = False  # Flag to indicate if the wall is aligned

        self.wall_finder_srv = self.create_service(
            FindWall, 
            'find_wall', 
            self.find_wall_callback
        )

        self.twist_publisher = self.create_publisher(
            Twist, 
            '/cmd_vel',
            10
        )

        self.sub_laser = self.create_subscription(
            LaserScan,
            "/scan",
            self.laser_callback,
            QoSProfile(depth=10, reliability=ReliabilityPolicy.BEST_EFFORT),
            callback_group=self.group
        )

        self.initial_configuration = False
        self.turn_sign = +1
        self.laser_min_idx = 0
        self.laser_min = -1.0
        self.angle_to_rotate = 0.0
        self.laser_front = 0.0
        self.n_ranges = 0
        self.front_laser_idx = 0
        self.right_laser_idx = 0

        self.dist_tol = 0.03
        self.laser_idx_tol = 6

        self.vel_angular_z = 0.2
        self.vel_linear_x = 0.05

        self.first_turn_finished = False
        self.second_turn_finished = False

    def laser_callback(self, msg):
        if not self.initial_configuration:
            self.n_ranges = len(msg.ranges)
            self.front_laser_idx = int(self.n_ranges / 2)
            self.right_laser_idx = (self.front_laser_idx + int(self.n_ranges / 4)) % self.n_ranges
            self.initial_configuration = True
            self.get_logger().info('Front laser idx: "%s"' % str(self.front_laser_idx))
            self.get_logger().info('Right laser idx: "%s"' % str(self.right_laser_idx))

        self.laser_min = min(msg.ranges)
        self.laser_min_idx = msg.ranges.index(self.laser_min)

    def move_robot(self, linear_x, angular_z, duration):
        msg = Twist()
        msg.linear.x = linear_x
        msg.angular.z = angular_z

        start_time = time.time()
        while time.time() - start_time < duration:
            self.twist_publisher.publish(msg)
            time.sleep(0.1)

        msg.linear.x = 0.0
        msg.angular.z = 0.0
        self.twist_publisher.publish(msg)

    def find_wall_callback(self, request, response):
        while self.laser_min < 0:
            self.get_logger().info('WAITING FOR IDENTIFYING THE NEAREST WALL')
            time.sleep(0.5)

        while abs(self.laser_min_idx - self.front_laser_idx) > self.laser_idx_tol:
            turn_sign = self.turn_sign
            self.move_robot(0.0, turn_sign * self.vel_angular_z, 0.5)
            self.get_logger().info('FIRST TURN')
            self.move_robot(0.0, 0.0, 0.25)

        self.first_turn_finished = True
        self.move_robot(0.0, 0.0, 0.5)
        self.get_logger().info('First turn finished, the robot is looking at the nearest wall')

        linear_x_sign = 1 if self.laser_front < 0.3 else -1
        while abs(self.laser_front - 0.3) > self.dist_tol:
            self.move_robot(linear_x_sign * self.vel_linear_x, 0.0, 0.5)
            self.get_logger().info('LINEAR MOTION')

        self.move_robot(0.0, 0.0, 0.5)
        self.get_logger().info('The robot is 30 cm away from the wall')

        while abs(self.laser_min_idx - self.right_laser_idx) > self.laser_idx_tol:
            self.move_robot(0.0, self.vel_angular_z, 0.5)
            self.get_logger().info('SECOND TURN')
            self.move_robot(0.0, 0.0, 0.25)

        self.second_turn_finished = True
        self.move_robot(0.0, 0.0, 0.5)
        self.get_logger().info('The robot is aligned with the right wall')

        self.wall_aligned = True
        response.wallfound = True
        return response

def main(args=None):
    rclpy.init(args=args)
    wall_finder_node = WallFinderServer()
    executor = MultiThreadedExecutor(num_threads=3)
    executor.add_node(wall_finder_node)

    try:
        executor.spin()
    finally:
        executor.shutdown()
        wall_finder_node.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()

Thanks I hope you can Help

Regards,
Ghassan

Hi @ghassan11 ,

Did you compile from scratch and execute the package once you made changes?

cd ~/ros2_ws
rm -rf ./build ./install ./log
colcon build && source install/setup.bash
ros2 launch ...

Regards,
Girish

No i will do it now but the code is correct ?

@girishkumar.kannan

Hi Girish,

I fixed the code and it Works very well in simulation but In the Real Robot Lab it is Not working I provide you a video showing what is happening in the Real Robot Lab

this is the video showing what is happening in the Real Robot Lab with your advices :

And this is my updated code of the server and the main code:

server code :

from rclpy.qos import ReliabilityPolicy, QoSProfile
from rclpy.callback_groups import ReentrantCallbackGroup
from rclpy.executors import MultiThreadedExecutor
from sensor_msgs.msg import LaserScan
from geometry_msgs.msg import Twist
from custom_interfaces.srv import FindWall
import rclpy
from rclpy.node import Node
import time
import math

class WallFinderServer(Node):
    def __init__(self):
        super().__init__('wall_finder_server')

        self.group = ReentrantCallbackGroup()

        self.wall_aligned = False  # Flag to indicate if the wall is aligned

        self.wall_finder_srv = self.create_service(
            FindWall, 
            'find_wall', 
            self.find_wall_callback)

        self.twist_publisher = self.create_publisher(
            Twist, 
            '/cmd_vel',
            10)

        self.sub_laser = self.create_subscription(
            LaserScan,
            "/scan",
            self.laser_callback,
            QoSProfile(depth=10, reliability=ReliabilityPolicy.BEST_EFFORT),
            callback_group=self.group
        )

        self.initial_configuration = False
        self.turn_sign = +1
        self.laser_min_idx = 0
        self.laser_min = -1.0
        self.angle_to_rotate = 0.0
        self.laser_front = 0.0
        self.n_ranges = 0
        self.front_laser_idx = 0
        self.right_laser_idx = 0

        self.dist_tol = 0.03
        self.laser_idx_tol = 6

        self.vel_angular_z = 0.2
        self.vel_linear_x = 0.05

        self.first_turn_finished = False
        self.second_turn_finished = False

    def laser_callback(self, msg):
        if not self.initial_configuration:
            self.n_ranges = len(msg.ranges)
            self.front_laser_idx = int(self.n_ranges / 2)
            # Calculate the right laser index based on the front laser index
            self.right_laser_idx = (self.front_laser_idx + int(self.n_ranges / 4)) % self.n_ranges
            self.initial_configuration = True
            self.get_logger().info('Front laser idx: "%s"' % str(self.front_laser_idx))
            self.get_logger().info('Right laser idx: "%s"' % str(self.right_laser_idx))

        self.laser_min = min(msg.ranges)
        self.laser_min_idx = msg.ranges.index(self.laser_min)
        min_range_angle = (2 * math.pi * (self.laser_min_idx + 1)) / self.n_ranges

        if not self.first_turn_finished:
            self.angle_to_rotate = min_range_angle - math.pi
            if self.angle_to_rotate < 0:
                self.turn_sign = -1
            self.get_logger().info('Angle to rotate: "%s"' % str(self.angle_to_rotate * 180 / math.pi))
        elif not self.second_turn_finished:
            self.angle_to_rotate = min_range_angle - (3 * math.pi / 2)
            self.get_logger().info('Angle to rotate 2: "%s"' % str(self.angle_to_rotate * 180 / math.pi))

        self.laser_front = msg.ranges[self.front_laser_idx]

    def move_robot(self, linear_x, angular_z, duration):
        # Move the robot with the given velocities for the specified duration
        msg = Twist()
        msg.linear.x = linear_x
        msg.angular.z = angular_z

        start_time = time.time()
        while time.time() - start_time < duration:
            self.twist_publisher.publish(msg)
            time.sleep(0.1)
        msg.linear.x = 0.0
        msg.angular.z = 0.0
        self.twist_publisher.publish(msg)

    def find_wall_callback(self, request, response):
        while self.laser_min < 0:
            self.get_logger().info('WAITING FOR IDENTIFYING THE NEAREST WALL')
            time.sleep(0.5)

        while abs(self.laser_min_idx - self.front_laser_idx) > self.laser_idx_tol:
            turn_sign = self.turn_sign
            self.move_robot(0.0, turn_sign * self.vel_angular_z, 0.5)
            self.get_logger().info('FIRST TURN')
            self.move_robot(0.0, 0.0, 0.25)

        self.first_turn_finished = True
        self.move_robot(0.0, 0.0, 0.5)
        self.get_logger().info('First turn finished, the robot is looking at the nearest wall')

        linear_x_sign = 1 if self.laser_front < 0.3 else -1
        while abs(self.laser_front - 0.3) > self.dist_tol:
            self.move_robot(linear_x_sign * self.vel_linear_x, 0.0, 0.5)
            self.get_logger().info('LINEAR MOTION')

        self.move_robot(0.0, 0.0, 0.5)
        self.get_logger().info('The robot is 30 cm away from the wall')

        while abs(self.laser_min_idx - self.right_laser_idx) > self.laser_idx_tol:
            self.move_robot(0.0, self.vel_angular_z, 0.5)
            self.get_logger().info('SECOND TURN')
            self.move_robot(0.0, 0.0, 0.25)

        self.second_turn_finished = True
        self.move_robot(0.0, 0.0, 0.5)
        self.get_logger().info('The robot is aligned with the right wall')

        self.wall_aligned = True
        response.wallfound = True
        return response


def main(args=None):
    # initialize the ROS communication
    rclpy.init(args=args)
    wall_finder_node = WallFinderServer()
    # Create a MultiThreadedExecutor with 3 threads
    executor = MultiThreadedExecutor(num_threads=3)
    # Add the node to the executor
    executor.add_node(wall_finder_node)
    try:
        # Spin the executor
        executor.spin()
    finally:
        # Shutdown the executor
        executor.shutdown()
        wall_finder_node.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()

and this is the main_code or wall_following :

import rclpy
from rclpy.node import Node
from sensor_msgs.msg import LaserScan
from geometry_msgs.msg import Twist
from custom_interfaces.srv import FindWall

class WallFollower(Node):
    def __init__(self):
        super().__init__('wall_follower')

        self.publisher_ = self.create_publisher(Twist, '/cmd_vel', 10)
        self.subscription_ = self.create_subscription(
            LaserScan,
            '/scan',
            self.laser_callback,
            10
        )
        self.wall_distance_ = 0.3
        self.front_wall_distance_ = 0.5
        self.laser_forward = 0
        self.wall_aligned = False
        self.ranges = []

        # Create the find_wall service client
        self.find_wall_client = self.create_client(FindWall, 'find_wall')
        self.request_sent = False
        if not self.find_wall_client.wait_for_service(timeout_sec=1.0):
            self.get_logger().error('Service not available')
        else:
            self.get_logger().info('Service is available')


        self.timer = self.create_timer(0.1, self.timer_callback)

    def timer_callback(self):
        # If not aligned and not requested find_wall service, 
        # AND if odom recording hasn't started, start 
        # Existing find wall logic
        if not self.wall_aligned and not self.request_sent:
            request = FindWall.Request()
            future = self.find_wall_client.call_async(request)
            future.add_done_callback(self.find_wall_response_callback)
            self.request_sent = True
            
        if self.wall_aligned:
            self.wall_following_behavior()
            

    def find_wall_response_callback(self, future):
        try:
            response = future.result()
            if response and response.wallfound:
                self.get_logger().info('Wall found! Robot is aligned with the wall.')
                self.wall_aligned = True
            else:
                self.get_logger().info('Wall not found yet.')
        except Exception as e:
            self.get_logger().error('Service call failed: %s' % str(e))

    def wall_following_behavior(self):
        ranges = self.ranges
        if not ranges:
            return

        right_ray_index = int(len(ranges) * 3 / 4)  
        self.laser_forward = ranges[0]

        if self.laser_forward < self.front_wall_distance_:
            self.update_velocity(0.0, 0.35) 
            return

        right_distance = ranges[right_ray_index]

        if right_distance > self.wall_distance_ + 0.05:
            self.update_velocity(0.15, -0.35)  
        elif right_distance < self.wall_distance_ - 0.05:
            self.update_velocity(0.15, 0.35)  
        else:
            self.update_velocity(0.15, 0.0)  

    def laser_callback(self, msg):
        self.ranges = msg.ranges

    def update_velocity(self, linear, angular):
        msg = Twist()
        msg.linear.x = linear
        msg.angular.z = angular
        self.publisher_.publish(msg)

def main(args=None):
    rclpy.init(args=args)
    wall_follower = WallFollower()

    executor = rclpy.executors.MultiThreadedExecutor(num_threads=3)
    executor.add_node(wall_follower)

    try:
        executor.spin()
    finally:
        executor.shutdown()
        wall_follower.destroy_node()
        rclpy.shutdown()

if __name__ == '__main__':
    main()

I hope you can help

Regards,
Ghassan

@girishkumar.kannan
@albertoezquerro
@ralves
@rtellez
@roalgoal
@bayodesegun

Please any one can Help :grin:

By the way did I mention the full team :sweat_smile:

It looks like the robot is going towards the wall when it should go away from the wall. Are you sure that the orientation of the scan in the real robot is correct for your code?

It starts following the wall once it gets on the robot’s left side, that’s another clue that this is simply an orientation mixup.

You need to be able to test this yourself and not have it solved for you in order to really learn what is happening

I will Try to solve it :saluting_face:
So the issue maybe is in the orientation of the scan :thinking: ?

@girishkumar.kannan
@roalgoal
@ralves
@albertoezquerro

Hello,

I am really stuck with this issue. I wrote two different sets of code, and the last one works very well in the simulation. However, I don’t know what is happening in the real robot lab; the robot seems to be stuck. I think the readings might be incorrect. I hope someone can help. I don’t need the entire solution; I am just looking for suggestions.

I will provide my code for reference.

import rclpy
from rclpy.node import Node
from rclpy.qos import ReliabilityPolicy, QoSProfile
from rclpy.callback_groups import ReentrantCallbackGroup
from rclpy.executors import MultiThreadedExecutor
from sensor_msgs.msg import LaserScan
from geometry_msgs.msg import Twist
from custom_interfaces.srv import FindWall
import time
import math

class WallFinderServer(Node):
    def __init__(self):
        super().__init__('wall_finder_server')

        self.group = ReentrantCallbackGroup()

        self.wall_aligned = False

        self.wall_finder_srv = self.create_service(
            FindWall,
            'find_wall',
            self.find_wall_callback
        )

        self.twist_publisher = self.create_publisher(
            Twist,
            '/cmd_vel',
            10
        )

        self.sub_laser = self.create_subscription(
            LaserScan,
            "/scan",
            self.laser_callback,
            QoSProfile(depth=10, reliability=ReliabilityPolicy.BEST_EFFORT),
            callback_group=self.group
        )

        self.initial_configuration = False
        self.laser_min_idx = 0
        self.laser_min = -1.0
        self.laser_front = 0.0
        self.n_ranges = 0
        self.front_laser_idx = 0
        self.right_laser_idx = 0

        self.dist_tol = 0.03
        self.laser_idx_tol = 6

        self.vel_angular_z = 0.2
        self.vel_linear_x = 0.05

        self.first_turn_finished = False
        self.second_turn_finished = False

    def laser_callback(self, msg):
        if not self.initial_configuration:
            self.n_ranges = len(msg.ranges)
            self.front_laser_idx = int(self.n_ranges / 2)
            self.right_laser_idx = (self.front_laser_idx + int(self.n_ranges / 4)) % self.n_ranges
            self.initial_configuration = True

        self.laser_min = min(msg.ranges)
        self.laser_min_idx = msg.ranges.index(self.laser_min)
        min_range_angle = (2 * math.pi * (self.laser_min_idx + 1)) / self.n_ranges

        if not self.first_turn_finished:
            self.angle_to_rotate = min_range_angle - math.pi
        elif not self.second_turn_finished:
            self.angle_to_rotate = min_range_angle - (math.pi / 2)

        self.laser_front = msg.ranges[self.front_laser_idx]

    def move_robot(self, linear_x, angular_z, duration):
        msg = Twist()
        msg.linear.x = linear_x
        msg.angular.z = angular_z

        start_time = time.time()
        while time.time() - start_time < duration:
            self.twist_publisher.publish(msg)
            time.sleep(0.1)
        msg.linear.x = 0.0
        msg.angular.z = 0.0
        self.twist_publisher.publish(msg)

    def find_wall_callback(self, request, response):
        while self.laser_min < 0:
            time.sleep(0.5)

        while abs(self.laser_min_idx - self.front_laser_idx) > self.laser_idx_tol:
            turn_sign = 1 if self.angle_to_rotate > 0 else -1
            self.move_robot(0.0, turn_sign * self.vel_angular_z, 0.5)
            self.move_robot(0.0, 0.0, 0.25)

        self.first_turn_finished = True
        self.move_robot(0.0, 0.0, 0.5)

        linear_x_sign = 1 if self.laser_front > 0.3 else -1
        while abs(self.laser_front - 0.3) > self.dist_tol:
            self.move_robot(linear_x_sign * self.vel_linear_x, 0.0, 0.5)

        self.move_robot(0.0, 0.0, 0.5)

        while abs(self.laser_min_idx - self.right_laser_idx) > self.laser_idx_tol:
            self.move_robot(0.0, -self.vel_angular_z, 0.5)
            self.move_robot(0.0, 0.0, 0.25)

        self.second_turn_finished = True
        self.move_robot(0.0, 0.0, 0.5)

        self.wall_aligned = True
        response.wallfound = True
        return response

def main(args=None):
    rclpy.init(args=args)
    wall_finder_node = WallFinderServer()
    executor = MultiThreadedExecutor(num_threads=3)
    executor.add_node(wall_finder_node)
    try:
        executor.spin()
    finally:
        executor.shutdown()
        wall_finder_node.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()

 

This is the best code that works in simulation Please I don’t need the solution only if you can explain me what is happening or the issue Please

Thank you.

You still haven’t said anything about the problem besides asking to look at your code so it can be fixed for you.

What is the problem that you are experiencing in the real robot? What is your strategy to solve it?

I gave you the hint that maybe the orientation is wrong. Have you verified that in the real robot? Is the front/back/left/right side of the real robot the same as the simulation?

Why does the robot line up with the wall to its left? is that how your code works in the simulation?

Hi @ghassan11 ,

I think I know what the problem is. Try to check the number of range values that you get from the simulation robot and the real robot, that is, the laser scanner’s reported values in a single LaserScan message. I think the simulation scan range count is different from real robot scan range count.
You have learnt how to check this information from laser scanner in your course. Refer back in case you have forgotten.

Also, if above is the case, try to find a fix by yourself. Don’t post your whole code again and ask us the answers. Attempt to do some research on your own - that is the way what you learned will stay learnt.

Regards,
Girish

PS: Please don’t tag everyone to a post. Please don’t tag everyone to a post more than once. Also, this is a public forum, so the full team can see your issue when they get time.

1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.