Apply Coursera Control of Mobile Robots with ROS and ROSbots — Part 1

Written by rosbots | Published 2018/01/26
Tech Story Tags: arduino | raspberry-pi | opencv | robotics | robot-operating-system

TLDRvia the TL;DR App

ROSbots is a ROS + OpenCV robot kit for Makers. We recently launched our ROSbots version 2.0 robot kit which is based off the Raspberry Pi 3.

The kit includes a camera, wheel encoders, two rechargeable lithium battery power sources, and even an Arduino-compatible UNO board for hardware PWM, interrupt, and ADC support.

Hardware is fun, but more importantly, we want to use hardware to apply robotics concepts. That requires learning software and the know-how to implement these robotics concepts with modern software tools like ROS and OpenCV.

As the 1st post from a multi-part series, we plan on publishing about concepts learned from the Coursera Control of Mobile Robots course and applying them to the ROSbots robot using ROS. The Control of Mobile Robots course sets the foundation to understand mobile robot control theory — how to control your robot predictably and how to use sensor data to estimate pose and have your robot understand its surroundings.

(Update 3/24/2018: part 2 of the series — where we talk about unicycle and differential drive robot models — has been published.)

Upon completing our multi-part series, you will have a working understanding of robotics control theory and ROS.

(Follow @rosbots for updates. Follow us on Instagram and Facebook too!)

If you have your own ROSbots robot, we welcome you to follow along. Hands-on doing with your own ROSbots kit will add that more more color to what we write than simply reading this post.

In this post, we’ll be prepping to implement the control models described in week 1 of Control of Mobile Robots. Specifically we’ll be doing the following in this post:

  1. Learn how the L9110 Motor Driver on the ROBbots robot works.
  2. Walk through the Arduino sketch code that implements a ROS node to drive the L9110 to spin our wheels.
  3. Compile and upload the ROS-Arduino sketch to our ROSbots’ UNO board, and run the ROS node on the ROSbots’ main brain — ie its Raspberry Pi.
  4. Give you a hands-on feel for how ROS’s messaging system works — use some built in ROS tools to control our motors.

We expect you to know a bit about electronics, have played with Arduinos, have some software programming experience and be comfortable with electronics and coding lingo.

If you are a good top-down learner, then it’s NOT required for you to have taken the Control of Mobile Robots course, nor is it required for you to have knowledge of ROS. But if you have done both, it will definitely be intellectually beneficial.

The L9110 motor driver has 2 channels — fancy talk to say it has the ability to control 2 motors.

L9110 mounted on the ROSbots robot and another one shown right side up.

There are 2 input control pins per channel — IA and IB — that “drive” the 2 output pins — OA and OB connected to the ROSbots robot’s motors. Hence there are 4 input pins and 4 output pins total.

There is a set of IA/IB/OA/OB pins for one channel A (which is connected to our left motor/wheel) and another for channel B (which is connected to the right motor/wheel).

IA is what we PWM to modulate the motor speed. The IB pin controls motor direction.

The L9110 pin table summarizes the input/output behavior:

L9110 input and output pin table

Want a quick show-and-tell with your ROSbots robot?

  1. Place the wire connected to A-IA, specifically G-6 on your ROSbots’ breadboard, into any hole on the top row of the breadboard (VCC).
  2. Place the wire connected to A-IB, specifically G-5, into any hole on the bottom row of the breadboard (GND).
  3. The left wheel will spin forward.
  4. Now swap the connections — G-6 into GND, and G-5 into VCC, now the left wheel will spin backwards.

We will drive the L9110 with the UNO board on our ROSbots robot by writing a ROS-capable Arduino Sketch for it.

The main.cpp sketch code can be found in rosbots_driver Github repo (don’t forget to star and follow!).

Let’s skip over a bunch of ROS specific code and jump directly to this block around line 16 onwards.

Notice that the right wheel’s IA (PWM) and IB (direction) pins are connected to the pins 5 and 4 respectively on the UNO board; left wheel’s IA and IB are connected to pins 6 and 7.

Next let’s look at the block of code that actually drives the pins to turn the wheels.

Ignore the debug code in the comments

In the turnWheel(…) function, we clamp the input variable wheel_power between -1.0 (full reverse) and 1.0 (full forward). That modulates the PWM voltages that output to the respective L9110’s IA pin (aka pwm_pin ) and the digital voltage output to the IB pin (aka fr_pin, as in fwd-reverse).

The simple math during the analogWrite(…) linearly adjusts the PWM pulse width according to the direction specified by the sign of wheel_power — positive means forward, negative means reverse.

As the wheel_power goes from -1.0 to 1.0, you can see the pwm_pin and fr_pin transition from full reverse, to stop, to full forward as described by the L9110 pin table in the beginning of this post.

Let’s compile and upload this sketch code to our UNO board to see it in action.

ROSbots uses platformio to compile and upload ROS-Arduino sketch codes to the UNO board.

  1. We’ll assume you got your ROSbots robot set up with these instructions.
  2. SSH into your ROSbots’ Raspberry Pi — we’ll be doing the remaining steps on the RPi.
  3. Run the following in your RPi terminal (feel free to cut-n-paste directly): ~/$ upload_firmware ~/gitspace/rosbots_driver/platformio/rosbots_firmware/examples/motor_driver (all one line)

Success??

On our RPi, type rosnode list to get a list of ROS nodes running — you should see the following:

/rosout/uno_serial_node

Type rostopic list to get a list of ROS topics being published or subscribed to — you should see the following:

/diagnostics/rosout/rosout_agg/wheel_power_left/wheel_power_right

What are ROS nodes and topics? What does all this mean?

Inspired by the publisher/subscriber distributed messaging architecture, ROS is set up as a bunch of independent processes known as ROS nodes that communicate to each other via messages. One ROS node can be running the process that reads out of the Pi camera, then subsequently publish the images as an “image” message type out on a “foo” topic channel. Another ROS node who’s responsible for detecting cats in incoming images will subscribe to the “foo” topic channel. Like the standard pub/sub model, publishers and subscribers do not care about who has subscribed or who is publishing upstream and downstream.

In summary, any ROS node can be a publisher and/or subscriber of a specific message type communicated through a named channel known as a ROS topic.

In our example here, we wrote some Arduino sketch code to be a ROS node that subscribes to two topics — wheel_power_right and wheel_power_left. The message on these channels will be Float32 types (versus “images” in the hypothetical example above).

Take a look at this piece of the Arduino sketch code you compiled and uploaded:

You’ll notice that our UNO board subscribing to the two topic channels— wheel_power_right and wheel_power_left — with these 2 blocks of code.

When we get a message on either of these topics, we call the rightWheelCb(…) and leftWheelCb(…) callback respectively. That callback, if you recall, implemented the code to drive the L9110’s input pins.

If you recall typing rostopic list the topic names wheel_power_right and wheel_power_left were listed.

Life is good. Right?

Our sketch code lives on our UNO board. But how does our UNO board communicate to the rest of the ROS system running on the Raspberry Pi?

The UNO board is connected to our RPi via the USB and communicates to it via serial port. That’s all fine and dandy except ROS does not directly talk “serial port”!?

If you recall again, when you typed rosnode list, you saw an /uno_serial_node listed as one of the running ROS nodes. In order for ROS to be able to talk “serial port”, we need a bridge that serializes the ROS messages into serial port packets sent to our UNO to process. This bridge application is the ROS node known as rosserial — we named the node /uno_serial_node.

The /uno_serial_node’s job is to open a serial port connection to the UNO board and then serialize/deserialize ROS messages to and from the UNO board.

Type rostopic info /wheel_power_left and you’ll see /uno_serial_node as the subscriber. Why doesn’t it say our UNO code?

Well remember our UNO board cannot talk to the ROS system directly — it only can talk with the /uno_serial_node via the serial port. Our UNO code does specify to the /uno_serial_node that it wants to subscribe to the /wheel_power_left topic and the /uno_serial_node subscribes to that topic on the UNO’s behalf. You can think of the rosserial /uno_serial_node as the mediator between the ROS world and the Arduino Sketch world.

OK — the UNO is a subscriber to topics /wheel_power_left and /wheel_power_right (via rosserial /uno_serial_node) which will drive the wheels depending on the Float32 message received. But who is the publisher?

No one for now. Instead we will use the ROS rostopic tool to manually publish some ROS messages on these topic channels to drive the wheels.

From within your RPi bash terminal:

  1. From any directory, doesn’t matter, type (or cut-n-paste)rostopic pub -1 /wheel_power_left std_msgs/Float32 '{data: 1.0}' — your left wheel should spin forward
  2. Type (or cut-n-paste)rostopic pub -1 /wheel_power_left std_msgs/Float32 '{data: 0.0}' — your left wheel should stop
  3. Type (or cut-n-paste)rostopic pub -1 /wheel_power_left std_msgs/Float32 '{data: -1.0}' — your left wheel should spin backwards
  4. Type (or cut-n-paste)rostopic pub -1 /wheel_power_left std_msgs/Float32 '{data: -0.5}' — your left wheel should spin backwards slower.

The rostopic pub command tells ROS we want to publish. If you type rostopic pub --help you’ll see a couple of options. The -1 option says just publish a message once versus continuously. The next option is the topic channel name. std_msgs/Float32 is the message type. '{data: 1.0}' is the actual payload data. It’s in a JSON-like curly brace syntax because ROS generalizes messages as data structures. So the Float32 ROS message type defined from a bunch of standard ROS package of std_msgs (notice Float32 listed in the link). The Float32 message type is actually a data structure of one entity, a 32-bit float.

Congrats — you just successfully published your first set of ROS messages on a topic and wrote code to implement a ROS node that subscribes to and processes that message. Feel free to try the same exercise for the right wheel.

Have Questions?

If you have questions, post them on answers.ros.org with the subject “ROSbots question: whatever your question is” and tag the post with “rosbots”. We’ll be monitoring the forum and answer accordingly.

How does all this relate back to Coursera’s Control of Mobile Robots course?

We are effectively building the components to turn the Unicycle Model described in week 1 of the course into a Differential Drive Robot Model. Then we will add the feedback from the ROSbots’ wheel encoders to implement a PID controller for wheel velocity which will be able to allow us to estimate pose — position and orientation — of our robot.

The final post in this series will completely implement the coding project described in the course. But instead of using Matlab, we will use ROS and our ROSbots robot!

Follow @rosbots on Medium for updates. Follow us on Instagram and Facebook too!

Feel free to comment here. But if you have technical questions, please post them on answers.ros.org (subject “ROSbots question: blahblah”, tag “rosbots”).

Don’t hesitate to reach out with general feedback, if you want to collaborate, or just to say hello. And if you haven’t already done so, purchase your own ROSbots robot here to follow along.

Thanks!Jack “the ROSbots Maker”


Published by HackerNoon on 2018/01/26