# Default to C99 if(NOT CMAKE_C_STANDARD) set(CMAKE_C_STANDARD 99) endif()
# Default to C++17 if(NOT CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD 17) endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compile_options(-Wall -Wextra -Wpedantic) endif()
# find dependencies find_package(ament_cmake REQUIRED) # uncomment the following section in order to fill in # further dependencies manually. # find_package(<dependency> REQUIRED) find_package(rclcpp REQUIRED) find_package(gazebo_msgs REQUIRED) find_package(ament_index_cpp REQUIRED)
if(BUILD_TESTING) find_package(ament_lint_auto REQUIRED) # the following line skips the linter which checks for copyrights # uncomment the line when a copyright and license is not present in all source files #set(ament_cmake_copyright_FOUND TRUE) # the following line skips cpplint (only works in a git repo) # uncomment the line when this package is not in a git repo #set(ament_cmake_cpplint_FOUND TRUE) ament_lint_auto_find_test_dependencies() endif()
// Show progress in the terminal window RCLCPP_INFO(node->get_logger(), "Creating Service client to connect to '/spawn_entity'"); // Create SpawnEntity // rclcpp::Client<gazebo_msgs::srv::SpawnEntity>::SharedPtr client = node->create_client<gazebo_msgs::srv::SpawnEntity>("/spawn_entity"); auto client = node->create_client<gazebo_msgs::srv::SpawnEntity>("/spawn_entity");
// Get the spawn_entity service RCLCPP_INFO(node->get_logger(), "Connecting to '/spawn_entity' service..."); while (!client->wait_for_service(1s)) { if (!rclcpp::ok()) { RCLCPP_INFO(node->get_logger(), "spawn client was interrupted while \ waiting for the service. Exiting."); return 0; } RCLCPP_INFO(node->get_logger(), "Service not available, waiting again..."); }
// Get the file path for the robot model // may throw PackageNotFoundError exception string package_share_directory = ament_index_cpp::get_package_share_directory("warehouse_robot_spawner_pkg"); fs::path dir(package_share_directory); fs::path sdfFilePath = dir / fs::path("models") / fs::path("mobile_warehouse_robot") / fs::path("model.sdf"); cout << "robt_sdf = " << sdfFilePath << endl; // Get the content of robot sdf file ifstream sdfFile(sdfFilePath); string line; stringstream buffer; if (sdfFile.is_open()) { buffer << sdfFile.rdbuf(); // cout << "buffer = " << buffer.str() << endl; sdfFile.close(); } else { cout << "======== open sdf failed ========" << endl; }
# Copyright 2019 Open Source Robotics Foundation, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License.
""" Demo for spawn_entity. Launches Gazebo and spawns a model """ # A bunch of software packages that are needed to launch ROS2 import os from launch import LaunchDescription from launch.actions import IncludeLaunchDescription from launch.launch_description_sources import PythonLaunchDescriptionSource from launch.substitutions import ThisLaunchFileDir,LaunchConfiguration from launch_ros.actions import Node from launch.actions import ExecuteProcess from ament_index_python.packages import get_package_share_directory
#GAZEBO_MODEL_PATH has to be correctly set for Gazebo to be able to find the model #spawn_entity = Node(package='gazebo_ros', node_executable='spawn_entity.py', # arguments=['-entity', 'demo', 'x', 'y', 'z'], # output='screen') spawn_entity = Node(package='cpp_warehouse_robot_spawner_pkg', executable='client', arguments=['WarehouseBot', 'demo', '-1.5', '-4.0', '0.0'], output='screen')
# Default to C99 if(NOT CMAKE_C_STANDARD) set(CMAKE_C_STANDARD 99) endif()
# Default to C++14 if(NOT CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD 14) endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compile_options(-Wall -Wextra -Wpedantic) endif()
# find dependencies find_package(ament_cmake REQUIRED) # uncomment the following section in order to fill in # further dependencies manually. # find_package(<dependency> REQUIRED) find_package(geometry_msgs REQUIRED) find_package(rclcpp REQUIRED) find_package(nav_msgs REQUIRED) find_package(std_msgs REQUIRED) find_package(sensor_msgs)
if(BUILD_TESTING) find_package(ament_lint_auto REQUIRED) # the following line skips the linter which checks for copyrights # uncomment the line when a copyright and license is not present in all source files #set(ament_cmake_copyright_FOUND TRUE) # the following line skips cpplint (only works in a git repo) # uncomment the line when this package is not in a git repo #set(ament_cmake_cpplint_FOUND TRUE) ament_lint_auto_find_test_dependencies() endif()
class RobotEstimator: public rclcpp::Node { public: RobotEstimator() : Node("Estimator") { auto default_qos = rclcpp::QoS(rclcpp::SystemDefaultsQoS()); // Subscribe to messages of type nav_msgs/Odometry(positon and orientation of robot) odom_sub_ = this->create_subscription<nav_msgs::msg::Odometry>( "/demo/odom", default_qos, std::bind(&RobotEstimator::OnOdomMsg, this, _1));
// This node subscribes to messages of tpye geometry_msgs/Twist.msg // We are listening to the velocity commands here // The maximum number of queued messages is 10 velocity_sub_ = this->create_subscription<geometry_msgs::msg::Twist>( "demo/cmd_vel", default_qos, std::bind(&RobotEstimator::OnVelocityMsg, this, _1));
// This node Pulbishes the estimated position (x, y, yaw), // the type of messages is std_msg/Float64MultiArray est_state_pub_ = this->create_publisher<std_msgs::msg::Float64MultiArray>("/demo/state_est", default_qos);
void OnVelocityMsg(const geometry_msgs::msg::Twist::SharedPtr msg) { /* Listen to the velocity commands (linear forward velocity in the x direction in the robot's reference frame and angular velocity (yaw rate) around the robot's z-axis. [v,yaw_rate] [meters/second, radians/second] */ // Forward velocity in the robot's reference frame auto v = msg->linear.x; // Angular velocity around the robot's z axis auto yaw_rate = msg->angular.z; }
// void OnSensorMsg(const sensor_msgs::msg::LaserScan::SharedPtr _msg) // { // // Find closest hit // float min_range = _msg->range_max + 1; // int idx = -1; // for (auto i = 0u; i < _msg->ranges.size(); ++i) { // auto range = _msg->ranges[i]; // if (range > _msg->range_min && range < _msg->range_max && range < min_range) { // min_range = range; // idx = i; // } // }
using namespace std; using namespace std::placeholders;
class RobotController : public rclcpp::Node { public: RobotController() : Node("Controller") { auto default_qos = rclcpp::QoS(rclcpp::SystemDefaultsQoS()); // This node subscribes to messages of type Float64MultiArray // over a topic named: /demo/state_est // The message represents the current estimated state: // [x, y, yaw] est_state_sub_ = this->create_subscription<std_msgs::msg::Float64MultiArray>( "/demo/state_est", default_qos, std::bind(&RobotController::OnStateEstimatedMsg, this, _1));
// This node publishes the desired linear and angular velocity of the // robot(in the robot chassis coordinate frame) to the /demo/cmd_vel topic // Using the diff_drive plugin enables the robot model to read this // /demo/cmd_vel topic and excute the motion accordingly cmd_pub_ = this->create_publisher<geometry_msgs::msg::Twist>( "/demo/cmd_vel", default_qos); } private: void OnStateEstimatedMsg(const std_msgs::msg::Float64MultiArray::SharedPtr msg) { // Extract the position and orientation data // This callback is called each time a new messaege is received on // "/demo/state_est" topic vector<double> currState(msg->data.begin(), msg->data.end()); currentX_ = msg->data[0]; currentY_ = msg->data[1]; currentYaw_ = msg->data[2]; // Command the robot to keep following the wall FollowWall(); }
void OnSensorMsg(const sensor_msgs::msg::LaserScan::SharedPtr msg) { // This method gets called every time a LaserScan message is received on // the "/demo/laser/out" topic // Read the laser scan data that indicates distances // to obstacles in meters and extract 5 distinct laser readings to work with. // Each reading is separated by 45 degrees. // Assumes 181 laser readings, separated by 1 degree. // (e.g. -90 to 90 degrees.....0 to 180 degrees)
void FollowWall() { // This method causes the robot to follow the boundary of a wall. // Create a geometry_msgs/Twist message auto cmdMsg = std::make_unique<geometry_msgs::msg::Twist>();
cmdMsg->linear.x = 0.0; cmdMsg->linear.y = 0.0; cmdMsg->linear.z = 0.0; cmdMsg->angular.x = 0.0; cmdMsg->angular.y = 0.0; cmdMsg->angular.z = 0.0; // Logic for following the wall // >d means no wall detected by that laser beam // <d means an wall was detected by that laser beam double d = dist_thresh_wf; if (leftfront_dist > d && front_dist > d && rightfront_dist > d) { wall_following_state = "search for wall"; cmdMsg->linear.x = forward_speed; cmdMsg->angular.z = (-1) * turning_speed_wf_slow; //turn right to wall } else if (leftfront_dist > d && front_dist < d && rightfront_dist > d) { wall_following_state = "turn left"; cmdMsg->angular.z = turning_speed_wf_fast; } else if (leftfront_dist > d && front_dist > d && rightfront_dist < d) { if (rightfront_dist < dist_too_close_to_wall) { // Getting too close to the wall wall_following_state = "turn left"; cmdMsg->linear.x = forward_speed; cmdMsg->angular.z = turning_speed_wf_fast; } else { // Go straight ahead wall_following_state = "follow wall"; cmdMsg->linear.x = forward_speed; } } else if (leftfront_dist < d && front_dist > d && rightfront_dist > d) { wall_following_state = "search for wall"; cmdMsg->linear.x = forward_speed; cmdMsg->angular.z = (-1) * turning_speed_wf_slow; // turn right to find wall } else if (leftfront_dist > d && front_dist < d && rightfront_dist < d) { wall_following_state = "turn left"; cmdMsg->angular.z = turning_speed_wf_fast; } else if (leftfront_dist < d && front_dist < d && rightfront_dist > d) { wall_following_state = "turn left"; cmdMsg->angular.z = turning_speed_wf_fast; } else if (leftfront_dist < d && front_dist < d && rightfront_dist < d) { wall_following_state = "turn left"; cmdMsg->angular.z = turning_speed_wf_fast; } else if (leftfront_dist < d && front_dist > d && rightfront_dist < d) { wall_following_state = "search for wall"; cmdMsg->linear.x = forward_speed; cmdMsg->angular.z = (-1) * turning_speed_wf_slow; // turn right to find wall } else { // do nothing } // Send velocity command to the robot cmd_pub_->publish(std::move(cmdMsg)); }
// Initialize the LaserScan sensor readings to some large value // Values are in meters. double left_dist = 999999.9; // Left double leftfront_dist = 999999.9; // Left-front double front_dist = 999999.9; // Front double rightfront_dist = 999999.9; // Right-front double right_dist = 999999.9; // Right /* ################### ROBOT CONTROL PARAMETERS ################## */ // Maximum forward speed of the robot in meters per second // Any faster than this and the robot risks falling over. double forward_speed = 0.025;
// Current position and orientation of the robot in the global reference frame double currentX_{0.0}; double currentY_{0.0}; double currentYaw_{0.0};
/* ############# WALL FOLLOWING PARAMETERS ####################### */ // Finite states for the wall following mode // "turn left": Robot turns towards the left // "search for wall": Robot tries to locate the wall // "follow wall": Robot moves parallel to the wall string wall_following_state = "turn left"; // Set turning speeds (to the left) in rad/s // These values were determined by trial and error. double turning_speed_wf_fast = 3.0; // Fast turn double turning_speed_wf_slow = 0.05; // Slow turn // Wall following distance threshold. // We want to try to keep within this distance from the wall. double dist_thresh_wf = 0.50; // in meters
// We don't want to get too close to the wall though. double dist_too_close_to_wall = 0.19; // in meters };
int main(int argc, char * argv[]) { // Forward command line arguments to ROS rclcpp::init(argc, argv);
// Create a node auto node = std::make_shared<RobotController>();