Pages

Monday, May 9, 2011

NIXIE TUBES

I just recently bought six IN-14 nixie tubes from e-bay and was immediately faced with the with the thought: "How am I gonna make these work?" Looking up over the internet, I found rather expensive nixie tube clock controllers and custom nixie tube controller boards. The biggest problem with them is the large pin-count and near 175 V needed to power them. After lots of time searching the net for nixie tube circuits I came up with an idea of a cheap modular nixie tube controller system. I even managed to have blue LEDs incorporated into this system. I am really happy how simple the circuitry turned out to be.

Once I get some male and female headers to get this modular and scalable system presentable for a youtube video, I shall post circuit diagrams, protoboard layout and step-by-step tutorial.

Here are some build pics (some of you will figure out the what to do just by looking at the pictures):

K155ID1 Nixie controller ICs:

Simple breadboard circuit components: (5v regulator, DC-DC boost converter, Nixie controller IC, IN-14 nixie tube)

Simple breadboard circuit works!

A single module of the system:
Beautiful :)

Tuesday, February 8, 2011

Arduino Based PC Ambient Lighting

I really like the concept of ambient lighting systems which synchronize with entertainment to create a great immersive experience. And since I had a RGB led strip lying around I decided to use my Arduino and a Processing sketch to create such a system for computers which really turned out great!

Here is a video of my setup and a nice demo of it working with a Star Wars video clip:


Materials:
If you would like to setup this system, it is quite simple and does not require any Arduino shields. The materials you will need other than an Arduino are:
+RGB LED Strip (<=$15.95): You can get really cheap ones but I went with this Sparkfun LED strip due to ease of shipping (http://www.sparkfun.com/products/10261).
+ULN2003A (~$00.63): This chip is a transistor array for driving the LED strip which requires 12V signals with the 5V digital signals from the Arduino (order from DigiKey: http://www.digikey.com)
+12V DC supply ($5.95-$18.99): I am very sure you can get really cheap wall to 12V DC supplies but I was lazy and snipped off the end off a Garmin 12V car GPS charger (http://www.amazon.com/Garmin-AC-Vehicle-Power-Adapter/dp/B0011V1KZ6/ref=sr_1_2?ie=UTF8&qid=1297231222&sr=8-2) Another charger which is much cheaper (http://www.pololu.com/catalog/product/1466)

Schematic:
The LED driver circuit is extremely simplified due to the ULN2003A chip which eliminates the need for a separate transistor circuit for each R, G and B channel of the LED. Here is the schematic:
A closeup of my setup:


Code:
The system works by taking screenshots continuously and averaging the all the pixel colors. This data is then sent to the Arduino over USB. The Arduino receives this data and controls the LED strip color accordingly using pulse-width modulating each channel (Red, Green, Blue).

Processing Code: (open Processing IDE: http://processing.org/, copy-paste code, run)
//Developed by Rajarshi Roy
import java.awt.Robot; //java library that lets us take screenshots
import java.awt.AWTException;
import java.awt.event.InputEvent;
import java.awt.image.BufferedImage;
import java.awt.Rectangle;
import java.awt.Dimension;
import processing.serial.*; //library for serial communication


Serial port; //creates object "port" of serial class
Robot robby; //creates object "robby" of robot class

void setup()
{
port = new Serial(this, Serial.list()[0],9600); //set baud rate
size(100, 100); //window size (doesn't matter)
try //standard Robot class error check
{
robby = new Robot();
}
catch (AWTException e)
{
println("Robot class not supported by your system!");
exit();
}
}

void draw()
{
int pixel; //ARGB variable with 32 int bytes where
//sets of 8 bytes are: Alpha, Red, Green, Blue
float r=0;
float g=0;
float b=0;

//get screenshot into object "screenshot" of class BufferedImage
BufferedImage screenshot = robby.createScreenCapture(new Rectangle(new Dimension(1368,928)));
//1368*928 is the screen resolution


int i=0;
int j=0;
//1368*928
//I skip every alternate pixel making my program 4 times faster
for(i =0;i<1368; i=i+2){
for(j=0; j<928;j=j+2){
pixel = screenshot.getRGB(i,j); //the ARGB integer has the colors of pixel (i,j)
r = r+(int)(255&(pixel>>16)); //add up reds
g = g+(int)(255&(pixel>>8)); //add up greens
b = b+(int)(255&(pixel)); //add up blues
}
}
r=r/(684*464); //average red (remember that I skipped ever alternate pixel)
g=g/(684*464); //average green
b=b/(684*464); //average blue


port.write(0xff); //write marker (0xff) for synchronization
port.write((byte)(r)); //write red value
port.write((byte)(g)); //write green value
port.write((byte)(b)); //write blue value
delay(10); //delay for safety

background(r,g,b); //make window background average color
}


Arduino Code: (transfer this program to the Arduino)
//Developed by Rajarshi Roy
int red, green, blue; //red, green and blue values
int RedPin = 9; //Red pin 9 has a PWM
int GreenPin = 10; //Green pin 10 has a PWM
int BluePin = 11; //Blue pin 11 has a PWM
void setup()
{

Serial.begin(9600);
//initial values (no significance)
int red = 255;
int blue = 255;
int green = 255;
}

void loop()
{

//protocol expects data in format of 4 bytes
//(xff) as a marker to ensure proper synchronization always
//followed by red, green, blue bytes
if (Serial.available()>=4) {
if(Serial.read() == 0xff){
red = Serial.read();
green= Serial.read();
blue = Serial.read();
}
}
//finally control led brightness through pulse-width modulation
analogWrite (RedPin, red);
analogWrite (GreenPin, green);
analogWrite (BluePin, blue);
delay(10); //just to be safe
}

I hope this project is easy to understand and setup. And even if you do not intend to set up this system, I hope the code and circuit shows some concept that you will find useful for other projects :) Comments are highly appreciated and my ears are open to any new ideas!


Followup-----------------------------------------------------------------
I am truly truly amazed by the reception of this project and I feel extremely encouraged to put up more such projects in the future :D I am truly grateful for your support!

Here is a high-res image (click to enlarge) of a simplified layout and connections (slightly modified from the original post in terms of which Arduino pin corresponds to R, G, B):
Also, I slightly modified the Arduino code to reflect the changes in the pin numbering:
 //Developed by Rajarshi Roy
int red, green, blue; //red, green and blue values
int RedPin = 10; //Red: PWM pin 10
int GreenPin = 11; //Green: PWM pin 11
int BluePin = 9; //Blue: PWM pin 9
void setup()
{
Serial.begin(9600);
//initial values (no significance)
int red = 255;
int blue = 255;
int green = 255;
}

void loop()
{
//protocol expects data in format of 4 bytes
//(xff) as a marker to ensure proper synchronization always
//followed by red, green, blue bytes
if (Serial.available()>=4) {
if(Serial.read() == 0xff){
red = Serial.read();
green= Serial.read();
blue = Serial.read();
}
}
//finally control led brightness through pulse-width modulation
analogWrite (RedPin, red);
analogWrite (GreenPin, green);
analogWrite (BluePin, blue);
delay(10); //just to be safe
}
Also, note that different led strips might have different pin ordering, so connect accordingly.
I would also like to mention that in the video, a scrolling text can be seen while the Processing code was running. This was originally there for me to debug my code. However, I removed that portion of the code in my final publish to make things slightly faster.

Finally, the comments to this post are filled with great questions, and great answers contributed by the awesome people of the DIY community. Also, many kind souls have contributed awesome snippets of code to add functionality such as multiple display and so on. Enjoy!

Tuesday, August 10, 2010

Arduino based Human Interface Device (continued)

Continuing from my last blog-post about creating Arduino based Human Interface devices, here is the video I promised:


The PS2dev library (http://www.arduino.cc/playground/ComponentLib/Ps2mouse) lets the Arduino emulate a PS/2 device and I used a PS/2 to USB converter off the shelf for 3 bucks since my laptop does not have a PS/2 port. To use the PS2dev library, drag and drop the files ps2dev.h and ps2dev.cpp into your Arduino IDE before you upload it. They should appear as tabs with the corresponding names. Also, you have to go to the ps2dev.h tab and comment out #include "WConstants.h" and add a line #include <Wprogram.h> until the start of the header file appears like:

#ifndef ps2dev_h
#define ps2dev_h

//#include "WConstants.h"
#include <Wprogram.h>

Now comes the code :) It is extremely shabby since I probably have unnecessary headers and variables lying around. And also I did not organize the code into any objects or classes whatsoever. However, I am planning to write a nice keyboard and mouse class using the PS2dev library so that future Arduino HIDers can effortlessly implement absolute/relative mouse movements, key-presses without referring to PS/2 scan codes and have a much much cleaner code :D

Please refer to this link: (http://www.computer-engineering.org/ps2keyboard/) to understand what I have done with the keyboard object. My Wii Nunchuck portion of the code was adapted and modified from the WiiChuck class in the Arduino playground (http://www.arduino.cc/playground/Main/WiiChuckClass). Also note that the pins 3 and 4 of the PS/2 connector can power the Arduino very well :)

Color code for better understanding:
PS/2 keyboard portions
Wii nunchuck portions

--------------------------
#include "ps2dev.h" // to emulate a PS/2 device
#include <Wire.h> // to communicate over the I2C port
#include <string.h>
#include <math.h>
#undef int
#include <stdio.h>

uint8_t outbuf[6]; // array to store arduino input
int cnt = 0;
int ledPin = 13;

PS2dev keyboard(3,2); // PS2dev object (2:data, 3:clock)
int enabled =0; // pseudo variable for state of "keyboard"

int joy_x_axis; //byte 1
int joy_y_axis; //byte 2
int accel_x_axis; //byte 3
int accel_y_axis; //byte 4
int accel_z_axis; //byte 5
int z_button = 0;
int c_button = 0;
int roll = 0;
int pitch = 0;

void ack() {
//acknowledge commands
while(keyboard.write(0xFA));
}


int keyboardcommand(int command) {
unsigned char val;
switch (command) {
case 0xFF: //reset
ack();
//the while loop lets us wait for the host to be ready
while(keyboard.write(0xAA)!=0);
break;
case 0xFE: //resend
ack();
break;
case 0xF6: //set defaults
//enter stream mode
ack();
break;
case 0xF5: //disable data reporting
//FM
enabled = 0;
ack();
break;
case 0xF4: //enable data reporting
//FM
enabled = 1;
ack();
break;
case 0xF3: //set typematic rate
ack();
keyboard.read(&val); //do nothing with the rate
ack();
break;
case 0xF2: //get device id
ack();
keyboard.write(0xAB);
keyboard.write(0x83);
break;
case 0xF0: //set scan code set
ack();
keyboard.read(&val); //do nothing with the rate
ack();
break;
case 0xEE: //echo
//ack();
keyboard.write(0xEE);
break;
case 0xED: //set/reset LEDs
ack();
keyboard.read(&val); //do nothing with the rate
ack();
break;
}
}

void setup() {
Wire.begin (); // join i2c bus with address 0x52
nunchuck_init (); // send the initilization handshake
delay(2000); //initialization time just in case
// send the keyboard start up
while(keyboard.write(0xAA)!=0);
}

void nunchuck_init ()
{
Wire.beginTransmission (0x52);// transmit to device 0x52
Wire.send (0x40); // sends memory address
Wire.send (0x00); // sends sent a zero.
Wire.endTransmission (); // stop transmitting
}

void send_zero ()
{
Wire.beginTransmission (0x52);// transmit to device 0x52
Wire.send (0x00); // sends one byte
Wire.endTransmission (); // stop transmitting
}

void loop() {
Wire.requestFrom (0x52, 6); // request data from nunchuck
while (Wire.available ())
{
outbuf[cnt] = nunchuk_decode_byte (Wire.receive ());
// receive byte as an integer
digitalWrite (ledPin, HIGH); // sets the LED on
cnt++;
}

// If we recieved the 6 bytes, then go process them
if (cnt >= 5)
{
process ();
}

unsigned char c;
//if host device wants to send a command:
if( (digitalRead(3)==LOW) || (digitalRead(2) == LOW)) {
while(keyboard.read(&c)) ;
keyboardcommand(c);
}
else{ //send keypresses accordingly using scancodes
if(joy_y_axis > 198){keyboard.write(0x1D);}
else{ keyboard.write(0xF0); keyboard.write(0x1D);}

if(joy_y_axis < 68){keyboard.write(0x1B);}
else{ keyboard.write(0xF0); keyboard.write(0x1B);}

if(joy_x_axis < 58){keyboard.write(0x1C);}
else{ keyboard.write(0xF0); keyboard.write(0x1C);}

if(joy_x_axis > 190){keyboard.write(0x23);}
else{ keyboard.write(0xF0); keyboard.write(0x23);}


if(pitch < 65){keyboard.write(0x43);}
else{ keyboard.write(0xF0); keyboard.write(0x43);}

if(pitch > 115){keyboard.write(0x42);}
else{ keyboard.write(0xF0); keyboard.write(0x42);}

if(roll > 125 ){keyboard.write(0x3B);}
else{ keyboard.write(0xF0); keyboard.write(0x3B);}

if(roll < 55){keyboard.write(0x4B);}
else{ keyboard.write(0xF0); keyboard.write(0x4B);}


if(!z_button){keyboard.write(0x29);}
else{ keyboard.write(0xF0); keyboard.write(0x29);}

if(!c_button){keyboard.write(0x12);}
else{ keyboard.write(0xF0); keyboard.write(0x12);}
}

cnt = 0;
send_zero (); // send the request for next bytes
delay (10);
}


void process (){
joy_x_axis = outbuf[0]; //byte 1
joy_y_axis = outbuf[1]; //byte 2
accel_x_axis = outbuf[2] * 2 * 2; //byte 3
accel_y_axis = outbuf[3] * 2 * 2; //byte 4
accel_z_axis = outbuf[4] * 2 * 2; //byte 5

z_button = 0;
c_button = 0;

roll = 0;
pitch = 0;
// byte outbuf[5] contains bits for z and c buttons
// it also contains the least significant bits for the accelerometer data
// so we have to check each bit of byte outbuf[5]
if ((outbuf[5] >> 0) & 1) //'&1' to see only LSB after left shifts
{
z_button = 1; //bit 0
}
if ((outbuf[5] >> 1) & 1)
{
c_button = 1; //bit 1
}

if ((outbuf[5] >> 2) & 1)
{
accel_x_axis += 1;
}
if ((outbuf[5] >> 3) & 1)
{
accel_x_axis += 2;
}

if ((outbuf[5] >> 4) & 1)
{
accel_y_axis += 1;
}
if ((outbuf[5] >> 5) & 1)
{
accel_y_axis += 2;
}

if ((outbuf[5] >> 6) & 1)
{
accel_z_axis += 1;
}
if ((outbuf[5] >> 7) & 1)
{
accel_z_axis += 2;
}

//out here the values 499, 518 and 216.0 might differ
//due to the slight differences nunchucks
roll = (atan2( (accel_z_axis-499), (accel_x_axis-515) )/3.14159*180);
pitch = (acos( (accel_y_axis-518)/216.0 )/3.14159*180);
}


// Encode data to format that most wiimote drivers except
// only needed if you use one of the regular wiimote drivers
char nunchuk_decode_byte (char x)
{
x = (x ^ 0x17) + 0x17;
return x;
}

--------------------------
The indentations in the code disappeared when I published this post. Apologies for that. Hope this is helps all Arduino fans making Human Interface Devices. Please leave your comments (:

Followup-----------------------------------------------------------------
Here is the schematic for the device :)
Also, if your computer does not have a PS/2 port, you can use an active-type USB to PS/2 adapter such as this one:
http://www.amazon.com/PS2-Keyboard-To-USB-Adapter/dp/B000BSJFJS/ref=sr_1_9?s=electronics&ie=UTF8&qid=1322089610&sr=1-9

Enjoy!

Thursday, August 5, 2010

Arduino based Human Interface Device




This summer I have been tinkering with my Arduino micro-controller and recently bought Wii Nunchuck in a quest to create a Wii Nunchuck based HID for playing games. Since the beginning of summer I have tried many different methods for doing so and here are some advantages and disadvantages of each:

This software is excellent and hassle-free for sending keypresses to your computer. You just have to use a command from your Arduino sketch such as Serial.print("\033left."); to send a keypress (in this case left arrow button). However, the disadvantage of using AAC keys is that keys are pressed and released. There is no way to press and hold down any key other than Shift, Ctrl and Alt. This isn't good for playing games where you usually need more than three keys.

Another great software that allows you to do a bunch of useful stuff such as opening/closing programs, sending emails, and sending keypresses to programs from your Arduino. It is also well documented. However, I had problems opening some games and holding down keys.

This method really worked well as I could hold down and release keys whenever I wanted to and worked with most games. I simply added this class to my Processing sketch in three lines:
import java.awt.Robot;
import java.awt.AWTException;
import java.awt.event.InputEvent;
Created an object of the class: Robot ricky
And generated key-downs, key-ups and mouse mouse movements:
ricky.keyPress(KeyEvent.VK_I);
ricky.keyRelease(KeyEvent.VK_I);
ricky.mouseMove(x,y);
And my Arduino program sent the data from the Wii Nunchuck to the Processing sketch.
However, this method did not work with some older games on compatibility mode, and definitely would need some tweaking to make it work in different computers (like installing Arduino driver and Processing).

Thus, my final attempt was to make a truly plug-n-play Arduino based "adapter" that would allow me to hook up my Wii Nunchuck and play games with it on any computer, on any games, in any OS. So I used the PS2dev library from the Arduino playground (http://www.arduino.cc/playground/ComponentLib/Ps2mouse) which allows you to let the Arduino emulate a PS/2 device. I wrote a code for emulating a PS/2 keyboard and it works great :D. Now you can play Paratroopers (image below) on your old IBM pc using the Wii Nunchuck over the PS/2 protocol or hook it up to your Altera DE2 for whatever you can think of ;)

As for me, I connected it up to a USB to PS/2 converter to play games. The pins 3 and 4 of the PS/2 port powers the Arduino :) Here are some pictures of my build:
The joystick generates W,A,S,D based on position. The accelerometer roll and pitch generates I,J,K,L. The z-button generates Spacebar and the c-button generates Shift. Good enough for most games :) Mouse positions can be controlled using numpad keys in most OSs so thats not a problem either :)

I will be posting my code and a video for you to enjoy in my next blog-post. I hope this article is useful for all Arduino fans interested in making their own custom HIDs over the PS/2 or USB ports.

Followup-----------------------------------------------------------------
Here is the schematic for the device :)
Also, if your computer does not have a PS/2 port, you can use an active-type USB to PS/2 adapter such as this one:
http://www.amazon.com/PS2-Keyboard-To-USB-Adapter/dp/B000BSJFJS/ref=sr_1_9?s=electronics&ie=UTF8&qid=1322089610&sr=1-9

Enjoy!