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.
SwiftyBones is a
modular Swift library for interacting with both the digital GPIO 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 and/or Analog pins.
Since SwiftyBones is a modular library you only need to include the functionality required for
your projects rather than all of the functionality.Currently SwiftyBones supports both digital GPIO and Analog however I need to add PWM support soon
for my robotics projects that my daughter and I want to work on this summer so
you should hopefully see it supported soon as well.
SwiftyBones comes with a script called swiftybuild.sh that will help you build swift
projects with multiple files.This
script comes in very handy since SwiftyBones itself contains multiple files.
There are several example projects (with Fritzing diagrams)
included with SwiftyBones to help you get started using Swift and SwiftyBones with
your next IoT, Robotic or any other project you are working on with the
Beaglebone Black.
Please feel free to send me any suggestions that you may
have for this project.Also please feel
free to contribute code especially if you know how to get PWM working with the
4.1+ kernel.