User Tools

Site Tools


ros:ros-dartv2

Back to ROS main page

Here we will see how to create the ROS driver for an existing non ROS robot.

Hardware

The DART V2 robot is an educational robot, built at ENSTA Bretagne to teach mobile robotics. The DARTV2 robot is a 4×4 wheeled robot with differential drive. The actuators are :

  1. 2 left motors : front and rear left wheels with the same command
  2. 2 right motors : same as above for right wheels
  3. the 2 digits seven segment display : if not changed show the ID (number) of the robot

The motors are driven by a T-REX power board, connected in I2C. The sensors are :

  1. Pololu IMU 9V5 inertial motion unit, i2C bus
  2. Home made encoders (odometers) on rear wheels, i2C bus
  3. T-REX encoders (odometers) on front wheels, i2C bus
  4. 4 cardinal (front, left, right and rear) ultrasonic sensors, I2C bus
  5. 2 diagonal (front-left and front-right) ultrasonic sensors , I2C bus

Software : ROS drivers

This first version the DARTV2 ROS drivers is written in Python 2.7. We will see after how to to the same drivers in C++ and in Python 3 for ROS2.

ROS drivers Python 2.7 for kinetic and melodic

ROS kinetic is running on the robot and ROS melodic on the host computer.

Connect the Robot to the ROS master on the host computer

The workspace is created on the robot , to get the link between the robot and the host computer we define the host computer as the master. The master executes the roscore command. The IP address of the master is for example 172.20.22.34 and the master runs ROS melodic (Ubuntu 18.04) :

export ROS_IP=172.20.22.34
export ROS_MASTER_URI=http://172.20.22.34:11311
source /opt/ros/melodic/setup.bash
roscore

The robot runs ROS kinetic and the link to the master is defined as follows :

export ROS_IP=172.20.25.102
export ROS_HOSTNAME=DART02
export ROS_MASTER_URI=http://172.20.22.34:11311
source /opt/ros/kinetic/setup.bash

Create ROS workspace and package

On the robot, create a folder to implement the ROS nodes with the drivers code. Then create a ROS package called dartv2_driversfor the drivers :

cd $HOME
mkdir -p ros/dart_drivers_py27_ws/src
cd ros/dart_drivers_py27_ws/src
catkin_create_pkg dartv2_drivers std_msgs message_generation  rospy
cd ..
catkin_make

Add folders for Python scripts, launch files and custom messages :

cd $HOME/ros/dart_drivers_py27_ws/src/dartv2_drivers
mkdir bin
mkdir launch
mkdir msg

The python code of the node will be in the src folder. The bin folder contains the python executable code of the nodes. The file names of the nodes codes are generally not ended by .py, and must be executable.

To check that all is working fine, we create a simple python node. We are using recommendations in this ROS makefile guide to create the folder tree structure. The node is called hello and is located in bin folder. It uses a function defined in hello.py located in src folder.

cd $HOME/ros/dart_drivers_py27_ws/src/dartv2_drivers
cd bin
cat << EOF > hello
#! /usr/bin/env python
import dartv2_drivers.hello as drt
if __name__ == '__main__':
    drt.say('my friend!')
EOF
chmod +x hello
cd ../src
mkdir dartv2_drivers
cd dartv2_drivers
touch __init__.py
cat << EOF > hello.py
def say(name):
    print('Hello ' + name)
EOF

A Python setup file (setup.py) must be added in the package folder (dart_drivers_py27_ws) :

cd $HOME/ros/dart_drivers_py27_ws/src/dartv2_drivers
cat << EOF > setup.py
## ! DO NOT MANUALLY INVOKE THIS setup.py, USE CATKIN INSTEAD
from distutils.core import setup
from catkin_pkg.python_setup import generate_distutils_setup
# fetch values from package.xml
setup_args = generate_distutils_setup(
     packages=['dartv2_drivers'],
     package_dir={'': 'src'},
)
setup(**setup_args)
EOF

The line # catkin_python_setup() in CMakeLists.txt must be uncommented to execute setup.py during catkin_make. This change can be made with sed. Once it's done the workspace is updated :

cd $HOME/ros/dart_drivers_py27_ws/src/dartv2_drivers
sed -i 's/# catkin_python_setup()/catkin_python_setup()/g' CMakeLists.txt
cd ../..
catkin_make
source devel/setup.bash

Finally, the test program should execute well and it can be removed

rosrun dartv2_drivers hello
rm $HOME/ros/dart_drivers_py27_ws/src/dartv2_drivers/bin/hello
rm $HOME/ros/dart_drivers_py27_ws/src/dartv2_drivers/src/dartv2_drivers/hello.py*

First driver - Odometers

We will use a custom message format for the odometers. A micro-controller gives the value of the 2 rear wheel odometers with a time stamp. The micro-controller is also giving the battery voltage. The front odometers are given by the T-REX motor power board. All these data will be placed in custom messages. So we need to setup the node so that custom message can be recognized and made available to ROS. The custom messages are defined is the msg folder :

cd $HOME/ros/dart_drivers_py27_ws/src/dartv2_drivers/msg
cat << EOF > Odometers.msg
int32 odom_front_left
int32 odom_front_right
int32 odom_rear_left
int32 odom_rear_right
float32 time_stamp_rear
EOF
cat << EOF > Battery.msg
float32 v
EOF

To use the new messages, the package has to be recompiled and then the messages can be accessed (with rosmsg for example) :

cd $HOME/ros/dart_drivers_py27_ws
catkin_make
source devel/setup.bash 
rosmsg show dartv2_drivers/Battery 
rosmsg show dartv2_drivers/Odometers 

CMakeLists.txt (in dartv2_drivers folder) must be modified to be able to import new messages in Python code. In CMakeLists.txt, remove comments in add_message_files section and add the .msg file names, also remove comments in generate_messages section. In CMakeLists.txt, the default add_message_files section should look like this :

## Generate messages in the 'msg' folder
# add_message_files(
#   FILES
#   Message1.msg
#   Message2.msg
# )

To add our custom messages we change it to :

## Generate messages in the 'msg' folder
add_message_files(
  FILES
  Odometers.msg
  Battery.msg
)

After removing comments in generate_messages section of CMakeLists.txt, you should have this :

## Generate added messages and services with any dependencies listed here
generate_messages(
  DEPENDENCIES
  std_msgs
)
cd $HOME/ros/dart_drivers_py27_ws
catkin_make
source devel/setup.bash

Once the custom messages are defined and recognized, a dummy publisher can be written and tested

cd $HOME/ros/dart_drivers_py27_ws/src/dartv2_drivers/bin
cat << EOF > Odometers
#!/usr/bin/env python
# license removed for brevity
import rospy
from dartv2_drivers.msg import Odometers, Battery
import dartv2_drivers.drivers.encoders as odo_rear_drv
import time
def talker():
    global odo_rear
    pub = rospy.Publisher('dartv2_odometers_pub', Odometers)
    rospy.init_node('dartv2_odometers', anonymous=True)
    r = rospy.Rate(1) #1hz
    msg = Odometers()
    t0 = time.time()
    while not rospy.is_shutdown():
        orl,orr,odt = odo_rear.read_encoders_both(dt=True)
        msg.odom_rear_left = orl
        msg.odom_rear_right = orr
        rospy.loginfo(msg)
        pub.publish(msg)
        r.sleep()
if __name__ == '__main__':
    try:
        odo_rear = odo_rear_drv.EncodersIO()
        talker()
    except rospy.ROSInterruptException: pass
EOF
chmod +x Odometers
rosrun dartv2_drivers Odometers

Motors

The motors are actuators. Instead of a “talking” node we need to define a “listening” node. In ROS motor command is generally achieved thorough the classical topic /cmd_vel. Here, we will use a more simple topic based on a custom message that directly controls the PWM of the left and right sides :

cd $HOME/ros/dart_drivers_py27_ws/src/dartv2_drivers/msg
cat << EOF > Motors.msg
int16 pwm_l
int16 pwm_r
EOF

Launch

roslaunch dartv2_drivers dartv2_drivers.launch

in another terminal send PWM commands to wheel motors

rostopic pub -1  dartv2_motors dartv2_drivers/Motors "{pwm_l: -90, pwm_r: 90}"
rostopic pub -1  dartv2_motors dartv2_drivers/Motors "{pwm_l: 0, pwm_r: 0}"

Sonars

DART V2 uses two types of sonars :

  • 4 cardinal sonars (front,left,back and right) managed by a dedicated micro-controller via I2C bus
  • 2 front diagonal sonars (front-left and front-right) directly connected on I2C

The 4 cardinal sonars are used in mode 2 (sync) that gives a new measurement every 200 ms, associated with the time stamp of the measurement. All 4 sonars are fired simultaneously. The 2 diagonal sonars are acquired simultaneously every 200 ms. The python code Sonars publishes the results on a custom message defined in Sonars.msg :

cd $HOME/ros/dart_drivers_py27_ws/src/dartv2_drivers/msg
cat << EOF > Sonars.msg
float32 front
float32 left
float32 back
float32 right
float32 front_left
float32 front_right
EOF

The add_message_files section of CMakeList.txt must be updated to add Sonars.msg.

IMU

IMU is a mini IMU 9 from Pololu. The raw data message is mode of the 3 coordinates of the magnetic filed, the acceleration along the 3 axis and rotation speed around the 3 axis. A custom message, ImuRaw.msg is created :

cd $HOME/ros/dart_drivers_py27_ws/src/dartv2_drivers/msg
cat << EOF > ImuRaw.msg
float32 magx
float32 magy
float32 magz
float32 accelx
float32 accely
float32 accelz
float32 gyrox
float32 gyroy
float32 gyroz
EOF

The add_message_files section of CMakeList.txt must be updated to add ImuRaw.msg.

ros/ros-dartv2.txt · Last modified: 2023/03/31 12:12 by 127.0.0.1