I’m currently stuck on the second part of the rosject for the ros2 c++ in 5 days course. I’m subscribing to the /scan topic and have the state variables updated in the callback. I would like to use while loops to get the robot to reach a certain state depending on the front, right, and closest distances, but I would need those values to be continuously updating, which I haven’t been able to do for a few days now. I guess my question is, how can I execute the while loop code while still updating the state variables the callback is responsible for? Thanks
#include "rclcpp/executors.hpp"
#include <ros2_project/find_wall_move.hpp>
using namespace std::chrono_literals;
using std::placeholders::_1;
FindWall::FindWall(std::shared_ptr<rclcpp::Node> node) {
// Other variables
this->running_ = true;
this->state_ = 0;
// this->front_distance_ = 0;
// this->closest_distance_ = 0;
// this->right_distance_ = 0;
node_ = node;
RCLCPP_INFO(this->node_->get_logger(), "Starting ");
// Rate
rclcpp::WallRate loop_rate(500ms);
RCLCPP_INFO(node_->get_logger(), "Creating publisher ");
// ROS Publishers
pub_cmd_vel_ =
node_->create_publisher<geometry_msgs::msg::Twist>("/cmd_vel", 10);
RCLCPP_INFO(node_->get_logger(), "Creating subscriber ");
// ROS Subscribers
sub_laser_scan = node_->create_subscription<sensor_msgs::msg::LaserScan>(
"/scan", 10, std::bind(&FindWall::topic_callback, this, _1));
}
FindWall::~FindWall(void) {}
void FindWall::rateSleep(void) {}
// return the appropriate velocity commands based on the state the vehicle is in
geometry_msgs::msg::Twist FindWall::getStateVelocity() {
geometry_msgs::msg::Twist vel;
switch (state_) {
case 0: // vehicle is stopped
vel.linear.x = 0;
vel.angular.z = 0;
break;
case 1: // turning to the right
vel.linear.x = 0;
vel.angular.z = -.3;
break;
case 2: // turning to the left
vel.linear.x = 0;
vel.angular.z = .3;
break;
case 3: // move forward
vel.linear.x = .3;
vel.angular.z = 0;
break;
case 4: // move backward
vel.linear.x = -.3;
vel.angular.z = 0;
break;
}
return vel;
}
bool call_back_hit = false;
// returns True if the vehicle has found the nearest wall and positioned itself,
// false otherwise
bool FindWall::runTimeStateMachine(void) {
if(!call_back_hit){
return false;
}
geometry_msgs::msg::Twist vel;
// If the statemachine is no longer running, stop movement and return true
if (!running_) {
vel.linear.x = 0;
vel.angular.z = 0;
pub_cmd_vel_->publish(vel);
return true;
}
// otherwise, get the velocity for the current state and move robot
vel = this->getStateVelocity();
this->pub_cmd_vel_->publish(vel);
RCLCPP_INFO(this->node_->get_logger(), "State [%d], Vel [%.2f, %.2f]", state_,
vel.linear.x, vel.angular.z);
RCLCPP_INFO(this->node_->get_logger(),
"Front distance: %f, Closest Distance: %f", "Right Distance %f",
this->front_distance_, this->closest_distance_,
this->right_distance_);
rclcpp::Rate loop_rate(100);
if (front_distance_ == closest_distance_) {
if (front_distance_ == 0 && closest_distance_ == 0) {
RCLCPP_INFO(this->node_->get_logger(), "stuck...");
loop_rate.sleep();
} else { // if the front is the closest and is not 0, then proceed to move
// forward
if (front_distance_ > .3) { // if it's too far, move forward
RCLCPP_INFO(this->node_->get_logger(), "Too Far...");
while (front_distance_ > .3) {
RCLCPP_INFO(this->node_->get_logger(), "Moving forward...");
this->changeState(3);
vel = this->getStateVelocity();
this->pub_cmd_vel_->publish(vel);
}
stopRobot();
} else if (front_distance_ < .3) { // if its too close, move backward
while (front_distance_ < .3) {
RCLCPP_INFO(this->node_->get_logger(), "Too close...");
RCLCPP_INFO(this->node_->get_logger(), "Moving backward...");
this->changeState(4);
vel = this->getStateVelocity();
this->pub_cmd_vel_->publish(vel);
}
stopRobot();
}
}
} else {
while (front_distance_ != closest_distance_) {
RCLCPP_INFO(this->node_->get_logger(), "Front not aligned");
RCLCPP_INFO(this->node_->get_logger(), "aligning front...");
this->changeState(1);
vel = getStateVelocity();
this->pub_cmd_vel_->publish(vel);
}
stopRobot();
}
if (closest_distance_ == .3 && right_distance_ != closest_distance_) {
while (right_distance_ != closest_distance_) {
RCLCPP_INFO(this->node_->get_logger(), "Aligning rightwith Wall..");
this->changeState(2);
vel = getStateVelocity();
this->pub_cmd_vel_->publish(vel);
}
stopRobot();
}
if (right_distance_ == closest_distance_ && closest_distance_ == .3) {
this->running_ = false;
return false;
}
this->running_ = true;
return false;
}
void FindWall::stopRobot(void) {
geometry_msgs::msg::Twist vel;
changeState(0);
vel = getStateVelocity();
this->pub_cmd_vel_->publish(vel);
}
// this function changes the current state based on laser readings
void FindWall::changeState(int state) {
state_ = state;
RCLCPP_INFO(this->node_->get_logger(), "Change to state [%d]", state_);
}
// read the laser scan from the scan topic and set the distance variables equal
// to this value
void FindWall::topic_callback(
const sensor_msgs::msg::LaserScan::SharedPtr msg) {
call_back_hit = true;
RCLCPP_INFO(this->node_->get_logger(), "callback");
front_distance_ = msg->ranges[180];
right_distance_ = msg->ranges[90];
closest_distance_ = msg->range_min;
}
int main(int argc, char *argv[]) {
rclcpp::init(argc, argv);
std::shared_ptr<rclcpp::Node> node = rclcpp::Node::make_shared("FindWall");
RCLCPP_INFO(node->get_logger(), "Start Init FindWall");
FindWall FindWall(node);
rclcpp::spin(node);
rclcpp::Rate loop_rate(20);
bool finished_statemachine = false;
while (rclcpp::ok() && !finished_statemachine) {
finished_statemachine = FindWall.runTimeStateMachine();
loop_rate.sleep();
}
rclcpp::shutdown();
return 0;
}