Showing posts with label BeagleBone. Show all posts
Showing posts with label BeagleBone. Show all posts

Saturday, May 21, 2016

BuddyBot Update and Parts List

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.

I did add both sensors to the SwiftyBones Component library.  I also rewrote a large portion of the SwiftyBones_BuddyBot code.

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:








Here is the component list:

1X Battery Pack  (Recommend having a spare)
2X Mini Boards (1 Pack) for LED and Button 
100 Ohm resistor  (one for each LED)
10K Ohm resistor for button
1K Ohm Resistor and 3.3K OhmResistor for MaxSonar Range Finders

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 setup  your BeagleBone Black with Swift.

I use my SwiftyBones library to program BuddyBot

Finally you can find the current code for BuddyBot on the SwiftyBones_BuddyBotgithub page.

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.

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.

Thursday, April 28, 2016

Beaglebone Black Analog input with Swift and the TMP36 sensor

In my earlier posts that should how to use Swift with the Beaglebone Black I used the SwiftyGPIO library to interact with digital GPIO ports.  While using digital GPIO ports can be very powerful the Beaglebone Black also has analog ports.  In this post I will show how we can use the TMP36 temperature sensor with an analog port to determine the temperature.

With the digital ports we measure one of two values (high or low).  With the analog ports we measure a range a values.  The Beaglebone Black provides seven analog ports labeled AIN0 through AIN6.  These ports are located on the P9 header and the following list shows what pin corresponds to which analog inputs:

AIN0  -  39
AIN1  -  40
AIN2  -  37
AIN3  -  38
AIN4  -  33
AIN5  -  36
AIN6  -  35

The following image shows the full headers:




Lets get started, if you have not already installed Swift on your Beaglebone Black you can check out my earlier post that talks about how to install it and also how to use the SwiftyGPIO library.  In this post we cannot use the SwiftyGPIO library because it does not support analog ports instead we will interact directly with GPIO ports through the file system.  This is how the SwiftGPIO actually works behind the scenes when you use it to access the digital GPIO.

Like always the first thing we need to do is to connect our sensor to the Beaglebone Black.  The following diagram shows how I connected the TMP36 temperature sensor to my Beaglebone Black.  Note that I have the TMP36 sensor connected to the AIN1 port.





Now that we have the TMP36 Temperature sensor wired to our Beaglebone Black lets power it up and see how we would read the Analog port.  Before we write our Swift code lets see how we would read the port manually from the shell.  The first thing we would need to do is to enable the analog ports.  To enable the ports we would echo “BB-ADC” to the  /sys/devices/platform/bone_capemgr/slots file.  Before we do that, lets look at the file.  If we run the following command we can see the contents of the file:

cat /sys/devices/platform/bone_capemgr/slots

The contents of the file should look something like this:

 0: PF----  -1
 1: PF----  -1
 2: PF----  -1
 3: PF----  -1
 4: P-O-L-   0 Override Board Name,00A0,Override Manuf,cape-universaln

Now lets enable the analog ports by running the following command:

echo BB-ADC > /sys/devices/platform/bone_capemgr/slots

If we cat out the contents of the slots file again, it should now look something like this:

 0: PF----  -1
 1: PF----  -1
 2: PF----  -1
 3: PF----  -1
 4: P-O-L-   0 Override Board Name,00A0,Override Manuf,cape-universaln
 5: P-O-L-   1 Override Board Name,00A0,Override Manuf,BB-ADC

The last line shows that the analog ports are now enabled.  Now that the ports are enabled, lets see how we can read the AIN1 port.  We can do that by reading the contents of the  /sys/bus/iio/devices/iio:device0/in_voltage1_raw file like this:

cat /sys/bus/iio/devices/iio:device0/in_voltage1_raw

The output of this command should be a number around 1700 or so.  If you look in the /sys/bus/iio/devices/iio:device0/ directory, you should see 7 in_voltage files numbered 0 through 7.  These files correspond to the seven AIN ports therefore if we connected our TMP36 temperature sensor to AIN2 instead of AIN1 we would read the in_voltage2_raw file.

Now that we know how to get the value from the analog ports, lets see how we would do this with Swift and convert that value to the current temperature.  The first thing we need to do is to create a function that will read the value from a file.  The following will do this and return an optional that would be either a String value or nil.

func readStringFromFile(path: String) -> String? {
      let fp = fopen(path, "r")
      guard fp != nil else {
            return nil
      }
      var oString = ""
      let bufSize = 8
      let buffer: UnsafeMutablePointer<UInt8> = UnsafeMutablePointer.alloc(bufSize)
       defer {
            fclose(fp)
            buffer.dealloc(bufSize)
      }

      repeat {
            let count: Int = fread(buffer, 1, bufSize, fp)
            guard ferror(fp) == 0 else {
                  break
            }
            if count > 0 {
                  oString += stringFromBytes(buffer, count: count)
            }
      } while feof(fp) == 0
      return oString
}    
In this function we use the fopen() function to open the file.   We use a guard statement to verify that the file opened properly.  If the file did not open properly we return nil.  To ensure that the file is properly closed and the buffer that we used to read the data is properly released we use a defer block to close the file and release the buffer.

We then continuously read from the file with a repeat block until we reach the end of the file.  When we read from the analog files, we will only go though this loop once and read four or less bytes of data but it is good practice to keep the repeat block to ensure we are reading all data.

We convert the bytes that we read from the file to a string using the stringFromBytes() function.   The following code shows this function:

func stringFromBytes(bytes: UnsafeMutablePointer<UInt8>, count: Int) -> String {
      var retString = ""
      for index in 0..<count {
            if bytes[index] > 47 && bytes[index] < 58 {
                  retString += String(Character(UnicodeScalar(bytes[index])))
            }
      }
      return retString
}

In this function we loop through the byte array and if the value of the individual element is greater than 47 or less than 58 (ASCII representations of 0-9 because we only want numbers) then we convert the byte to a character and append it to the return string.

Using these two functions we would read the TMP36 temperature sensor and calculate the temperature like this:

var file = "/sys/bus/iio/devices/iio:device0/in_voltage1_raw"
if let input = readStringFromFile(file) {
      if let rawValue = Double(input) {  
            print("RawValue:  \(rawValue)")
            let milliVolts = (rawValue / 4096.0) * 1800.0
            print("milliVolts:  \(milliVolts)")
            let celsius = (milliVolts - 500.0) / 10.0
            print("Celsius:  \(celsius)")
            let fahrenheit = (celsius * 9.0 / 5.0) + 32.0
            print("Fahrenheit:  \(fahrenheit)")
      }
}
In this code we begin by reading the value from the /sys/bus/iio/devices/iio:device0/in_voltage1_raw file.  We then convert that string value to a Double value.  Once we have the Double value we need to convert it to millivolts using the (value/4096) * 1800 equations.  We then convert the millivolts to the temperature in Celsius and then convert the Celsius temperature to Fahrenheit.  This code will print out all of the values so you can see how everything is calculated.

To put all of this together, we would create a file named main.swift at put the following code into it:

import Glibc           
           
func stringFromBytes(bytes: UnsafeMutablePointer<UInt8>, count: Int) -> String {
      var retString = ""
      for index in 0..<count {
            if bytes[index] > 47 && bytes[index] < 58 {
                  retString += String(Character(UnicodeScalar(bytes[index])))
            }
      }
      return retString
}
           
func readStringFromFile(path: String) -> String? {
      let fp = fopen(path, "r")
      guard fp != nil else {
            return nil
      }
      var oString = ""
      let bufSize = 8
      let buffer: UnsafeMutablePointer<UInt8> = UnsafeMutablePointer.alloc(bufSize)
       defer {
            fclose(fp)
            buffer.dealloc(bufSize)
      }

      repeat {
            let count: Int = fread(buffer, 1, bufSize, fp)
            guard ferror(fp) == 0 else {
                  break
            }
            if count > 0 {
                  oString += stringFromBytes(buffer, count: count)
            }
      } while feof(fp) == 0
      return oString
}    
           
var file = "/sys/bus/iio/devices/iio:device0/in_voltage1_raw"    
while(true) {
      if let input = readStringFromFile(file){
            if let rawValue = Double(input) {  
                  print("RawValue:  \(rawValue)")
                  let milliVolts = (rawValue / 4096.0) * 1800.0
                  print("milliVolts:  \(milliVolts)")
                  let celsius = (milliVolts - 500.0) / 10.0
                  print("Celsius:  \(celsius)")
                  let fahrenheit = (celsius * 9.0 / 5.0) + 32.0
                  print("Fahrenheit:  \(fahrenheit)")
                  usleep(1000000)
            }
      } else {
            break
      }
}
We would then compile this application like this: 

swiftc –o temperature main.swift

To run the application we need to ensure that we initiate the analog ports first with the echo BB-ADC > /sys/devices/platform/bone_capemgr/slots command.  You will only need to run this command once after booting your Beaglebone.  Once you initiate the analog ports you can read the temperature like this.

./temperature

If everything is properly connected you should see the temperature printed to the screen.