ROSject section 2 services+topics

Hi All,

I have been working on ROSject section 2.
I initialize the service and the subscriber/publisher together, but ideally, I should only trigger the publisher and subscriber once the service has been called. But I can’t find how to do that elegantly.
Paraphrasing the post ROSject part II: How to work with services and subscriptions at the same time, and how the service should wait for the end of the sub-node in order to proceed with its message?

Thank you!

I have copied my code here:

#! /usr/bin/env python

import rospy
from service_rosject.srv import FindWall, FindWallResponse
from sensor_msgs.msg import LaserScan
from geometry_msgs.msg import Twist

state_dict_ = {
    0: 'find the wall',
    1: 'Forward',
    2: 'follow the wall position',
    3: 'Stop!',
}

found_the_wall = False
state_ = 0


def service_callback(request):
    global found_the_wall
    print("My_callback Find wall has been called")
    resp = FindWallResponse()
    if found_the_wall is True:
        resp.wallfound = True
    else:
        resp.wallfound = False

    return resp.wallfound  # the service Response class, in this case FindWall


def scan_callback(msg):
    global state_
    global found_the_wall
    print("Scan callback has been called")
    minimum = min(msg.ranges)
    index = msg.ranges.index(minimum)

    if state_ == 0:  # find the wall - Rotate to Closest wall to front
        if index > 358 and index < 362:
            state_ = 1  # Moved facing the wall! Forward
            print("Moved facing the wall!")
        else:
            if index < 360:
                move.angular.z = -3.14/18.0  # turn right
            else:
                move.angular.z = 3.14/18.0  # turn left
            pub_.publish(move)
    if state_ == 1:  # Forward to the wall!
        if msg.ranges[360] > 0.3:
            move.angular.z = 0
            move.linear.x = 0.1
            pub_.publish(move)
        else:
            move.angular.z = 0
            move.linear.x = 0.0
            print("We are at 30cm from the wall")
            state_ = 2  # Last action, rotate
            pub_.publish(move)
    if state_ == 2:  # Rotate to be in position
        if index > 168 and index < 175:
            move.angular.z = 0  # stop
            pub_.publish(move)
            print("Done !")
            found_the_wall = True
            state_ = 3  # Stop!
        elif index <= 168:
            move.angular.z = -0.1  # turn right
            pub_.publish(move)
        else:
            move.angular.z = 0.1  # turn left
            pub_.publish(move)
    if state_ == 3:  # Stop!
        print("Stop !")

    print("index: ", index)
    print("dist: ", minimum)


rospy.init_node('reading_laser')
# create the Service called my_service with the defined callback
my_service = rospy.Service('/find_wall', FindWall, service_callback)
pub_ = rospy.Publisher('/cmd_vel', Twist, queue_size=1)
sub = rospy.Subscriber('/scan', LaserScan, scan_callback)
move = Twist()
rospy.spin()  # maintain the service open.

Hi @CEPE-AO ,

Welcome to the Community!

Firstly, to let you know, it will be better to start using Classing in Python - so you do not have to deal with all those global literals.

The way you have initialized service, subscriber and their respective callbacks are correct (from the program point of view).

Regarding the state_dict - I am not sure why you need one, since service messages have only request & response, you can send the result (response) only after the service completes - it may succeed or fail - but only after the service completes. Service messages do not support feedback like action messages.

Your callback routines needs some modification.
Your scan callback just reads the value from /scan topic and stores the ranges info in a variable that you can use all throughout the program or in a class.
Most of your service logic goes into your service_callback.
You will not be requiring the use of states. You may just place the logic one after another and just use print statements or ROS log prints. Unlike ROS2, you can just make use of while loops in ROS1 (if I am wrong somebody correct me).

That would be all. Let me know if you need more clarification or help.

Regards,
Girish

1 Like

Hi,
Thank you very much for your help.
Classes in ROS only come in section 8 of ROS Basics in 5 days, but the ROSject section 2 is advised to do once Unit 6 is completed.
I had state_dict originally to make it easier to print on the terminal which state I’m in, but actually never ended up using it. I need to learn about the ROS log prints as I have not yet seen them in the course.
It makes sense if the logic actually goes in the service_callback, and keep the /scan callback just to collect the data.

I’ll carry on with the ROS Basics in 5 days and get back to my ROSject. I’ll update back here once I have more.

@CEPE-AO ,

Sounds Good! You must learn Class structuring, it will be easier for you in the rosject itself when you add actions.
I believe the very next chapter after Services is “Using Classes”. I would recommend you finish Classes chapter and then continue with your rosject. I have finished that course and saying this from my experience. You will need classes to complete rosject easily.

Regards,
Girish

1 Like