All of my robots that I have created use a motor controller board
similar to the Rover 5 four channelmotor controller that I use in BuddyBot (the first robot programming in the Swift programming language with SwiftyBones). These motor controllers are very convenient
and easy to use however they can get a little expensive when you are on a
budget and want to create multiple robots.
Fortunately an H-Bridge is a very cheap
alternative to the more expensive motor controllers boards.
An H-Bridge is an electric circuit that allows us to apply
voltage to our motors in either direction allowing the motor to run forwards or
backwards.The term H-Bridge comes from
the typical graphic representation of the circuit which looks like a capital
H.The following image shows how an
H-Bridge works.
An H-Bridge is built with four, usually, solid state
switches.As we see in the previous
image, when switches 1 and 3 (I1 and I3) are open and switches 2 and 4 (I2 and
I4) are closed the right side of the motor is connected to the power supply
while the left side is connected to ground spinning the motor in one direction.If switches 1 and 3 (I1 and I3) are closed
and switches 2 and 4 (I2 and I4) are open then the left side of the motor is
connected to the power supply while the right side is connected to ground spinning
the motor in the other direction.
For some fun (and this blog post) I created a H-Bridge using
four 2n4401 NPN transistors as shown in the following
image:
I am not going to explain how this was built because we do
not need to create our own H-Bridges, I just did it for fun (my wife says my
idea of fun is a bit weird but what can I say).We can buy them as an IC like the
L293D which is designed as a motor controller.In this post I will show how to control two
motors with the L293D H-Bridge motor controller and the BeagleBone Black.
The L293D is a dual H-Bridge motor driver IC which means
that it is capable of driving two motors simultaneously.The
following image shows the pin layout for the L293D IC.
Since the output from the GPIO ports on the BeagleBone Black
is usually not enough to drive our motors, the L293D has both a Vcc (3.3V from
the BeagleBone Black) and a Vmotor (power for the motors 6V->12V).TheL293D also has two enable pins which should remain high to enable the
motors.If the enable pins are low the
H-Bridge will be disabled.
Each side of the IC has two inputs and two outputs.Each of the inputs should go to a separate
GPIO pin on the BeagleBone Black.To
make the motor turn in the forward direction one input should be high and the
other input low. To make the motor turn
in the reverse direction we should reverse which pin is high and which pin is
low.As an example if we are using the
left side of the IC for our motor we could set IN1 to high and IN2 to low to
drive our motor in one direction and then set IN1 low and IN2 high to drive our
motor in the other direction. The OUT1 and OUT2 pins should be connected to the
DC motor that we are trying to drive.
The L293D has four GND pins.All four GND pins need to be connected to a ground even if you are only driving
one motor with the IC.The following
diagram shows how I have the L293D connected to my BeagleBone Black to drive
two motors:
As you can see we are using six GPIO pins to drive our two
motors.Pins 15 and 25 of the P9 header
are connected to the enable pins on the L293D IC.Both of these pins will need to be high to
enable the motors.We have pins 11 and
13 of the P9 header connected to the IN1 and IN2 pins on the IC.We also have pins 21 and 23 of the P9 header
connected to the IN3 and IN4 pins.
The DC motors that we are driving with the L293D are
connected to the OUT pins of the IC.To
drive the first motor we will use the following table to see how we should set
pins 11, 13 and 15.
Pin 11
(IN1)
Pin 13
(IN2)
Pin 15
(Enable1)
Result
High
Low
High
Motor spins one direction
Low
High
High
Motor spins other direction
High
High
High
Stopped
Low
Low
High
Stopped
X
X
Low
Stopped
The same table can be applied to the second motor as well
just substitute pins 11, 13 and 15 with pins 21, 23 and 25.
Now how can we program this with Swift.For the SwiftyBones library I wrote a component called SBHBridge that makes it very easy to add an H-Bridge to your project.You would create an instance of the SBHBridge type like this:
var
leftMotor = try SBHBridge(forwardHeader: .P9, forwardPin: 11,
reverseHeader: .P9,
reversePin: 13,
enableHeader: .P9,
enablePin: 15,
componentName:
"Left Motor")
var
rightMotor = try SBHBridge(forwardHeader: .P9, forwardPin: 23,
reverseHeader: .P9,
reversePin: 25,
enableHeader: .P9,
enablePin: 27,
componentName:
"Left Motor")
Now we can spin the motor in the forward direction like
this:
leftMotor.goForward()
rightMotor.goForward()
or in the reverse
direction like this:
leftMotor.goReverse()
rightMotor.goReverse()
We can also enable or disable the motor using the enableMotor(Bool) function:
leftMotor.enableMotor(true)
rightMotor.enableMotor(true)
Adding an H-Bridge to your robotics project is a cheap and
simple way to drive your motors. The SwiftyBones library makes it incredible easy to use it with your next project.
In this post I will show the latest updates to BuddyBot and
also give a list of parts that I used to build him.You can use this parts list to build your own
Swift based robot.
This weekend we added a couple new sensors and changed BuddyBot’s
look a little bit.The MaxSonar range finders work great unless BuddyBot is coming up
on an object at too large of an angle.To help the sonar range finders we added two IR Obstacle Avoidancesensors.We
also had an issue where BuddyBot always wanted to climb on the dog pillows and
he ended up tipping over.To stop this
we also added a tilt sensor to detect when BuddyBot
attempted to climb something.
Lets start off by seeing some new pictures of BuddyBot:
I did not include any new videos on this post because the new sensors simply enhanced BuddyBot's earlier functionality and did not really add anything else. You can see videos of BuddyBot in the BuddyBot gets obstacle avoidance post.
I will say that I am not too fond of the IR ObstacleAvoidance sensors.I might be doing something wrong but in order to get two of them to work
I need to power one of them on, let it initialize and then power the other one
on.If I let them both power up with
everything else they both constantly detect an obstacle.
The tilt sensor works well when the rover is running inside the house however I did have to set it to
detect at a higher tilt then I originally wanted because the vibration of the
rover itself set it off occasionally.When
I ran BuddyBot outside, the rough terrain constantly set the tilt sensor off.
A couple of people have asked about the components that make
up BuddyBot so they could build one similar to it.With that in mind, lets look at the
components of BuddyBot.
BuddyBot’s Components
The following images has BuddyBot’s components labeled:
You can either solder some of the components (like the LED and Buttons) or attach them all to the solder less breadboard.I have the Kendal 937D Soldering Station and really like it.Trust me, if I can use it to solder then anyone can because I am not
very good at soldering but I am working on it J.
I printed off a lot of parts and you can find the parts on
Thingiverse thing:1580488.I have the
Monoprice Maker Select 3D printer and it is
AWESOME.If you are looking for an
entry-level 3D printer I would absolutely recommend this printer.It has been nothing but terrific for me.
You can use this blog post to setupyour BeagleBone Black with
Swift.
If you have any questions about how to build a BuddyBot,
please ask.
BuddyBot’s Future
I asked my daughters what projects they wanted to work on this
summer since I was not planning on writing any books over the summer.My oldest said that she wanted to build
robots again.BuddyBot was created so I
would have a good working robot as a base for our projects and also a good
library for her to work with.
Now that school is just about over I plan on turning the
creative aspect over to my daughters.Over the next week or two I will be showing them how BuddyBot was built
(the component and electronic aspect of it) and also going over how he was
programmed.At that point I will discuss
various upgrades we can do depending on if they want to expand BuddyBot from a
hardware and software point of view (more Sensors) or from simply a software
point of view (expand on his programming).Some of the ideas I came up with are:
1.Adding another MaxSonar Range Finder to
detect if BuddyBot approaches a ledge or stairs
2.Adding some sound detecting sensors so
BuddyBot can move toward sounds
3.Adding a path sensor so BuddyBot can follow a
path
4.Update the code so BuddyBot will try to reach
the other end of a room while avoiding obstacles
5.Have them design some parts to print for
BuddyBot
I have also started designing a new robot that I will work
on while my daughters work on BuddyBot.I will use Swift with SwiftyBones for this new Robot as well because I
am finding that Swift is a great development platform for robotic development.
BuddyBot, the robot programmed in the Swift programming language just got its first upgrades. The first thing you may notice is I printed
out a couple of new trays to hold the components so it looks better. Secondly I added a MaxSonar_EZ2 range finder so it can detect obstacles in front of it and
turn. Right now it simply turns right
when it gets close to an obstacle.
Here is the new BuddyBot
The following video shows my daughters playing with
BuddyBot.
I also just added a component library to the SwiftyBoneslibrary and I used some of those
components to build this version of BuddyBot.You can read about the component library on the wiki page.
I think the next upgrade is going to be a second MaxSonar
sensor.Rather than having one sensor in
the center I am thinking about putting two sensors on the front, one on the
right and one on the left, so BuddyBot can make decisions on which way to turn
rather than always turning right.This
means I will need to print out a new tray that will hold two sensors.
As far as I know, this is the first robot programming
entirely in the Swift programming language.I programmed it as an example of what can be done using Swift with the new SwiftyBones library and the BeagleBone Black.
EDIT: See the first update to BuddyBot here
The second update to BuddyBot is here
the third update with parts list is here
SwiftyBones is
a modular Swift library for interacting with both the digital GPIO, PWM and
Analog pins on the BeagleBone Black. This
library is written to make it easy to write Swift applications that run on the
Beaglebone Black that interacts with external
sensors, LED or any device connected to the Digital GPIO, PWM and/or Analog
pins. You can read about the
SwiftyBones library on its github page here.
Here is a picture of the robot (no comments about the messy
wiring please) J
Before I explain how everything works, below is a video of
the robot in action:
3. Now we need to copy the image over to the SD
card. I would recommend using at least a 8 gig SD
card. Everything needed will take up 3.3 gig which will fit on a 4
gig card but you are not leaving yourself much extra space. I
use Pi Filler to copy the
image onto the SD card. Once installed, run the Pi Filler app and
follow the on screen prompts.
4. Once you have the image on the SD Card, go
ahead and plug it into your BeagleBone Black and power it up.
5. If you are using a SD card greater than 4 gig,
you will need to manually expand the file system since the image only uses 4
gig. To do this you can following these
instructions.
6. Now we are set to install Swift. The
instructions to do this are on the iachieved.it
site.
7.The last thing we
need to do is to download the SwiftyBones library.You can do that by running the following
command:wget https://github.com/hoffmanjon/SwiftyBones/archive/master.zip
Programming our
Robot:
The first thing we need to do is to create a directory
structure for our code.My directory
structure looks like this (I am naming the robot Buddy):
Buddy|
|
|--SwiftyBones|
||-SwiftyBonesCommon.swift
||-SwiftyBonesDigitalGPIO.swift
||-SwiftyBonesPWM.swift
|
|--BuddyBot|
||-BuddyBot.swift
|
|--main.swift
|--swiftybuild.sh
I have two subdirectories below the main directory named SwiftyBones and BuddyBot. The SwiftyBones
directory contains the three SwiftyBones files that I need for my robot. The SwiftyBonesCommon.swift
file contains the common code needed for any project that uses
SwiftyBones. The SwiftyBonesDigitalGPIO.swift
file contains the code to interact with digital GPIO pins and the SwiftyBonesPWM.swift file contains the
code to interact with the PWM pins. The BuddyBot directory contains one file
which is the code for my specific robot and is the code that interacts with the
SwiftBones library.
SwiftyBones provides a script called swiftybuild.sh that can be used to easily compile applications that contains multiple files and subdirectories like this one. It basically searches the current directory and all subdirectories for any file that has the .swift extensions and then compiles them and builds the application.
Lets look at the BuddyBot.swift
code first:
#if
arch(arm) && os(Linux)
import Glibc
#else
import Darwin
#endif
public
struct BuddyBot {
private let FORWARD = DigitalGPIOValue.LOW
private let REVERSE =
DigitalGPIOValue.HIGH
private let runningLed: SBDigitalGPIO
private let startButton: SBDigitalGPIO
private let rightMotorDirection:
SBDigitalGPIO
private let leftMotorDirection:
SBDigitalGPIO
private let rightMotorPower: SBPWM
private let leftMotorPower: SBPWM
init?() {
let
runningLed = SBDigitalGPIO(id: "gpio30", direction: .OUT)
let
startButton = SBDigitalGPIO(id: "gpio60", direction: .IN)
let rightMotorDirection =
SBDigitalGPIO(id: "gpio26", direction: .OUT)
let
rightMotorPower = SBPWM(header: .P8, pin: 13)
let leftMotorDirection =
SBDigitalGPIO(id: "gpio46", direction: .OUT)
let
leftMotorPower = SBPWM(header: .P8, pin: 19)
if runningLed == nil ||
startButton == nil ||
rightMotorDirection == nil
||
rightMotorPower == nil ||
leftMotorDirection == nil ||
leftMotorPower == nil{
return nil
}
self.runningLed = runningLed!
self.startButton = startButton!
self.rightMotorDirection =
rightMotorDirection!
self.rightMotorPower =
rightMotorPower!
self.leftMotorDirection =
leftMotorDirection!
self.leftMotorPower =
leftMotorPower!
enableTracks(false)
}
func goForward(speed: Int) {
enableTracks(false)
rightMotorDirection.setValue(FORWARD)
leftMotorDirection.setValue(FORWARD)
rightMotorPower.setValue(speed)
leftMotorPower.setValue(speed)
enableTracks(true)
}
func goReverse(speed: Int) {
enableTracks(false)
rightMotorDirection.setValue(REVERSE)
leftMotorDirection.setValue(REVERSE)
rightMotorPower.setValue(speed)
leftMotorPower.setValue(speed)
enableTracks(true)
}
func turnRight(speed: Int) {
enableTracks(false)
rightMotorDirection.setValue(REVERSE)
leftMotorDirection.setValue(FORWARD)
rightMotorPower.setValue(speed)
leftMotorPower.setValue(speed)
enableTracks(true)
}
func turnLeft(speed: Int) {
enableTracks(false)
rightMotorDirection.setValue(FORWARD)
leftMotorDirection.setValue(REVERSE)
rightMotorPower.setValue(speed)
leftMotorPower.setValue(speed)
enableTracks(true)
}
func allStop() {
enableTracks(false)
rightMotorDirection.setValue(FORWARD)
leftMotorDirection.setValue(FORWARD)
rightMotorPower.setValue(0)
leftMotorPower.setValue(0)
}
func enableTracks(enable: Bool) {
rightMotorPower.setEnable(enable)
leftMotorPower.setEnable(enable)
}
func ledOn(on: Bool) {
let newValue = (on) ?
DigitalGPIOValue.HIGH : DigitalGPIOValue.LOW
We start the code off by defining a number of
constants.These are:
1.FORWARD – The motors that control the
tracks on my robot can go in the forward or reverse direction. We set the direction pin LOW
to go forward. This constant defines the forward direction as being low.
2.REVERSE – The motors that control the
tracks on my robot can go in the forward or reverse direction. We set the direction pin
HIGH to go in reverse. This constant defines the reverse direction as being
high.
3.runningLed:This constant will define the GPIO pin for
the LED .
4.startButton:This constant will define the GPIO pin for
the start button.
5.rightMotorDirection:This constant defines the GPIO pin that is connected
to direction pin on the motor controller board that is connected to the right
motor.
6.leftMotorDirection:This constant defines the GPIO pin that is
connected to direction pin on the motor controller board that is connected to
the left motor.
7.rightMotorPower:This constant defines the PWM pin that is
connected to the PWM pin on the motor controller board that controls the speed
of the right motor.
8.leftMotorPower:This constant defines the PWM pin that is
connected to the PWM pin on the motor controller board that controls the speed
of the left motor.
We have one failable initializer in our BuddyBot type.In this
initializer we initialize all of the pins and if any of them fail to properly initialize
then the initializer fail and we will return nil.
After the initializer we have several methods that we can
use with our BuddyBot type.The first two are goForward()
and goReverse().Calling these two methods will cause the
robot to move in the forward or reverse directions.In these two functions we start off by
disabling the tracks by calling the enableTracks()
method with a value of false.I would
recommend always disabling the tracks prior to setting the direction.We then set the direction of the tracks
(FORWARD in the goForward() method and
REVERSE in the goReverse() method)
followed by setting the speed we want to go.The speed can be set anywhere from 0 to 10000 where a value of 10000
causes the motor to go full speed and a value of 0 causes the motor to stop. Finally we enable the tracks by calling the enableTracks() method with a value of true.
The next two methods turnRight()
and turnLeft() are very
similar to the goForward() and goReverse() methods except we set one
track to move in the forward direction and one in the reverse direction causing
the robot will turn.
The allStop()
method disables the tracks, sets the direction of both tracks to forward and
sets the speed of the tracks to 0.This
stops the robot in place.
The ledON()
method will turn the LED on or off depending on the value passed in.A value of true will turn the LED on and a
value of false will turn the LED off.Finally the getStartButton()
will return true if the button is being pressed is being pressed.
To understand more about how SwiftyBones works, you can read
about the library on its github page here.
Now lets look at the main.swift file.This is the file that is executed when our
application starts.The following is the
code from the BuddyBot main.swift file:
#if arch(arm) && os(Linux)
import Glibc
#else
import Darwin
#endif
if let buddy = BuddyBot() {
buddy.ledOn(true)
while
!buddy.getStartButton() {}
buddy.goForward(7000)
usleep(6000000)
buddy.turnLeft(3000)
usleep(1500000)
buddy.turnRight(3000)
usleep(1500000)
buddy.goReverse(5000)
usleep(3000000)
buddy.allStop()
buddy.ledOn(false)
} else {
print("Error
init")
}
In this code we start off by initializing an instance of the
BuddyBot type.If we get an instance of the BuddyBot type (the initializer did not
fail) we then turn on the LED using the ledOn()
method.We then use the goForward(), turnLeft(),
turnRight(), goReverse()
and allStop() methods from
the BuddyBot type to make the robot move.We use the usleep()
method to wait a certain amount of time between each step.
We use the swiftybuild.sh script to compile the
application.This script will search the
currently directory and all subdirectories for files with the .swift
extensions.It will then compile all of
those files and build the application.
That is how the first robot programming using the Swift
language was written and built.To learn
more about SwiftyBones go to its github page here.