Sunday, May 8, 2016

BuddyBot - The Swift robot gets its first upgrades

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 created a new github page for the BuddyBot code.   

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.

Thursday, May 5, 2016

The first robot programed in Swift with SwiftyBones


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:



Wiring the Robot
For this project I am using the Rover 5 Tracked Chassis with the Rover 5 Motor Controller Board.  Everything is connected similar to what I did in the My first working robot, It’s alive post from 2014.  For instructions on how everything is connected please see that post.

I use a LED to indicate that everything has been initiated and a button to start the robot. I wired them as shown in the following diagram





Setting up the BeagleBone Black
1.  Get the latest Debian 8.3 image from Beagle Board’s site.  You can find the image here.
2.  We need to unzip the images.  We can do this using TheUnarchiver for Mac.
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
            runningLed.setValue(newValue)
      }

      func getStartButton() -> Bool {
            let butVal = startButton.getValue()
            return (butVal == DigitalGPIOValue.LOW) ? false : true
      }    
}

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.


Monday, May 2, 2016

Swift and the Beaglebone Black – Better together with SwiftyBones

UPDATE:  SwiftBones has been updated for Swift 3.  I have created a new repository that is located here: https://github.com/hoffmanjon/SwiftyBones3 

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.