Using a Beaglebone with an HC-SR04 sonar

Over the last couple of days, now that Robogames 2013 has come and gone, I’ve been working on projects that are more experiments than anything else.  A few weeks before Robogames, I noticed that there were sonars for real cheap on http://www.wrighthobbies.com/.  At the time I didn’t realize that these were all over the internet and are essentially a cheap Chinese knockoff of devices like the Ping))) and SRF04/5.  These things are dirt cheap, buying in bulk from Ebay can lead gets you prices approaching $1.50 a unit.  Seems insane because I once bought a 5 pack of Ping)))s for $100, but one can by a pack of 10 of these little guys for $15.  Needless to say I didn’t have high expectations for them.  So I ordered a couple so that I could test against my collection of Ping)))s and SRF04s.  Much to my surprise, they perform just as well as the Ping))) and the SRF04.  I don’t know how long they will be available at this price, so I ordered a whole lot more of them.  Their interface is the same as an SRF05, and you can connect the trigger pin and the echo pin and use only one I/O line per sonar, giving it the same interface as a Ping))).  One of my personal side projects is the Beaglebot, a small, tabletop or hardwood roving bot that I want to entirely operate using the Beaglebone, as in, without external AVRs, arduinos, etc.  So I set out to understanding Linux kernel development so that I could write kernel drivers for all of my hardware.  I was very happy to discover that kernel module development is actually really easy, nothing like driver development is with Windows.  Within a week I had an LED driven by PWM and you could control its max brightness and blink rate from sysfs.  At this point I was feeling confident enough to tackle driving a sonar from my Beaglebone.  My testing of the sonars previously had used an Arduino Uno and interrupts to keep the CPU free from having to wait on the sonars to respond and to be able to do stuff during measurements, etc.  This is exactly how you should write drivers for operating systems.  So I wrote my sonar driver.  And when I loaded it up and debugged it as best I could, I was disheartened that I could not get the sonar working properly, for I was getting extremely variant or random measurements.  With all of my experience with microcontrollers, my thought had been that interrupt handlers would execute when interrupts occurred, but it’s a bit more complicated than that.  Interrupts aren’t handled immediately, but rather put onto a queue which is sorted by priority and processed sequentially.  This is not good for a device where its input is time dependent.  So I began to explore other options and discovered that the Beaglebone has two high speed microcontroller cores, known as PRUs (Programmable Realtime Units), built into the CPU that can access the entirety of the memory map, meaning that they can access all of the memory, all of the IO, and the communications buses.  They both have an interrupt to the CPU so that they can signal when they’ve completed some action, in this case, that the sonar has taken a reading.  Before toying with the code, we have to hook up the sonar to the Beaglebone.  The HC-SR04 is a 5V device, and will not operate at any less than that.  As the beaglebone, along with every other ARM Cortex based system, has a maximum voltage of 3.3V, we have to protect the beaglebone from the sonar.  Essentially all I did for this was connect an NPN transistor between one of the beaglebone’s IO pins and ground.  This is fine considering that each of the IO lines on the beaglebone has a configurable pullup or pulldown resistor, we just have to note that the signal is now inverted.  The base of the transistor is connected through a 220 ohm resistor to the echo line of the sonar.  From experimenting, turns out 3.3V is enough to cause the sonar to trigger, so we can hook one of the beaglebone’s IO lines right up to the trigger pin.  The schematic is essentially this

bb-hcsr04-circuit-diagram

And this is what the  setup looks like

bb-hcsr04-circuit

bb-hcsr04-occillosope

The software I have provided on github assumes that the sonar’s trigger is using GPIO1_6 and the inverted echo signal is on GPIO1_7.  The operation of the HC-SR04 sonar is fairly straight forward.  One sends a trigger pulse of at least 10 microseconds.  The device then waits for the echo line to activate (in our inverted case, high to low transition) and measures the time from there until it deactivates (low to high in our case).  This time is the round trip flight time of the sonar pulse.  Divide this number by 58, and you have the distance to target in centimeters.

The code on the Beaglebone side is a bit less straightforward.  Unfortunately there is no higher level language available for the PRU than PRU Assembler.  Oh well I suppose.  The guide on how to use the sample code is here on my github: https://github.com/Teknoman117/beaglebot/tree/master/hcsr04-demo  In the mean time, here is a YouTube video of my sonar code in action

C++ Plugins with Boost::Function on Linux

Over the past few weeks, one of the concepts that I’ve been experimenting with is plugin architecture.  The idea of having a core application which can be extended by shared objects without recompiling the core program.  Or, possibly, a way of defining more services in an application based around plugins.  What I’ve done so far hasn’t been much, but, I haven’t spent much time working on it.  When I started out on researching it, one of the things I wanted was to be able to was define a C++ object in a plugin and be able to instantiate that object in the main program.  So, this is what I have come up with.  There are three parts of this solution: the plugin class definition in plugin.hpp, the plugin in someplugin.cpp, and the loader code in loader.cpp.  I’ve also included a CMakeLists.txt file to compile it with cmake.

plugin.hpp

#ifndef _PLUGIN_HPP_
#define _PLUGIN_HPP_

#include <string>

namespace plugins
{
  class Plugin 
  {  
  public:
    virtual std::string toString() = 0;
  };
}

#endif

awesomeplugin.cpp

#include "plugin.hpp"

namespace plugins
{
  class AwesomePlugin : public Plugin
  {  
  public:
    // A function to do something, so we can demonstrate the plugin
    std::string toString()
    {
      return std::string("Coming from awesome plugin");
    }
  };
}

extern "C" 
{
  // Function to return an instance of a new AwesomePlugin object
  plugins::Plugin* construct()
  {
    return new plugins::AwesomePlugin();
  }
}

loader.cpp

#include <iostream>
#include <vector>
#include <dlfcn.h>
#include <boost/function.hpp>

#include "plugin.hpp"

typedef std::vector<std::string>             StringVector;
typedef boost::function<plugins::Plugin* ()> pluginConstructor;

int main (int argc, char** argv)
{
  // Assemble the names of plugins to load
  StringVector plugins;
  for(int i = 1; i < argc; i++)
  {
    plugins.push_back(argv[i]);
  }

  // Iterate through all the plugins and call construct and use an instance
  for(StringVector::iterator it = plugins.begin(); it != plugins.end(); it++)
  {
    // Alert that we are attempting to load a plugin
    std::cout << "Loading plugin \"" << *it << "\"" << it->c_str() << std::endl;

    // Load the plugin's .so file
    void *handle = NULL;
    if(!(handle = dlopen(it->c_str(), RTLD_LAZY)))
    {
      std::cerr << "Plugin: " << dlerror() << std::endl;
      continue;
    }
    dlerror();

    // Get the pluginConstructor function
    pluginConstructor construct = (plugins::Plugin* (*)(void)) dlsym(handle, "construct");
    char *error = NULL;
    if((error = dlerror()))
    {
      std::cerr << "Plugin: " << dlerror() << std::endl;
      dlclose(handle);
      continue;
    }

    // Construct a plugin
    plugins::Plugin *plugin = construct();
    std::cout << "[Plugin " << *it << "] " << plugin->toString() << std::endl;
    delete plugin;

    // Close the plugin
    dlclose(handle);
  }

  return 0;
}

CMakeLists.txt

# Project Stuff
cmake_minimum_required (VERSION 2.6)
project (PluginDemo)

# Default Options
add_definitions("-std=c++0x")

# Find Boost
find_package(Boost REQUIRED)
include_directories(${Boost_INCLUDE_DIRS})

# Pull in the project includes
include_directories(${PROJECT_SOURCE_DIR}/include)
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
set(LIBS ${LIBS} pthread boost_thread rt)

# Build the plugin experiment
add_executable(pluginloader src/loader.cpp)
target_link_libraries(pluginloader ${LIBS} dl)
add_library(awesomeplugin SHARED src/awesomeplugin.cpp)

Basically create a directory with the folders bin, lib, and src. Put loader.cpp, awesomeplugin.cpp, and plugin.hpp in src, and CMakeLists.txt in the directory. Open a terminal and run “cmake . && make”. Run the pluginloader program and pass it the path to the plugin’s .so in the lib folder. Here is the output from my computer.

nathaniel@XtremePC:~/Programming/Experimentation> cmake .
— The C compiler identification is GNU
— The CXX compiler identification is GNU
— Check for working C compiler: /usr/bin/gcc
— Check for working C compiler: /usr/bin/gcc — works
— Detecting C compiler ABI info
— Detecting C compiler ABI info – done
— Check for working CXX compiler: /usr/bin/c++
— Check for working CXX compiler: /usr/bin/c++ — works
— Detecting CXX compiler ABI info
— Detecting CXX compiler ABI info – done
— Boost version: 1.46.1
— Configuring done
— Generating done
— Build files have been written to: /home/nathaniel/Programming/Experimentation
nathaniel@XtremePC:~/Programming/Experimentation> make
Scanning dependencies of target awesomeplugin
[ 50%] Building CXX object CMakeFiles/awesomeplugin.dir/Plugins/awesomeplugin.cpp.o
Linking CXX shared library lib/libawesomeplugin.so
[ 50%] Built target awesomeplugin
Scanning dependencies of target pluginloader
[100%] Building CXX object CMakeFiles/pluginloader.dir/Plugins/loader.cpp.o
Linking CXX executable bin/pluginloader
[100%] Built target pluginloader
nathaniel@XtremePC:~/Programming/Experimentation> bin/pluginloader lib/libawesomeplugin.so
Loading plugin “lib/libawesomeplugin.so”
[Plugin lib/libawesomeplugin.so] Coming from awesome plugin
nathaniel@XtremePC:~/Programming/Experimentation>

– Teknoman117

Hacking new MCUs into Arduino IDE

Its probably safe to assume that most of you who end of reading this have heard about the Arduino.   For those of you who haven’t heard of it, they are the latest microcontroller craze and they are selling by the tens of thousands.  Basically its a development board for a few lucky Atmel AVRs and it has a standard expansion connector set to adapt with numerous peripheral boards.  Personally, I’m not too much of a fan of them, for most of my projects I don’t need a board with a boot loader.  I own an AVR ISP mk.ii programmer and I don’t need to spend $35+ on a board with a $2 ATmega328 when I can by an ATmega644 or a larger chip for $4 and build my own dev board for another few dollars or so.  Although, I do understand that they are nice for prototyping and what I’m doing is more of an end-product type thing.

The robot I built with my friends from the UC Merced Robotics Society for Robomagellan in the spring 2012 semester used a pair of Arduinos and I wanted to use the code I developed there with my pre-existing software framework for the AVRs.  Since I don’t have any arduinos hanging around, I needed to either port the code or just make my own arduino.  My favorite AVR is the Atmega644, it has a ton of I/O and the most flash of any DIP variant AVR.  I came across this web page on using a chip from the most popular of the arduinos in its bare chip form to run a christmas frame.  It goes over how to add a definition to the  arduino IDE hardware list.  As I was reading through it, I noticed a few places where I could set different MCUs, frequencies, etc.  So I decided to try it out.

There are a multitude of steps in adding a whole new MCU to the arduino environment, these are assuming you are adding a new class of chip (such as the ATmega644)

  • Create a new “variant.”  This defines how the arduino IDE’s digital pins and analog pins map to the physical pins on the device.  This file also covers the pwm and pcint pins as well
  • Modify “wiring_private.h”
  • Add a new hardware entry

The arduino ide manages different devices in what they seem to call variants.  Each variant is a definition of the chip that you are using.  It defines how pins map to internal components of the AVR.  The first step is defining how many analog and digital pins exists on the device.  The rest of the file is mapping arduino digital pin numbers to registers in the device.  It also covers how these pins translate to their corresponding PCINT pins and which pins have PWM capabilities and what timer drives it.  You can get this in my github repository.

The next step is to modify the wiring_private.h header and add the new mcu’s external interrupt count.  You can see where I added the ATmega644 on line 57 of wiring_private.h

The last step is to add an entry for the board you are using.  The board I used is rather old.  It was designed by Wrighthobbies about 7 years ago.  It was literally not much more than a board that broke out the pins of an ATmega32 and provided a stk200 compatible programming header, a reset button, two 5V regulators, an optional oscillator, and some power rails.  The ATmega644 and its variants are pin for pin compatible with the ATmega32, so I just replaced the chips.  Although, you can add a comment to your order at Wrighthobbies and Eddy will just ship an ATmega644 with it.

The hardware testing of the ATmega644 arduino mod with it hooked up to my avrispmkii and an LED

We need to add an entry into “Arduino.app/Contents/Resources/Java/hardware/arduino/boards.txt” to reflect the devboard’s settings

devboard_m644.name = Wright Hobbies Devboard w/ ATmega644 and ext 11.0592 MHz osc

devboard_m644.upload.protocol=stk500
devboard_m644.upload.maximum_size=65536
devboard_m644.upload.using=avrispmkii

devboard_m644.bootloader.low_fuses=0xCE
devboard_m644.bootloader.high_fuses=0xDD
devboard_m644.bootloader.extended_fuses=0×FF

devboard_m644.build.mcu=atmega644
devboard_m644.build.f_cpu=11059200UL
devboard_m644.build.core=Arduino
devboard_m644.build.variant=atmega644
  • <board name>.name – provides the textual name of your board that you are presented in the Arduino IDE.
  • <board name>.upload.protocol – the protocol which your programmer uses.  In the case of the AVR ISP mk.ii this is stk500
  • <board name>.upload.maximum_size – the size in bytes of the flash ram on your AVR
  • <board name>.upload.using – the programmer which you want to use with your chip
  • <board name>.bootloader.low_fuses – the low fuse byte to set in your chip (see http://www.engbedded.com/fusecalc)
  • <board name>.bootloader.high_fuses – the high fuse byte to set in your chip (see http://www.engbedded.com/fusecalc)
  • <board name>.bootloader.extended_fuses – the extended fuse byte to set in your chip (see http://www.engbedded.com/fusecalc)
  • <board name>.build.mcu – the MCU you are adding
  • <board name>.build.f_cpu – the frequency it operates at
  • <board name>.build.core – currently, unless you want to write your own core library, set it to arduino
  • <board name>.build.variant – set to the variant of the chip you created earlier

Here is an example of it in the editor

See the board name in the bottom right corner

There is one caveat when doing this though, you have to use the “Upload with Programmer” option instead of just the upload button.  Here are two YouTube videos of it working and all of the sources for this are available on GitHub in my repo – http://github.com/Teknoman117/avr-libraries

Blinking LED

Ramping LED