Sunday, April 29, 2012

Raspberry Pi, and a video

I haven't put in much effort or made much progress lately. I have a problem with increasing the brightness of the IR LED (ie current through it) which broadcasts serial in IR, modulated with a 38KHz carrier signal. Using an AND gate, or just plain transistors, it just doesn't seem to transmit the same signal. I think I will leave the detail for another post.

The other thing is that I'm waiting for my Raspberry Pi Linux on ARM mini-PC to arrive (in about 5 weeks). I'm planning to try to use this to compress and transmit video from a USB HD webcam, at as high a resolution as it can do quickly, over WiFi. Framerate and latency are the most important, followed by resolution and quality. This will also provide network connectivity for the Arduino, in the form of a serial-to-network program, much the same as I currently have with the wireless IP Camera, except a lot smaller, lighter, lower-power, more powerful and hackable :)

So I'm not going to put any more effort into improving analog video capture as hopefully that will all be redundant soon, it will be all purely digital :)

I'll leave this post with some video of my current car being driven around at Hackerspace Brisbane. Sorry it seems to be upside down.


Wednesday, January 11, 2012

Camera update

I discovered the Wifi cam that I disparaged isn't as bad as I thought. However, the actual USB webcam inside does a maximum of 15 FPS - see the datasheet. So the specifications of the Wifi IP cam which say it does 30 FPS is a lie. But the advantages of wifi make it attractive to keep it around, if only just as a wifi <-> serial bridge for the Arduino.


I say it's not as bad as I thought. It turns out that part of the reason it seemed so slow was because the Processing app's Capture class uses lots of CPU, and this in turn seems to slow everything down - my serial pings went over 100ms, and the latency seemed terrible. But when I ran the video stream separately in Firefox, and ran the app, the serial ping was back to normal 17-35ms, and I could actually navigate! However, Firefox's CPU usage was still very high - this may be a problem with the HTTP server implementation if it doesn't state the image size in the MJPEG stream, it has to examine the stream to find the end of each JPEG.

15 FPS is still too slow, but the image quality is much better than a captured analog PAL source. So I wonder if I could plug in another webcam which does better? Probably not, as it would have a very limited driver support. I would have to significantly hack on it, and it's not an ideal platform, so I'd probably want to develop my own ARM board which is getting quite complicated. There are ARM development boards at 60 MHz though which aren't too expensive, about $60, ie about the same as an Arduino Mega with a whole lot more flexibility. I don't know what CPU speed the wifi cam runs at. Just add a USB wifi adapter, much the same as the wifi cam, which is cheaper than an ethernet shield.

So in case I do end up going down this (convoluted, yak-shaving) path, I looked at what decent webcams are available, with the following requirements in order:
  1. frame rate - at least 30FPS at 640x480.
  2. USB 2.0 - it's not going to be able to do high resolutions or frame rates limited to USB 1.1 12 MB/s. Needs 480MB/s.
  3. image size - as stated, at least 640x480, ideally 720p, which means also 16:9
  4. field of view - all the cheap stuff is really narrow view. if I want widescreen, and gaming style, it should be high FOV like 80 degrees hopefully.
  5. onboard JPEG compression, so a device can simply take those JPEGs and put them in an MJPEG stream with minimal CPU overhead. Most do this anyway. 
  6. good visibility in low light, or I could just put headlights on the car. So then, quick white balance.
Other nice-to-have features are autofocus, and really nice would be switching between visible and IR light. 

Note that due to the USB 2.0 probably no camera can really do 720p at 30fps.

I found the following cameras which are actually all quite decent, and less than $100:
  • Logitech Webcam Pro 9000 - 720p at 24 fps, or 30fps at a bit lower resolution, limited by USB bus.
  • Logitech HD Pro Webcam c910 - full 1080p, though I'd never use it, apparently better low-light performance, and quite wide FOV. 
  • PlayStation Eye - 640x480 at 60 Hz is max res, also 320x200 at 120 Hz. I like the high res, would like to play with one and see. But may be better for machine vision or UI stuff (which is its intention).
  • Microsoft HD 5000 - 720p, not sure about FOV, but this got me - auto focus! Which is also tunable. 
But for the time being I have a new 5.8GHz wireless analog system so I will try that out. Still limited by the capture device but the range is much better.

Saturday, December 10, 2011

Quick test for servo characteristics

I got some new servos and wanted to see what their range and noise was like. Running a looping test is not very informative, and typing commands over and over is tedious. I like interactive stuff.

So I wrote up a quick program in Processing to allow you to use the  mouse or keyboard to set the angle of a servo on any pin. You just move the mouse within a white box to set the angle, or use keys for more fine control (if you're Michael J. Fox, for example). You move the mouse quickly up and down in the box to get an idea of how fast/responsive the servo is.

I hope someone finds this useful. The Processing PDE source file is pasted below. There's no code for Arduino, just the bitlash library.

Requires:
  • Arduino IDE
  • Bitlash Arduino library: a command-line-like interface to arduino functions and pins - http://bitlash.net/wiki/start - I used 1.1, there is also a new 2.0 RC4 which may be compatible.
  • Processing IDE - processing.org
 Caveats:
  • Only works for angles between 0 and 200. every servo I've ever used only has a range of at most 170 degrees, usually starting 5 - 20 degrees, ending 165 - 180 degrees. It's not hard to change if you have special servos. Using this program I have determined my new Dynam 34g servo's range to be 5-175 degrees, but I would limit it to 10-170 in order to avoid damaging them.
Possible improvements:
  • Allow individual, or simultaneous control of multiple servos; the standard arduino can control up to 8, and so the bitlash code only supports 8. The Mega can control more, but this requires a small change to the bitlash servo example. There are also shields and other things which can expand the servo control capabilities, which would require more extensive changes in bitlash; in fact with a large number, it might be worthwhile developing a custom protocol.
  • Put it in source control for shared access and versioning. Link to that instead of pasting source here. 
Source for ServoTestBitlash.pde:

/**
  * Quickly test servo min and max angles, speed, torque and noise, using Arduino with Bitlash library.
  *
  * 1. upload bitlash servo code to arduino (part of library examples).
  * 2. configure the variables below for the pin your servo is on, and serial port.
  * 3. run it.
  *
  * The angle is initialised to 90 degrees (roughly center).
  * Move the mouse cursor up and down in the white area to change the angle.
  * The current angle is shown at the top.
  * For more fine control, move the mouse off the screen and press W and S to increase and decrease the servo angle.
  *
  * Author: Joel Byrnes, December 2011.
  * email: arduino (at) adeptusproductions.com
  */

import processing.serial.*;

/***** modify this for your setup ******/

int servoPin = 9;
String serialPort = "/dev/tty.usbserial-A700eEtE";

/***** end modify part *****/

int pos = 90;
Serial port;
int lastMouseY;
  
void setup() {
  port = new Serial(this, serialPort, 57600);
  port.write("\n");
  setPos(servoPin, pos);

  size(350, 350);
  noStroke();
  frameRate(50);
}

void draw() {
  if (mouseY != lastMouseY) {
    if ((mouseY-50) < 0 || (mouseY-50) > 200) return;
    lastMouseY = mouseY;
    pos = mouseY - 50;
  }

  background(0);
  rect(50, 50, 250, 250);
  text("0", 10, 50);
  text("200", 10, 300);
  setPos(servoPin, pos);
}

void keyPressed() {
  if (key == 'w') {
    pos++;
  } else if (key == 's') {
    pos--;
  }
  else return;
 
  setPos(servoPin, pos);
}

void setPos(int pin, int position) {
  println(pos);
  text("angle: " + pos, 150, 25);
  port.write("servo(" + pin + "," + position + ")\n");
}

Monday, October 3, 2011

Augmented reality? Local Positioning System?

It occurred to me the car video would be a good target for augmented reality. I already have overlays, but you could insert location-based data over the video, for example the other cars, pit stops, navigation, maybe even explosions!

The trouble (as with any augmented reality system) is tracking distance, rotation, angle etc so as to place the augmented items correctly on screen. For a while I have been considering the idea of a LPS (local positioning system), like GPS, for accurate location of items in a small area. Fast compass measurements would also be necessary.


I recently attended a talk on lightweight java game library, which is mainly a simple, fast wrapper for OpenGL, so rendering objects is actually pretty easy :) Minecraft uses LWJGL.

Just thoughts, so far...

WiFi IP camera

While I haven't posted for a while, there was some fervent activity for a bit. My hackerspace comrade tjhowse found that there are cheap WiFi cameras you can get with an ARM processor and embedded ucLinux, which are in fact quite hackable. They also have pan-tilt stepper motors, but they have been geared way down so they are incredibly slow. Finally, they have decent IR leds so they can see in the dark; they are designed as controllable IP security cameras after all.

The innocent Wifi camera before being hacked.

The default web UI is quite decent.


I won't go into detail right now but the photo album is here and here are some threads on the topic:

http://groups.google.com/group/hackerspace_brisbane/browse_thread/thread/f5eae6b6d9922e00

http://groups.google.com/group/hackerspace_brisbane/browse_thread/thread/7336980c0f887d25

Added wires for serial connection and power.
Ultimately though, I found that:
  • The latency is actually quite low on a non-congested wireless network - as little as 35ms, which is quite adequate. 
  • The latency spikes a bit sometimes, not sure if this is congestion or CPU problems on the system
  • It is hard to connect up the Arduino over serial reliably, though I have basically solved that. 
  • It is great to have clear video without interference and static
  • However, the video is too slow. Framerate is uneven and low, and there is a significant delay - no good for what should be a fast-paced reflexive game. Not sure if this is due to CPU power, the capture device, or network problems.
So it was fun hacking it, and in fact I might keep it for data comms. Maybe remove the camera and just run the base board. That will require hacking the firmware, but that's a solved problem.

I was able to run the camera off the car's battery, through the Arduino's regulator! The reg got hot quickly though.

Thursday, June 2, 2011

Debug pin with software serial

I have been intending to re-purpose the hardware serial interface on the JeeNode to run IR comms, because being hardware and buffered it won't miss data if it's doing something else other than listening, as it would with any software serial library.

But at the same time, while doing development, I like to have debug output. Until I actually start doing the IR thing, I can still use the serial port for this. But I would like to keep that ready to do at any time. Or I can send them over the RF12, but I would like to reduce my wireless usage as much as possible, and not clutter up my UI's text window. Again, until I have multiple cars going, wireless contention isn't as much of an issue, but I prefer to do things properly the first time as long as it isn't going to be harder than fixing it later.

Then I thought, I could use software serial. It's slower and ties up the CPU, but I don't have a lot of or very frequent debug output, so it should be fine. Furthermore, I can just turn off debug output when it's not useful (mainly, when the car is moving around). I added #define and #if-#endif statements to turn the serial output on or off entirely, in a method like this (from memory):

#define DEBUG_ENABLED 1

void debugln(char[] msg) {
  #if DEBUG_ENABLED
  debugSerial.println(msg);
  #endif
}

So if I turn off DEBUG_ENABLED, then calls in the code such as debugln("Car ready") won't have any impact. And including a library should only take up some memory.

First I tried NewSoftSerial, which I have tested out before and decided was too slow (with Arduino and XBee). This caused my steering servo to freak out at the same interval as the messages being sent, no matter what pin I tried to use for debug. I also didn't see any serial output. I think the freak out was because NSS uses interrupts, which is probably shared with either that servo output (it's probably a PWM pin, I didn't check) or the RF12 code. I don't need or want an interrupt-enabled library because this is going to be used sparingly and only for output.

Side note: it's annoying that every such library demands you give it both an Rx and Tx pin. If I only want to send, why do I have to give it a receive pin?

So I tried out SoftwareSerial instead, which is part of the core Arduino library. It didn't cause any apparent problems with servo or RF12, but it also didn't seem to work at all. No matter what pin I chose, from a digital to an analog, or a few other pins on the JeeNode ISP or other headers which are not used at the moment, nothing came out. I set it to 4800 baud (9600 being the max anyway) but the LEDs didn't even light up. I added Serial.println after the debug and that was still outputting.

In short: is the RF12, Ports, or Servo library interfering with SoftwareSerial?

Update: it turns out you need to set the Tx pin to OUTPUT mode. I would have thought the library would do that, I really would.

So that started working, but then I had a problem with debugging just after sending a status update: the output was scrambled. I guessed that the rf12 library was sending and that was throwing off the serial timings. I asked on the JeeLabs forums if there was a way to fix it, and jcw himself (creator of Jeenode) replied. If you add a rf12_sendWait(1); after the sendStart command, it waits for the send to complete before returning to the program flow. That's a double-edged sword; You can guarantee your timings won't be thrown off by the background sending, but at the same time you delay returning to the program, I'm not sure for how long. If I want to keep the loop very tight, it might be a problem. I could also reduce the size of my sends as much as possible. But so far it seems ok.

Forum post is at http://forum.jeelabs.net/node/259

Now with pan/tilt mount

I thought of a quick and dirty way to test how the pan/tilt mount would work with the new car, without having to build the whole support and everything...



That tape is actually pretty sturdy... but I haven't driven it around much. At all actually. There isn't much room and it's late and the car is noisy. But it should be pretty awesome :)

This new car with its 7.2V battery (which after charging is like 8.5V) also means I can run the camera off the same battery, yay! So I don't need an extra battery holder for that. I will also add a MOSFET so that when I turn on the car, it allows current to the camera - so a single switch to turn everything on/off.

I'll record some video from the car camera when I am able to drive it around.

I also need to update that UI - I have the prototype pretty much done, I just have to do the work to put it into the app.