Hey, i wanted to control my pc with the x and y axis accelerometer from sparkfun. How can i get the data from the sensor to the computer so it can move the cursor around based on the x and y axis tilt.
i did this a while ago and found 2 ways.
-
Get a program on the pc to sit and listen on a serial port and move the mouse according to what it gets over serial.
-
reverse engineer an old mouse and have the arduino emulate encoders. I found an old dell ps2 mouse that had the chip "SPCP05A" inside with VERY little external components
I went with step 1 and successfully made a very good wii nunchuck mouse.. (not published since it uses dead APIs and written in VB6, which is also closed source...)
rewriting in java or python is on my todo
yeah I was thinking of something like number 2 . Have you found anything like tutorials on this? Thanks:))
really if you just find a ball mouse, tie grounds, and send 5v to the optical encoder sensor (black) that should be enough.
the mice ir light sensors have 3 wires... so +5, gnd, signal? i don't understand how they can determine direction on the encoder when all they see is 10101010101010.... todbot did an ir encoder with 2 ir/phototransistor pairs, so it could determine direction
with one slightly offset, or with 2 patterns
101010101010101
100100100100101
i'd say find some oscilloscope program.. that would help a TON.
you may want to just buy a wii nunchuck. has a 3 axis accelerometer, x,y joystick, and 2 buttons. 20$ with no shipping.
After seeing your initial post i went ahead & implemented option 1 (i was bored tonight), but didn't see you preferred 2 until i got done..
But, if anybody's interested, here's how i did it with a server process on the PC.
I tested this using 2 potentiometers hooked up to analogInputs, but interfacing that Sparkfun accelerometer should work out almost exactly the same.
C Code for the PC Server (assuming windows)
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
//#define CMDLINE
#ifdef CMDLINE
#define DispErr(x) printf(x)
#else
#define DispErr(x) MessageBox(NULL, x, "serMouse Error", MB_OK | MB_ICONERROR);
#endif
#define STATE_CMD0 0x00
#define STATE_CMD1 0x01
#define STATE_X0 0x10
#define STATE_X1 0x11
#define STATE_Y0 0x20
#define STATE_Y1 0x21
#define CMD_CMD '%'
#define CMD_X 'x'
#define CMD_Y 'y'
#define CMD_SET 's'
#define CMD_QUIT 'q'
HANDLE hSerial;
int serialOpen(char *name);
BOOL serialRead(unsigned char *byte);
int serialWrite(unsigned char *data, int size);
void getScreenSize(int *w, int *h);
int main(int argc, char **argv)
{
char comString[64];
unsigned char workByte;
int quit = 0;
unsigned char state = 0x00;
unsigned short readX, readY;
int screenWidth, screenHeight;
printf("\n");
getScreenSize(&screenWidth, &screenHeight);
if(argc < 2)
{
DispErr("No port specified, defaulting to \"COM1\".");
sprintf(comString, "COM1");
}
else
sprintf(comString, "COM%s", argv[1]);
if(serialOpen(comString) < 0)
{
DispErr("Unable to Open COM Port!\n");
return -1;
}
//first byte sent to arduino is 0x00, so it knows that we're not programming
workByte = 0x00;
serialWrite(&workByte, 1);
while(!quit)
{
if(serialRead(&workByte))
{
switch(state)
{
case STATE_CMD0:
if(workByte == CMD_CMD)
state = STATE_CMD1;
break;
case STATE_CMD1:
{
switch(workByte)
{
case CMD_X:
state = STATE_X0;
break;
case CMD_Y:
state = STATE_Y0;
break;
case CMD_SET:
SetCursorPos((int)((float)readX / 1023.0 * (float)screenWidth),
(int)((float)readY / 1023.0 * (float)screenHeight));
state = STATE_CMD0;
break;
case CMD_QUIT:
quit = 1;
break;
}
}
break;
case STATE_X0:
readX = ((unsigned short)workByte) << 8;
state = STATE_X1;
break;
case STATE_X1:
readX |= (unsigned short)workByte;
state = STATE_CMD0;
break;
case STATE_Y0:
readY = ((unsigned short)workByte) << 8;
state = STATE_Y1;
break;
case STATE_Y1:
readY |= (unsigned short)workByte;
state = STATE_CMD0;
break;
}
}
else
Sleep(10);
}
CloseHandle(hSerial);
return 0;
}
int serialOpen(char *name)
{
DCB dSerial;
hSerial = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if(hSerial == INVALID_HANDLE_VALUE)
return -1;
if(!GetCommState(hSerial, &dSerial))
return -2;
dSerial.BaudRate=CBR_9600;
dSerial.ByteSize=8;
dSerial.StopBits=ONESTOPBIT;
dSerial.Parity=NOPARITY;
if(!SetCommState(hSerial, &dSerial))
return -3;
return 0;
}
BOOL serialRead(unsigned char *byte)
{
int readSize;
if(ReadFile(hSerial, byte, 1, &readSize, NULL))
if(readSize)
return TRUE;
return FALSE;
}
int serialWrite(unsigned char *data, int size)
{
unsigned int wrote;
WriteFile(hSerial, data, size, &wrote, NULL);
return wrote;
}
void getScreenSize(int *w, int *h)
{
RECT rc;
HWND deskWnd = GetDesktopWindow();
GetWindowRect(deskWnd, &rc);
*w = rc.right;
*h = rc.bottom;
}
And Arduino Code:
byte calibrated;
int potAMin, potAMax, potAVal;
int potBMin, potBMax, potBVal;
void setup()
{
calibrated = 0;
potAMin = potBMin = 1023;
potAMax = potBMax = 0;
potAVal = potBVal = 511;
pinMode(2, OUTPUT); //potA need-to-configure LED
pinMode(3, OUTPUT); //potB need-to-configure LED
digitalWrite(2, HIGH);
digitalWrite(3, HIGH);
Serial.begin(9600);
}
void loop()
{
int i, tmpVal;
byte serByte;
potAVal = analogRead(0);
potBVal = analogRead(1);
switch(calibrated)
{
case 0: //nothing calibrated yet
{
tmpVal = potAVal;
while(abs(tmpVal - potAVal) < 10) //wait until the pot starts changing values
potAVal = analogRead(0);
for(i=0; i<4000; i++) //then poll values for 4 seconds (turn pot to min. & max. a few times)
{
potAVal = analogRead(0);
if(potAVal < potAMin)
potAMin = potAVal;
if(potAVal > potAMax)
potAMax = potAVal;
delay(1);
}
calibrated = 1;
digitalWrite(2, LOW); //LED off = pot configured
}
break;
case 1: //only potA calibrated
{
tmpVal = potBVal;
while(abs(tmpVal - potBVal) < 10) //wait until the pot starts changing values
potBVal = analogRead(1);
for(i=0; i<4000; i++) //then poll values for 4 seconds (turn pot to min. & max. a few times)
{
potBVal = analogRead(1);
if(potBVal < potBMin)
potBMin = potBVal;
if(potBVal > potBMax)
potBMax = potBVal;
delay(1);
}
calibrated = 2;
digitalWrite(3, LOW); //LED off = pot configured
}
break;
case 2: //both pots configured
{
Serial.write('%'); //ready to command
Serial.write('x'); //send x value
potAVal = (int)(((float)(potAVal - potAMin) / (float)(potAMax - potAMin)) * 1023.0);
serByte = (potAVal & 0xFF00)>>8;
Serial.write(serByte);
serByte = potAVal & 0x00FF;
Serial.write(serByte);
Serial.write('%'); //ready to command
Serial.write('y'); //send y value
potBVal = (int)(((float)(potBVal - potBMin) / (float)(potBMax - potBMin)) * 1023.0);
serByte = (potBVal & 0xFF00)>>8;
Serial.write(serByte);
serByte = potBVal & 0x00FF;
Serial.write(serByte);
Serial.write('%'); //ready to command
Serial.write('s'); //set cursor command
delay(10); //~100 samples per second
}
break;
}
}
Here is a link that has (almost) everything you ever wanted to know about PS/2 mice and how to interface with them:
http://www.computer-engineering.org/ps2mouse/
Emulating a PS/2 mouse is a bit harder than just reading from it. It may take up most of your cycles on the Arduino, but I don't see any reason it can't be done.
[thefatmoop]:
The IR sensor has three pins because two of them are signals and one is probably Vcc. Direction is determined by the order of signals, since it uses quadrature encoding.
I believe that the sensor uses either "open collector" or "open drain" outputs, which means you have to have a pull-up (or pull-down) resistor to read them. Unfortunately, I haven't found any good way to tell what the best resistor value is. Most of those parts are not labeled.
hey thanks for all of the comments, i just have one question, because i do not know much about running the c code. What do i need to do to run this code thanks
hey yeah i will post all my work done too as soon as my CMS is ready (including the vb6 sources)
Well i agree with it's harder to emulate than to read, but i don't have anywhere near the time to do it. (or programming skills prob lol)
Someone needs to make a library to emulate ps2!
If you want to mess around with the source you'll need to compile it.
If you don't have a C compiler i'd recommend getting MinGW; then you can compile it with "gcc filename.c -o filename.exe".
If you just want to run it, here's a link to my compilation of the program (with copies of the source):
http://files.filefront.com/serMousezip/;12975117;/fileinfo.html
Just run the program with the name of the COM port to use for your Arduino (like "sermouse 4" for COM4).