Quiz 6.5 action quiz distance didn't compute correctly

Hello there,

I have the following error inthe 6.5 quiz ros2 basics c++

It tells me that the distance didn’t compute correctly.
The distance is calculated with:

float get_distance_travelled() {
    float distance_travelled =
        sqrt(pow(this->current_pos_x - this->start_pos_x, 2) +
             pow(this->current_pos_y - this->start_pos_y, 2));
    return distance_travelled;
  }

there are 20 feedbacks and 20 messages in /total_distance published in 20 secs.
Can somebody tell me what have I missed?

Thank you in advance.

#include "rclcpp/rclcpp.hpp"
#include "rclcpp_action/rclcpp_action.hpp"

#include <functional>
#include <memory>
#include <thread>

#include "actions_quiz_msg/action/distance.hpp"
#include "nav_msgs/msg/odometry.hpp"
#include "std_msgs/msg/float64.hpp"
//#include "nav_msgs/msg/detail/odometry__struct.hpp"

class MyActionServer : public rclcpp::Node {
public:
  using Distance = actions_quiz_msg::action::Distance;
  using GoalHandleMove = rclcpp_action::ServerGoalHandle<Distance>;

  explicit MyActionServer(
      const rclcpp::NodeOptions &options = rclcpp::NodeOptions())
      : Node("my_action_quiz_server", options) {
    using namespace std::placeholders;

    this->action_server_ = rclcpp_action::create_server<Distance>(
        this, "distance_as",
        std::bind(&MyActionServer::handle_goal, this, _1, _2),
        std::bind(&MyActionServer::handle_cancel, this, _1),
        std::bind(&MyActionServer::handle_accepted, this, _1));

    subscription_ = this->create_subscription<nav_msgs::msg::Odometry>(
        "odom", 10, std::bind(&MyActionServer::odom_callback, this, _1));

    publisher_ =
        this->create_publisher<std_msgs::msg::Float64>("total_distance", 10);
  }

private:
  rclcpp_action::Server<Distance>::SharedPtr action_server_;
  rclcpp::Publisher<std_msgs::msg::Float64>::SharedPtr publisher_;
  rclcpp::Subscription<nav_msgs::msg::Odometry>::SharedPtr subscription_;
  float start_pos_x = 0;
  float start_pos_y = 0;
  float current_pos_x = 0;
  float current_pos_y = 0;

  void odom_callback(const nav_msgs::msg::Odometry::SharedPtr msg) {
    this->current_pos_x = msg->pose.pose.position.x;
    this->current_pos_y = msg->pose.pose.position.y;
  }

  rclcpp_action::GoalResponse
  handle_goal(const rclcpp_action::GoalUUID &uuid,
              std::shared_ptr<const Distance::Goal> goal) {
    RCLCPP_INFO(this->get_logger(), "Received goal request with secs %d",
                goal->seconds);
    (void)uuid;
    return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
  }

  rclcpp_action::CancelResponse
  handle_cancel(const std::shared_ptr<GoalHandleMove> goal_handle) {
    RCLCPP_INFO(this->get_logger(), "Received request to cancel goal");
    (void)goal_handle;
    return rclcpp_action::CancelResponse::ACCEPT;
  }

  void handle_accepted(const std::shared_ptr<GoalHandleMove> goal_handle) {
    using namespace std::placeholders;
    // this needs to return quickly to avoid blocking the executor, so spin up a
    // new thread
    std::thread{std::bind(&MyActionServer::execute, this, _1), goal_handle}
        .detach();
  }

  float get_distance_travelled() {
    float distance_travelled =
        sqrt(pow(this->current_pos_x - this->start_pos_x, 2) +
             pow(this->current_pos_y - this->start_pos_y, 2));
    return distance_travelled;
  }

  void execute(const std::shared_ptr<GoalHandleMove> goal_handle) {
    RCLCPP_INFO(this->get_logger(), "Executing goal");
    const auto goal = goal_handle->get_goal();
    auto feedback = std::make_shared<Distance::Feedback>();
    auto &current_distance_feedback = feedback->current_dist;
    auto result = std::make_shared<Distance::Result>();
    std_msgs::msg::Float64 distance_msg;
    rclcpp::Rate loop_rate(1);
    float distance_travelled = 0;
    

    for (int i = 0; (i < goal->seconds) && rclcpp::ok(); ++i) {
      // Check if there is a cancel request
      if (goal_handle->is_canceling()) {
        result->status = false;
        result->total_dist = distance_travelled;
        goal_handle->canceled(result);
        RCLCPP_INFO(this->get_logger(), "Goal canceled");
        return;
      }
      // get distance traveled and send feedback
      distance_travelled = get_distance_travelled();
      current_distance_feedback = distance_travelled;
      distance_msg.data = distance_travelled;

      publisher_->publish(distance_msg);
      goal_handle->publish_feedback(feedback);
      RCLCPP_INFO(this->get_logger(), "Publish feedback");

      loop_rate.sleep();
    }

    // Check if goal is done
    if (rclcpp::ok()) {
      result->status = true;
      result->total_dist = distance_travelled;
      // total_distance_publisher->publish(distance_msg);
      goal_handle->succeed(result);
      RCLCPP_INFO(this->get_logger(), "Goal succeeded");
    }
  }
}; // class MyActionServer

int main(int argc, char **argv) {
  rclcpp::init(argc, argv);

  auto action_server = std::make_shared<MyActionServer>();

  rclcpp::executors::MultiThreadedExecutor executor;
  executor.add_node(action_server);
  executor.spin();
  executor.remove_node(action_server);
  rclcpp::shutdown();
  return 0;
}

Action node client quiz

#include <inttypes.h>
#include <memory>
#include <string>
#include <iostream>

#include "rclcpp/rclcpp.hpp"
#include "rclcpp_action/rclcpp_action.hpp"

#include "actions_quiz_msg/action/distance.hpp"
#include "std_msgs/msg/float64.hpp"

class MyActionClient : public rclcpp::Node
{
public:
  using Distance = actions_quiz_msg::action::Distance;
  using GoalHandleMove = rclcpp_action::ClientGoalHandle<Distance>;

  explicit MyActionClient(const rclcpp::NodeOptions & node_options = rclcpp::NodeOptions())
  : Node("my_action_quiz_client", node_options), goal_done_(false)
  {
    this->client_ptr_ = rclcpp_action::create_client<Distance>(
      this->get_node_base_interface(),
      this->get_node_graph_interface(),
      this->get_node_logging_interface(),
      this->get_node_waitables_interface(),
      "distance_as");

    this->timer_ = this->create_wall_timer(
      std::chrono::milliseconds(500),
      std::bind(&MyActionClient::send_goal, this));
  }

  bool is_goal_done() const
  {
    return this->goal_done_;
  }

  void send_goal()
  {
    using namespace std::placeholders;

    this->timer_->cancel();

    this->goal_done_ = false;

    if (!this->client_ptr_) {
      RCLCPP_ERROR(this->get_logger(), "Action client not initialized");
    }

    if (!this->client_ptr_->wait_for_action_server(std::chrono::seconds(10))) {
      RCLCPP_ERROR(this->get_logger(), "Action server not available after waiting");
      this->goal_done_ = true;
      return;
    }

    auto goal_msg = Distance::Goal();
    goal_msg.seconds = 20;

    RCLCPP_INFO(this->get_logger(), "Sending goal");

    auto send_goal_options = rclcpp_action::Client<Distance>::SendGoalOptions();
                
    send_goal_options.goal_response_callback =
      std::bind(&MyActionClient::goal_response_callback, this, _1);

    send_goal_options.feedback_callback =
      std::bind(&MyActionClient::feedback_callback, this, _1, _2);

    send_goal_options.result_callback =
      std::bind(&MyActionClient::result_callback, this, _1);
      
    auto goal_handle_future = this->client_ptr_->async_send_goal(goal_msg, send_goal_options);
  }

private:
  rclcpp_action::Client<Distance>::SharedPtr client_ptr_;
  rclcpp::TimerBase::SharedPtr timer_;
  bool goal_done_;

  void goal_response_callback(const GoalHandleMove::SharedPtr & goal_handle)
  {
    if (!goal_handle) {
      RCLCPP_ERROR(this->get_logger(), "Goal was rejected by server");
    } else {
      RCLCPP_INFO(this->get_logger(), "Goal accepted by server, waiting for result");
    }
  }

  void feedback_callback(
    GoalHandleMove::SharedPtr,
    const std::shared_ptr<const Distance::Feedback> feedback)
  {
    RCLCPP_INFO(
      this->get_logger(), "Feedback received: %f", feedback->current_dist);
  }

  void result_callback(const GoalHandleMove::WrappedResult & result)
  {
    this->goal_done_ = true;
    switch (result.code) {
      case rclcpp_action::ResultCode::SUCCEEDED:
        break;
      case rclcpp_action::ResultCode::ABORTED:
        RCLCPP_ERROR(this->get_logger(), "Goal was aborted");
        return;
      case rclcpp_action::ResultCode::CANCELED:
        RCLCPP_ERROR(this->get_logger(), "Goal was canceled");
        return;
      default:
        RCLCPP_ERROR(this->get_logger(), "Unknown result code");
        return;
    }

    RCLCPP_INFO(this->get_logger(), "Result status received: %d", result.result->status);
    RCLCPP_INFO(this->get_logger(), "Distance received: %f", result.result->total_dist);
  }
};  // class MyActionClient

int main(int argc, char ** argv)
{
  rclcpp::init(argc, argv);
  auto action_client = std::make_shared<MyActionClient>();
    
  rclcpp::executors::MultiThreadedExecutor executor;
  executor.add_node(action_client);

  while (!action_client->is_goal_done()) {
    executor.spin_once();
  }
  executor.remove_node(action_client);
  rclcpp::shutdown();
  return 0;
}

Following are my different shells while making the robot go forward.

Shell 1 action server

user:~/ros2_ws$ ros2 launch actions_quiz actions_quiz_server.launch.py
[INFO] [launch]: All log files can be found below /home/user/.ros/log/2023-07-03-14-25-50-071580-4_xterm-22512
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [action_quiz_server_node-1]: process started with pid [22513]
[action_quiz_server_node-1] [INFO] [1688394420.270499813] [my_action_quiz_server]: Received goal request with secs 20
[action_quiz_server_node-1] [INFO] [1688394420.270880178] [my_action_quiz_server]: Executing goal
[action_quiz_server_node-1] [INFO] [1688394420.271080877] [my_action_quiz_server]: Publish feedback
[action_quiz_server_node-1] [INFO] [1688394421.271168110] [my_action_quiz_server]: Publish feedback
[action_quiz_server_node-1] [INFO] [1688394422.271304598] [my_action_quiz_server]: Publish feedback
[action_quiz_server_node-1] [INFO] [1688394423.271211568] [my_action_quiz_server]: Publish feedback
[action_quiz_server_node-1] [INFO] [1688394424.271231409] [my_action_quiz_server]: Publish feedback
[action_quiz_server_node-1] [INFO] [1688394425.271231018] [my_action_quiz_server]: Publish feedback
[action_quiz_server_node-1] [INFO] [1688394426.271239781] [my_action_quiz_server]: Publish feedback
[action_quiz_server_node-1] [INFO] [1688394427.271836915] [my_action_quiz_server]: Publish feedback
[action_quiz_server_node-1] [INFO] [1688394428.271193733] [my_action_quiz_server]: Publish feedback
[action_quiz_server_node-1] [INFO] [1688394429.271223898] [my_action_quiz_server]: Publish feedback
[action_quiz_server_node-1] [INFO] [1688394430.271201994] [my_action_quiz_server]: Publish feedback
[action_quiz_server_node-1] [INFO] [1688394431.271201209] [my_action_quiz_server]: Publish feedback
[action_quiz_server_node-1] [INFO] [1688394432.271210343] [my_action_quiz_server]: Publish feedback
[action_quiz_server_node-1] [INFO] [1688394433.271117438] [my_action_quiz_server]: Publish feedback
[action_quiz_server_node-1] [INFO] [1688394434.271235867] [my_action_quiz_server]: Publish feedback
[action_quiz_server_node-1] [INFO] [1688394435.271191260] [my_action_quiz_server]: Publish feedback
[action_quiz_server_node-1] [INFO] [1688394436.271247630] [my_action_quiz_server]: Publish feedback
[action_quiz_server_node-1] [INFO] [1688394437.271198158] [my_action_quiz_server]: Publish feedback
[action_quiz_server_node-1] [INFO] [1688394438.271240933] [my_action_quiz_server]: Publish feedback
[action_quiz_server_node-1] [INFO] [1688394439.271197938] [my_action_quiz_server]: Publish feedback
[action_quiz_server_node-1] [INFO] [1688394440.271253272] [my_action_quiz_server]: Goal succeeded

Shell 2 action client

user:~/ros2_ws$ ros2 launch actions_quiz actions_quiz_client.launch.py
[INFO] [launch]: All log files can be found below /home/user/.ros/log/2023-07-03-14-26-59-526966-4_xterm-22674
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [action_quiz_client_node-1]: process started with pid [22675]
[action_quiz_client_node-1] [INFO] [1688394420.270001602] [my_action_quiz_client]: Sending goal
[action_quiz_client_node-1] [INFO] [1688394420.271100552] [my_action_quiz_client]: Goal accepted by server, waiting for result
[action_quiz_client_node-1] [INFO] [1688394420.271599083] [my_action_quiz_client]: Feedback received: 0.000003
[action_quiz_client_node-1] [INFO] [1688394421.273842201] [my_action_quiz_client]: Feedback received: 0.000003
[action_quiz_client_node-1] [INFO] [1688394422.271418979] [my_action_quiz_client]: Feedback received: 0.057028
[action_quiz_client_node-1] [INFO] [1688394423.271316661] [my_action_quiz_client]: Feedback received: 0.388979
[action_quiz_client_node-1] [INFO] [1688394424.271371746] [my_action_quiz_client]: Feedback received: 0.720939
[action_quiz_client_node-1] [INFO] [1688394425.271325985] [my_action_quiz_client]: Feedback received: 1.052899
[action_quiz_client_node-1] [INFO] [1688394426.271360680] [my_action_quiz_client]: Feedback received: 1.384438
[action_quiz_client_node-1] [INFO] [1688394427.271977662] [my_action_quiz_client]: Feedback received: 1.713078
[action_quiz_client_node-1] [INFO] [1688394428.271306666] [my_action_quiz_client]: Feedback received: 2.051677
[action_quiz_client_node-1] [INFO] [1688394429.271331373] [my_action_quiz_client]: Feedback received: 2.380317
[action_quiz_client_node-1] [INFO] [1688394430.271571706] [my_action_quiz_client]: Feedback received: 2.715597
[action_quiz_client_node-1] [INFO] [1688394431.271364874] [my_action_quiz_client]: Feedback received: 3.047557
[action_quiz_client_node-1] [INFO] [1688394432.271389264] [my_action_quiz_client]: Feedback received: 3.382836
[action_quiz_client_node-1] [INFO] [1688394433.271304852] [my_action_quiz_client]: Feedback received: 3.704837
[action_quiz_client_node-1] [INFO] [1688394434.271364860] [my_action_quiz_client]: Feedback received: 4.036798
[action_quiz_client_node-1] [INFO] [1688394435.271289107] [my_action_quiz_client]: Feedback received: 4.372077
[action_quiz_client_node-1] [INFO] [1688394436.272632823] [my_action_quiz_client]: Feedback received: 4.700717
[action_quiz_client_node-1] [INFO] [1688394437.271323760] [my_action_quiz_client]: Feedback received: 5.035996
[action_quiz_client_node-1] [INFO] [1688394438.271502087] [my_action_quiz_client]: Feedback received: 5.367957
[action_quiz_client_node-1] [INFO] [1688394439.271786366] [my_action_quiz_client]: Feedback received: 5.703236
[action_quiz_client_node-1] [INFO] [1688394440.271496141] [my_action_quiz_client]: Result status received: 1
[action_quiz_client_node-1] [INFO] [1688394440.271549273] [my_action_quiz_client]: Distance received: 5.703236
[INFO] [action_quiz_client_node-1]: process has finished cleanly [pid 22675]

Shell 3 ros2 topic

user:~$ ros2 topic echo /total_distance
data: 3.1116537684283685e-06
---
data: 3.1116537684283685e-06
---
data: 0.05702805146574974
---
data: 0.38897904753685
---
data: 0.7209389805793762
---
data: 1.0528990030288696
---
data: 1.384437918663025
---
data: 1.7130779027938843
---
data: 2.0516769886016846
---
data: 2.380317211151123
---
data: 2.715596914291382
---
data: 3.0475566387176514
---
data: 3.382836103439331
---
data: 3.7048373222351074
---
data: 4.036797523498535
---
data: 4.372076988220215
---
data: 4.700716972351074
---
data: 5.035996437072754
---
data: 5.367956638336182
---
data: 5.703236103057861
---

ros2 action list

user:~$ ros2 action list
/distance_as

Hi @pabled91 ,

There could be a rounding issue that is probably not letting the autograder to match the distance values.

Try to round the values to 3 decimal places. That might fix your issue.

Regards,
Girish

Hello,

what method do you recommend to use for rounding to 3 decimals?
At what level should I round? juste after reading odometry or after calculating the distance and before publishing?

Couldn’t it be that I’m not really measuring the distance travelled but the distance to the start point?

thank you

Hi @pabled91 ,

The simplest way to round off to 3 decimal places in C++ is to multiply with 1000 as a float, then convert the value to int, and finally divide the value by 1000 and store it as a float.

The best place to implement the round off is before publishing into the topic and before sending it as a feedback.

Also make sure to set the distance variables to zero before the action starts, so that you do not start the value with some random non-zero number.

Regards,
Girish

I realize I showed you the code of the client instead of the server. I edited my first message to add what I did.
As said before could it be that I wasn’t not really measuring the distance travelled but the distance to the start point so I made another version for the server but it didn’t work as well. I again had that the distance computing was wrong. But for me the distance measured is coherent with the floor grid.

#include "rclcpp/rclcpp.hpp"
#include "rclcpp_action/rclcpp_action.hpp"

#include <functional>
#include <memory>
#include <thread>

#include "actions_quiz_msg/action/distance.hpp"
#include "nav_msgs/msg/odometry.hpp"
#include "std_msgs/msg/float64.hpp"
//#include "nav_msgs/msg/detail/odometry__struct.hpp"

class MyActionServer : public rclcpp::Node {
public:
  using Distance = actions_quiz_msg::action::Distance;
  using GoalHandleMove = rclcpp_action::ServerGoalHandle<Distance>;

  explicit MyActionServer(
      const rclcpp::NodeOptions &options = rclcpp::NodeOptions())
      : Node("my_action_quiz_server", options) {
    using namespace std::placeholders;


    /*  
    float number = 0.123456789;
    RCLCPP_INFO(this->get_logger(), "number = %f",number);
    float rounded_number = round_3_decimals(number);
    RCLCPP_INFO(this->get_logger(), "Rounded number = %f\n\n",rounded_number);
    */

    this->action_server_ = rclcpp_action::create_server<Distance>(
        this, "distance_as",
        std::bind(&MyActionServer::handle_goal, this, _1, _2),
        std::bind(&MyActionServer::handle_cancel, this, _1),
        std::bind(&MyActionServer::handle_accepted, this, _1));

    subscription_ = this->create_subscription<nav_msgs::msg::Odometry>(
        "odom", 10, std::bind(&MyActionServer::odom_callback, this, _1));

    publisher_ =
        this->create_publisher<std_msgs::msg::Float64>("total_distance", 10);
  }

private:
  rclcpp_action::Server<Distance>::SharedPtr action_server_;
  rclcpp::Publisher<std_msgs::msg::Float64>::SharedPtr publisher_;
  rclcpp::Subscription<nav_msgs::msg::Odometry>::SharedPtr subscription_;
  float start_pos_x = 0;
  float start_pos_y = 0;
  float current_pos_x = 0;
  float current_pos_y = 0;

  void odom_callback(const nav_msgs::msg::Odometry::SharedPtr msg) {
    this->current_pos_x = msg->pose.pose.position.x;
    this->current_pos_y = msg->pose.pose.position.y;
  }

  rclcpp_action::GoalResponse
  handle_goal(const rclcpp_action::GoalUUID &uuid,
              std::shared_ptr<const Distance::Goal> goal) {
    RCLCPP_INFO(this->get_logger(), "Received goal request with secs %d",
                goal->seconds);
    (void)uuid;
    return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
  }

  rclcpp_action::CancelResponse
  handle_cancel(const std::shared_ptr<GoalHandleMove> goal_handle) {
    RCLCPP_INFO(this->get_logger(), "Received request to cancel goal");
    (void)goal_handle;
    return rclcpp_action::CancelResponse::ACCEPT;
  }

  void handle_accepted(const std::shared_ptr<GoalHandleMove> goal_handle) {
    using namespace std::placeholders;
    // this needs to return quickly to avoid blocking the executor, so spin up a
    // new thread
    std::thread{std::bind(&MyActionServer::execute, this, _1), goal_handle}
        .detach();
  }

  float get_distance_travelled() {
    
    float distance_travelled =
        sqrt(pow(this->current_pos_x - this->start_pos_x, 2) +
             pow(this->current_pos_y - this->start_pos_y, 2));
    return distance_travelled;
  }

  void execute(const std::shared_ptr<GoalHandleMove> goal_handle) {
    RCLCPP_INFO(this->get_logger(), "Executing goal");
    const auto goal = goal_handle->get_goal();
    auto feedback = std::make_shared<Distance::Feedback>();
    auto &current_distance_feedback = feedback->current_dist;
    auto result = std::make_shared<Distance::Result>();
    std_msgs::msg::Float64 distance_msg;
    rclcpp::Rate loop_rate(1);
    float distance_travelled = 0;
    this->start_pos_x = this->current_pos_x;
    this->start_pos_y = this->current_pos_y;
    //RCLCPP_INFO(this->get_logger(), "start pos \nx = %f \ny= %f", this->start_pos_x, this->start_pos_y);
    

    for (int i = 0; (i < goal->seconds) && rclcpp::ok(); ++i) {
      // Check if there is a cancel request
      if (goal_handle->is_canceling()) {
        result->status = false;
        result->total_dist = distance_travelled;
        goal_handle->canceled(result);
        RCLCPP_INFO(this->get_logger(), "Goal canceled");
        return;
      }
      // get distance traveled and send feedback
      distance_travelled += get_distance_travelled();
      this->start_pos_x = this->current_pos_x;
      this->start_pos_y = this->current_pos_y;
      current_distance_feedback = distance_travelled;
      distance_msg.data = distance_travelled;

      publisher_->publish(distance_msg);
      goal_handle->publish_feedback(feedback);
      RCLCPP_INFO(this->get_logger(), "Publish feedback");

      loop_rate.sleep();
    }

    // Check if goal is done
    if (rclcpp::ok()) {
      result->status = true;
      result->total_dist = distance_travelled;
      // total_distance_publisher->publish(distance_msg);
      goal_handle->succeed(result);
      RCLCPP_INFO(this->get_logger(), "Goal succeeded");
    }
  }
}; // class MyActionServer

int main(int argc, char **argv) {

  
  rclcpp::init(argc, argv);
  auto action_server = std::make_shared<MyActionServer>();

  rclcpp::executors::MultiThreadedExecutor executor;
  executor.add_node(action_server);
  executor.spin();
  executor.remove_node(action_server);
  rclcpp::shutdown();
  return 0;
}

Like this? I only have 1 trials left because of my computer having a problem. The execution of the gradebot didn’t went correcly.

float round_3_decimals (float number){
    float A = number * 1000;
    RCLCPP_INFO(this->get_logger(), "number*1000 = %f",A);
    int B = A;
    float C = B;
    RCLCPP_INFO(this->get_logger(), "int then float step = %f",C);
    float rounded = C/1000;
    return rounded;
  }
user:~/ros2_ws$ ros2 launch actions_quiz actions_quiz_server.launch.py
[INFO] [launch]: All log files can be found below /home/user/.ros/log/2023-07-04-13-43-18-083659-1_xterm-1356
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [action_quiz_server_node-1]: process started with pid [1357]
[action_quiz_server_node-1] [INFO] [1688478198.316793442] [my_action_quiz_server]: number = 0.123457
[action_quiz_server_node-1] [INFO] [1688478198.317048840] [my_action_quiz_server]: number*1000 = 123.456795
[action_quiz_server_node-1] [INFO] [1688478198.317081319] [my_action_quiz_server]: int then float step = 123.000000
[action_quiz_server_node-1] [INFO] [1688478198.317099534] [my_action_quiz_server]: Rounded number = 0.123000

Hi @pabled91 ,

Yes your implementation of the rounding function is correct. But you don’t have to exactly make a function for that. You could have just used one line:

float rounded = float(int(float(number) * 1000.0) / 1000.0);

You can add this line in your get_distance_travelled() function, just before the return line.
Use this line before the return statement:

float distance_travelled = float(int(float(distance_travelled) * 1000.0) / 1000.0);

I do not see any issues in your client and server codes.

Try and check if the client and the distance topics output the same values after implementing the roundoff function.

Once they are the same values, you can submit the quiz. In case you still get the same error, then report back here. The Construct team can help you with your attempts or the auto grader.

Regards,
Girish

I tried your rounding function and mine. Each time I get the same kind of result where the rounding is done but there are numbers that appear at the end.

Can you confirm me that this is normal? And because of this the topic data and the feedbacks are not exactly the same.

user:~/ros2_ws$ ros2 launch actions_quiz actions_quiz_client.launch.py
[INFO] [launch]: All log files can be found below /home/user/.ros/log/2023-07-04-20-44-19-928732-1_xterm-3657
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [action_quiz_client_node-1]: process started with pid [3658]
[action_quiz_client_node-1] [INFO] [1688503461.903984132] [my_action_quiz_client]: Sending goal
[action_quiz_client_node-1] [INFO] [1688503461.972648401] [my_action_quiz_client]: Goal accepted by server, waiting for result
[action_quiz_client_node-1] [INFO] [1688503461.973230957] [my_action_quiz_client]: Feedback 1 received: 0.000000
[action_quiz_client_node-1] [INFO] [1688503462.906542817] [my_action_quiz_client]: Feedback 2 received: 0.486000
[action_quiz_client_node-1] [INFO] [1688503463.905163041] [my_action_quiz_client]: Feedback 3 received: 0.971000
[action_quiz_client_node-1] [INFO] [1688503464.905181990] [my_action_quiz_client]: Feedback 4 received: 1.456000
[action_quiz_client_node-1] [INFO] [1688503465.905286581] [my_action_quiz_client]: Feedback 5 received: 1.942000
[action_quiz_client_node-1] [INFO] [1688503466.905218941] [my_action_quiz_client]: Feedback 6 received: 2.427000
[action_quiz_client_node-1] [INFO] [1688503467.906279422] [my_action_quiz_client]: Feedback 7 received: 2.912000
[action_quiz_client_node-1] [INFO] [1688503468.905164180] [my_action_quiz_client]: Feedback 8 received: 3.398000
[action_quiz_client_node-1] [INFO] [1688503469.905182884] [my_action_quiz_client]: Feedback 9 received: 3.883000
[action_quiz_client_node-1] [INFO] [1688503470.905142588] [my_action_quiz_client]: Feedback 10 received: 4.364000
[action_quiz_client_node-1] [INFO] [1688503471.905185683] [my_action_quiz_client]: Feedback 11 received: 4.845000
[action_quiz_client_node-1] [INFO] [1688503472.905177649] [my_action_quiz_client]: Feedback 12 received: 5.330000
[action_quiz_client_node-1] [INFO] [1688503473.905290885] [my_action_quiz_client]: Feedback 13 received: 5.815001
[action_quiz_client_node-1] [INFO] [1688503474.905215123] [my_action_quiz_client]: Feedback 14 received: 6.300001
[action_quiz_client_node-1] [INFO] [1688503475.905125117] [my_action_quiz_client]: Feedback 15 received: 6.785001
[action_quiz_client_node-1] [INFO] [1688503476.906473632] [my_action_quiz_client]: Feedback 16 received: 7.270001
[action_quiz_client_node-1] [INFO] [1688503477.905188685] [my_action_quiz_client]: Feedback 17 received: 7.755001
[action_quiz_client_node-1] [INFO] [1688503478.905144507] [my_action_quiz_client]: Feedback 18 received: 8.240001
[action_quiz_client_node-1] [INFO] [1688503479.905134846] [my_action_quiz_client]: Feedback 19 received: 8.726001
[action_quiz_client_node-1] [INFO] [1688503480.905402227] [my_action_quiz_client]: Feedback 20 received: 9.211000
[action_quiz_client_node-1] [INFO] [1688503481.905125711] [my_action_quiz_client]: Result status received: 1
[action_quiz_client_node-1] [INFO] [1688503481.905179968] [my_action_quiz_client]: Distance received: 9.211000
[INFO] [action_quiz_client_node-1]: process has finished cleanly [pid 3658]
user:~/ros2_ws$ ros2 launch actions_quiz actions_quiz_client.launch.py
[INFO] [launch]: All log files can be found below /home/user/.ros/log/2023-07-04-20-44-19-928732-1_xterm-3657
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [action_quiz_client_node-1]: process started with pid [3658]
[action_quiz_client_node-1] [INFO] [1688503461.903984132] [my_action_quiz_client]: Sending goal
[action_quiz_client_node-1] [INFO] [1688503461.972648401] [my_action_quiz_client]: Goal accepted by server, waiting for result
[action_quiz_client_node-1] [INFO] [1688503461.973230957] [my_action_quiz_client]: Feedback 1 received: 0.000000
[action_quiz_client_node-1] [INFO] [1688503462.906542817] [my_action_quiz_client]: Feedback 2 received: 0.486000
[action_quiz_client_node-1] [INFO] [1688503463.905163041] [my_action_quiz_client]: Feedback 3 received: 0.971000
[action_quiz_client_node-1] [INFO] [1688503464.905181990] [my_action_quiz_client]: Feedback 4 received: 1.456000
[action_quiz_client_node-1] [INFO] [1688503465.905286581] [my_action_quiz_client]: Feedback 5 received: 1.942000
[action_quiz_client_node-1] [INFO] [1688503466.905218941] [my_action_quiz_client]: Feedback 6 received: 2.427000
[action_quiz_client_node-1] [INFO] [1688503467.906279422] [my_action_quiz_client]: Feedback 7 received: 2.912000
[action_quiz_client_node-1] [INFO] [1688503468.905164180] [my_action_quiz_client]: Feedback 8 received: 3.398000
[action_quiz_client_node-1] [INFO] [1688503469.905182884] [my_action_quiz_client]: Feedback 9 received: 3.883000
[action_quiz_client_node-1] [INFO] [1688503470.905142588] [my_action_quiz_client]: Feedback 10 received: 4.364000
[action_quiz_client_node-1] [INFO] [1688503471.905185683] [my_action_quiz_client]: Feedback 11 received: 4.845000
[action_quiz_client_node-1] [INFO] [1688503472.905177649] [my_action_quiz_client]: Feedback 12 received: 5.330000
[action_quiz_client_node-1] [INFO] [1688503473.905290885] [my_action_quiz_client]: Feedback 13 received: 5.815001
[action_quiz_client_node-1] [INFO] [1688503474.905215123] [my_action_quiz_client]: Feedback 14 received: 6.300001
[action_quiz_client_node-1] [INFO] [1688503475.905125117] [my_action_quiz_client]: Feedback 15 received: 6.785001
[action_quiz_client_node-1] [INFO] [1688503476.906473632] [my_action_quiz_client]: Feedback 16 received: 7.270001
[action_quiz_client_node-1] [INFO] [1688503477.905188685] [my_action_quiz_client]: Feedback 17 received: 7.755001
[action_quiz_client_node-1] [INFO] [1688503478.905144507] [my_action_quiz_client]: Feedback 18 received: 8.240001
[action_quiz_client_node-1] [INFO] [1688503479.905134846] [my_action_quiz_client]: Feedback 19 received: 8.726001
[action_quiz_client_node-1] [INFO] [1688503480.905402227] [my_action_quiz_client]: Feedback 20 received: 9.211000
[action_quiz_client_node-1] [INFO] [1688503481.905125711] [my_action_quiz_client]: Result status received: 1
[action_quiz_client_node-1] [INFO] [1688503481.905179968] [my_action_quiz_client]: Distance received: 9.211000
[INFO] [action_quiz_client_node-1]: process has finished cleanly [pid 3658]
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_action/rclcpp_action.hpp"

#include <functional>
#include <memory>
#include <thread>

#include "actions_quiz_msg/action/distance.hpp"
#include "nav_msgs/msg/odometry.hpp"
#include "std_msgs/msg/float64.hpp"
//#include "nav_msgs/msg/detail/odometry__struct.hpp"

class MyActionServer : public rclcpp::Node {
public:
  using Distance = actions_quiz_msg::action::Distance;
  using GoalHandleMove = rclcpp_action::ServerGoalHandle<Distance>;

  explicit MyActionServer(
      const rclcpp::NodeOptions &options = rclcpp::NodeOptions())
      : Node("my_action_quiz_server", options) {
    using namespace std::placeholders;


    /*  
    float number = 0.123456789;
    RCLCPP_INFO(this->get_logger(), "number = %f",number);
    float rounded_number = round_3_decimals(number);
    RCLCPP_INFO(this->get_logger(), "Rounded number = %f\n\n",rounded_number);
    */

    this->action_server_ = rclcpp_action::create_server<Distance>(
        this, "distance_as",
        std::bind(&MyActionServer::handle_goal, this, _1, _2),
        std::bind(&MyActionServer::handle_cancel, this, _1),
        std::bind(&MyActionServer::handle_accepted, this, _1));

    subscription_ = this->create_subscription<nav_msgs::msg::Odometry>(
        "odom", 10, std::bind(&MyActionServer::odom_callback, this, _1));

    publisher_ =
        this->create_publisher<std_msgs::msg::Float64>("total_distance", 10);
  }

private:
  rclcpp_action::Server<Distance>::SharedPtr action_server_;
  rclcpp::Publisher<std_msgs::msg::Float64>::SharedPtr publisher_;
  rclcpp::Subscription<nav_msgs::msg::Odometry>::SharedPtr subscription_;
  float start_pos_x = 0;
  float start_pos_y = 0;
  float current_pos_x = 0;
  float current_pos_y = 0;

  void odom_callback(const nav_msgs::msg::Odometry::SharedPtr msg) {
    this->current_pos_x = msg->pose.pose.position.x;
    this->current_pos_y = msg->pose.pose.position.y;
  }

  rclcpp_action::GoalResponse
  handle_goal(const rclcpp_action::GoalUUID &uuid,
              std::shared_ptr<const Distance::Goal> goal) {
    RCLCPP_INFO(this->get_logger(), "Received goal request with secs %d",
                goal->seconds);
    (void)uuid;
    return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
  }

  rclcpp_action::CancelResponse
  handle_cancel(const std::shared_ptr<GoalHandleMove> goal_handle) {
    RCLCPP_INFO(this->get_logger(), "Received request to cancel goal");
    (void)goal_handle;
    return rclcpp_action::CancelResponse::ACCEPT;
  }

  void handle_accepted(const std::shared_ptr<GoalHandleMove> goal_handle) {
    using namespace std::placeholders;
    // this needs to return quickly to avoid blocking the executor, so spin up a
    // new thread
    std::thread{std::bind(&MyActionServer::execute, this, _1), goal_handle}
        .detach();
  }

  float get_distance_travelled() {
    
    float distance_travelled =
        sqrt(pow(this->current_pos_x - this->start_pos_x, 2) +
             pow(this->current_pos_y - this->start_pos_y, 2));
    //float distance_travelled_rounded = float(int(float(distance_travelled) * 1000.0) / 1000.0);
    float distance_travelled_rounded = round_3_decimals (distance_travelled);
    return distance_travelled_rounded;
  }

  float round_3_decimals (float number){
    float A = number * 1000;
    RCLCPP_INFO(this->get_logger(), "number*1000 = %f",A);
    int B = A;
    float C = B;
    RCLCPP_INFO(this->get_logger(), "int then float step = %f",C);
    float rounded = C/1000;
    return rounded;
  }


  void execute(const std::shared_ptr<GoalHandleMove> goal_handle) {
    RCLCPP_INFO(this->get_logger(), "Executing goal");
    const auto goal = goal_handle->get_goal();
    auto feedback = std::make_shared<Distance::Feedback>();
    auto &current_distance_feedback = feedback->current_dist;
    auto result = std::make_shared<Distance::Result>();
    std_msgs::msg::Float64 distance_msg;
    rclcpp::Rate loop_rate(1);
    float distance_travelled = 0;
    this->start_pos_x = this->current_pos_x;
    this->start_pos_y = this->current_pos_y;
    //RCLCPP_INFO(this->get_logger(), "start pos \nx = %f \ny= %f", this->start_pos_x, this->start_pos_y);
    

    for (int i = 0; (i < goal->seconds) && rclcpp::ok(); ++i) {
      // Check if there is a cancel request
      if (goal_handle->is_canceling()) {
        result->status = false;
        result->total_dist = distance_travelled;
        goal_handle->canceled(result);
        RCLCPP_INFO(this->get_logger(), "Goal canceled");
        return;
      }
      // get distance traveled and send feedback
      distance_travelled += get_distance_travelled();
      this->start_pos_x = this->current_pos_x;
      this->start_pos_y = this->current_pos_y;
      current_distance_feedback = distance_travelled;
      distance_msg.data = distance_travelled;

      publisher_->publish(distance_msg);
      goal_handle->publish_feedback(feedback);
      RCLCPP_INFO(this->get_logger(), "Publish feedback");

      loop_rate.sleep();
    }

    // Check if goal is done
    if (rclcpp::ok()) {
      result->status = true;
      result->total_dist = distance_travelled;
      // total_distance_publisher->publish(distance_msg);
      goal_handle->succeed(result);
      RCLCPP_INFO(this->get_logger(), "Goal succeeded");
    }
  }
}; // class MyActionServer

int main(int argc, char **argv) {

  
  rclcpp::init(argc, argv);
  auto action_server = std::make_shared<MyActionServer>();

  rclcpp::executors::MultiThreadedExecutor executor;
  executor.add_node(action_server);
  executor.spin();
  executor.remove_node(action_server);
  rclcpp::shutdown();
  return 0;
}

Could it be because we were using float instead of double(float64)?
Everything is in float64

user:~$ ros2 interface show nav_msgs/msg/Odometry

        Pose pose
                Point position
                        float64 x
                        float64 y
                        float64 z

I tryed to put everything in double. It seems better but there still is a difference that appears between feedback and topic data

[action_quiz_client_node-1] [INFO] [1688505663.177835810] [my_action_quiz_client]: Feedback 1 received: 0.000000
[action_quiz_client_node-1] [INFO] [1688505664.177845747] [my_action_quiz_client]: Feedback 2 received: 0.485000
[action_quiz_client_node-1] [INFO] [1688505665.177871600] [my_action_quiz_client]: Feedback 3 received: 0.970000
[action_quiz_client_node-1] [INFO] [1688505666.177878870] [my_action_quiz_client]: Feedback 4 received: 1.455000
[action_quiz_client_node-1] [INFO] [1688505667.177844395] [my_action_quiz_client]: Feedback 5 received: 1.940000
[action_quiz_client_node-1] [INFO] [1688505668.177834871] [my_action_quiz_client]: Feedback 6 received: 2.425000
[action_quiz_client_node-1] [INFO] [1688505669.177842267] [my_action_quiz_client]: Feedback 7 received: 2.910000
[action_quiz_client_node-1] [INFO] [1688505670.177829836] [my_action_quiz_client]: Feedback 8 received: 3.395000
[action_quiz_client_node-1] [INFO] [1688505671.177840541] [my_action_quiz_client]: Feedback 9 received: 3.880000
[action_quiz_client_node-1] [INFO] [1688505672.177848967] [my_action_quiz_client]: Feedback 10 received: 4.361000
[action_quiz_client_node-1] [INFO] [1688505673.177833236] [my_action_quiz_client]: Feedback 11 received: 4.846000
[action_quiz_client_node-1] [INFO] [1688505674.177865345] [my_action_quiz_client]: Feedback 12 received: 5.331000
[action_quiz_client_node-1] [INFO] [1688505675.177890508] [my_action_quiz_client]: Feedback 13 received: 5.816000
[action_quiz_client_node-1] [INFO] [1688505676.177836961] [my_action_quiz_client]: Feedback 14 received: 6.301000
[action_quiz_client_node-1] [INFO] [1688505677.177832444] [my_action_quiz_client]: Feedback 15 received: 6.787000
[action_quiz_client_node-1] [INFO] [1688505678.177836983] [my_action_quiz_client]: Feedback 16 received: 7.272000
[action_quiz_client_node-1] [INFO] [1688505679.177851141] [my_action_quiz_client]: Feedback 17 received: 7.757000
[action_quiz_client_node-1] [INFO] [1688505680.177829858] [my_action_quiz_client]: Feedback 18 received: 8.243000
[action_quiz_client_node-1] [INFO] [1688505681.177841933] [my_action_quiz_client]: Feedback 19 received: 8.728000
[action_quiz_client_node-1] [INFO] [1688505682.177812600] [my_action_quiz_client]: Feedback 20 received: 9.213000
user:~$ ros2 topic echo /total_distance
data: 0.0
---
data: 0.485
---
data: 0.97
---
data: 1.455
---
data: 1.94
---
data: 2.425
---
data: 2.9099999999999997
---
data: 3.3949999999999996
---
data: 3.8799999999999994
---
data: 4.361
---
data: 4.846
---
data: 5.331
---
data: 5.816000000000001
---
data: 6.301000000000001
---
data: 6.787000000000001
---
data: 7.272000000000001
---
data: 7.7570000000000014
---
data: 8.243000000000002
---
data: 8.728000000000002
---
data: 9.213000000000001
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_action/rclcpp_action.hpp"

#include <functional>
#include <memory>
#include <thread>

#include "actions_quiz_msg/action/distance.hpp"
#include "nav_msgs/msg/odometry.hpp"
#include "std_msgs/msg/float64.hpp"
//#include "nav_msgs/msg/detail/odometry__struct.hpp"

class MyActionServer : public rclcpp::Node {
public:
  using Distance = actions_quiz_msg::action::Distance;
  using GoalHandleMove = rclcpp_action::ServerGoalHandle<Distance>;

  explicit MyActionServer(
      const rclcpp::NodeOptions &options = rclcpp::NodeOptions())
      : Node("my_action_quiz_server", options) {
    using namespace std::placeholders;


    /*  
    float number = 0.123456789;
    RCLCPP_INFO(this->get_logger(), "number = %f",number);
    float rounded_number = round_3_decimals(number);
    RCLCPP_INFO(this->get_logger(), "Rounded number = %f\n\n",rounded_number);
    */

    this->action_server_ = rclcpp_action::create_server<Distance>(
        this, "distance_as",
        std::bind(&MyActionServer::handle_goal, this, _1, _2),
        std::bind(&MyActionServer::handle_cancel, this, _1),
        std::bind(&MyActionServer::handle_accepted, this, _1));

    subscription_ = this->create_subscription<nav_msgs::msg::Odometry>(
        "odom", 10, std::bind(&MyActionServer::odom_callback, this, _1));

    publisher_ =
        this->create_publisher<std_msgs::msg::Float64>("total_distance", 10);
  }

private:
  rclcpp_action::Server<Distance>::SharedPtr action_server_;
  rclcpp::Publisher<std_msgs::msg::Float64>::SharedPtr publisher_;
  rclcpp::Subscription<nav_msgs::msg::Odometry>::SharedPtr subscription_;
  double start_pos_x = 0;
  double start_pos_y = 0;
  double current_pos_x = 0;
  double current_pos_y = 0;

  void odom_callback(const nav_msgs::msg::Odometry::SharedPtr msg) {
    this->current_pos_x = msg->pose.pose.position.x;
    this->current_pos_y = msg->pose.pose.position.y;
  }

  rclcpp_action::GoalResponse
  handle_goal(const rclcpp_action::GoalUUID &uuid,
              std::shared_ptr<const Distance::Goal> goal) {
    RCLCPP_INFO(this->get_logger(), "Received goal request with secs %d",
                goal->seconds);
    (void)uuid;
    return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
  }

  rclcpp_action::CancelResponse
  handle_cancel(const std::shared_ptr<GoalHandleMove> goal_handle) {
    RCLCPP_INFO(this->get_logger(), "Received request to cancel goal");
    (void)goal_handle;
    return rclcpp_action::CancelResponse::ACCEPT;
  }

  void handle_accepted(const std::shared_ptr<GoalHandleMove> goal_handle) {
    using namespace std::placeholders;
    // this needs to return quickly to avoid blocking the executor, so spin up a
    // new thread
    std::thread{std::bind(&MyActionServer::execute, this, _1), goal_handle}
        .detach();
  }

   double get_distance_travelled() {
    
    double distance_travelled =
        sqrt(pow(this->current_pos_x - this->start_pos_x, 2) +
             pow(this->current_pos_y - this->start_pos_y, 2));
    double distance_travelled_rounded = double(int(double(distance_travelled) * 1000.0) / 1000.0);
    //float distance_travelled_rounded = round_3_decimals (distance_travelled);
    return distance_travelled_rounded;
    //return distance_travelled;
  }

/*
  float round_3_decimals (float number){
    float A = number * 1000;
    RCLCPP_INFO(this->get_logger(), "number*1000 = %f",A);
    int B = A;
    float C = B;
    RCLCPP_INFO(this->get_logger(), "int then float step = %f",C);
    float rounded = C/1000;
    return rounded;
  }
*/

  void execute(const std::shared_ptr<GoalHandleMove> goal_handle) {
    RCLCPP_INFO(this->get_logger(), "Executing goal");
    const auto goal = goal_handle->get_goal();
    auto feedback = std::make_shared<Distance::Feedback>();
    auto &current_distance_feedback = feedback->current_dist;
    auto result = std::make_shared<Distance::Result>();
    std_msgs::msg::Float64 distance_msg;
    rclcpp::Rate loop_rate(1);
    double distance_travelled = 0;
    this->start_pos_x = this->current_pos_x;
    this->start_pos_y = this->current_pos_y;
    //RCLCPP_INFO(this->get_logger(), "start pos \nx = %f \ny= %f", this->start_pos_x, this->start_pos_y);
    

    for (int i = 0; (i < goal->seconds) && rclcpp::ok(); ++i) {
      // Check if there is a cancel request
      if (goal_handle->is_canceling()) {
        result->status = false;
        result->total_dist = distance_travelled;
        goal_handle->canceled(result);
        RCLCPP_INFO(this->get_logger(), "Goal canceled");
        return;
      }
      // get distance traveled and send feedback
      distance_travelled += get_distance_travelled();
      this->start_pos_x = this->current_pos_x;
      this->start_pos_y = this->current_pos_y;
      current_distance_feedback = distance_travelled;
      distance_msg.data = distance_travelled;

      publisher_->publish(distance_msg);
      goal_handle->publish_feedback(feedback);
      RCLCPP_INFO(this->get_logger(), "Publish feedback");

      loop_rate.sleep();
    }

    // Check if goal is done
    if (rclcpp::ok()) {
      result->status = true;
      result->total_dist = distance_travelled;
      // total_distance_publisher->publish(distance_msg);
      goal_handle->succeed(result);
      RCLCPP_INFO(this->get_logger(), "Goal succeeded");
    }
  }
}; // class MyActionServer

int main(int argc, char **argv) {

  
  rclcpp::init(argc, argv);
  auto action_server = std::make_shared<MyActionServer>();

  rclcpp::executors::MultiThreadedExecutor executor;
  executor.add_node(action_server);
  executor.spin();
  executor.remove_node(action_server);
  rclcpp::shutdown();
  return 0;
}

Hi @pabled91 ,

Yes, that is fine. That is the float accuracy issue. Using double is no different than using float.
So, you can ignore those 1’s in the end of the decimals. Just use float. You won’t need double.

You can submit your quiz. If the auto grader still reports any issues, post it here.

Regards,
Girish

1 Like

Hi @girishkumar.kannan,

I put the version with float and it worked.

Thank you very much for your help and patience answering all my doubts.

Regards,
Pablo

Hi @pabled91 ,

Glad to know that your problem is resolved!

Regards,
Girish

1 Like

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