I am trying to build a simple "mouse" which controls the cursor by movements of the head (which are measured by the accelerometer). For this, I have an Arduino Leonardo (since it can be recognized as a mouse) and an ADXL345.
Since I am new to Arduino's and programming, I wanted to use a code I found on the internet to achieve this. However, this code is optimized for a different accelerometer (memsic 2125). I assume that with certain modifications, the code should also be able to work for my accelerometer.
Is this true? And what exactly do I have to change in the code (or only the assignment of the pins, since my accelerometer has different pins)?
From what I see in the data sheets, the two sensors communicate in very different ways. ADXL is an I2C device and the other outputs a pulse width proportional to acceleration. If you post the code maybe we could find the common parts. I won't follow links to code.
Details
/
Accelerometer_Mouse
This code reads the Memsic 2125 two-axis accelerometer, converts the pulses output by the 2125 into milli-g's (1/1000 of earth's gravity) and prints a mapped version of them over the serial connection to the computer.output. It then takes these mapped values and uses them for virtual mouse movement, clicking, and scrolling.
The circuit:
X output of accelerometer to digital pin 2
Y output of accelerometer to digital pin 3
+V of accelerometer to +5V
GND of accelerometer to ground
created by David Kerns of The Athenian School on Dec 3 2012, with a large portion of code taken from David A. Mellis' and Tom Igoe's found here: http://www.arduino.cc/en/Tutorial/Memsic2125
/
const int xPin = 2; // const for X output of the accelerometer const int yPin = 3; // const for Y output of the accelerometer
void setup() {
Serial.begin(9600); // initialize serial communications:
pinMode(xPin, INPUT); // xPin connected to the accelerometer is input pinMode(yPin, INPUT); // yPin connected to the accelerometer is input
Mouse.begin();
Serial.begin(9600); // Set up serial communication at 9600bps Serial.println("ready"); //Print ready once setup loop is finished
}
void loop() {
int pulseX, pulseY; // Variables to read the pulse widths from accelerometer: int accelerationX, accelerationY; // Variables to contain the resulting accelerations
pulseX = pulseIn(xPin,HIGH); // read pulse from x-axes pulseY = pulseIn(yPin,HIGH); // read pulse from y-axes
/ convert the pulse width into acceleration accelerationX and accelerationY are in milli-g's: earth's gravity is 1000 milli-g's, or 1g.
/ accelerationX = ((pulseX / 10) - 500) 8; accelerationY = ((pulseY / 10) - 500) 8;
accelerationX = map(accelerationX, -500, 500, -20, 20); //map the acceleration output to more manageable values
accelerationY = map(accelerationY, -400, 400, -20, 20); //map the acceleration output to more manageable values
Serial.print(accelerationX); // print the x acceleration result Serial.print("\t"); // print a tab character: Serial.print(accelerationY); // print the y acceleration result Serial.println(); //print a new line delay(50);
if(accelerationX < -17){ // override loop for scrolling, if accelerationX < -17
Mouse.move(0, 0, accelerationY); // mouse scroll function at the rate of accelerationY
} else { // when accelerationX is > -17 (most of the time), do this loop
if ((accelerationY > 4 || accelerationY < -4) // if accelerationY > 4 or < -4 || accelerationX < -4)) // or if accelerationY > 4 and < -4
(accelerationX > 4
{
Mouse.move(-accelerationX, -accelerationY, 0); // move the mouse the negative accelerations(X and Y), do not scroll
}
}
if(accelerationY > 20){ //if the accelerationY value reaches a value of 20,
Mouse.click(); //left click the computer's mouse
}
if (accelerationY > 35){ //if the accelerationY value reaches a value of 35,
Mouse.click(); //left click once Mouse.click(); //left click again (resulting in a double click)
} if (accelerationX > 20){ //if the accelerationX value reaches a value of 20,
Mouse.click(MOUSE_RIGHT); //right click the computer's mouse
}
}
I already got the wiring and the code to communicate with the ADXL345 (didn't make the code myself btw).
Here's the code:
/**
* @file readADXL345.ino
* @author Nico
* @date 29-10-2013
* @version 1.0
* @mainPage
* Simple sketch for reading the ADXL345 interface board and displaying raw data on the Serial output
*/
/**
* SVN version control. do not remove
* $Revision$
* $Date$
* $Author$
*/
#ifdef __IN_ECLIPSE__
#include "readADXL345.h"
#endif
#include <ADXL345.h>
//
// pin definitions
//
#define CS 10 // chip select for SD card
#define ADXL345_WORKS 13 // led on indicates ADXL exists
//
// other definitions
//
#define DELAY_PER_MEASUREMENT 1000L // one measurement per second
//
// card definitions
//
// ADXL345 Card
// pin 1 = GND Connect to GND row
// pin 2 = VCC Connect to 5V
// pin 3 = CS Not Connected
// pin 4 = INT1 Not Connected
// pin 5 = INT2 Not Connected
// pin 6 = SDO Not Connected
// pin 7 = SDA Connect to A4
// pin 8 = SCK Connect to A5
//
// ADXL345 accelerometer
//
ADXL345 accel(0x53); // accelerometer instance
AccelerometerRaw rawData; // structure with the raw (=int) data from ADXL345
//
// global variables
//
/**
* @name readADXL345()
* @return uint8_t value of the sensor
* Reads the sensor returns the value where Bit 0 = Z, Bit 1 = Y, Bit2 = X
* The value represents the plan that is lying down. This is determined by
* reading the raw sensor data and determining which value is largest. If negative it is 0
* else it is a 1
*/
void readADXL345(){
//
// read the raw dat from the accelerometer
//
rawData = accel.ReadRawAxis();
}
/**
* @name setup()
* initializes the sketch once by power on or Reset
*/
void setup()
{
//
// define IO pins if required
//
pinMode(CS, OUTPUT); // SD card select
pinMode(ADXL345_WORKS, OUTPUT); // If lit, ADXL345 is connected
//
// Check that the accelerometer is in fact connected.
//
if(accel.EnsureConnected()){
digitalWrite(ADXL345_WORKS, HIGH); // If we are connected, light our status LED.
} else {
digitalWrite(ADXL345_WORKS, LOW); // If we are not connected, turn our LED off.
}
//
// Set the range of the accelerometer to a maximum of 2G.
//
accel.SetRange(2, true);
//
// Tell the accelerometer to start taking measurements.
//
accel.EnableMeasurements();
//
// open Serial
//
Serial.begin(9600);
}
/**
* @name loop()
* loop functions is called continuously
*/
void loop()
{
//
// read the data
//
readADXL345(); // read the raw data from the ADXL345
//
// display the data on the Serial
//
Serial.print(rawData.XAxis);
Serial.print(" | ");
Serial.print(rawData.YAxis);
Serial.print(" | ");
Serial.println(rawData.ZAxis);
//
// delay some time
//
delay(DELAY_PER_MEASUREMENT);
}
Is it possible to combine this code with the other code?
Sure you can combine them. First look at what the old code does. It gets the values for X and Y acceleration (doesn't use Z) and then maps them to ±20 and uses the mapped values to send to the mouse function. Replace the part that reads the values and then modify the mapping. What values are returned by the new accelerometer code? The old code returned ±500(X) and ±400(Y).
I cleaned up the old code and got it so that it would auto format. I could not get it to compile though (I use a UNO and don't have the Mouse library).
//Details
/*
Accelerometer_Mouse
This code reads the Memsic 2125 two-axis accelerometer, converts the pulses output by the 2125 into milli-g's (1/1000 of earth's gravity) and prints a mapped version of them over the serial connection to the computer.output. It then takes these mapped values and uses them for virtual mouse movement, clicking, and scrolling.
The circuit:
X output of accelerometer to digital pin 2
Y output of accelerometer to digital pin 3
+V of accelerometer to +5V
GND of accelerometer to ground
created by David Kerns of The Athenian School on Dec 3 2012, with a large portion of code taken from David A. Mellis' and Tom Igoe's found here: http://www.arduino.cc/en/Tutorial/Memsic2125
*/
const int xPin = 2; // const for X output of the accelerometer
const int yPin = 3; // const for Y output of the accelerometer
void setup() {
Serial.begin(9600); // initialize serial communications:
pinMode(xPin, INPUT); // xPin connected to the accelerometer is input pinMode(yPin, INPUT);
// yPin connected to the accelerometer is input
Mouse.begin();
Serial.begin(9600); // Set up serial communication at 9600bps
Serial.println("ready"); //Print ready once setup loop is finished
}
void loop() {
int pulseX, pulseY; // Variables to read the pulse widths from accelerometer:
int accelerationX, accelerationY; // Variables to contain the resulting accelerations
pulseX = pulseIn(xPin,HIGH); // read pulse from x-axes
pulseY = pulseIn(yPin,HIGH); // read pulse from y-axes
// convert the pulse width into acceleration accelerationX and accelerationY are in milli-g's: earth's gravity is 1000 milli-g's, or 1g.
accelerationX = ((pulseX / 10) - 500) 8;
accelerationY = ((pulseY / 10) - 500) 8;
accelerationX = map(accelerationX, -500, 500, -20, 20); //map the acceleration output to more manageable values
accelerationY = map(accelerationY, -400, 400, -20, 20); //map the acceleration output to more manageable values
Serial.print(accelerationX); // print the x acceleration result
Serial.print("\t"); // print a tab character:
Serial.print(accelerationY); // print the y acceleration result
Serial.println(); //print a new line delay(50);
if(accelerationX < -17){ // override loop for scrolling, if accelerationX < -17
Mouse.move(0, 0, accelerationY); // mouse scroll function at the rate of accelerationY
}
else { // when accelerationX is > -17 (most of the time), do this loop
if (accelerationY > 4 || accelerationY < -4) /*if accelerationY > 4 or < -4 || accelerationX < -4)) // or if accelerationY > 4 and < -4(accelerationX > 4)*/
{
Mouse.move(-accelerationX, -accelerationY, 0); // move the mouse the negative accelerations(X and Y), do not scroll
}
}
if(accelerationY > 20){ //if the accelerationY value reaches a value of 20,
Mouse.click(); //left click the computer's mouse
}
if (accelerationY > 35){ //if the accelerationY value reaches a value of 35,
Mouse.click(); //left click once
Mouse.click(); //left click again (resulting in a double click)
}
if (accelerationX > 20){ //if the accelerationX value reaches a value of 20,
Mouse.click(MOUSE_RIGHT); //right click the computer's mouse
}
}
thanks for cleaning the code, but what do you actually mean with the code being able to auto format?
And.. so first I have to change the mapping in the old code. I have seen that in the first code, the values are called xPin and yPin. In the second one they are XAxis and YAxis. Is that the only thing I'm going to have to change to make the mapping similar?
And after having changed the mapping, I will have to change the values. To do that, I will have to read the values from my accelerometer first. Will do that tomorrow since I don't have the Arduino with me right now.
So after having changed those two things I can put the two codes together?
In the IDE, auto format is in the Tools menu. It helps with indentation and checks for matching {} and().
accelerationX = map(accelerationX, -500, 500, -20, 20); //map the acceleration output to more manageable values
accelerationY = map(accelerationY, -400, 400, -20, 20); //map the acceleration output
This is the mapping I meant. Once you have the ADXL connected and working (providing data) you will put the X data into accelerationX and the Y data to accelerationY and adjust the mapping to get usable numbers for mouse control.
There will be no need for xPin or yPin as the ADXL connects to A4 & A5 (SDA & SCL of the I2C bus). Don't forget the 4.7K (or there about) pull up resistors.
Right. After removing the old code that sets up and reads the old accelerometer. So you know the values that the ADXL outputs and the values that the Mouse() function expects then you can use the map() function to transfer acceleration to requested movements. Do you have the ADXL working? What values is the ADXL returning???? Do you know the values of the Mouse() function parameters?
Hi, sorry for the late reply but I'm having some trouble with my sensor. It used to work but now it only returns 0 as values. =( I am trying to solve this problem and will post again once I got it working and have the proper values..
groundfungus:
Right. After removing the old code that sets up and reads the old accelerometer. So you know the values that the ADXL outputs and the values that the Mouse() function expects then you can use the map() function to transfer acceleration to requested movements. Do you have the ADXL working? What values is the ADXL returning???? Do you know the values of the Mouse() function parameters?
Hi, I got the accelerometer working. The values it returns range from 260 to -260, both for x and y.
How do I get to know the values of the Mouse() function parameters?
The problem is that I can only move the cursor, so I can't do mouse clicks. For mouse clicks, I wanted to use the Z-axis since it is still unused.
The problem is that I don't know how to "control" the Z-axis, since for me, it behaves the same as the Y-axis (different values, but they increase and decrease by the same amount).
I have done some research but still haven't figured out how to move the Z-axis without moving the X and Y axis... ??