添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
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:
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?
2022-11-21 19-15-07 的屏幕截图1920×1080 216 KB

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…

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?

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

MeineLiebeAxt:

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?