# basic_bocbot **Repository Path**: verwing/basic_bocbot ## Basic Information - **Project Name**: basic_bocbot - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-10-14 - **Last Updated**: 2024-10-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Build Robot using Robot Operating System (ROS 2) and Gazebo Simulator Step-by-step developer guide to build a robot using [ROS 2](https://index.ros.org/doc/ros2/) (eloquent) and [Gazebo](http://gazebosim.org/). Make sure that you have installed ROS and Gazebo, following links will guide you. - [ROS 2 Eloquent Elusor installation.](https://index.ros.org/doc/ros2/Installation/Eloquent/) **Binary Packages** installation is sufficient for this project, however if interested you can also choose **Building from source.** - [Gazebo installation](http://gazebosim.org/tutorials?cat=install) While this project is build on Ubuntu 18.04, these instruction should also work on Windows 10 if you have ROS 2 and Gazebo installed, as you will learn, APIs, commands and process is same. This guide assumes that you are - Developer with basic knowledge of programming in C++ and Python or - Already knows ROS 1 and want to start with ROS 2, you can skip to [The Robot](#the-robot) below. ### Table of Contents * **[Introduction](#introduction)** * **[Basics](#basics)** * [Robot](#robot) * [ROS](#ROS) * [Gazebo](#gazebo) * **[The Robot](#the-robot)** * **[Setup](#setup)** ## Introduction **Why learn Robotics?** Robots are becoming more and more common. Apart from being pretty common in manufacturing processes, you also see them these days in the form of toys for kids, self operating vacuum cleaners, self driving cars, delivery drones, planet explorers to [humanoid robots](https://en.wikipedia.org/wiki/Sophia_(robot)) becoming citizen and getting award from UN. These are just few examples, and many more to come in future. So its a good idea to learn a thing or two about them! **How to go about it?** Before building an actual robot, you may want to use simulator to test your idea first. Once you are satisfied with your robot in simulation, then you can go on building an actual one. ROS provides you framework to build various components of robots and establish secure communication between them, Gazebo provides simulation facilities to test your algorithms and robot design using realistic scenarios. **What will I learn here?** You will learn how to put ROS and Gazebo together to create a robot with 4-wheels, camera and laser scan sensor and test its operations in a simulated world. Let's get familiar with some basic concepts. ## Basics ### Robot No matter what type of robot you are trying to build, your robot needs to perform three step process of perception, decision and action. * Perception Just like we humans perceive or sense environment around us using our eyes, ears, nose and touch, robots perceive their environment using one or more sensors. Some examples of sensor you may already know are radar, laser scan, camera, lidar, temperature sensor, sonar, chemical detection sensors etc. * Decision Based on inputs from sensors and current state of robot, robot can perform some decision making. Decisions can be as simple as answering weather yes or no question or as complicated as travelling on a path in unknown terrain on different planet. * Action Robot can perform various actions depending on decisions made using input. For example, move from one place to another, move various parts like robot arm, send messages to another robots, speed up, slow down, stop etc. We will see how ROS provide framework to perform these three basic processes. ### ROS Robot Operating System is **not** an operating system like Linux or Windows, rather it is a framework that sits on top of an operating system and provide facilities for developing and running various components of a Robot. Just like Microsoft Foundation Classes (MFC) is a framework to develop and run desktop application on windows in C++, or ASP.Net is a framework to develop and run website. Similarly ROS is a framework and provides facilities and libraries to develop and run a Robot using C++ and Python. ROS 2 is next version of ROS 1. Most of the concepts are still same in ROS 2 however there are significant improvements in design and communications between various component. ROS 2 uses [DDS](https://index.ros.org/doc/ros2/Concepts/DDS-and-ROS-middleware-implementations/). It would be helpful but not required to learn ROS 1. As some of the concepts documentation still at ROS 1 wiki. Below are some useful links to learn about ROS. - [ROS 1 tutorials](http://wiki.ros.org/ROS/Tutorials) - [ROS 2 tutorials](https://index.ros.org/doc/ros2/) - [nodes concept](http://wiki.ros.org/Nodes) - [nodes in ROS 2](https://index.ros.org/doc/ros2/Tutorials/Understanding-ROS2-Nodes/#ros2nodes) - [topics](http://wiki.ros.org/Topics) - [Service/Client](http://wiki.ros.org/Services) - [Publish/Subscribe](https://index.ros.org/doc/ros2/Tutorials/Writing-A-Simple-Cpp-Publisher-And-Subscriber/) - [Quality of Services](https://index.ros.org/doc/ros2/Concepts/About-Quality-of-Service-Settings/) - [build system colcon](https://index.ros.org/doc/ros2/Tutorials/Colcon-Tutorial/) ### Gazebo Gazebo is widely used simulator with ROS. There are many amazing tutorials available online. Below are few link to get started. - http://gazebosim.org/tutorials - https://subscription.packtpub.com/book/hardware_and_creative/9781783554713/1/ch01lvl1sec11/simulators-of-ros Assuming that you are now familiar with ROS and Gazebo, let's put it all together. ## The Robot Goal is to perform some action (drive the robot) based on the input gathered from sensors. We are going to do that in following steps. * Build the simple office environment in gazebo simulator (see images below) * Build the robot that will have (lets call it bocbot - **b**unch **o**f **c**oders **bot**) * Chassis (blue) * 4 wheels (white) * Camera (red) * Laser scan (black) * Write node in C++ to process camera and laser scan input * Write C++ node to send commands to wheels to drive the robot Robot ![Robot](images/robot.png) World ![World](images/world.png) ## Steps **Setup** Open a new terminal and [source your ROS 2 installation](https://index.ros.org/doc/ros2/Tutorials/Configuring-ROS2-Environment/#configros2) so that ros2 commands will work. ```linux $ source /opt/ros/eloquent/setup.bash $ echo $ROS_DISTRO eloquent $ ``` Create Workspace ```linux $ mkdir -p bocbot_ws/src $ cd bocbot_ws/src ``` **1. Building office environment in gazebo simulator** Create bocbot package ```linux $ ros2 pkg create --build-type ament_cmake bocbot going to create a new package package name: bocbot destination directory: /home/trainer/bocbot_ws/src package format: 3 version: 0.0.0 description: TODO: Package description maintainer: ['trainer '] licenses: ['TODO: License declaration'] build type: ament_cmake dependencies: [] creating folder ./bocbot creating ./bocbot/package.xml creating source and include folder creating folder ./bocbot/src creating folder ./bocbot/include/bocbot creating ./bocbot/CMakeLists.txt $ cd bocbot ``` Create directory for world file for office environment ```linux $ mkdir worlds $ cd worlds $ touch bocbot_office.world ``` A world file in Gazebo contains all the objects in the simulated environment. These objects are your robot model, its environment, lighting, sensors, and other objects. Gazebo uses [SDF](http://sdformat.org/) xml file format to save your simulation. The world file usually has a .world extension. Below is basic format of world file. ```xml ... ... ... ... ... ``` Paste following code in `boc_office.world` that contains description of objects in simulation, such as light, ground plane, walls and the white ball, built with **Building Editor**.
boc_office.world (click to expand) ```xml 1 0 0 10 0 -0 0 0.8 0.8 0.8 1 0.2 0.2 0.2 1 1000 0.9 0.01 0.001 -0.5 0.1 -0.9 1 0 0 1 100 100 65535 100 50 10 0 0 0 1 100 100 0 0 0 0 0 -9.8 6e-06 2.3e-05 -4.2e-05 0.001 1 1000 0.4 0.4 0.4 1 0.7 0.7 0.7 1 1 EARTH_WGS84 0 0 0 0 -1.27854 7.44696 0 0 -0 0 4 0.15 2.5 0 0 1.25 0 -0 0 10 0 0 1.25 0 -0 0 4 0.15 2.5 1 1 1 1 0 -7.92943 1.85 0 0 -0 -1.5708 0 0 0 2.5 0.15 2.5 0 0 1.25 0 -0 0 10 0 0 1.25 0 -0 0 2.5 0.15 2.5 0.996078 0.47451 0.0196078 1 0 -0.891787 -0.14494 0 0 -0 -1.5708 0 0 0 2.5 0.15 2.5 0 0 1.25 0 -0 0 10 0 0 1.25 0 -0 0 2.5 0.15 2.5 0.996078 0.47451 0.0196078 1 0 -2.06679 -1.31994 0 0 -0 3.14159 0 0 0 1.75 0.15 2.5 0 0 1.25 0 -0 0 10 0 0 1.25 0 -0 0 1.75 0.15 2.5 0.921569 0.807843 0.615686 1 0 -0.908613 2.9996 0 0 -0 -1.5708 0 0 0 2.75 0.15 2.5 0 0 1.25 0 -0 0 10 0 0 1.25 0 -0 0 2.75 0.15 2.5 0.996078 0.47451 0.0196078 1 0 0.391387 2.19961 0 0 -0 0 0 0 0 1.75 0.15 2.5 0 0 1.25 0 -0 0 10 0 0 1.25 0 -0 0 1.75 0.15 2.5 0.921569 0.807843 0.615686 1 0 2.63138 3.01972 0 0 -0 -1.5708 0 0 0 2.5 0.15 2.5 0 0 1.25 0 -0 0 10 0 0 1.25 0 -0 0 2.5 0.15 2.5 0.996078 0.47451 0.0196078 1 0 3.80638 2.21972 0 0 -0 0 0 0 0 2.5 0.15 2.5 0 0 1.25 0 -0 0 10 0 0 1.25 0 -0 0 2.5 0.15 2.5 0.921569 0.807843 0.615686 1 0 5.74898 2.68495 0 0 -0 -1.5708 0 0 0 2.25 0.15 2.5 0 0 1.25 0 -0 0 10 0 0 1.25 0 -0 0 2.25 0.15 2.5 0.921569 0.807843 0.615686 1 0 6.81909 0.722229 0 0 -0 0 0 0 0 1.75 0.15 2.5 0 0 1.25 0 -0 0 10 0 0 1.25 0 -0 0 1.75 0.15 2.5 0.996078 0.47451 0.0196078 1 0 5.82943 -0.902428 0 0 -0 -1.5708 0 0 0 2.25 0.15 2.5 0 0 1.25 0 -0 0 10 0 0 1.25 0 -0 0 2.25 0.15 2.5 0.921569 0.807843 0.615686 1 0 6.87943 -1.70243 0 0 -0 0 0 0 0 4 0.15 2.5 0 0 1.25 0 -0 0 10 0 0 1.25 0 -0 0 4 0.15 2.5 1 1 1 1 0 -7.92943 -2 0 0 -0 -1.5708 0 0 0 16 0.15 2.5 0 0 1.25 0 -0 0 10 0 0 1.25 0 -0 0 16 0.15 2.5 1 1 1 1 0 -0.004434 -3.925 0 0 -0 0 0 0 0 7.92057 0 0 0 -0 1.5708 -3.92553 0 1.25 0 -0 0 0.148947 0.15 2.5 1 1 1 1 0 0.148947 0.15 2.5 -3.92553 0 1.25 0 -0 0 10 0.524473 0 1.25 0 -0 0 6.95105 0.15 2.5 1 1 1 1 0 6.95105 0.15 2.5 0.524473 0 1.25 0 -0 0 10 -3.40105 0 2.25 0 -0 0 0.9 0.15 0.5 1 1 1 1 0 0.9 0.15 0.5 -3.40105 0 2.25 0 -0 0 10 0 0 0 -0.004434 3.925 0 0 -0 3.14159 -0.655307 0 1.25 0 -0 0 14.6894 0.15 2.5 1 1 1 1 0 14.6894 0.15 2.5 -0.655307 0 1.25 0 -0 0 10 7.79469 0 1.25 0 -0 0 0.410614 0.15 2.5 1 1 1 1 0 0.410614 0.15 2.5 7.79469 0 1.25 0 -0 0 10 7.13939 0 2.25 0 -0 0 0.9 0.15 0.5 1 1 1 1 0 0.9 0.15 0.5 7.13939 0 2.25 0 -0 0 10 0 0 0 3 0.15 2.5 0 0 1.25 0 -0 0 10 0 0 1.25 0 -0 0 3 0.15 2.5 0.996078 0.47451 0.0196078 1 0 -3.24179 2.45506 0 0 -0 -1.5708 0 0 0 2.5 0.15 2.5 0 0 1.25 0 -0 0 10 0 0 1.25 0 -0 0 2.5 0.15 2.5 0.921569 0.807843 0.615686 1 0 -2.06679 1.03006 0 0 -0 0 0 0 0 1 232 785000000 118 702538223 1551031600 831011974 118381 0 0 0 0 -0 0 1 1 1 0 0 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 3.55994 -1.22025 0.1 0.018695 -0 0 1 1 1 3.55994 -1.22025 0.1 0.018695 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 0.673102 -0.134423 0 0 -0 0 1 1 1 -7.25633 1.71558 0 0 0 -1.5708 0 0 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 -0.218688 -0.279363 0 0 0 -1.5708 0 0 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 -1.39369 -1.45436 0 0 -0 3.14159 0 0 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 -0.235508 2.86522 0 0 0 -1.5708 0 0 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 1.06449 2.06519 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 3.30448 2.88532 0 0 0 -1.5708 0 0 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 4.47948 2.0853 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 6.42208 2.55052 0 0 0 -1.5708 0 0 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 7.49219 0.587807 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 6.50253 -1.03685 0 0 0 -1.5708 0 0 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 7.55253 -1.83685 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 -7.25633 -2.13442 0 0 0 -1.5708 0 0 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 0.668672 -4.05942 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 8.59367 -0.134423 0 0 -0 1.5708 0 0 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 0.668672 3.79062 0 0 -0 3.14159 0 0 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 -2.56869 2.32064 0 0 0 -1.5708 0 0 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 -1.39369 0.895637 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 0 0 0 0 -0 0 0 0 10 0 -0 0 15.4065 -7.32713 9.3415 -0 0.531643 2.6842 orbit perspective 1 0.1 0 0 0.1 0 0.1 0 0 0 0 -0 0 -0 -0 0 0 -0 0 1 0 0 0 0 0 0 0 -0 0 0.1 1 __default__ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 10 0 0 0 0 -0 0 0.1 1 1 0 0 0 0 0 1 0 0 1 0 0 1e+06 0 1 1 0 0.2 1e+13 1 0.01 0 1 -0.01 0 0.2 1e+13 1 0 1 3.55994 1.41227 0 0 -0 0 ```
At this point you should be able to launch world in gazebo using ``` linux $ gazebo boc_office.world ``` You should see this. You will later know why white ball is there. ![Robot](images/boc_office.png) Alternatively you can create your own world by following below tutorials. [Building the world](http://gazebosim.org/tutorials?cat=build_world) [Create buildings in the world](http://gazebosim.org/tutorials?cat=build_world&tut=building_editor) Make sure that you save your world file as `boc_office.world` in `bocbot_ws/src/bocbot/worlds` directory. **2. Building the robot** You are now familiar with SDF files to describe objects in simulation. ROS uses Universal Robot Description Format (URDF) to model a robot where various dynamic and kinematic properties are described in xml. [You can learn more here](https://industrial-training-master.readthedocs.io/en/melodic/_source/session3/Intro-to-URDF.html) Simple URDF looks like ```xml ``` As we define various robot elements in URDF, it tends to get very big. To manage various component individually and reuse them, ROS has a package called `xacro` (XML Macro) that enables you to combine different URDF files in one file. It also provides template facility to define variables in these files. We save those files with `.xacro` extension. [You can learn more about XACRO here.](http://wiki.ros.org/xacro) We are going to create two xacro files, one to describe robot and other one describing gazebo plugins briefly explained below, used for interactions in simulation. For gazebo plugins to work, make sure that you have following ROS 2 packages installed. gazebo_dev gazebo_msgs gazebo_plugins gazebo_ros gazebo_ros_pkgs You can check this by running following command ```linux $ ros2 pkg list ``` The set of ROS 2 packages for interfacing with Gazebo are contained within a meta package named gazebo_ros_pkgs In case you need to install them, use following command ```linux $ sudo apt install ros-eloquent-gazebo-ros-pkgs ``` Note: all ros packages follow this convention ros--, note underscores in package name are replaced by dash "-". **Gazebo Plugins** A plugin is a chunk of code that is compiled as a shared library and inserted into the simulation. The plugin has direct access to all the functionality of Gazebo through the standard C++ classes. Plugins are useful because they: * let developers control almost any aspect of Gazebo * are self-contained routines that are easily shared * can be inserted and removed from a running system [You can learn more about plugins here.](http://gazebosim.org/tutorials/?tut=plugins_hello_world) Instead of writing our own, we are going to use existing plugins provided by gazebo_ros_pkgs. We will use 1. Skid steer drive controller to help move wheels of robot independently, provided by `libgazebo_ros_diff_drive.so`, [more details here.](https://github.com/ros-simulation/gazebo_ros_pkgs/wiki/ROS-2-Migration:-Skid-Steer-drive) 2. Camera controller to read images captured by camera in simulation, provided by `libgazebo_ros_camera.so`, [more details here.](https://github.com/ros-simulation/gazebo_ros_pkgs/wiki/ROS-2-Migration:-Camera) 3. Laser scan controller to read point cloud data from laser scanner, provided by `libgazebo_ros_ray_sensor.so`, [more details here.](https://github.com/ros-simulation/gazebo_ros_pkgs/wiki/ROS-2-Migration:-Ray-sensors) You will find these libraries in `/opt/ros/eloquent/lib` directory. We will define various properties required by these controllers in `bocbot.gazebo` file. Create directory for urdf files. ```linux $ cd ~/bocbot_ws/src/bocbot $ mkdir urdf $ cd urdf $ touch bocbot.gazebo ``` Paste following code to `bocbot.gazebo` file
bocbot.gazebo (click to expand) ```xml /bocbot /cmd_vel:=mr_cme_vel /odom:=odom 100.0 2 odom front_left_wheel_joint back_left_wheel_joint 0.4 0.2 front_right_wheel_joint back_right_wheel_joint 0.4 0.2 robot_footprint 20 true true true world 30.0 1 1.3962634 800 800 R8G8B8 0.02 300 0.0 0.0 0.0 0.0 0.0
0.5 0.5
/bocbot camera/image_raw:=/bocbot/camera/image camera/camera_info:=/bocbot/camera/image/camera_info camera camera 0.07
0 0 0 0 0 0 false 40 720 1 -1.570796 1.570796 0.10 30.0 0.01 gaussian 0.0 0.01 30 /bocbot ~/out:=scan sensor_msgs/LaserScan
```
We will now define robot description in `bocbot.urdf.xacro` file. ```linux $ cd urdf $ touch bocbot.urdf.xacro ``` Paste following code to `bocbot.urdf.xacro` file
bocbot.urdf.xacro (click to expand) ```xml 0 0 0.1 0 0 0 Gazebo/Blue Gazebo/Red Gazebo/Black ```
Xacro code explained ![Robot](images/robot_overview.png) Here is what we did above In `bocbot.urdf.xacro` file * We created links for `robot_footprint`, `chassis`, `front_left_wheel`, `front_right_wheel`, `back_left_wheel`, `back_right_wheel` `camera` and `hokuyo` laser sensor * We joint them together by specifying following joints, `robot_footprint_joint` joins `chassis` and `robot_footprint` wheels are attached to `chassis` via `front_left_wheel_joint`, `front_right_wheel_joint`, `back_left_wheel_joint`, `back_right_wheel_joint` `camera` and `hokuyo` are attached to `chassis` via `camera_joint` and `hokuyo_joint` respectively * In the file referenced via xacro using line `` we imported `bocbot.gazebo` file where we specify configuration for plugins. * We specified `libgazebo_ros_diff_drive.so` controller configuration for wheel joint names in our robot, separation between them and diameter, how much torque to produce and how often to publish [odometry](http://www.hmc.edu/lair/ARW/ARW-Lecture01-Odometry.pdf) at `/odom` via update rate. Also specified to listen on `/cmd_vel` topic for any velocity commands. * Similarly for `libgazebo_ros_camera.so` plugin config we specified camera properties and re-mapped original topics published by plugin to publish RGB images at `/bocbot/camera/image` and camera specific info at `/bocbot/camera/image/camera_info`. * Third we configured `libgazebo_ros_ray_sensor.so` to use hokuyo laser sensor and publish data at `/bocbot/scan`. if namespace is not specified `/bocbot` then data will be published at `/scan` topic. Same is true for above plugins. At this point your `~\bocbot_ws\src\bocbot` directory should look like this ```linux . ├── CMakeLists.txt ├── include │   └── bocbot ├── package.xml ├── src ├── urdf │   ├── bocbot.gazebo │   └── bocbot.urdf.xacro └── worlds └── boc_office.world ``` **Invoking xacro from colcon build process** We need to tell build process to invoke xacro tool to generate urdf file from bocbot.urdf.xacro and bocbot.gazebo files. To do so, we need to edit CMakeLists.txt files to specify dependencies. ```cmake # Generate .urdf files from .urdf.xacro files find_package(xacro REQUIRED) # Xacro files file(GLOB xacro_files urdf/*.urdf.xacro) foreach(it ${xacro_files}) # remove .xacro extension string(REGEX MATCH "(.*)[.]xacro$" unused ${it}) set(output_filename ${CMAKE_MATCH_1}) # create a rule to generate ${output_filename} from {it} xacro_add_xacro_file(${it} ${output_filename}) list(APPEND urdf_files ${output_filename}) endforeach(it) # add an abstract target to actually trigger the builds add_custom_target(media_files ALL DEPENDS ${urdf_files}) ``` Also we need to tell build process to install our `urdf`, `worlds` and `meshes` directories to `install` folder. As all your packages are served to ROS environment from your install directory that will be created when we build our package. Following lines in CMakeLists.txt will do that. ```cmake install(DIRECTORY worlds DESTINATION share/${PROJECT_NAME}) install(DIRECTORY urdf DESTINATION share/${PROJECT_NAME}) install(DIRECTORY meshes DESTINATION share/${PROJECT_NAME}) ``` You can copy entire CMakeLists.txt from below
CMakeLists.txt (click to expand) ```cmake cmake_minimum_required(VERSION 3.5) project(bocbot) # 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( REQUIRED) # Generate .urdf files from .urdf.xacro files find_package(xacro REQUIRED) # Xacro files file(GLOB xacro_files urdf/*.urdf.xacro) foreach(it ${xacro_files}) # remove .xacro extension string(REGEX MATCH "(.*)[.]xacro$" unused ${it}) set(output_filename ${CMAKE_MATCH_1}) # create a rule to generate ${output_filename} from {it} xacro_add_xacro_file(${it} ${output_filename}) list(APPEND urdf_files ${output_filename}) endforeach(it) # add an abstract target to actually trigger the builds add_custom_target(media_files ALL DEPENDS ${urdf_files}) 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() install(DIRECTORY worlds DESTINATION share/${PROJECT_NAME}) install(DIRECTORY urdf DESTINATION share/${PROJECT_NAME}) ament_package() ```
At this point you should be able to build your package. If you are using new terminal, make sure to source ros environment. ```linux $ source /opt/ros/eloquent/setup.bash $ cd ~/bocbot_ws $ colcon build Starting >>> bocbot Finished <<< bocbot [1.08s] Summary: 1 package finished [1.15s] $ ``` Notice `bocbot.urdf` file is generated in `urdf` directory after build. To see the robot in gazebo we need to create a launch directory and launch file. You can learn about [launch system in ROS 2 here](https://index.ros.org/doc/ros2/Tutorials/Launch-system/). ```linux $ cd ~/bocbot_ws/src/bocbot $ mkdir launch $ cd launch $ touch world.launch.py ``` In launch file we are going to do two things. 1. launch gazebo with predefined settings and our `boc_office.world` 2. call spawn_entity service provided by gazebo to spawn our robot defined in `bocbot.urdf` in the world. Paste following code to `world.launch.py` it's self-explanatory.
world.launch.py (click to expand) ```python import os from ament_index_python.packages import get_package_share_directory from launch import LaunchDescription from launch.actions import ExecuteProcess, DeclareLaunchArgument from launch_ros.actions import Node from launch.substitutions import LaunchConfiguration # this is the function launch system will look for def generate_launch_description(): robot_name = 'bocbot' world_file_name = 'boc_office.world' # full path to urdf and world file world = os.path.join(get_package_share_directory(robot_name), 'worlds', world_file_name) urdf = os.path.join(get_package_share_directory(robot_name), 'urdf', 'bocbot.urdf') # read urdf contents because to spawn an entity in # gazebo we need to provide entire urdf as string on command line xml = open(urdf, 'r').read() # double quotes need to be with escape sequence xml = xml.replace('"', '\\"') # this is argument format for spwan_entity service spwan_args = '{name: \"bocbot\", xml: \"' + xml + '\" }' # create and return launch description object return LaunchDescription([ # start gazebo, notice we are using libgazebo_ros_factory.so instead of libgazebo_ros_init.so # That is because only libgazebo_ros_factory.so contains the service call to /spawn_entity ExecuteProcess( cmd=['gazebo', '--verbose', world, '-s', 'libgazebo_ros_factory.so'], output='screen'), # tell gazebo to spwan your robot in the world by calling service ExecuteProcess( cmd=['ros2', 'service', 'call', '/spawn_entity', 'gazebo_msgs/SpawnEntity', spwan_args], output='screen'), ]) ```
Add following line to `CMakeLists.txt` to install our launch folder after build. ```cmake install(DIRECTORY launch DESTINATION share/${PROJECT_NAME}) ``` Your final `~\bocbot_ws\src` directory structure should look like this ```linux . └── bocbot ├── CMakeLists.txt ├── include │   └── bocbot ├── launch │   └── world.launch.py ├── package.xml ├── src ├── urdf │   ├── bocbot.gazebo │   ├── bocbot.urdf │   └── bocbot.urdf.xacro └── worlds └── boc_office.world ``` Build and launch ```linux $ cd ~/bocbot_ws $ colcon build ``` We will have to source our bash file before launching robot. Sourcing our workspace bash file will append our package `bocbot` to the existing ros environment we sourced earlier and make it available for various `ros2` commands, like any other ros package. ```linux $ source install/setup.bash $ ros2 launch bocbot world.launch.py ``` Note: You can tab complete all ros2 commands, after typing ros2, press tab to see available options. You should see robot and world as shown in image below. Congratulations! on your own first robot in simulation. Lets see what's up and running. ![World](images/first_run.png) Open new terminal and source ros and our workspace environment. ``` $ source /opt/ros/eloquent/setup.bash $ cd bocbot_ws $ source install/setup.bash $ ros2 node list /bocbot/camera_controller /bocbot/gazebo_ros_head_hokuyo_controller /bocbot/skid_steer_drive_controller /gazebo /launch_ros_14244 $ ``` You can see our three plugins have started nodes for camera, laser scan and skid drive. You can see more information about these nodes using ```linux $ ros2 node info /bocbot/skid_steer_drive_controller /bocbot/skid_steer_drive_controller ======================================================================================== Report : NONE Context : DDS::OpenSplice::DataReader::wait_for_historical_data Date : 2020-02-07T10:42:45-0800 Node : codezilla Process : python3.6 <15390> Thread : main thread 7f6955c32740 Internals : DataReader.cpp/855/6.9.190705OSS///0 Subscribers: /bocbot/cmd_vel: geometry_msgs/msg/Twist /bocbot/parameter_events: rcl_interfaces/msg/ParameterEvent /clock: rosgraph_msgs/msg/Clock ======================================================================================== Report : NONE Context : DDS::OpenSplice::DataReader::wait_for_historical_data Date : 2020-02-07T10:42:45-0800 Node : codezilla Process : python3.6 <15390> Thread : main thread 7f6955c32740 Internals : DataReader.cpp/855/6.9.190705OSS///0 Publishers: /bocbot/odom: nav_msgs/msg/Odometry /bocbot/parameter_events: rcl_interfaces/msg/ParameterEvent /bocbot/rosout: rcl_interfaces/msg/Log /tf: tf2_msgs/msg/TFMessage ======================================================================================== Report : NONE Context : DDS::OpenSplice::DataReader::wait_for_historical_data Date : 2020-02-07T10:42:45-0800 Node : codezilla Process : python3.6 <15390> Thread : main thread 7f6955c32740 Internals : DataReader.cpp/855/6.9.190705OSS///0 Service Servers: /bocbot/skid_steer_drive_controller/describe_parameters: rcl_interfaces/srv/DescribeParameters /bocbot/skid_steer_drive_controller/get_parameter_types: rcl_interfaces/srv/GetParameterTypes /bocbot/skid_steer_drive_controller/get_parameters: rcl_interfaces/srv/GetParameters /bocbot/skid_steer_drive_controller/list_parameters: rcl_interfaces/srv/ListParameters /bocbot/skid_steer_drive_controller/set_parameters: rcl_interfaces/srv/SetParameters /bocbot/skid_steer_drive_controller/set_parameters_atomically: rcl_interfaces/srv/SetParametersAtomically ======================================================================================== Report : NONE Context : DDS::OpenSplice::DataReader::wait_for_historical_data Date : 2020-02-07T10:42:45-0800 Node : codezilla Process : python3.6 <15390> Thread : main thread 7f6955c32740 Internals : DataReader.cpp/855/6.9.190705OSS///0 Service Clients: ======================================================================================== Report : NONE Context : DDS::OpenSplice::DataReader::wait_for_historical_data Date : 2020-02-07T10:42:45-0800 Node : codezilla Process : python3.6 <15390> Thread : main thread 7f6955c32740 Internals : DataReader.cpp/855/6.9.190705OSS///0 Action Servers: ======================================================================================== Report : NONE Context : DDS::OpenSplice::DataReader::wait_for_historical_data Date : 2020-02-07T10:42:45-0800 Node : codezilla Process : python3.6 <15390> Thread : main thread 7f6955c32740 Internals : DataReader.cpp/855/6.9.190705OSS///0 Action Clients: ``` As you can see all the topics this node is publishing to, subscribed to, services provided by this node and to which services this node is acting as client. This skid controller is publishing `/bocbot/odom: nav_msgs/msg/Odometry` , that is, publishing messages of type [nav_msgs::msg::Odometry](http://docs.ros.org/api/nav_msgs/html/msg/Odometry.html) to `/bocbot/odom` and listening for messages of type [geometry_msgs::msgs::Twist](http://wiki.ros.org/geometry_msgs) at `/bocbot/cmd_vel` topic. You can also check which topics are available in system and more information about, use following commands. ```linux $ ros2 topic list /bocbot/camera/image /bocbot/camera/image/camera_info /bocbot/cmd_vel /bocbot/odom /bocbot/parameter_events /bocbot/rosout /bocbot/scan /clock /parameter_events /rosout /tf $ ros2 topic info /bocbot/cmd_vel Type: geometry_msgs/msg/Twist Publisher count: 0 Subscriber count: 1 $ ``` Operating your robot with keyboard You can see our `/bocbot/skid_steer_drive_controller` subscribed to `/bocbot/cmd_vel`, no one is publishing to this topic. Lets send messages to this topic and see if our robot follows these commands. For that we are going to use `teleop_twist_keyboard` package. [You can learn more about it here.](http://wiki.ros.org/teleop_twist_keyboard) Install `teleop_twist_keyboard` ```linux $ sudo apt install ros-eloquent-teleop-twist-keyboard ``` Open new terminal, source ros and our workspace and run follwoing command ```linux $ ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args -r __ns:=/bocbot ``` While maintaining keyboard focus on this window, you can use keys `i` to move forward and `j` to stop. See your robot moves in the gazebo environment. Play around with other keystrokes. Next we are going to write our own nodes in C++ to process images and drive bocbot! //todo ball chaser package drive bot process image RVIZ Further improvements Useful links https://discourse.ros.org/t/new-ros-online-course-for-beginner/5320 [ROS 1 Course](https://www.youtube.com/playlist?list=PLRG6WP3c31_U7TFGduEIJWVtkOw6AJjFf) Many tutorials are available online, free and paid, but they are mostly for ROS 1 as ROS 2 is relatively new. On ROS 2 website there are amazing [tutorials](https://index.ros.org/doc/ros2/Tutorials/) about each facility provided by ROS, when you are ready to learn more in detail.