[ROS Q&A] 191 – How to Launch the Parrot Drone Simulation Locally

[ROS Q&A] 191 – How to Launch the Parrot Drone Simulation Locally

Welcome to the ROS Q&A series again. In this post, we are going to answer and solve a question from a user on Gazebo Answers which asks how to launch a Parrot Drone simulation locally. The question can be found here.

What will you learn in this post

  • How to spawn a drone simulation in your local computer

List of resources referenced in this post

Downloading the required materials

Before downloading the repositories, let’s first create a catkin workspace for the parrot drone, which we will call parrot_ws. Let’s do that with the commands below:

mkdir -p ~/parrot_ws/src
cd ~/parrot_ws/

Now we have the parrot_ws (parrot workspace). Let’s then download the required git repositories which contain the simulation:

cd ~/parrot_ws/src
git clone --branch kinetic-gazebo7 https://bitbucket.org/theconstructcore/parrot_ardrone.git
git clone https://bitbucket.org/theconstructcore/spawn_robot_tools.git

You should now have the folders parrot_ardrone and spawn_robot_tools on the ~/parrot_ws/src folder.

Installing ignition-math, used by sjtu_drone

Before compiling the packages we downloaded in the previous step, we will need to install the Ignition Math library, which is used by the sjtu_drone drone found on the parrot_ardrone repository we cloned previously.

We can install the Ignition Math library with the following commands:

sudo sh -c 'echo "deb http://packages.osrfoundation.org/gazebo/ubuntu-stable `lsb_release -cs` main" > /etc/apt/sources.list.d/gazebo-stable.list'
wget http://packages.osrfoundation.org/gazebo.key -O - | sudo apt-key add -
sudo apt-get update
sudo apt-get install libignition-math4-dev -y

Now that we have the Ignition Math library installed, we can proceed to compile the packages in our workspace.

Compiling the drone package

Now that we have everything in place, we can compile our packages we downloaded previously.

IMPORTANT: it may happen that when compiling the package, catkin_make can’t find the ignition library, so we need to export the CXXFLAGS accordingly. In my local computer, the ignition library is found at /usr/include/ignition/math4, so to compile we use the following commands:

cd ~/parrot_ws

export CXXFLAGS=-isystem\ /usr/include/ignition/math4

source /opt/ros/kinetic/setup.bash

catkin_make

If everything worked as expected, great. If not, try removing the devel and build first with cd ~/parrot_ws/; rm -rf build/ devel/  and compile it again with the commands exemplified above.

If everything went ok, you should have something like:

root@79e5b2505ede:~/parrot_ws# export CXXFLAGS=-isystem\ /usr/include/ignition/math4 
root@79e5b2505ede:~/parrot_ws# source /opt/ros/kinetic/setup.bash; catkin_make
Base path: /root/parrot_ws
Source space: /root/parrot_ws/src
Build space: /root/parrot_ws/build
Devel space: /root/parrot_ws/devel
Install space: /root/parrot_ws/install
####
#### Running command: "cmake /root/parrot_ws/src -DCATKIN_DEVEL_PREFIX=/root/parrot_ws/devel -DCMAKE_INSTALL_PREFIX=/root/parrot_ws/install -G Unix Makefiles" in "/root/parrot_ws/build"
####
...
-- catkin 0.7.14
-- BUILD_SHARED_LIBS is on
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- ~~  traversing 6 packages in topological order:
-- ~~  - custom_teleop
-- ~~  - drone_demo
-- ~~  - ardrone_as
-- ~~  - sjtu_drone
-- ~~  - spawn_robot_tools_pkg
-- ~~  - drone_construct
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- +++ processing catkin package: 'custom_teleop'
-- ==> add_subdirectory(parrot_ardrone/custom_teleop)
-- +++ processing catkin package: 'drone_demo'
-- ==> add_subdirectory(parrot_ardrone/drone_demo)
-- +++ processing catkin package: 'ardrone_as'
-- ==> add_subdirectory(parrot_ardrone/ardrone_as)
-- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy
-- Generating .msg files for action ardrone_as/Ardrone /root/parrot_ws/src/parrot_ardrone/ardrone_as/action/Ardrone.action
Generating for action Ardrone
-- ardrone_as: 7 messages, 0 services
-- +++ processing catkin package: 'sjtu_drone'
-- ==> add_subdirectory(parrot_ardrone/sjtu_drone)
-- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy
-- Boost version: 1.58.0
-- Found the following Boost libraries:
--   thread
--   signals
--   system
--   filesystem
--   program_options
--   regex
--   iostreams
--   date_time
--   chrono
--   atomic
-- Found Protobuf: /usr/lib/x86_64-linux-gnu/libprotobuf.so  
...
-- Generating done
-- Build files have been written to: /root/parrot_ws/build
####
#### Running command: "make -j4 -l4" in "/root/parrot_ws/build"
####
Scanning dependencies of target _ardrone_as_generate_messages_check_deps_ArdroneActionFeedback
Scanning dependencies of target _ardrone_as_generate_messages_check_deps_ArdroneGoal
Scanning dependencies of target _ardrone_as_generate_messages_check_deps_ArdroneActionGoal
Scanning dependencies of target _ardrone_as_generate_messages_check_deps_ArdroneResult
[  0%] Built target _ardrone_as_generate_messages_check_deps_ArdroneResult
...
Scanning dependencies of target plugin_drone
[  1%] Building CXX object parrot_ardrone/sjtu_drone/CMakeFiles/plugin_ros_cam.dir/src/plugin_ros_cam.cpp.o
[  3%] Building CXX object parrot_ardrone/sjtu_drone/CMakeFiles/plugin_ros_imu.dir/src/plugin_ros_imu_native.cpp.o
[  5%] Building CXX object parrot_ardrone/sjtu_drone/CMakeFiles/plugin_drone.dir/src/plugin_drone.cpp.o
[  7%] Building CXX object parrot_ardrone/sjtu_drone/CMakeFiles/plugin_ros_sonar.dir/src/plugin_ros_sonar.cpp.o
...
[  9%] Linking CXX shared library /root/parrot_ws/src/parrot_ardrone/sjtu_drone/plugins/libplugin_ros_imu.so
[ 11%] Linking CXX shared library /root/parrot_ws/src/parrot_ardrone/sjtu_drone/plugins/libplugin_ros_sonar.so
[ 11%] Built target plugin_ros_sonar
[ 13%] Building CXX object parrot_ardrone/sjtu_drone/CMakeFiles/plugin_ros_cam.dir/src/util_ros_cam.cpp.o
[ 13%] Built target plugin_ros_imu
Scanning dependencies of target plugin_ros_init
[ 15%] Building CXX object parrot_ardrone/sjtu_drone/CMakeFiles/plugin_ros_init.dir/src/plugin_ros_init.cpp.o
[ 17%] Building CXX object parrot_ardrone/sjtu_drone/CMakeFiles/plugin_drone.dir/src/pid_controller.cpp.o
[ 19%] Linking CXX shared library /root/parrot_ws/src/parrot_ardrone/sjtu_drone/plugins/libplugin_drone.so
[ 19%] Built target plugin_drone
Scanning dependencies of target spawn_drone
[ 21%] Building CXX object parrot_ardrone/sjtu_drone/CMakeFiles/spawn_drone.dir/src/spawn_drone.cpp.o
...
[ 23%] Linking CXX executable /root/parrot_ws/src/parrot_ardrone/sjtu_drone/bin/spawn_drone
[ 23%] Built target spawn_drone
Scanning dependencies of target spawn_robot_tools_pkg_xacro_generated_to_devel_space_
[ 23%] Built target spawn_robot_tools_pkg_xacro_generated_to_devel_space_
Scanning dependencies of target ardrone_as_generate_messages_cpp
[ 25%] Generating C++ code from ardrone_as/ArdroneFeedback.msg
[ 27%] Generating C++ code from ardrone_as/ArdroneActionResult.msg
[ 29%] Generating C++ code from ardrone_as/ArdroneAction.msg
[ 31%] Generating C++ code from ardrone_as/ArdroneResult.msg
[ 33%] Generating C++ code from ardrone_as/ArdroneActionGoal.msg
[ 35%] Generating C++ code from ardrone_as/ArdroneGoal.msg
[ 37%] Generating C++ code from ardrone_as/ArdroneActionFeedback.msg
Scanning dependencies of target ardrone_as_generate_messages_py
[ 37%] Built target ardrone_as_generate_messages_cpp
[ 39%] Generating Python from MSG ardrone_as/ArdroneFeedback
Scanning dependencies of target ardrone_as_generate_messages_nodejs
[ 41%] Generating Javascript code from ardrone_as/ArdroneFeedback.msg
[ 43%] Generating Javascript code from ardrone_as/ArdroneActionResult.msg
[ 47%] Generating Javascript code from ardrone_as/ArdroneAction.msg
[ 47%] Generating Python from MSG ardrone_as/ArdroneActionResult
[ 49%] Generating Javascript code from ardrone_as/ArdroneResult.msg
[ 50%] Generating Javascript code from ardrone_as/ArdroneActionGoal.msg
[ 52%] Generating Python from MSG ardrone_as/ArdroneAction
[ 54%] Generating Javascript code from ardrone_as/ArdroneGoal.msg
[ 56%] Generating Javascript code from ardrone_as/ArdroneActionFeedback.msg
[ 58%] Generating Python from MSG ardrone_as/ArdroneResult
[ 58%] Built target ardrone_as_generate_messages_nodejs
Scanning dependencies of target ardrone_as_generate_messages_eus
[ 60%] Generating EusLisp code from ardrone_as/ArdroneFeedback.msg
[ 62%] Generating EusLisp code from ardrone_as/ArdroneActionResult.msg
[ 64%] Generating Python from MSG ardrone_as/ArdroneActionGoal
[ 66%] Generating EusLisp code from ardrone_as/ArdroneAction.msg
[ 68%] Generating Python from MSG ardrone_as/ArdroneGoal
[ 70%] Generating EusLisp code from ardrone_as/ArdroneResult.msg
[ 72%] Generating EusLisp code from ardrone_as/ArdroneActionGoal.msg
[ 74%] Generating Python from MSG ardrone_as/ArdroneActionFeedback
[ 76%] Generating EusLisp code from ardrone_as/ArdroneGoal.msg
[ 78%] Generating EusLisp code from ardrone_as/ArdroneActionFeedback.msg
[ 80%] Generating Python msg __init__.py for ardrone_as
[ 82%] Generating EusLisp manifest code for ardrone_as
[ 82%] Built target ardrone_as_generate_messages_py
Scanning dependencies of target ardrone_as_generate_messages_lisp
[ 84%] Generating Lisp code from ardrone_as/ArdroneFeedback.msg
[ 86%] Generating Lisp code from ardrone_as/ArdroneActionResult.msg
[ 88%] Generating Lisp code from ardrone_as/ArdroneAction.msg
[ 90%] Generating Lisp code from ardrone_as/ArdroneResult.msg
[ 92%] Generating Lisp code from ardrone_as/ArdroneActionGoal.msg
[ 94%] Generating Lisp code from ardrone_as/ArdroneGoal.msg
[ 96%] Generating Lisp code from ardrone_as/ArdroneActionFeedback.msg
[ 96%] Built target ardrone_as_generate_messages_lisp
[ 96%] Built target ardrone_as_generate_messages_eus
Scanning dependencies of target ardrone_as_generate_messages
[ 96%] Built target ardrone_as_generate_messages
...
[ 98%] Linking CXX shared library /root/parrot_ws/src/parrot_ardrone/sjtu_drone/plugins/libplugin_ros_cam.so
[ 98%] Built target plugin_ros_cam
[100%] Linking CXX shared library /root/parrot_ws/src/parrot_ardrone/sjtu_drone/plugins/libplugin_ros_init.so
[100%] Built target plugin_ros_init

Once the package is compiled, in every shell you need to source the parrot_ws so that ROS can find the compiled packages. In each shell you can run the commands below:

cd ~/parrot_ws/
source devel/setup.bash
rospack profile

Launching the simulation

Now that you have everything in place, you should be able to launch the simulation with the command below:

source ~/parrot_ws/devel/setup.bash

rosrun drone_construct start_simulation_localy.sh

That is it. You should now have something like the image below:

drone_construct simulation in ROSDS

drone_construct simulation in ROSDS

 

Moving the drone around

With the simulation running, you should now be able to make the robot take off, be able to move it and then make it land using the commands below:

rostopic pub /drone/takeoff std_msgs/Empty "{}"
rostopic pub /drone/land std_msgs/Empty "{}"

rostopic pub /drone/takeoff std_msgs/Empty "{}"
rosrun teleop_twist_keyboard teleop_twist_keyboard.py

After running rosrun teleop_twist_keyboard teleop_twist_keyboard.py you can easily move the robot using the keyboard.

So that is the post for today. You can also find a live version of this post on our YouTube channel in the link below. Also, please consider subscribing to our channel if you liked the content and press the bell for a new video every day.

 

Related course:

 

 

#drone #parrot #Simulation #Gazebo #Robot #rostutorials #Ubuntu

Post Edited by Miguel, Yuhong and Ruben.

[ROS Q&A] 190 – Air Drag in Gazebo

[ROS Q&A] 190 – Air Drag in Gazebo

What will you learn in this post

  • How to create a Gazebo plugin to generate dragging when a model moves.
  • How to create a simple propulsion system plugin

List of resources used in this post

Start the provided ROSject

The first thing you need to do is to have a copy of the ROSject we mentioned above. Click on the link to get an automatic copy. You should now see a ROSject called BuoyancyBot on your list of ROSjects, something like the image below:

BuoyancyBot simulation on ROSDS

BuoyancyBot simulation on ROSDS

After clicking on the Open button to open the ROSject, you should have the environment like the one in the image below:

BuoyancyBot opened on ROSDS

BuoyancyBot opened on ROSDS

Finding the code

After opening the ROSject, you can see the code on the ~/simulation_ws/src folder. There you will find the folders buoyancy_tests_pkg and spawn_robot_tools. It is worth mentioning that the plugin we created is called fluid_resitance.cpp, which has the content below. Bear in mind that you can find that code on the ROSject:

#include "ros/callback_queue.h"
#include "ros/ros.h"
#include "ros/subscribe_options.h"
#include "std_msgs/Float32.h"
#include <functional>
#include <gazebo/common/common.hh>
#include <gazebo/gazebo.hh>
#include <gazebo/msgs/msgs.hh>
#include <gazebo/physics/physics.hh>
#include <gazebo/transport/transport.hh>
#include <ignition/math/Vector3.hh>
#include <thread>

namespace gazebo {
class FluidResitance : public ModelPlugin {
public:
  void Load(physics::ModelPtr _parent, sdf::ElementPtr _sdf) {

    if (_sdf->HasElement("fluid_resitanceTopicName")) {
      this->fluid_resitanceTopicName =
          _sdf->Get<std::string>("fluid_resitanceTopicName");
    } else {
      ROS_WARN("No Topic Given name given, setting default name %s",
               this->fluid_resitanceTopicName.c_str());
    }

    if (_sdf->HasElement("NameLinkToApplyResitance")) {
      this->NameLinkToApplyResitance =
          _sdf->Get<std::string>("NameLinkToApplyResitance");
    } else {
      ROS_WARN("No NameLinkToApplyResitance Given name given, setting default "
               "name %s",
               this->NameLinkToApplyResitance.c_str());
    }

    if (_sdf->HasElement("rate")) {
      this->rate = _sdf->Get<double>("rate");
    } else {
      ROS_WARN("No rate Given name given, setting default "
               "name %f",
               this->rate);
    }

    // Store the pointer to the model
    this->model = _parent;
    this->world = this->model->GetWorld();
    this->link_to_apply_resitance =
        this->model->GetLink(this->NameLinkToApplyResitance);

    // Listen to the update event. This event is broadcast every
    // simulation iteration.
    this->updateConnection = event::Events::ConnectWorldUpdateBegin(
        std::bind(&FluidResitance::OnUpdate, this));

    // Create a topic name
    // std::string fluid_resitance_index_topicName = "/fluid_resitance_index";

    // Initialize ros, if it has not already bee initialized.
    if (!ros::isInitialized()) {
      int argc = 0;
      char **argv = NULL;
      ros::init(argc, argv, "model_mas_controler_rosnode",
                ros::init_options::NoSigintHandler);
    }

    // Create our ROS node. This acts in a similar manner to
    // the Gazebo node
    this->rosNode.reset(new ros::NodeHandle("model_mas_controler_rosnode"));

#if (GAZEBO_MAJOR_VERSION >= 8)
    this->last_time = this->world->SimTime().Float();
#else
    this->last_time = this->world->GetSimTime().Float();
#endif

    // Freq
    ros::SubscribeOptions so = ros::SubscribeOptions::create<std_msgs::Float32>(
        this->fluid_resitanceTopicName, 1,
        boost::bind(&FluidResitance::OnRosMsg, this, _1), ros::VoidPtr(),
        &this->rosQueue);
    this->rosSub = this->rosNode->subscribe(so);

    // Spin up the queue helper thread.
    this->rosQueueThread =
        std::thread(std::bind(&FluidResitance::QueueThread, this));

    ROS_WARN("Loaded FluidResitance Plugin with parent...%s, With Fluid "
             "Resitance = %f "
             "Started ",
             this->model->GetName().c_str(), this->fluid_resitance_index);
  }

  // Called by the world update start event
public:
  void OnUpdate() {
    float period = 1.0 / this->rate;

    // Get simulator time
#if (GAZEBO_MAJOR_VERSION >= 8)
    float current_time = this->world->SimTime().Float();
#else
    float current_time = this->world->GetSimTime().Float();
#endif
    float dt = current_time - this->last_time;

    if (dt <= period){
        ROS_DEBUG(">>>>>>>>>>TimePassed = %f, TimePeriod =%f ",dt, period);
        return;
    }else{
        this->last_time = current_time;
        this->ApplyResitance();
    }


  }

public:
  void SetResitance(const double &_force) {
    this->fluid_resitance_index = _force;
    ROS_WARN("model_fluid_resitance_index changed >> %f",
             this->fluid_resitance_index);
  }

  void UpdateLinearVel() {
#if (GAZEBO_MAJOR_VERSION >= 8)
    this->now_lin_vel = this->model->RelativeLinearVel();
#else
    this->now_lin_vel = this->model->GetRelativeLinearVel();
#endif
  }

  void ApplyResitance() {

    this->UpdateLinearVel();

#if (GAZEBO_MAJOR_VERSION >= 8)
    ignition::math::Vector3d force, torque;
#else
    math::Vector3 force, torque;
#endif

    ROS_WARN("LinearSpeed = [%f,%f,%f] ",this->now_lin_vel.x, this->now_lin_vel.y, this->now_lin_vel.z);

    force.x = -1.0 * this->fluid_resitance_index * this->now_lin_vel.x;
    force.y = -1.0 * this->fluid_resitance_index * this->now_lin_vel.y;
    force.z = -1.0 * this->fluid_resitance_index * this->now_lin_vel.z;

    // Changing the mass
    this->link_to_apply_resitance->AddRelativeForce(force);
#if (GAZEBO_MAJOR_VERSION >= 8)
    this->link_to_apply_resitance->AddRelativeTorque(
        torque -
        this->link_to_apply_resitance->GetInertial()->CoG().Cross(force));
#else
    this->link_to_apply_resitance->AddRelativeTorque(
        torque -
        this->link_to_apply_resitance->GetInertial()->GetCoG().Cross(force));
#endif

    ROS_WARN("FluidResitanceApplying = [%f,%f,%f] ",force.x, force.y, force.z);
  }

public:
  void OnRosMsg(const std_msgs::Float32ConstPtr &_msg) {
    this->SetResitance(_msg->data);
  }

  /// \brief ROS helper function that processes messages
private:
  void QueueThread() {
    static const double timeout = 0.01;
    while (this->rosNode->ok()) {
      this->rosQueue.callAvailable(ros::WallDuration(timeout));
    }
  }

  // Pointer to the model
private:
  physics::ModelPtr model;

  // Pointer to the update event connection
private:
  event::ConnectionPtr updateConnection;

  // Mas of model
  double fluid_resitance_index = 1.0;

  /// \brief A node use for ROS transport
private:
  std::unique_ptr<ros::NodeHandle> rosNode;

  /// \brief A ROS subscriber
private:
  ros::Subscriber rosSub;
  /// \brief A ROS callbackqueue that helps process messages
private:
  ros::CallbackQueue rosQueue;
  /// \brief A thread the keeps running the rosQueue
private:
  std::thread rosQueueThread;

  /// \brief A ROS subscriber
private:
  physics::LinkPtr link_to_apply_resitance;

private:
  std::string fluid_resitanceTopicName = "fluid_resitance";

private:
  std::string NameLinkToApplyResitance = "base_link";

private:
#if (GAZEBO_MAJOR_VERSION >= 8)
  ignition::math::Vector3d now_lin_vel;
#else
  math::Vector3 now_lin_vel;
#endif

private:
  double rate = 1.0;

private:
  float last_time = 0.0;

private:
  /// \brief The parent World
  physics::WorldPtr world;
};

// Register this plugin with the simulator
GZ_REGISTER_MODEL_PLUGIN(FluidResitance)
} // namespace gazebo

Compile the plugin

Once you have the ROSject, be it on ROSDS or on your own computer, you can easily compile it with:

cd ~/simulation_ws/

catkin_make

Everything should have compiled without any problems. If compiling in your own computer raises errors, please remember running the command source /opt/ros/kinetic/setup.bash before calling catkin_make .

Using the plugin

The plugin we compiled previously has to be loaded by gazebo. We do that on the file

~/simulation_ws/src/buoyancy_tests_pkg/buoyancy_tests_pkg/urdf/simple_floating_sphere_buoyancy_control.urdf, by using the instructions below:

<!-- Add plugin Air Resistance -->
<gazebo>
    <plugin name="fluid_resitance_plugin" filename="libfluid_resitance_plugin.so">
        <fluid_resitanceTopicName>/fluid_resitance</fluid_resitanceTopicName>
        <NameLinkToApplyResitance>simple_sphere_base_link</NameLinkToApplyResitance>
        <rate>2.0</rate>
    </plugin>
</gazebo>

Lights, Camera Action

With everything in place, we can now run the simulation.  To launch the Simple Fluid Machine, we launch the simulation that has the mass control, the fluid resistance and the propulsion plugins enabled:

roslaunch buoyancy_tests_pkg main_sphere_buoyancy_control.launch

You should get something like:

buoyancy_bot

buoyancy_bot

We can now start the Propulsion Control. After running the command below, you have to keep pressing the direction you want to apply force:

rosrun buoyancy_tests_pkg keyboard_propulsion.py
propulsion

propulsion

 

You can see all the publications of the plugins through the Gazebo Console Log.

Change the Fluid Resistance

You can change the fluid resistance anytime you want by publishing into this topic:

/fluid_resitance
For that you can do the following:
rostopic pub /fluid_resitance std_msgs/Float32 "data: 10.0"
This will apply a fluid resistance that follows this formula:
FluidResitance_X_Axis = -1* FluidResitance * LinearSpeed_X_Axis
FluidResitance_Y_Axis = -1* FluidResitance * LinearSpeed_Y_Axis
FluidResitance_Z_Axis = -1* FluidResitance * LinearSpeed_Z_Axis

If you have applied a movement and you change the FluidResistance, you should see a variation in the time the robot takes to stop. The higher the friction, the faster it will stop its movement.

Air Dragging in Gazebo on ROSDS

Air Dragging in Gazebo on ROSDS

There is more to it but have a look at the HectorPluginsAerodinamics, in which this code is based upon.

Change the Mass or buoyancy

By changing the mass, it will change the buoyancy of the model. This is to simulate the water intake of submarines or the buoyancy system that an air flying machine like a blimp could have.

rostopic pub /model_mass std_msgs/Float32 "data: 0.0"
Mass_0 = 7.23822947387 –> Neutral buoyancy because its the mass of the object
Mass > Mass_0 –> It will sink
Mass < Mass_0 –> It will rise

This mass you can find it in the URDF of the  model: buoyancy_tests_pkg/urdf/simple_floating_sphere_buoyancy_control.urdf

<inertial>
    <origin xyz="0 0 0" rpy="0 0 0"/>
    <mass value="7.23822947387" />
    <inertia ixx="0.00576" ixy="0.0" ixz="0.0" iyy="0.00576" iyz="0.0" izz="0.00576"/>
</inertial>

See the Full code

To see the full code, open the IDE by going to the top menu and select Tools->IDE

IDE - fluidresitance on ROSDS

IDE – fluidresitance on ROSDS

You can also have a look at it from the git: https://bitbucket.org/theconstructcore/buoyancy_tests_pkg/src/master/

Bear in mind that this code is a simplification of the Hector plugins. It’s simply made easier to use. Check out the original source: https://github.com/tu-darmstadt-ros-pkg/hector_quadrotor/blob/kinetic-devel/hector_quadrotor_gazebo_plugins/src/gazebo_quadrotor_aerodynamics.cpp

So, that is the post for today. Remember that we also have a live version of this post on our YouTube channel, as can be seen on the link below. If you liked the content of this post or video, please consider subscribing to our channel and pressing the bell for a new video every single day:

Related resources:

#airdrag #fluidresitance #Simulation #Gazebo #Robot #rostutorials #Ubuntu

Post edited by Miguel, Yuhong and Ruben.

ROS2 Tutorials #5: How to create a ROS2 Package for Python

ROS2 Tutorials #5: How to create a ROS2 Package for Python

About

In this post, you will learn how to create a simple ROS2 package for Python. You don’t need a ROS2 installation for this as we will use the ROS Development Studio (ROSDS), an online platform that provides access to ROS (1 or 2) computers and other powerful ROS tools within a browser!

PS: If you have ROS2 installed locally on your machine, you can skip Step 1.

Step 1: Create a Project (ROSject) on ROSDS

Head to http://rosds.online and create a project with a similar configuration as the one shown below. You can change the details as you like, but please ensure you select “Ubuntu 18.04 + ROS2 Crystal” under “Configuration”.

Once done with that, open your ROSject. This might take a few moments, please be patient.

Step 2: Source the ROS2 workspace

Once the ROSject is open, head to the Tools menu and pick the Shell tool (if on your local PC just fire up a terminal) and run the following command to source the workspace:

user:~$ source /opt/ros/crystal/setup.bash
ROS_DISTRO was set to 'melodic' before. Please make sure that the environment does not mix paths from different distributions.
user:~$

If you get that ROS_DISTRO warning, just ignore it.

Step 3: Create a ROS2 Python package in your ROS2 workspace

The syntax for creating a ROS2 Python package is ros2 pkg create <package_name>.

In the same terminal as in Step 2, change to your ROS2 workspace src directory and create a package there:

user:~$ cd ros2_ws/src
user:~/ros2_ws/src$ ros2 pkg create ros2_demo_py
going to create a new package
package name: ros2_demo_py
destination directory: /home/user/ros2_ws/src
package format: 2
version: 0.0.0
description: TODO: Package description
maintainer: ['user <user@todo.todo>']
licenses: ['TODO: License declaration']
build type: ament_cmake
dependencies: []
creating folder ./ros2_demo_py
creating ./ros2_demo_py/package.xml
creating source and include folder
creating folder ./ros2_demo_py/src
creating folder ./ros2_demo_py/include/ros2_demo_py
creating ./ros2_demo_py/CMakeLists.txt
user:~/ros2_ws/src$

Step 4: Delete CMakeLists.txt , create setup.py and setup.cfg and edit package.xml

Unlike ROS1, ROS2 Python packages don’t use CMakeList.txt, but a new setup.py file. Let’s create one here. In the Shell:

user:~/ros2_ws/src$ cd ros2_demo_py/
user:~/ros2_ws/src/ros2_demo_py$ rm CMakeLists.txt
user:~/ros2_ws/src/ros2_demo_py$ touch setup.py
user:~/ros2_ws/src/ros2_demo_py$ touch setup.cfg
user:~/ros2_ws/src/ros2_demo_py$

Fire up the IDE, locate the setup.py file and paste in the following code:

from setuptools import setup

package_name = 'ros2_demo_py'

setup(
    name=package_name,
    version='0.7.0',
    packages=[package_name],
    install_requires=['setuptools'],
    zip_safe=True,
    author='You',
    author_email='you@youremail.com',
    maintainer='YourFirstname Lastname',
    maintainer_email='your@youremail.com',
    keywords=['ROS'],
    classifiers=[
        'Intended Audience :: Developers',
        'License :: OSI Approved :: Apache Software License',
        'Programming Language :: Python',
        'Topic :: Software Development',
    ],
    description='A simple ROS2 Python package',
    license='Apache License, Version 2.0',
    tests_require=['pytest'],
    entry_points={
        'console_scripts': [
            'demo = ros2_demo_py.demo:main'
        ],
    },
)

Locate the setup.cfg file and paste in the following code:

[develop]
script-dir=$base/lib/ros2_demo_py
[install]
install-scripts=$base/lib/ros2_demo_py

Locate package.xml and replace the contents with this snippet:

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
  <name>ros2_demo_py</name>
  <version>0.7.3</version>
  <description>A simple ROS2 Python package</description>

  <maintainer email="sloretz@openrobotics.org">Shane Loretz</maintainer>
  <license>Apache License 2.0</license>

  <exec_depend>rclpy</exec_depend>
  <exec_depend>std_msgs</exec_depend>

  <!-- These test dependencies are optional
  Their purpose is to make sure that the code passes the linters -->
  <test_depend>ament_copyright</test_depend>
  <test_depend>ament_flake8</test_depend>
  <test_depend>ament_pep257</test_depend>
  <test_depend>python3-pytest</test_depend>

  <export>
    <build_type>ament_python</build_type>
  </export>
</package>

Step 5: Create the Python code

In the Shell, run the following commands:

user:~/ros2_ws/src/ros2_demo_py$ mkdir ros2_demo_py && cd ros2_demo_py
user:~/ros2_ws/src/ros2_demo_py/ros2_demo_py$ touch demo.py
user:~/ros2_ws/src/ros2_demo_py/ros2_demo_py$ touch __init__.py
user:~/ros2_ws/src/ros2_demo_py/ros2_demo_py$

We created the __init__.py file so that the ros2_demo_py folder could be recognized as a python module directory.

Locate the demo.py file, open it in the IDE and paste in the following code:

# Copyright 2016 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.

import rclpy
from rclpy.node import Node

from std_msgs.msg import String


class MinimalPublisher(Node):

    def __init__(self):
        super().__init__('minimal_publisher')
        self.publisher_ = self.create_publisher(String, 'topic')
        timer_period = 0.5  # seconds
        self.timer = self.create_timer(timer_period, self.timer_callback)
        self.i = 0

    def timer_callback(self):
        msg = String()
        msg.data = 'Hello World: %d' % self.i
        self.publisher_.publish(msg)
        self.get_logger().info('Publishing: "%s"' % msg.data)
        self.i += 1


def main(args=None):
    rclpy.init(args=args)

    minimal_publisher = MinimalPublisher()

    rclpy.spin(minimal_publisher)

    # Destroy the node explicitly
    # (optional - otherwise it will be done automatically
    # when the garbage collector destroys the node object)
    minimal_publisher.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()

Step 6: Compile the package and source the workspace

We have created all the files needed. Now let’s compile.

user:~/ros2_ws/src/ros2_demo_py/ros2_demo_py$ cd /home/user/ros2_ws/
user:~/ros2_ws$ colcon build --symlink-install

Starting >>> ros2_demo_py
Finished <<< ros2_demo_py [0.78s]

Summary: 1 package finished [0.90s]
user:~/ros2_ws$ source install/setup.bash # source the workspace
user:~/ros2_ws$

Step 7: Test-run the package

Here comes the moment of truth…will it run?

user:~/ros2_ws$ ros2 run ros2_demo_py demo
[INFO] [minimal_publisher]: Publishing: "Hello World: 0"
[INFO] [minimal_publisher]: Publishing: "Hello World: 1"
[INFO] [minimal_publisher]: Publishing: "Hello World: 2"
[INFO] [minimal_publisher]: Publishing: "Hello World: 3"
[INFO] [minimal_publisher]: Publishing: "Hello World: 4"
...

Great, it ran! We’re done here!!

Extra 1: ROSject link

Get the ROSject containing all code used in the post in the following link: http://www.rosject.io/l/bd0cfbd/

Extra 2: Video

Prefer to watch a video demonstrating the steps above? We have one for you below!

Related Resources

Feedback

Did you like this post? Do you have questions about what is explained? Whatever the case, please leave a comment on the comments section below, so we can interact and learn from each other.

If you want to learn about other ROS topics, please let us know in the comments area and we will do a video or post about it ?

 

Code edited by Bayode Aderinola

[Morpheus Chair] Gazebo Simulation with MoveIt! for your Robot Arm | S4.Ep.4

[Morpheus Chair] Gazebo Simulation with MoveIt! for your Robot Arm | S4.Ep.4

About

In this video you will learn:

  • How to create a gazebo simulation for your Robot Arm
  • How to integrate the gazebo simulation with moveit
  • How to add a Depth sensor in gazebo

Special Thanks to Clarkson University and specially James Carrol and its team for lending us this robot

Related course

Robot-creation-URDF Course Cover - ROS Online Courses - Robot Ignite Academy

URDF for Robot Modeling Course

List of materials

 

 

#moveit #robotmanipulator #dynamixel #Gazebo #Robot #rostutorials #Ubuntu

[Morpheus Chair] Move Robot Arm with MoveIt!  | S4.Ep.4

[Morpheus Chair] Move Robot Arm with MoveIt! | S4.Ep.4

In today’s post, we are going to connect what we learned in the two previous posts, which are How to control a Robot Arm with ROS and Creating a MoveIt! Package with MoveIt! Setup Assistant. Please make sure you read those posts before following on this one since the content is built upon them.

Remember that if you are new to ROS, we recommend you taking the ROS Basics in 5 Days (Python) or ROS Basics in 5 Days (C++) depending on which programming language you prefer.

What we will learn

In this post we will learn :

  • How to move the real robot with MoveIt!

Special Thanks to Clarkson University and especially James Carrol and its team for lending us this robot.

Getting the code

The code we created in the two previous posts are available in the following ROSject: http://www.rosject.io/l/b64de8d/

You can open it by clicking on the Open button or you can download it by clicking on the download button, the ones pointed below by the red and green arrows respectively.

 

The ROSJect mentioned here basically contains the following git repositories on it:

Open the Notebook

When you open a ROSject, by default you have the Jupyter Notebook automatically open, but if that doesn’t happen, you can manually open it by clicking on Tools -> Jupyter Notebook as shown in the image below:

 

Now on the Jupyter Notebook window let’s click openmanipulator_morpheus_chair_notebooks, then click on Notes_Commands.ipynb to open it. That notebook contains the instructions we are going to follow in this post.

Start Demo Pick and place Everything:

In order to start the demo, let’s first run the Service Server that will be used to move the arm:
roslaunch open_manipulator_core controller_launch.launch

Now, let’s run the MoveIt! package that we created in the previous post:

roslaunch open_manipulator_moveit_config moveit_planning_execution.launch sim:=false

 

rosrun open_manipulator_core platform_pick_and_place.py
rostopic echo /gripper_command

 

 

 

 

 

List of materials

Related Courses

ROS Manipulation Course Cover - ROS Online Courses - Robot Ignite Academy

ROS Manipulation Course

ROS Industrial robots Course Cover - ROS Online Courses - Robot Ignite Academy

ROS for Industrial Course

 

 

 

 

 

 

 

 

#moveit #robotmanipulator #dynamixel #Gazebo #Robot #rostutorials #Ubuntu

Pin It on Pinterest