Problem when testing a customed action server

Hi,
I am doing rosject of course " ROS Basics in 5 Days" and in third part I create a new action server with new action type:

# goal
---
# result
geometry_msgs/Point32[] list_of_odoms
---
# feedback
float32 current_total

when I test this action with axclient tool, I meet with 2 problem:
1.
this new action has not defined goal. So how can I “send a goal” to axclient? Just leave it blank and directly press send a goal?

If the first problem is just solved as what I said, then I get another error:

AttributeError: 'float' object has no attribute 'current_total'

I am not sure what caused this. I don’t think it is because I somewhere wrongly call the attribute. Here is my code:

#! /usr/bin/env python
import rospy
import actionlib
import time
import math
from section_action.msg import OdomRecordResult, OdomRecordFeedback, OdomRecordAction
from nav_msgs.msg import Odometry
from geometry_msgs.msg import Point32

class Odom_Record_Class():

    def __init__(self):

        # define action server of 'odom record'
        self.odom_record_action_server = actionlib.SimpleActionServer(
            "odom_record_action_server", OdomRecordAction, self.action_goal_callback, False)
        self.odom_record_action_server.start()
        rospy.loginfo('the action of odom recording is ready......')

        # define subscriber of '/odom'
        self.odom_sub = rospy.Subscriber('/odom', Odometry, self.sub_callback)
        # in order to get infomation in '/odom'
        self.odom_data = Odometry()

        # in order to restore the info (x,y,theta) from '/dom'
        self.current_pose = Point32()
        self.previous_pose = Point32()
        self.result_point32_list = OdomRecordResult()

        # in order to feedback the current total distance that robot has moved so far
        self.feedback = OdomRecordFeedback()

    def sub_callback(self, msg):

        # get pose info from '/odom'
        self.odom_data = msg

    def action_goal_callback(self, goal):

        # get initial pose
        self.current_pose.x = self.odom_data.pose.pose.position.x
        self.current_pose.y = self.odom_data.pose.pose.position.y
        self.current_pose.z = self.odom_data.pose.pose.orientation.z

        # robot doesn't move any distance at the beginning
        self.feedback = 0
        # records has nothing at the beginning
        self.result_point32_list = []

        # if the robot hasn't finished one lap, then keep moving
        while self.feedback <= 2:

            # send pose into previous_pose for distance calculation
            self.previous_pose.x = self.current_pose.x
            self.previous_pose.y = self.current_pose.y
            self.previous_pose.z = self.current_pose.z

            # update pose info
            self.current_pose.x = self.odom_data.pose.pose.position.x
            self.current_pose.y = self.odom_data.pose.pose.position.y
            self.current_pose.z = self.odom_data.pose.pose.orientation.z

            # calculate and publish current total distance
            interval_x = self.current_pose.x - self.previous_pose.x
            interval_y = self.current_pose.y - self.previous_pose.y
            interval_dist = math.sqrt(interval_x ** 2 + interval_y ** 2)
            self.feedback += interval_dist
            rospy.loginfo('current total distance is: ' +
                          str(self.feedback))
            self.odom_record_action_server.publish_feedback(
                self.feedback)

            # record pose every 1 second
            self.result_point32_list.append(self.current_pose)
            time.sleep(1)

        # return the records with all pose info
        self.odom_record_action_server.set_succeeded(self.result_point32_list)

    def main(self):

        rospy.loginfo('call action......')
        rospy.spin()


if __name__ == '__main__':

    rospy.init_node("odom_record_1_node")
    odom_record = Odom_Record_Class()
    odom_record.main()

the complete error info shows as below:

[ERROR] [1669054503.135606, 4361.412000]: Exception in your execute callback: 'float' object has no attribute 'current_total'
Traceback (most recent call last):
  File "/home/simulations/public_sim_ws/src/all/actionlib/actionlib/src/actionlib/simple_action_server.py", line 289, in executeLoop
    self.execute_callback(goal)
  File "/home/user/catkin_ws/src/section_action/scripts/ActionSection_OdomRecord_1.py", line 120, in action_goal_callback
    self.odom_record_action_server.publish_feedback(
  File "/home/simulations/public_sim_ws/src/all/actionlib/actionlib/src/actionlib/simple_action_server.py", line 175, in publish_feedback
    self.current_goal.publish_feedback(feedback)
  File "/home/simulations/public_sim_ws/src/all/actionlib/actionlib/src/actionlib/server_goal_handle.py", line 213, in publish_feedback
    self.action_server.publish_feedback(self.status_tracker.status, feedback)
  File "/home/simulations/public_sim_ws/src/all/actionlib/actionlib/src/actionlib/action_server.py", line 195, in publish_feedback
    self.feedback_pub.publish(af)
  File "/opt/ros/noetic/lib/python3/dist-packages/rospy/topics.py", line 882, in publish
    self.impl.publish(data)
  File "/opt/ros/noetic/lib/python3/dist-packages/rospy/topics.py", line 1066, in publish
    serialize_message(b, self.seq, message)
  File "/opt/ros/noetic/lib/python3/dist-packages/rospy/msg.py", line 152, in serialize_message
    msg.serialize(b)
  File "/home/user/catkin_ws/devel/lib/python3/dist-packages/section_action/msg/_OdomRecordActionFeedback.py", line 152, in serialize
    _x = self.feedback.current_total
AttributeError: 'float' object has no attribute 'current_total'

the catkin_make is successful. Please help…

Hi @MeineLiebeAxt ,

Yes! Just click on the “Send a Goal” button with goal blank text box.

You get this error because self.feedback = OdomRecordFeedback() just initializes self.feedback as a feedback message container. Therefore doing self.feedback = 0.0 makes no sense.
It must be self.feedback.current_total = 0.0

Try this fix and let me know if it worked.

– Girish

Hi @girishkumar.kannan ,
Thank you for you reply. Unfortunately it still doesn’t work.
My code is reviewed as:

import rospy
import actionlib
import time
import math
from section_action.msg import OdomRecordResult, OdomRecordFeedback, OdomRecordAction
from nav_msgs.msg import Odometry
from geometry_msgs.msg import Point32

class Odom_Record_Class():

    def __init__(self):

        # define action server of 'odom record'
        self.odom_record_action_server = actionlib.SimpleActionServer(
            "odom_record_action_server", OdomRecordAction, self.action_goal_callback, False)
        self.odom_record_action_server.start()
        rospy.loginfo(
            'the action /odom_record_action_server of odom recording is ready......')

        # define subscriber of '/odom'
        self.odom_sub = rospy.Subscriber('/odom', Odometry, self.sub_callback)
        # in order to get infomation in '/odom'
        self.odom_data = Odometry()

        # in order to restore the info (x,y,theta) from '/dom'
        self.current_pose = Point32()
        self.previous_pose = Point32()
        self.result_point32_list = OdomRecordResult()

        # in order to feedback the current total distance that robot has moved so far
        self.feedback = OdomRecordFeedback()

    def sub_callback(self, msg):

        # get pose info from '/odom'
        self.odom_data = msg

    def action_goal_callback(self, goal):

        # get initial pose
        self.current_pose.x = self.odom_data.pose.pose.position.x
        self.current_pose.y = self.odom_data.pose.pose.position.y
        self.current_pose.z = self.odom_data.pose.pose.orientation.z

        # robot doesn't move any distance at the beginning
        self.feedback.current_total = 0
        # records has nothing at the beginning
        self.result_point32_list = []

        # if the robot hasn't finished one lap, then keep moving
        while self.feedback.current_total <= 2:

            # send pose into previous_pose for distance calculation
            self.previous_pose.x = self.current_pose.x
            self.previous_pose.y = self.current_pose.y
            self.previous_pose.z = self.current_pose.z

            # update pose info
            self.current_pose.x = self.odom_data.pose.pose.position.x
            self.current_pose.y = self.odom_data.pose.pose.position.y
            self.current_pose.z = self.odom_data.pose.pose.orientation.z

            # calculate and publish current total distance
            interval_x = self.current_pose.x - self.previous_pose.x
            interval_y = self.current_pose.y - self.previous_pose.y
            interval_dist = math.sqrt(interval_x ** 2 + interval_y ** 2)
            self.feedback.current_total += interval_dist
            rospy.loginfo('current total distance is: ' +
                          str(self.feedback.current_total))
            self.odom_record_action_server.publish_feedback(
                self.feedback.current_total)

            # record pose every 1 second
            self.result_point32_list.append(self.current_pose)
            time.sleep(1)

        # return the records with all pose info
        self.odom_record_action_server.set_succeeded(self.result_point32_list)

    def main(self):

        rospy.loginfo('call action......')
        rospy.spin()


if __name__ == '__main__':

    rospy.init_node("odom_record_1_node")
    odom_record = Odom_Record_Class()
    odom_record.main()

The only difference is to add current_total to self.feedback.
And axclient still shows not correct, and the error info also:

[ERROR] [1669108780.594454, 67.138000]: Exception in your execute callback: 'float' objecthas no attribute 'current_total'
Traceback (most recent call last):
  File "/home/simulations/public_sim_ws/src/all/actionlib/actionlib/src/actionlib/simple_action_server.py", line 289, in executeLoop
    self.execute_callback(goal)
  File "/home/user/catkin_ws/src/section_action/scripts/ActionSection_OdomRecord_1.py", line 121, in action_goal_callback
    self.odom_record_action_server.publish_feedback(
  File "/home/simulations/public_sim_ws/src/all/actionlib/actionlib/src/actionlib/simple_action_server.py", line 175, in publish_feedback
    self.current_goal.publish_feedback(feedback)
  File "/home/simulations/public_sim_ws/src/all/actionlib/actionlib/src/actionlib/server_goal_handle.py", line 213, in publish_feedback
    self.action_server.publish_feedback(self.status_tracker.status, feedback)
  File "/home/simulations/public_sim_ws/src/all/actionlib/actionlib/src/actionlib/action_server.py", line 195, in publish_feedback
    self.feedback_pub.publish(af)
  File "/opt/ros/noetic/lib/python3/dist-packages/rospy/topics.py", line 882, in publish
    self.impl.publish(data)
  File "/opt/ros/noetic/lib/python3/dist-packages/rospy/topics.py", line 1066, in publish
    serialize_message(b, self.seq, message)
  File "/opt/ros/noetic/lib/python3/dist-packages/rospy/msg.py", line 152, in serialize_message
    msg.serialize(b)
  File "/home/user/catkin_ws/devel/lib/python3/dist-packages/section_action/msg/_OdomRecordActionFeedback.py", line 152, in serialize
    _x = self.feedback.current_total
AttributeError: 'float' object has no attribute 'current_total'

I have an idea:
I follow the course book to import this new action with:

from section_action.msg import OdomRecordResult, OdomRecordFeedback, OdomRecordAction

But actually the steps in course book have not told us to specificly make a msg directionary, but only action directionary. The case in course book with Fibonacci in actionlib_tutorials shows differently: it has both action and msg for Fibonacci:

/opt/ros/noetic/share/actionlib_tutorials/msg$ ls
AveragingActionFeedback.msg  FibonacciActionFeedback.msg
AveragingActionGoal.msg      FibonacciActionGoal.msg
AveragingAction.msg          FibonacciAction.msg
AveragingActionResult.msg    FibonacciActionResult.msg
AveragingFeedback.msg        FibonacciFeedback.msg
AveragingGoal.msg            FibonacciGoal.msg
AveragingResult.msg          FibonacciResult.msg

But after catkin_make, I found the msg of my new action in devel/share/section_action/msg. Should I manually copy this msg directionary to the same path with action directionary? Is this the problem of float has no attribute of current_total?

fine I tried that, it still doesn’t work. The error info remains the same with before…

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