C++ Basics Real Robot Project - need guidelines

Hello Construct Team and Forum members,

If it is possible I’d like to ask several questions regarding the project, mentioned in this topic.
This is a first project, linked to the course “C++ Basics”

  1. I can not resolve the mystery of a different forward/backward speed in simulation and lab environment. In this project, moving the robot is straightforward - assign a value to the interface class attribute. I believe it implements polling and posts the required message.
    I just assign robot_interface_->linear_velocity with positive or negative values. I noticed my robot moves backward always faster than forward. If I time both moves with the same simple delay, my robot moves a notably different distance backward.

  2. Robot’s scan returns range angle increment of 0.01 Rad, which supposed to result in 628 range samples. However, ranges vector size is 660 samples. How come ? What number I should rely on in exercises ? Increment or actual number of samples?

  3. " Part 3 - Obstacle Prediction Algorithm". I understand the approach, however range values multiplied by 100 and converted to int ALWAYS return several identical samples. Especially those, resulting in two digit numbers. For example - 0.250 and 0.257 will result into the same number 25. Maybe the multiplier should be 1000 ?

  4. Running a loop for Naive Obstacle Avoider without a small delay (~200ms) results in a segmentation fault. This happens when I attempt to change the direction. In this loop I constantly assign linear or angular velocity of the interface class. Is there a clash with the polling/posting of those in the interface class?

I appreciate any assistance. Thank you !

Dmitry

  1. The real robot might have different speeds for forwards and backwards. You should adjust that in code to compensate. And what exactly does this affect your algorithm? Take into account that controling a real robot is taking these physical inconsistencies into account. Thats why we do the RealRobotProjects, because real robots are not simulations.
  2. Use teh number os samples and the icrement of angle per sample.
  3. If you wnat more precission yes of course. That depends on your tests and if you neede it. The bigger the numebrs you work with the less efficient is your code but it has to work well, so its a compromise.
  4. I would need more details on that matter, maybe screenshots, code extracts.

Hi @duckfrost2 .

Thank you for the quick response.
I believe I will need more clarifications regarding the topics I just outlined above.
Just a reminder - all questions are related to the “Basic C++ first real project”

  1. Scan samples” - I found my problem. Interface class returns increment of 0.01, number of rays - 660. 0.01*660 = 6.6 > 2*Pi = 6.28 : I’d expect to find 628 samples for a scan, which cover exactly 2*Pi Rad. Looking a bit deeper, I realized the problem is in the increment printout, rounder to 3 digits after the point. Actual number is a bit smaller (0.0095), which exactly matches the samples number.
  2. Obstacle Prediction - I’d insist that project guidelines will never result in the “wall” detection. Multiplying by 100 and converting to int will always produce a few identical scan ranges. The only way I see it may work is increasing the threshold value in the obstacle avoidance loop. Increasing the “turn around” distance will cause increased rays length and this may produce distinct scaled values. I’ll give it a try.
  3. seg faut issue
    This is a given to students code in the interface class :

// declare and initialize control timer callback
control_timer = this->create_wall_timer(
std::chrono::milliseconds(100),
std::bind(&RobotInterface::control_callback, this), callback_group);
RCLCPP_INFO(this->get_logger(), “Initialized Control Timer”);


void RobotInterface::control_callback() {
// set robot speeds
twist_cmd.linear.x = linear_velocity;
twist_cmd.angular.z = angular_velocity;
// publish the twist command
publish_twist_cmd();
// print debug


}

void RobotInterface::publish_twist_cmd() {
// linear speed control
twist_cmd.linear.x = std::min(twist_cmd.linear.x, 0.150);
// angular speed control
twist_cmd.angular.z = std::min(twist_cmd.angular.z, 0.450);
// publish command
cmd_vel_pub->publish(twist_cmd);
}

As you see, nothing protects class members linear_velocity, angular_velocity from the concurrent write/read. Since this is a basic C++ course and the very first project, there are no instructions to manage this situation (I suggest this is a bit beyond just basics). Project instructions suggest just using these attributes:

Robot Interface Variables:

  • general constants:
    • pi, pi_inv
  • cmd_vel publisher variables:
    • linear_velocity, angular_velocity

If you expect students using sync primitives, there are should be some notes about it in C++ basic course or pre-baked implementation in the given interface class.

Otherwise, I’d link the seg fault to the junk, posted to the message due to the concurrency. Introducing delay (100-200ms) between assigning velocities, significantly reduces seg faults occupancies.
Maybe my approach is not perfect - I constantly assign velocities in the control loop, by changing them or confirming the direction. However, control callback is been called every 100ms unconditionally (value changed or not), so my approach is not drastically different.

  1. “Difference in front/back speed”. This is reproduced in both - simulation and lab.

// Forward
linear_velocity = 0.2
sleep_ms(1000)
linear_velocity = 0.0
sleep_ms(500)
// Now backward
linear_velocity = -0.2
sleep_ms(1000)
linear_velocity = 0.0
sleep_ms(500)

The above code sketch will cause the robot to move backward about 25% more. I have no clue why. I’d expect some difference, but not that much.

Hey folks, any thoughts on this ?

Hey @lifdmitry, we will have a look at this in more detail and get back to you. Thank you for highlighting that.

I suggest you try severa things:

  1. For the assyemtry in speed try: template
    static inline T clamp_abs(T v, T max_abs) {
    if (v > max_abs) return max_abs;
    if (v < -max_abs) return -max_abs;
    return v;
    }

void RobotInterface::publish_twist_cmd() {
twist_cmd.linear.x = clamp_abs(twist_cmd.linear.x, 0.150);
twist_cmd.angular.z = clamp_abs(twist_cmd.angular.z, 0.450);
cmd_vel_pub->publish(twist_cmd);
}

  1. For the Sgmentation fault have tried this:

// in constructor
auto cbg = this->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
rclcpp::TimerBase::Options topts;
topts.callback_group = cbg;
control_timer = this->create_wall_timer(100ms, std::bind(&RobotInterface::control_callback, this), topts);

// any subscription/service that writes linear_velocity/angular_velocity:
rclcpp::SubscriptionOptions subs_opts;
subs_opts.callback_group = cbg;
vel_sub = this->create_subscription(“cmd_vel_in”, 10, std::bind(&RobotInterface::vel_cb, this, _1), subs_opts);

Plae them n the same callback group.

1 Like

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