Robot not moving after class call

This is a two part question:
First question:
I typed my main_client program using OOPS.
The program runs fine until I call the class to start wall following program. I cannot seem to figure it out. why my robot wont move after the wall search and action server is successfully executed.
The program associated is :

#! /usr/bin/env python
import rospy
import actionlib
from geometry_msgs.msg import Twist
from std_msgs.msg import Empty
from sensor_msgs.msg import LaserScan
from rosject.srv import findwall, findwallRequest
from rosject.msg import OdomRecordActionFeedback, OdomRecordActionResult, OdomRecordActionGoal, OdomRecordAction

class rosject_client(object):
    def __init__(self):
        rospy.init_node('projectcall', anonymous = True)
        sub = rospy.Subscriber("/scan", LaserScan, self.callback)
        self.pub = rospy.Publisher("/cmd_vel", Twist, queue_size=1)
        self.var = Twist()


    def callback(self,msg):
    # logic for wall following
    
        self.Distancef=float(msg.ranges[359])
        self.Distancer=float(msg.ranges[175])
    
    def wallfollow(self):
        if self.Distancer >0.25 or self.Distancer == float('inf') and self.Distancef > 0.5:
            self.var.linear.x = 0.02
            self.var.angular.z = -0.08
        self.pub.publish(self.var)
        
        if self.Distancer < 0.2 or self.Distancer == float('inf') and self.Distancef > 0.5:
            self.var.linear.x = 0.02
            self.var.angular.z = 0.08
        self.pub.publish(self.var)
    
        if self.Distancer > 0.2 and self.Distancer < 0.25 and self.Distancef > 0.5:
            self.var.linear.x = 0.02
            self.var.angular.z = 0
        self.pub.publish(self.var)

        if self.Distancef < 0.5 or self.Distancef == float('inf'):
            self.var.linear.x = 0.02
            self.var.angular.z = 0.15
            print('i am turning to next wall')
        self.pub.publish(self.var)
    
def feedback_callback(feedback):
        _feedback = OdomRecordActionFeedback()

        print('Current Distance Traveled',feedback.current_total)

if __name__ == "__main__":

    rospy.init_node('projectcall', anonymous = True)

    #wall search service call
    rospy.wait_for_service('/find_wall')
    service_variable = rospy.ServiceProxy('/find_wall', findwall)
    obj = findwallRequest()
    result = service_variable(obj)
    rospy.loginfo('Service FindWall accomplished')

    # Odometry Action server call
    action_server_name = 'record_odom'
    client = actionlib.SimpleActionClient(action_server_name, OdomRecordAction)
    rospy.loginfo('Waiting for action Server '+action_server_name)
    client.wait_for_server()
    rospy.loginfo('Action Server Found...'+action_server_name)
    client.send_goal(Empty(), feedback_cb=feedback_callback)
    state_result = client.get_state()
    rate = rospy.Rate(1)
    rospy.loginfo("state_result: "+str(state_result))

    rosject_client() 
    rospy.loginfo("start wall fllowing")
    
    rospy.spin()

Second question:
I also typed the program without using OOPS and the program runs fine. All servers properly executed and the wall following works as well until the robot starts moving to next wall for wall following. At this point I get an exception that the index is out of range in my action server, where I am calculating the current distance. I cannot seem to figure out why?
Program associated:
Action server

#! /usr/bin/env python

import math
import rospy
import actionlib
from rosject.msg import OdomRecordResult, OdomRecordFeedback, OdomRecordAction
from geometry_msgs.msg import Point
from nav_msgs.msg import Odometry

    
class OdometryClass(object):

    _feedback = OdomRecordFeedback()
    _result= OdomRecordResult()

    def __init__(self):
    # creating action server
        self._as = actionlib.SimpleActionServer('record_odom', OdomRecordAction, self.goal_callback, False)
        self._as.start()
        rospy.init_node('Coordinates', anonymous = True)        
        self.rate = rospy.Rate(1)
        
    def callback(self,msg):
        #store odom value in variables
        
        self.a = msg.pose.pose.position.x
        self.b = msg.pose.pose.position.y
        self.c = msg.pose.pose.position.z

        self.instance_variable.x.append(self.a)
        self.instance_variable.y.append(self.b)
        self.instance_variable.z.append(self.c)
        

    def goal_callback(self,goal):
        print('Goal Recieved')
        rospy.Subscriber('/odom', Odometry,self.callback)
        success = True
        i = 0
        self._feedback.current_total = 0
        cal_rate = rospy.Rate(1)

        while not self._as.is_preempt_requested():
                       
            self.instance_variable = Point()
            self.instance_variable.x = [0]
            self.instance_variable.y = [0]
            self.instance_variable.z = [0]

            i +=1

            cal_rate.sleep()
            self._feedback.current_total += math.hypot(self.instance_variable.x[i+1]-self.instance_variable.x[i], self.instance_variable.y[i+1]-self.instance_variable.y[i])
            self._as.publish_feedback(self._feedback)
            print ('current distance travelled ', self._feedback.current_total)
            
    
        self._as.set_preempted()
        
        if success:
            self._result.list_of_odoms = self.instance_variable
            rospy.loginfo('The list of cordintes', self._result.list_of_odoms )
            self._as.set_succeeded(self._result)


if __name__ == '__main__':
    rospy.init_node('Coordinates', anonymous = True)
    OdometryClass()
    rospy.spin()

and
Main_client

#! /usr/bin/env python
#service calling program

import rospy
import actionlib
from geometry_msgs.msg import Twist
from std_msgs.msg import Empty
from sensor_msgs.msg import LaserScan
from rosject.srv import findwall, findwallRequest
from rosject.msg import OdomRecordActionFeedback, OdomRecordActionResult, OdomRecordActionGoal, OdomRecordAction


def feedback_callback(feedback):
    _feedback = OdomRecordActionFeedback()

    print('Current Distance Traveled',feedback.current_total)
    

def callback(msg):
    # logic for wall following
    
    Distancef=float(msg.ranges[359])
    Distancer=float(msg.ranges[175])
    
    if Distancer >0.25 or Distancer == float('inf') and Distancef > 0.5:
        var.linear.x = 0.02
        var.angular.z = -0.08
    pub.publish(var)
        
    if Distancer < 0.2 or Distancer == float('inf') and Distancef > 0.5:
        var.linear.x = 0.02
        var.angular.z = 0.08
    pub.publish(var)
    
    if Distancer > 0.2 and Distancer < 0.25 and Distancef > 0.5:
        var.linear.x = 0.02
        var.angular.z = 0
    pub.publish(var)

    if Distancef < 0.5 or Distancef == float('inf'):
        var.linear.x = 0.02
        var.angular.z = 0.15
        print('i am turning to next wall')
    pub.publish(var)
    
    


if __name__ == "__main__":
    rospy.init_node('projectcall')
    rospy.wait_for_service('/find_wall')
    service_variable = rospy.ServiceProxy('/find_wall', findwall)
    obj = findwallRequest()
    result = service_variable(obj)
    rospy.loginfo('Service FindWall accomplished')

    action_server_name = 'record_odom'
    client = actionlib.SimpleActionClient(action_server_name, OdomRecordAction)
    rospy.loginfo('Waiting for action Server '+action_server_name)
    client.wait_for_server()
    rospy.loginfo('Action Server Found...'+action_server_name)
    client.send_goal(Empty(), feedback_cb=feedback_callback)
    state_result = client.get_state()

    rate = rospy.Rate(1)

    rospy.loginfo("state_result: "+str(state_result))

    ####wall_following####
    pub = rospy.Publisher("/cmd_vel", Twist, queue_size=1)
    var = Twist()

    rospy.loginfo("start wall fllowing")

    # subscriber
    sub = rospy.Subscriber("/scan", LaserScan, callback)
    rospy.spin()

Hi @mamojiz97 ,

That is because you are not calling wallfollow() function in your main program.

To fix this, change this code block:

rosject_client() 
rospy.loginfo("start wall fllowing")

Into this version:

rc = rosject_client() 
rospy.loginfo("start wall fllowing")
rc.wallfollow()

Can you post the error output where you get the index out of range error? It would be helpful in tracing back to the program where the problem occurs during runtime.

Regards,
Girish

Hi @girishkumar.kannan

Yes, that was a silly oversight from me…

The error that I get for the second question is:

This Occurs only when the robot starts moving(turning) to the next wall.

Hi @mamojiz97 ,

The error output says you have an index out of range in the line:

self._feedback.current_total += math.hypot(self.instance_variable.x[i+1]-self.instance_variable.x[i], self.instance_variable.y[i+1]-self.instance_variable.y[i])

The best way you can get rid of this error is to print out all the values of the variables with indexes that you are using.

Try this:

print(self.instance_variable.x[i])
print(self.instance_variable.x[i+1])
print(self.instance_variable.y[i])
print(self.instance_variable.y[i+1])
self._feedback.current_total += math.hypot(self.instance_variable.x[i+1]-self.instance_variable.x[i], self.instance_variable.y[i+1]-self.instance_variable.y[i])

This is something you must debug yourself.

But I am guessing that you must use [i-1] instead of [i+1]. That might be the logic mistake that you are making, I do not know. I went through your code only at a glance - I did not understand what logic you have implemented.

Try this suggestion and let me know if you have fixed the problem.

Regards,
Girish

Hi @girishkumar.kannan
The formula for distance traveled which I believe is clear :

self._feedback.current_total += math.hypot(self.instance_variable.x[i+1]-self.instance_variable.x[i], self.instance_variable.y[i+1]-self.instance_variable.y[i])

We need x1, x2, y1, y2.

print(self.instance_variable.x[i]) # is x1
print(self.instance_variable.x[i+1]) # is x2
# similarly for y 
print(self.instance_variable.y[i]) #y1
print(self.instance_variable.y[i+1]) #y2

Every one second the logic takes values from the array with i+1 as x2 or y2 and i as x1 or y1.

This logic must take a lot of memory space and is not the best way to do it.

I did as you suggested and printed out the values. What I noticed is that for some reason x2, y2 from previous iteration for calculating distance is not x1,y1 in the next iteration. ( In other words the new position is not the old position for the next iteration) .

Hi @mamojiz97 ,

I went through your code again, I saw that you have done a mistake.

You have initialized self.instance_variable = Point(). Point() type is not a list. So you can only assign values to x, y and z, but you cannot append values to them as list.
You must instead create a list of Point() type variables and append each odometry value as Point() type into the list of Point().
Only that way you can achieve this. Also, You cannot do x+1 on a list, when you are reading from the back of the list. The most viable options to get the last two elements of a list is to do my_list[-1] and my_list[-2], where my_list[-1] is the last object/element on the list and my_list[-2] is the second to last object/element on the list.

Hope you understood this suggestion. You need to refactor your logic.

Regards,
Girish

Hi @girishkumar.kannan
I will work on the suggestion and hope to understand it much better.

Point() type is not a list sure. Its a message with float64 data type variables. It is new and difficult to understand why I cant assign a variable in Point() message such as to Float64 x to a list?

Hi @mamojiz97 ,

The best way to assign values to a Point() type variable in python is like below:

var_name = Point()
var_name.x = 1.2345
var_name.y = 2.3456
var_name.z = 3.4567

I hope this helps!

Regards,
Girish

1 Like

Hi @girishkumar.kannan
Yes that’s how i did and your answers helped me understand what I was doing. Thank you

1 Like

This topic was automatically closed after 2 days. New replies are no longer allowed.