Award Winning FIRST Robotics Robot Control Interface

April 8th, 2013

KwarqsDashboard is an award-winning control system developed in 2013 for FIRST Robotics Team 2423, The Kwarqs. For the second year in a row, Team 2423 won the Innovation in Control award at the 2013 Boston Regional. The judges cited this control system as the primary reason for the award.

It is designed to be used with a touchscreen, and robot operators use it to select targets and fire frisbees at the targets. Check out the shiny screenshot below:

Kwarqs Dashboard ScreenshotThere are a lot of really useful features that we built into this control interface, and once we got our mechanical and electrical bugs ironed out the robot was performing quite well. We’re looking forward to competing with it at WPI Battle Cry 2013 in May!  Here’s a list of some of the many features it has:

  • Written entirely in Python
    • Image processing using OpenCV python bindings, GUI written using PyGTK
    • Cross platform, fully functional in Linux and Windows 7/8
  • All control/feedback features use NetworkTables, so the same robot can be controlled using the SmartDashboard instead if needed
    • SendableChooser compatible implementation for mode switching
  • Animated robot drawing that shows how many frisbees are present, and tilts the shooter platform according to the current angle the platform is actually at.
  • Allows operators to select different modes of operation for the robot using brightly lit toggle switches
  • Operators can choose an autonomous mode on the dashboard, and set which target the robot should aim for in modes that use target tracking
  • Switches operator perspective when robot switches modes
  • Simulated lighted rocker switches to activate robot systems
  • Logfiles written to disk with errors when they occur

Target acquisition image processing features:

  • Tracks the selected targets in a live camera stream, and determines adjustments the robot should make to aim at the target
  • User can click on targets to tell the robot what to aim at
  • Differentiates between top/middle/low targets
  • Partially obscured targets can be identified
  • Target changes colors when the robot is aimed properly

Fully integrated realtime analysis support for target acquisition:

  •  Adjustable thresholding, saves settings to file
  • Enable/disable drawing features and labels on detected targets
  • Show extra threshold images
  • Can log captured images to file, once per second
  • Can load a directory of images for analysis, instead of connecting to a live camera

So, as you can see, lots of useful things. We’re releasing the full source code for it under a GPL license, so go ahead, download it, play with it, and let me know what you think! Hope you find this useful.

A lot of people made this project possible:

  • Some code structuring ideas and PyGTK widget ideas were derived from my work with Exaile
  • Team 341 graciously open sourced their image processing code in 2012, and the image processing is heavily derived from a port of that code to python.
  • Sam Rosenblum helped develop the idea for the dashboard, and helped refine some of the operating concepts.
  • Stephen Rawls helped refine the image processing code and distance calculations.
  • Youssef Barhomi created image processing stuff for the Kwarqs in 2012, and some of the ideas from that code were copied.

The included images were obtained from various places:

  • Linda Donoghue created the robot image
  • The fantastic lighted rocker switches were created by Keith Sereby, and are distributed with permission.
  • The green buttons were obtained via google image search, I don’t recall where

Download it on my FRC resources page!

VirtualKD 2.8 with VirtualBox 4.2

March 11th, 2013

If you try to install VirtualKD 2.8 on VirtualBox 4.2.x, you get an error similar to this:

Unable to cast COM object of type ‘VirtualBox.VirtualBoxClass’ to interface type ‘VirtualBox.IVirtualBox’. This operation failed because the QueryInterface call on the COM component for the interface with IID ‘{…}’ failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).

It turns out it’s a pretty easy thing to fix. The Interop.VirtualBox.dll distributed with VirtualKD is built for the 4.1 VirtualBox interface, so you just have to rebuild it for your version of VirtualBox. Create a C# project, and paste the following code into the Program.cs file to build a new Interop.VirtualBox.dll for 4.2.x.

using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;

namespace ConvertTypeLibToAssembly
{
    public class App
    {
        private enum RegKind
        {
            RegKind_Default = 0,
            RegKind_Register = 1,
            RegKind_None = 2
        }
    
        [ DllImport( "oleaut32.dll", CharSet = CharSet.Unicode, PreserveSig = false )]
        private static extern void LoadTypeLibEx( String strTypeLibName, RegKind regKind, 
            [ MarshalAs( UnmanagedType.Interface )] out Object typeLib );
        
        public static void Main()
        {
            Object typeLib;
            LoadTypeLibEx( @"C:\Program Files\Oracle\VirtualBox\VBoxC.dll", RegKind.RegKind_None, out typeLib ); 
            
            if( typeLib == null )
            {
                Console.WriteLine( "LoadTypeLibEx failed." );
                return;
            }
                
            TypeLibConverter converter = new TypeLibConverter();
            ConversionEventHandler eventHandler = new ConversionEventHandler();
            //AssemblyBuilder asm = converter.ConvertTypeLibToAssembly( typeLib, "Interop.Virtualbox.dll", 0, eventHandler, null, null, null, null );
            AssemblyBuilder asm = converter.ConvertTypeLibToAssembly(typeLib, "Interop.VirtualBox.dll", TypeLibImporterFlags.SafeArrayAsSystemArray, eventHandler, null, null, "VirtualBox", null); //using assembly name "VirtualBox" and SafeArrayAsSystemArray to be compatible to VisualStudio-Generated Interop-Assembly

            asm.Save("Interop.Virtualbox.dll");
        }
    }

    public class ConversionEventHandler : ITypeLibImporterNotifySink
    {
        public void ReportEvent( ImporterEventKind eventKind, int eventCode, string eventMsg )
        {
            // handle warning event here...
        }
        
        public Assembly ResolveRef( object typeLib )
        {
            // resolve reference here and return a correct assembly...
            return null; 
        }    
    }
}

Some of this code was grabbed from MSDN, and a single line was grabbed from VirtualBoxService. As the latter is GPL, this code may be GPL. I don’t claim any rights to it.

Problems with file descriptors being inherited by default in Python

February 6th, 2013

Have you ever run into a traceback that ends with something like this?

  File "C:\Python27\lib\logging\handlers.py", line 141, in doRollover
    os.rename(self.baseFilename, dfn)
WindowsError: [Error 32] The process cannot access the file because it is being used by another process

I certainly have, in a few places. The basic problem is that when python creates file objects on Windows (and I think on *nix as well), by default Python will mark the handle as being inheritable (I’m sure there’s a reason why… but, doesn’t make a whole lot of sense for this to be the default behavior to me). So if your script spawns a new process, that new process will inherit all the file handles from your script — and of course since it doesn’t realize that it even has those handles, it’ll never close them. A great example of this is launching a process, then exiting. When you launch your script again and try to open that handle… the other process still has it open, and depending on how the file was opened, you may not be able to open it due to a sharing violation.

It looks like they’re trying to provide ways to fix the problem in PEP 433 for Python 3.3, but that doesn’t help those of us still using Python 2.7. Here’s a snippet that you can put at the very beginning of your script to fix this problem on Windows:

import sys

if sys.platform == 'win32':
    from ctypes import *
    import msvcrt
    
    __builtins__open = __builtins__.open
    
    def __open_inheritance_hack(*args, **kwargs):
        result = __builtins__open(*args, **kwargs)
        handle = msvcrt.get_osfhandle(result.fileno())
        windll.kernel32.SetHandleInformation(handle, 1, 0)
        return result
        
    __builtins__.open = __open_inheritance_hack

Now, I admit, this is a bit of a hack… but it solves the problem for me. Hope you find this useful!

Notepad++ plugin to enable unindent on backspace key

December 3rd, 2012

When I first started using editors, I was a tabs person. I always set the tab size to 4 since I liked the way that looked, and used tabs instead of spaces. And it wasn’t really a philosophical reason behind it, it was very simple actually:

I really hate hitting backspace 4 times to unindent

Seems simple enough. Yes, I know you can use SHIFT-BACKSPACE or other voodoo to make it work, but I want to hit *one* key.

Because of this, I always used 4-space tabs instead of inserting spaces instead of tabs. However, at some point I started writing a project in python, and python tends to encourage spaces vs tabs. Notepad++ is my favorite editor, so I decided to write a plugin for Notepad++ to make using spaces a lot less annoying — and in particular, to make it so that when I hit backspace, it would magically eat the spaces back to the next indentation level.

In the process of trying to do this, I discovered that the Scintilla editing component actually has this functionality built-in — you just need to enable SCI_SETBACKSPACEUNINDENTS on the editor component. So I took the sample plugin for Notepad++ and added two lines of code that enabled this functionality, and it works great! Ever since then, I’ve used spaces instead of tabs, since I really can’t tell the difference — and that’s how I like it 🙂

I actually wrote this thing a rather long time ago, and never got around to actually cleaning it up and releasing it. I’ve decided to release it in its present form, since it’s so useful and very simple. It would be even better if Notepad++ had an option to enable this, but this works just as well until that happens.

This plugin is known to work in versions of Notepad++ since 4.x, and works in Notepad++ running under Wine also. Download the Notepad++ tabs plugin at my usual software page.

Note: I’ve now posted the code as a project on Github

glib.idle_add for tkinter in python

November 10th, 2012

After doing a lot of python GTK+ work on Exaile, I’ve found that it uses glib.idle_add() extensively — and usually with good reason. idle_add is great if you want to ensure that whatever you’re calling is being called on the GUI thread, so that way you don’t have to worry too much about thread interactions as long as you keep things separate.

Another mentor and I are developing a GUI video game along with a ‘fake wpilib’ for our FIRST Robotics programming students to help them learn how to program, and as such we’ve decided to use TKinter for the GUI toolkit (since it supports Python 3, and usually doesn’t require the kids to install anything special to make it work). However, as I started making things I couldn’t find the equivalent of idle_add() for TKinter, and I guess there isn’t one — after_idle() apparently blocks until the event loop is idle, and so that isn’t what I wanted.

A number of posts I found online advocated to poll a queue for input… but I *really* dislike polling, and try to avoid it when I can. So I wrote up this set of routines that is roughly equivalent to idle_add() in tkinter, and uses a queue while avoiding polling.

        
import Tkinter as tk
from queue import Queue, Empty

def idle_add(callable, *args):
    '''Call this with a function and optional arguments, and that function
       will be called on the GUI thread via an event.
       
       This function returns immediately.
    '''
    queue.put((callable, args))
    root.event_generate('<<Idle>>', when='tail')
    
def _on_idle(event):
    '''This should never be called directly, it is called via an 
       event, and should always be on the GUI thread
    '''
    while True:
        try:
            callable, args = queue.get(block=False)
        except queue.Empty:
            break
        callable(*args)
        
queue = Queue()
root = tk.Tk()
root.bind('<<Idle>>', _on_idle)

Drawing in color in PyGTK

October 15th, 2012

I’ve been playing with drawing on your own widgets in PyGTK on Windows, and I found it incredibly difficult to figure out how to draw something in color on a gtk.gdk.Drawable object using draw_line, draw_rectangle, etc. You can’t just set the color using the semi-obvious mechanism:

    gc = widget.window.new_gc()
    gc.set_foreground(gtk.gdk.Color(255,0,0))

I think the reason it doesn’t work is because if the color isn’t in the device-specific colormap, then GTK will ignore whatever color you set without bothering to warn you that something is wrong. However, I’ve finally hit on something that works. In your expose event (or elsewhere), you can put in something like the following:

    def on_expose_event(self, widget, event):

        gc = widget.window.new_gc()
        colormap = self.gc.get_colormap()
        color = colormap.alloc_color('yellow')
        gc.set_foreground(color)

        # whatever gtk.gdk.Drawable draw_* functions you call here
        # will use that color

Hope you find this useful!

Comments inadvertently disabled

October 10th, 2012

Apparently at some point my anti-spam plugin decided to stop working. No wonder I haven’t had any comments in a really long time…. should be working now!

Use GroupTagger to rapidly organize your audio files with Exaile 3.3.0 using the Grouping tag

October 6th, 2012

Well, I haven’t blogged here in quite awhile, but it’s been a pretty busy year! One project I’ve been spending a fair amount of time on is Exaile, a cross platform music player for GTK+ (its free and works on Windows, Linux, and even OSX — though, the installation for OSX is rather tricky). I’ve been DJ’ing Lindy Hop dances for almost a year now, and I’ve been fixing up Exaile to be an awesome music player for DJing — adding a BPM counter, secondary output device support (sometimes called pre-listening), and other things that I’ve found to be useful.

One feature in particular I want to highlight is a plugin I’ve created called GroupTagger. This super-useful plugin is distributed with the latest stable version of Exaile. This plugin allows you to easily and rapidly organize your music using the ‘Grouping’ tag in your audio files. The best part about this is that the data is stored in your MP3/OGG/FLAC/whatever audio files, so you can use the data with your favorite audio player if it supports it (Winamp, iTunes, others already do). A lot of people already categorize their music using this tag, and this plugin can manage music that is already tagged this way. To illustrate how useful this is, here are some screenshots and a mini-tutorial.

Read the rest of this entry »

BPM Counter Plugin for Exaile 0.3.2

October 3rd, 2011

I’ve been starting to use my desktop machine at home a lot lately, so I’ve been looking for a cross-platform audio player that I can use that doesn’t annoy me. After a long search (and discarding most of the linux audio players: amarok, banshee, etc as too annoying or not the right features or whatever) I finally stumbled across Exaile, which not only doesn’t annoy me greatly, but it’s written in python so its way easy to modify and figure out what it does 🙂

I’ve been doing a bit of swing dancing lately (in particular Lindy Hop), so I’ve been gathering music together to listen to, and I need BPM for the music… one thing Exaile did not already have was a BPM counter, so I wrote a manual beat counter for it. You can write plugins for Exaile, though the documentation is rather sparse. I must say though, using the GLADE widget editor thing has to be the most annoying GUI design tool ever…


Download it at my usual software site.

PS: In case anyone asks, I’m not interested in writing an automated beat counter… this works well enough for me 🙂

Winpdb Remote Debugger for Python ported to RobotPy on vxWorks

January 11th, 2011

I’m really excited about the idea of using python on our FIRST Robotics Team’s Robot this year, and one of the first things that got really annoying was the lack of debugging capability, since vxWorks doesn’t really have a console (I mean it does, but in the way that FRC has it setup, its not really a console in the traditional sense of the word). So I searched around and found Winpdb, a pretty neat remote debugger for python. So after playing with it for a bit, I’ve got it working on RobotPy and it seems to do the trick so far. 🙂

I’ll be creating some other tools as needed, so watch for more python in the future!

Download: http://www.virtualroadside.com/FRC/