LeapPad 2 on Ubuntu/Virtualbox

The developers over at LeapFrog have not supported Linux in the least – which sucks.  I found various articles on using VirtualBox, but none of them seemed to work.  At first, I hoped to get by without installing the software and connecting to a computer at all, but at some point the device got screwed up and would not boot without “a tuneup”.  I assume this repairs OS files that the kiddos somehow damaged by pulling the batteries during a filesystem write, or accidentally accomplished a boot-up key sequence that triggered the tuneup.

So here’s what I did to get it working on Ubuntu 14.04.

Rant first: I’m a little shocked at the technologies selected for the LeapPad – the hardware is actually pretty amazing for the price, but then they screwed everything over by selecting LAN over USB, Adobe Flash, and some other really bizarre software choices that practically guarantee a difficult time for most users, instead of a nice clean install and user experience.

This post partly borrows from some (IMO incomplete) UbuntuForums posts that talk about the same thing.

The instructions:

  • Install VirtualBox from Oracle’s website.
    • Download VirtualBox
    • Install using: sudo dpkg -i <filename>.deb
    • Download VirtualBox Extension Pack from the same page.
    • Install by clicking from the OS, or by running from the terminal: virtualbox Oracle_VM_VirtualBox_Extension_Pack-<VERSION>.vbox-extpack
    • Make sure users have access to the machine:
      • Some claim adding your user to the “vboxusers” group solves permissions issues – I simply run it as sudo.  Bad idea, I know, but when children’s hopes and dreams are on the line…
      • To be able to run as your own user instead of using sudo:
        sudo adduser USERNAME vboxusers
  • Download, import, and configure a free IE test virtual machine.
    • Download from https://dev.windows.com/en-us/microsoft-edge/tools/vms/linux/
      • I used Win7 with IE10 – ymmv.  If you have a license of Windows, that would also be a good option.
    • Run VirtualBox (again, either as sudo or you must have added yourself to the vboxusers group).
    • Go to “File -> Import Appliance…”.  Navigate to the downloaded IE test virtual machine *.ova file and import it.  Run it through the normal settings.
    • Before running the virtual machine, we need to enable USB 2.0.
      • Right click on the virtual machine, and select “Settings -> USB”, and then click on USB 2.0.
      • Plug in your LeapPad and wait a few seconds for it to enumerate.
      • On the right hand side of the screen, click on the USB icon with the green “+” sign on it.  Find the LeapPad, and click on it to add a filter that forces it to pass through to the virtual machine.
  • Start the virtual machine, install the LeapFrog Connect software.
    • Open up IE once you’re in the machine and go to the LeapFrog Connect download page.  Select your device (I’m working on a LeapPad 2, so that’s download option I selected).
    • Install the software.  Pick the default settings.
      • When installing the Adobe Flash update, I HAD to install McAfee antivirus to get it to work – without it, the LeapFrog Connect software would not kick-start the Adobe Flash install, and would hang.
  • Remove McAfee and disable the firewall.
    • Go to “Control Panel -> Programs -> Uninstall Programs”, and select McAfee from the list.
    • Go to “Control Panel -> System and Security -> Windows Firewall”.  On the left, there’s a link that says “Turn Windows Firewall on or off”.  Turn OFF Windows Firewall for all locations, then press “OK”.
  • Run the LeapFrog connect software.
    • Once it’s all the way up, plug your LeapPad into the USB port and turn it on.
    • If your device doesn’t appear, right click on the USB icon at the bottom right of your VirtualBox window and select your LeapPad from the list:virtualbox_usb
    • IMPORTANT FOR TUNEUP: Watch this icon closely.  If the LeapPad appears to not be talking, right click on this icon and re-capture the USB device.  During the tuneup, it disconnected several times (5%, 35%, and 80%, IIRC) and as long as the USB device was reconnected before the process timed out, the progress bar would continue.
    • During normal operation, it seemed to just work fine – only during odd operations did it crap out on me and I’d have to watch it closely and reconnect.
  • We’re done – Take a snapshot so you can come back to it after the 90 day trial expires on the IE virtual machine.

 

Hope this saves someone else hours of time figuring it out while their child is bawling on their shoulder!

 

Advertisements
Categories: General

Bluition

14 June 2012 21 comments

 

I’ve Made Some Special Modifications Myself

My current mode of transportation is a quasi-beat up, hot red Kymco ZX50 scooter.  Let’s face it – if it doesn’t look like much on the outside, you’d better make some special modifications yourself.  In comes Bluition.

 

The Run Down

Bluition is a bluetooth ignition device that allows me to control my scooter from my Android phone.  Here’s the run down:

  • My Droid 4 runs a program called Tasker.  Tasker is an AMAZING program that can run applications or other actions given specific events or states.  I’ve put instructions for it to call a specific Python script given a specific gesture is detected.
  • Python for Android provides a very simple scripting system.  It was amazing how few lines of code were needed to open up a Bluetooth connection and send commands to the bluetooth module on the scooter.
  • An RN-42 Bluetooth module from SparkFun receives the commands from the Android phone.  The commands include instructions to set GPIO pins high or low.
  • The RN-42 outputs are then connected to MOSFET drivers, which in turn drive mechanical relays.  Again, SparkFun parts.
  • The mechanical relays are connected into the scooter ignition, starter as well as a solenoid that pops opens the seat lid.
  • The solenoid was purchased from SparkFun also.  While it provides precious little force, I managed to eek just enough out of it to pop the scooter seat lid (which encloses the glove/helmet storage compartment) by connecting the solenoid plunger to the connector up through a bowden cable.
  • And foot bone is connected to the knee bone…

The setup was pretty simple and done dirt cheap – see the bill of materials below.  My favorite part was that I didn’t have to use a microcontroller.  As much as I love microcontrollers (my day job is firmware programming), it was nice for a change to be able to just focus on electronics and wiring.

This setup could be used for just about anything that just needs an on/off relay with the actual programming to a smart phone.  I’m sure if Han had one, he’d totally be scripting his droid to automatically control a mog feeder on the Falcon.

In the interest of time, I’m not going to fully comment how I made it.  If there’s enough interest (leave a note in the comments), I’ll draw up an Instructables tutorial on how to connect it and possibly even make pre-assembled kits.  Hopefully I’ll give you enough info below that if you have some experience you should be able to put it together without much trouble.

 

Bill of Materials

Let’s start with a BOM.  Links provided where available.  Some components were just lying around.  My SparkFun order for the parts I didn’t have was only $50, but the total is probably around $75-$100.

 

Tools

  • Socket wrench and set
  • Socket drivers
  • Pliers (regular and needle nose)
  • Wire cutters & strippers
  • Crimp tool
  • Soldering iron
  • A butane soldering iron was particularly handy when soldering on the scooter itself (but there are other ways)
  • Phillips and Flathead Screwdrivers
  • Allen wrench set
  • Power drill and bits, preferably with a step drill

 

Time

All told, I spent about three full weekends on this.  Now that it’s all figured out, if I had a PCB already built and the wiring diagram it would probably only take a rainy Saturday to do.

 

Build Pictures

Here are a few pictures that I took throughout the build process.  I have more, but these are a decent overview.

 

Build Notes

A few notes about individual items.

The Scooter

The goal was to keep the original scooter electrical setup intact so I’m not screwed if (when?) the electronics get a bad spike, water shooting into the console, etc. and blow up.  I mostly succeeded – at least I know I could use the scooter without the Bluition module if necessary.

Over half of the scooter exterior had to be removed in order to get access to all the wiring needed.  Things that came off: The front, the handlebar covers (still hanging there by control cables and wires, but all screws & bolts were out), the seat, storage compartment, carrier rack, and seat latch.

Wiring

The wiring was pretty straightforward, except for the ignition.  I’m no grease monkey, so this is my simple interpretation of the mechanic’s manual and various forum postings:  +12V gets connected, obviously.  But there was another connection that was grounded when the ignition switch was in the off position, then left floating when in the on position.

My (frail) understanding is that it grounds the Capacitor Discharge Igniter, which removes sparkability from the spark plugs and forces the engine to die.  If I didn’t connect this, I could start the scooter but the engine kept running when the ignition signal was removed.  You’ll notice there’s an extra relay in the pictures that looks like it was added haphazardly as an afterthought – bingo.

The starter was simple – there’s a starter switch on the handlebars.  Simply used tap splices, and connected both sides to a relay in parallel with the starter switch.

The solenoid relay just sucked power from the +12V rail.  Easy peasy.

I ran a Bluition power switch (sealed rocker) up to the handlebars so that, when not in use, the Bluition module wouldn’t suck the battery dry.

Seat Latch Solenoid

This was pretty tricky.  It boiled down to lubricating the Bowden cable well with silicone grease, and getting the Bowden cable entry and exists as parallel as possible with the path of the solenoid and latch.  On the solenoid side, I removed the spring and plastic washer and put a ball of solder on the cable to hold it in place.  The extra-hot butane soldering iron was helpful with this.

On the latch end, after trying many approaches I ended up just zipper tying the cable to the existing key-triggered cable.  I also zipper tied the solenoid to the chassis outside of the storage compartment area, and zipper tied the Bowden cable itself to places where it held the cable in locations that allowed parallel entry into the sleeve.

Bluition Installation

Running wire all over and getting all the signals wasn’t too bad.  Labeling the wires as I ran them helped a ton.  It was really nice using the tap splices over soldering.

The module itself was installed in the “glove box” console area.  I mounted each component onto a plastic sheet using foam tape, and then mounted the plastic sheet onto the inside of the console.  I had every intention of using Sugru to encapsulate the module, and I may still do so.  But until I know it’s going to work reliably I’ll hold off.

RN-42 Bluetooth Module

I was blown away at how cheap this sucker was – and it worked like a charm too!  Dead bug soldering was a bit of a pain, but not too bad.  I’ll post a schematic at a later date to show which wires went where, but just look at the data sheet – any of the PIO pins 7 or below can be used.  I couldn’t get PIO pins 8-11 to work – the datasheet says some modules don’t have these, and I can only assume this is one of them.  They can provide a few milliamps each, but they work just fine driving the MOSFET gates with a 120 ohm resistor in series.

 

Python Environment and Code

First, let’s talk about the environment.  BTW, it was WAY easier to get things working here than it was on my laptop in Ubuntu.  Here are the Android apps that I’ve used to make things happen:

  • Tasker– This program automates your smartphone in so many ways.  I set it up so that if I shook the phone in one of three axes, a Python script that performed a specific action occurred:
    • Front to Back Shake: Start the scooter
    • Up and Down Shake: Stop the scooter
    • Left to Right Shake: Open the seat lid
  • SL4A: Scripting Layer 4 Android is a program that provides a common layer for many different scripting languages so they can be ported to Android.  Python for Android is an interpreter used by SL4A.
  • Python for Android – Python interpreter used by SL4A to let us run the scripts.

Now for the fun part – code!  I was amazed at how simple it was in the Python for Android environment.  I think you will be too.  Before starting, make sure you’ve paired your Android phone with the RN-42 module through the “Settings -> Wireless and networks -> Bluetooth” menu.

Then, you can run scripts like the following that open up a Bluetooth connection, then enters command mode, then sends a GPIO command.  Easy peasy.  The following script is called StartScooter.py.

import android
import time

droid = android.Android()

# Over-the-air commands that modify the GPIO pin states on the RN-42 module.
IGN_ON = 'S&,1808\r' 
IGN_OFF = 'S&,1810\r'
SEAT_ON = 'S&,4040\r'
SEAT_OFF = 'S&,4000\r'
STRT_ON = 'S&,9080\r' 
STRT_OFF = 'S&,9000\r'
INIT_DDR = 'S@,D8D8\r'
print "Enabling Bluetooth..."
droid.toggleBluetoothState(True)
print "Connecting to scooter RN-42 module..."
# Change the X's in the following line to match your MAC address.
droid.bluetoothConnect('00001101-0000-1000-8000-00805F9B34FB', 'XX:XX:XX:XX:XX:XX')

print "Entering command mode..."
droid.bluetoothWrite('$$$')
res = droid.bluetoothReadLine()
print res

print "Initializing PIO direction..."
droid.bluetoothWrite(INIT_DDR)
res = droid.bluetoothReadLine()
print res

print "Sending ignition on command..."
droid.bluetoothWrite(IGN_ON)
res = droid.bluetoothReadLine()
print res

print "Sending starter on command..."
droid.bluetoothWrite(STRT_ON)
res = droid.bluetoothReadLine()
print res
time.sleep(1.7)

print "Sending starter off command..."
droid.bluetoothWrite(STRT_OFF)
res = droid.bluetoothReadLine()
print res 

droid.bluetoothStop()

Just write up a script with the basics of the above script in it, run it in SL4A, and it will toggle GPIO pins on the RN-42 module.  See the RN-42 user’s manual for more info on the GPIO commands, and the Python for Android documentation for more info on the Android API.

 

In Conclusion

In the altered words of Jack Handy:”If you ever get the chance to choose between regular heaven and Bluetooth heaven, choose Bluetooth heaven.  It may be a joke, but if not, mmmm boy!”

.

Categories: General

FIX: Include error in Eclipse after upgrading GCC

Just writing a quick post today. I’ve had an error for quite a while that’s been bugging me, and I finally got around to figuring out how to fix it. It’s kind of like when your copilot gets fleas – it bugs you, but sometimes you just deal with it because of more pressing issues.

I was trying to work around a problem a while back that I though would be fixed by upgrading the version of AVR-GCC I was using. While I got the new version working (4.3.5), it had removed the old version (4.3.4) and for the past few months I’ve constantly had to ignore warnings about not being able to find include folders.

The error was something like:

"Include path not found" /usr/lib/gcc/avr {version specific etc...}

The fix is pretty simple.  I found the solution here, but I didn’t follow it exactly.  It asks you to delete the following file – I didn’t want to risk losing any workspace settings, so I modified it instead.

  1. Open up your workspace.
  2. Open the file:  ${workspace}/.metadata/.plugins/org.eclipse.cdt.make.core/${projectname}.sc
  3. Find all the references to your old library path.  I found three references near the top of the file – simply delete those lines.
  4. Restart Eclipse.
Categories: General, How-To Tags: , ,

Life Update and Checkerbot Follow Up

Wow, it’s been altogether too long since I’ve posted.  Fortunately, and this is important, I’ve been able to spend a lot of great, quality time with my family.  We recently had a great time at the Oregon Beach and at the A.C. Gilbert Children’s Museum since my return from interning at the Robotics Institute at Carnegie Mellon University. (No, really, I was there!)  I’d been away from the wife and kid (“kids” including the one due in September!) for about a month, and it was great to be back.

For just a paragraph or two, I’ve gotta spill some philosophy.  Even before you have a family, and especially after you start one, hopefully everything you’re doing is for their current or future benefit.  There is nothing that can replace the fulfillment of a loving family, and like all great things, it requires preparation.  An interesting point of fact that is that Sam Walton, someone who spent his whole life innovating and who founded the largest retail chain in the world Wal-Mart, determined that he failed in life.  His last three words, given on his death bed while surrounded by his family that he hardly knew, were “I blew it!”

No one’s perfect, it’s just important to be making progress rather than regress.  New goal in life for me: Don’t blow it.  I gotta make a little bit more effort in that area, and I’m thinking even just a random act of kindness or two a day for the people I love will help.  Now, go to your room and think about it for 10 minutes, then come back and read the rest of my post. ;)


Me standing next to Boss, winner of the 2007 DARPA Urban ChallengeI had an amazing time at the Robotics Institute.  That’s me next to Boss, the autonomous Chevy Tahoe that won the DARPA Urban Challenge a few years back.  It drove itself, without collision and following all normal traffic rules, through a 60 mile urban obstacle course.  It is one of the most famous robots alive.  Boss vs Brad: Brad loses.  Boss vs Millenium Falcon: I’d love to see that show up on Youtube…

I got to work with a great group of people on a really fun, agriculture related robotic project.  I’ll probably share more on that in the future, but it’s not for me to talk about yet ;).  Most of the people around me were working on the Google XPrize project, and it was awesome to see that and other jaw-dropping amazing projects in the bay I was in.

I’d like to share a follow up post on how the checker playing robot went.  It was pretty fun, albeit stressful.  We knew at the outset that the chances of successfully navigating this project was 3,720 to 1, but we decided the risk was worth it.  Plus, we figured we could call the support desk to help us get through any ID10T errors.

The robot was based on the new XMega AVR processor.  It has quite a few more features than the standard AVR chips, which also made it a bit more difficult to use.  I recommend AVR processors highly, but unless you need functionality only provided by the XMega series, I would recommend most beginners stick with AVR chips from the ATMega series.  This project, however, needed the higher processing power, the larger RAM, and the higher flexibility of peripheral hardware offered by the XMegas.

I don’t want to repeat too much of the description of the design and process that my lab partners and I went through to do this project – it’s already available on the project website here.  You can download the SolidWorks CAD, EagleCAD, C code, and other project files from there.

So it wasn’t quite capable of playing checkers at the end of the term.  Our grades took a bit of a hit because of that, too, but it was great to try something new and the reason for this design is as follows:  We tried tackling this problem from a user’s point of view, which is something I believe is left out of academic and commercial projects all too often.  Who likes to play checkers?  Children and old men in the park.  Most other robots in the class were gantry or industrial robot arm based and relied on a laptop tether to function, which could never be practical when used by children or the elderly for safety, expense, and ease of use reasons.

Our robot weighed in under a pound and was, at least theoretically, easy to use and setup.  It used AA batteries and would be safe for anyone to use, and not expensive to replace if broken.

Now, if only it had worked :D.  The robot performs computer vision by reading images in from a UART based camera directly into the RAM of the XMega.  The XMega then determines where the checker pieces are at, calculates moves, and then goes out onto the board to execute those moves.  We fell just short of what was needed for full functionality in most areas due to lack of time and lack of experience with certain components.  As you’ll see in the video, poor motor control and localization was the primary point of failure.  Check the project website for a more detailed synopsis of what worked and what didn’t.

In this video, the robot has just captured an image and is moving from the image capture location to the checker board to make a move.  All decisions were autonomous, but the bot was stepped through its motions one step at a time and assisted when its localization or movements were out of place.

XBoot – Quick Start Guide (for a sweet XMega bootloader!)

So in my recent XMega wanderings,  I needed a good bootloader.  After muddling through various app notes and forum postings, I came across the culmination of what I couldn’t do on my own – XBoot!

In my defense, I’ve worked on bootloaders before.  But the errata sheet on the XMegas is longer than the list of men Princess Leia has broken the hearts of.  And I’ve become one of the many casualties of that list.  (Erm, the errata list…  awkward…)

Big thanks to Alex Forencich!  XBoot, a fantastic reincarnation of the AVR1605 app note, is open source and highly configurable bootloader, which at the time of writing is capable of UART or I2C bootloading XMega processors.  I believe his intentions are to expand both processor compatibility and protocol options, so visit the XBoot Google Code project for more info.

I’ll  be going through and explaining the options that I used, so this isn’t an exhaustive tutorial.  This guide assumes you have a working XMega development environment, AVRDude installed, and SVN (if you want to download the code this way).  WinAVR should work just fine with a few minor alterations, but I’ve only tested this on Kubuntu with the development environment described in this previous blog post.  Also, as a side note, I’ve been using XBoot with XBee Series 1 wireless modules and it works fantabulous (that’s so good, I had to come up with a new word for it).

Overview

Here’s the step-by-step big picture:

  1. Download the code.
  2. Pick a bootloader entry method.
  3. Configure communication parameters (Port/Baud Rate/I2C addressing, etc.).
  4. Compile & program XBoot onto the MCU.
  5. Send main application via XBoot and AVRDude.

Download the Code

So let’s get started.  Download the code from the XBoot download page and uncompress it, or (my preference) use SVN to download the code:

svn checkout http://avr-xboot.googlecode.com/svn/trunk/ avr-xboot

Configure XBoot

Once the code is downloaded, find the file named “xboot.h”.  Most configuration changes, if not all, will be made here.  We’ll take it one section at a time.  Line item references are from Rev12 out of the repository, but you should be able to match them up to any version.  The idea is that all available options are enabled, so comment out what you won’t be using.

// AVR1008 fixes
// Really only applicable to 256a3 rev A and B devices
//#define USE_AVR1008_EEPROM

Uncomment this line if you’ll be using an XMega256a3.  This fixes certain problems (remember Princess Leia the errata list?). I’ve heard this has hit some people but not others, even on the same silicon revision.  It may be useful for certain other chips and families – YMMV.  Check with Google if concerned.

Line 64:
// bootloader entrance
#define USE_ENTER_DELAY
//#define USE_ENTER_PIN
#define USE_ENTER_UART
//#define USE_ENTER_I2C

Here I picked the “USE_ENTER_DELAY” and “USE_ENTER_UART”, hence I commented the other two out.  Note that the “USE_ENTER_DELAY” just puts a delay at the start of the program, and isn’t mutually exclusive with the other options.  Here’s what the options mean:

  • USE_ENTER_DELAY: Delays entry by a timeout.  Timeout is set by “ENTER_BLINK_COUNT” and “ENTER_BLINK_WAIT”, but I found the default settings worked well.
  • USE_ENTER_PIN: Select this option if you want to enter the bootloader when a pin is in a certain state at power on.  Ex: You press a switch when you power cycle to enter the bootloader.  You’ll have to configure which port/pin at line 95, at the section titled “ENTER_PIN”.
  • USE_ENTER_UART: Select this option if you want to enter the bootloader if a character is received on the UART.  This requires using “USE_ENTER_DELAY” by necessity.  You’ll need to configure the UART options at line 111.
  • USE_ENTER_I2C: Select this option if you want to enter the bootloader if a byte is received through I2C.  I haven’t used this option, hence I won’t try to elaborate.

On to the next section:

Line 73:
// bootloader communication
#define USE_LED
#define USE_UART
//#define USE_I2C
//#define USE_I2C_ADDRESS_NEGOTIATION
//#define USE_ATTACH_LED

I’ll be using the UART and LED, so everything else is commented out.  If you use the LED, configure the next section also:

Line 106:
// LED
#define LED_PORT                PORTA
#define LED_PIN                 0
#define LED_INV                 1

If you’re using the UART, configure this section:

Line 111:
// UART
#define UART_BAUD_RATE                  19200
#define UART_PORT                       PORTD
#define UART_DEVICE_PORT                D1
#define UART_DEVICE                     token_paste2(USART, UART_DEVICE_PORT)
#define UART_DEVICE_RXC_ISR             token_paste3(USART, UART_DEVICE_PORT, _RXC_vect)
#define UART_DEVICE_DRE_ISR             token_paste3(USART, UART_DEVICE_PORT, _DRE_vect)
#define UART_DEVICE_TXC_ISR             token_paste3(USART, UART_DEVICE_PORT, _TXC_vect)
#define UART_TX_PIN                     PIN7_bm

Should be pretty self-explanatory.  You should only need to change UART_BAUD_RATE, UART_PORT, UART_DEVICE_PORT, and UART_TX_PIN.  If you use an exotic baud rate (non-standard and/or fast), you might want to change the settings at line 51 and select the 32MHz clock option.

That’s pretty much it for this section!

Compile & Program

This should work if you’re using AVR-GCC in Linux.  I can’t vouch for WinAVR, but it shouldn’t take much to change it.  That said, the only thing that really needs to change in the Makefile is the programmer name and the chip you’re compiling it for:

Line 42:
# MCU name
## MCU = atxmega16a4
## MCU = atxmega32a4
## MCU = atxmega64a1
## MCU = atxmega64a3
## MCU = atxmega64a4
## MCU = atxmega128a1
## MCU = atxmega128a3
## MCU = atxmega128a4
## MCU = atxmega192a1
## MCU = atxmega192a3
## MCU = atxmega256a1
## MCU = atxmega256a3b
MCU = atxmega256a3
#MCU = atxmega64a3
#MCU = atxmega128a1
#MCU = atxmega32a4

For me, I’ve been using the XMega256A3 chip.  At random, I decided to uncomment the atxmega256a3 line.  YMMV.

Line 209:
#AVRDUDE_PROGRAMMER = jtag2pdi
#AVRDUDE_PROGRAMMER = avr109
AVRDUDE_PROGRAMMER = avrispmkII

And I’m using an AVRISP mkII programmer, which is pretty cheap for an authentic Atmel programmer.  It only does PDI programming (no debugging), and needs to be updated to the latest firmware using AVR Studio (sorry, penguins – you’ll have to boot into Windows), but it does the XMega trick right nicely.

To compile and subsequently program:

$ make
$ make program

This should compile and program XBoot into the programmer.  Shazaam!  If you get any errors, feel free to leave me a comment and I’ll try to help you out.

Programming an Application Via XBoot

So now that you’ve got XBoot loaded, you can use AVRDude again to program your application to your XMega:

avrdude -p atxmega64a3 -P /dev/ttyUSB0 -c avr109 -b 19200 -U flash:w:main.hex

For those of you who may have installed Eclipse as described in previous posts, you can make Eclipse use the bootloader by:

  • Click on “Run -> Run Configurations…”
  • Right click on “C/C++ Application” on the left and select “New”
  • In the “Name:” textbox, enter “Program via XBoot”
  • In the “C/C++ Application:” textbox, enter “/usr/bin/avrdude” (or where ever it’s installed if you’re using Windows)
  • Click on the “Arguments” tab.  Enter the following line, modify to suit your needs, and then click “Apply” and “Close”
-c avr109 -p x256a3 -P /dev/ttyUSB0 -b 19200 -e -U flash:w:Debug/eclipse_project_name.hex

There you have it.  As always, if you need any help just ask in the comments below!

 

svn checkout http://avr-xboot.googlecode.com/svn/trunk/ avr-xboot-read-only

Checkers? What the … oh … Checkers!

In case you’ve noticed, my last few posts have not been about the ZephyrEye.  Not to fear – ZephyrEye is alive and well!  Boards should be readily available soon.  So for everyone out there interested in hacking together some Battlefront radar screens with your paintball/laser tag buddies, it is coming shortly.  Of course, if you can’t wait, feel free to grab the schematics and spin your own PCB ;)

So what the heck have I been posting about?  As I mentioned previously, I’m taking a Mechatronics course where we have to build a checker playing robot.  Here’s a conceptual animation for the design that my team and I came up with:

I used Blender3D to animate this video.  I’ve found with several of my robotics projects that most people get confused when I try to describe it.  By making a rough 3D sketch and animating the intended functionality, I’ve been able to talk with people much more effectively and get faster and better feedback about what will or won’t work.  It also helps me get several jumbled and mixed together concepts in my head down to a single, better defined concept.  If you’re planning on doing robotics, especially if you’re working on it from an electronics point of view, I’d highly recommend learning a 3D sketching system.  But I digress…

So this checker playing robot needs to be able to play checkers completely autonomously.  Most teams used either a stationary robotic arm or gantry style approach.  I’ve never been a big fan of either, in fact, I’m pretty enamored with the concept of small autonomous mobile robots.  A big reason for this is the ability to quickly apply swarm concepts to these robots if you build a few up, which is something I always toy around with in the back of my head but never do.

Here’s some of the primary system components and a simple description of each of them:

  • XMega256: Pretty powerful little chip.  I both appreciate this chip and its potential, and at the same time can’t believe how long the errata list is.  It’s pretty bad, but fortunately I haven’t run into too much trouble yet.  I’ll be using this for all of the checker-playing AI, computer vision, and localization tasks.  Yep, you heard me: computer vision on an AVR!
  • C328: OK, so the computer vision isn’t as hard as it could be – the COMedia C328 is a pretty easy to use (relatively speaking) UART camera.  The datasheet sucks, and it looks like it’s being discontinued.  I’m sure other similar parts will crop up soon, though.  I’ve been reading in raw 565 RGB images into the XMega RAM and finding color blobs with it.  I can also transmit a JPEG to a computer via XBee.
  • XBee: I use these for just about everything.  I usually write up a debug interface between the computer terminal and the robot so I can debug very quickly, and portably – it’s just as easy to debug and control from my desktop as it is my laptop, making presentations a lot easier.
  • Servos: We went with servos for motor control.  As my other posts have alluded, I’m using some hacked for continuous rotation, and instead of controlling position I’m controlling their speed with a standard servo signal.  To maintain balance (I didn’t want to go down the inverted pendulum road…), the bot also has a servo with a “propeller” mounted in front.  The propeller slides over checkers as the bot goes forward and backwards, but rotates when the bot turns to avoid strafing the board and moving checker pieces all over the place.
  • IR Sensors: There’s a bank of 6 IR emitter/detector pairs on the front of the bot.  These are used to detect where the bot is at on the checkerboard.    By monitoring the difference between when a left and IR detectors hit a checker square, you can also correct and maintain orientation so you don’t knock checkers all over the board.
  • Odometer Sensors: More IR sensors, this time the QRE1113 reflectance sensors.  These sensors monitor a band of alternating light/dark colors on the inside of the wheel, so every time the wheel moves a certain distance, the XMega gets a “tick” that’s worth a certain distance.
  • Chassis: A benefit of being in school, I have access to 3D printers that can take certain CAD files and actually “print” 3D objects in ABS plastic.  We used this for the chassis, which put all of our servo mounts, sensor mounts, and other typically difficult-to-make-precise-on-prototype features a lot more accurate.  It cost about $30 – not bad for what we get.

That’s the general idea.  Here’s a picture of where it’s at right now:

Here’s hoping that I get it done in time!  I don’t think it’ll get done in 12 parsecs, but that’s a measurement of space and not time anyway …

Servo Control with an XMega

I’m not going to go into a long treatise on PWM servo signals – there are plenty of references for that already.  I’d like to focus on a simple way to do a bunch of servos with fairly accurate timings on an XMega.  Also, I know this isn’t an optimal implementation – there are efficiency improvement that could be made on almost every front.  But it took me almost no time to come up with, and that says a lot.  I’m more of an idoit than I let on…

The method I’m going to line out below can drive up to 7 servos completely in interrupts.  It’ll use up your timers, but it’s easy peasy and will save you time if you don’t need all your timers for other tasks.

So, we’ve got a standard servo signal that’s composed of basically three stages:

  1. A twenty millisecond low period.
  2. A one millisecond high period.
  3. A variable high period:  To turn the servo to one extreme, force the signal low immediately.  To turn the servo to the opposite extreme, force the signal low after a full millisecond.  To turn it to some point in between, just vary the signal at this point between zero and one milliseconds.

With the advent of the XMega, the AVR series of microcontrollers now have an plethora of peripherals, notably for this article eight 16-bit timers.  EIGHT!  That’s power, baby.  For this example, I’ll only do two servos, which will require three timers.  That seems like a lot because with most ATMegas, that was about it – you only had 4 timers, and only two of those were 16-bit (and 8-bit timers == headaches

I started from App Note AVR1306, which describes the timers.  BTW, app notes are the way to become familiar with the XMegas, especially if you’re coming up from the previous AVR families.  Download the drivers along with the PDF, they’re pretty useful.  Include these in your project.  I’ve used these with only a few modifications, and they’ve worked pretty well for me so far.

Set up a global array that can be used for servo position variables:

volatile uint16_t servo[3];

Note it’s declared volatile – this is necessary for all variables you’ll be using between the main loop and an interrupt service routine.  Also note that I declared 3 spaces for two servos – on this particular one, I liked labeling the servos “Servo1”, “Servo2”, etc. instead of base zero.  Personal preference, but adding the extra byte keeps the numbering consistent between labels and array index.

Next up is the timer initialization routine.  Let’s look at it first.  The comments are fairly explanatory, and I’ll go through it a little more afterwards:

/*! \brief This function initializes timers for use as servo PWM signal drivers.
 *
 *    This function initializes timers for use as servo PWM signal drivers.
 *    It probably wouldn't hurt to improve this by making it modular at some point...
 *
 *    - TimerD0: 20ms servo timer.  This timer triggers the rest of the servo position timers.
 *    - TimerD1: 1-2ms Servo1 position timer.
 *    - TimerE0: 1-2ms Servo2 position timer.
 *
 */
void init_timers()
{
    //! TimerD0: 20ms Servo Timer
    TC_SetPeriod( &TCD0, 2500 );                            // Set period (2500 ticks = 20ms)
    TC0_SetOverflowIntLevel( &TCD0, TC_OVFINTLVL_MED_gc );  // Set Interrupt on Overflow
    TC0_ConfigClockSource( &TCD0, TC_CLKSEL_DIV256_gc );    // Set clock and prescaler (8us per tick)

    //! TimerD1: Servo1 Position Timer
    TC1_SetOverflowIntLevel( &TCD1, TC_OVFINTLVL_OFF_gc );  // Set Interrupt on Overflow, but not yet
    TC1_ConfigClockSource( &TCD1, TC_CLKSEL_DIV256_gc );    // Set clock and prescaler (8us per tick)

    //! TimerE0: Servo2 Position Timer
    TC0_SetOverflowIntLevel( &TCE0, TC_OVFINTLVL_OFF_gc );  // Set Interrupt on Overflow, but not yet
    TC0_ConfigClockSource( &TCE0, TC_CLKSEL_DIV256_gc );    // Set clock and prescaler (8us per tick)

    PMIC.CTRL |= PMIC_MEDLVLEN_bm;
    sei();
}

So, as the above code lines out, TimerD0 is the 20 millisecond timer.  Every twenty milliseconds, it fires.  When it does, it raises the servo signal and then enables TimerD1 and TimerE0, which subsequently time out the 1ms period + position offset.  These functions all come from the application note mentioned above.  The three functions used to set up TimerD0 sets the period, enables the overflow interrupt at the medium tier, and then sets the prescaler.   Pretty straightforward if you use the driver functions.

Here’s the ISR for TimerD0:

/*! \brief Timer/CounterD0 Overflow interrupt service routine
 *
 *  TimerD0 overflow interrupt service routine.
 *  Set for a 20ms period.  Sets servo output port pin, enables TCD1 which resets the pin.
 */
ISR(TCD0_OVF_vect)
{
    uint16_t period;

    /// SERVO1 Timer Enable
    period = 63 + SERVO1_OFFSET + servo[1];                // Calculate period
    SET_SERVO1;                                            // Raise the servo pin
    TC1_SetOverflowIntLevel( &TCD1, TC_OVFINTLVL_MED_gc ); // Set Interrupt on Overflow
    TC_SetPeriodBuffered( &TCD1, period);                  // Start TCD1, set period
    TC1_ConfigClockSource( &TCD1, TC_CLKSEL_DIV256_gc );   // Set clock and prescaler (8us per tick)

    /// SERVO2 Timer Enable
    period = 63 + SERVO2_OFFSET + servo[2];                // Calculate period
    SET_SERVO2;                                            // Raise the servo pin
    TC0_SetOverflowIntLevel( &TCE0, TC_OVFINTLVL_MED_gc ); // Enable timer overflow interrupt
    TC_SetPeriodBuffered( &TCE0, period);                  // Start timer, set period
    TC0_ConfigClockSource( &TCE0, TC_CLKSEL_DIV256_gc );   // Set clock and prescaler (8us per tick)
}

So, it does the following for both servos:

  • Calculates the period.  If everything were a perfect world, the constant 63 should be 125 (and a #define ;) which, with the prescaler given and a 32MHz clock, should be 1ms.  However, between natural delays in the code and the particular servos I was using, I calibrated that offset to be 63 to get the maximum range.  YMMV.
  • Raises the servo signal pin.  This macro is defined in my header file, and is pretty simple: #define SET_SERVO1 PORTD.OUTSET = PIN5_bm
  • Enables the interrupt
  • Sets the period.  You must use the TC_SetPeriodBuffered for this particular application (can’t remember why off the top of my head).
  • Set the clock source to enable the timer.

Did you notice a subtle difference between the TimerD1 and TimerE0 code?  There are two types of timers in the XMegas – Timer0’s and Timer1’s.  Hence, there are TC0_ prefixes and TC1_ prefixes that must be used for appropriate timers.  I’ll have to refer you to the datasheet, because once again I can’t remember what the difference is – it’s not relevant for this example.

Last, let’s look at the position timer ISR code:

/*! \brief Timer/CounterD1 Overflow interrupt service routine
 *
 *  Timer D1 overflow interrupt service routine.
 *  Ends the Servo1 position pulse and disables itself.
 */
ISR(TCD1_OVF_vect)
{
    CLR_SERVO1;                                            // Reset the servo pin low
    TC1_SetOverflowIntLevel( &TCD1, TC_OVFINTLVL_OFF_gc ); // Clear Interrupt on Overflow
    TC1_ConfigClockSource( &TCD1, TC_CLKSEL_OFF_gc );      // Stop clock
}

There’s not much to it:  Reset the signal low, disable the timer interrupt, and disable the timer clock source.  This all gets re-enabled in about 18-19ms!

Now, from just about anywhere in your program, when you want to update the servo position, you just have to change the value of the appropriate servo[] index.  Here’s an example main loop:

int main(void) {
    init_clock();
    init_io();
    init_timers();

    int i;
    for (i=0 ; i<20 ; i+=10)
    {
        servo[1] = i;
        servo[2] = i;
        _delay_ms(1000);
    }
}

I should mention that you need to include “pmic_driver.h” from the PMIC app note AVR1305, and “TC_driver.h” from AVR1306.  Also copy in the matching .c files into the same folder.

That’s really about it.  And it’s easy to add on to this and control another servo:

  1. Add an extra index into the “servos[]” array.
  2. Pick an unused timer and add it to the “timer_init()” function.
  3. Cut, paste, and modify timer code for the new timer in the 20ms timer ISR.
  4. Add an ISR for the new timer, again cutting, pasting, and modifying for the new servo.

That about does it.  It seems to work pretty well for my uses.  Make sure and calibrate the limits on your servo variables so that you maximize your reach (for the servos I tested it with, it was between 0 and 270) .  One problem I had was erratic behavior when it collided with another timer occasionally – this was fixed by adding lifting this up from the “LO” level interrupts to the “MED” level interrupts.  It could also be moved even higher to avoid problems even further.  This is an issue with the XMega, where it wouldn’t necessarily have been with an ATMega, because XMega interrupts have changed and a higher level interrupt can interrupt a lower level interrupt.  Good to keep in the back of your mind as you code…

As always, let me know in the comments if you need any help setting this up.

Categories: How-To Tags: , , , ,