Tuesday, December 1, 2015

Accelerometer witn an Arduino Motion Capture

The aim of this post was to introduce you how to create a gesture controlled robot using Arduino.
This can be breaks down into two key phases:
First one: Formation of a gesture control unit proficient of send wireless communications to a mobile rover stage. The development of this control unit will be discussed in this post.
Second one: Formation of a mobile rover stage proficient of receiving wireless commands from a gesture control unit. The following points are to explain a brief description of the requirements for the gesture control unit:
  1. The Arduino powered unit must be able of detect motion.
  2. The unit must be correlating the motion to a set of determined motions.
  3. The unit should be capable to provide visual feedback and instructions to the users via an LCD display.
  4. The unit must be able to transmit the signal via wireless communications.

Necessary Requirements:

1. Arduino Kit:

This kit includes:
4. XBee Shield for Arduino
6. XBee 1mW Wire Antenna - Series 1 (802.15.4)
7. 9V Battery Holder with Switch
8.Tools
  • Soldering Iron
  • Solder
  • Disoldering braid
  • Screwdriver

Assembly and Connections:

The first step towards construction of the control unit is to make the shields. This can be done by simply soldering all of the necessary pins into the board. Robomart.com provides superb instructions on how to properly build these shields. These guides also provide nice wiring guides and test code. However, I will go into the wiring and code in depth here as well.

With the shields and sensor properly assembled, the shields can be wired together with the Arduino UNO. The next one step will show the wiring for the ADXL 335.

Wiring for the ADXL 335:

The connection between the ADXL 335 and the Arduino can be able using 6 wires. The first connections are simply the 5V power and ground connections. The next three connections are for the output data from the 3 terminal of the accelerometer. 
Each of these outputs needs its own analog input pin. I choose pins A0, A1, and A2 for the X, Y, and Z outputs, respectively. The last connection needed is the 3V connection. This pin requires to be wired to the AREF pin on the Arduino board. This connection provides the sensor a baseline noise level for the Arduino. The readings will be quite useless without it.

LCD Display Connections:

The shield, not stacked, requires only 5V, ground, and 2 analog pins. The LCD requires the use of the I2C pins on the Arduino, found on A4 and A5. Looking at the shield, moving from the Reset button to the left, bottom row of pins, the 1st pin requires to be connected to A5 and the 2nd pin requires to be connected to pin A4. The ground pin is the 8th pin from the right and the 5V pin is the 10th pin from the right. The connections can be seen below.

Connections of the XBee:

The connecting of the XBee is quite simple. Simply, place the XBee unit into the suitable slots on the shield. Now, place the shield on the Arduino, again. Finally, reconnect the wires for the accelerometer and the LCD into the same place they were on the Arduino.

Coding:

The code used to employ the control unit will be discussed below. This section will break down the code as it pertains to the different key sections of the code.
Namely, the sections to be discussed are:
  1. Libraries and global variables
  2. Routine setup
  3. Button detection
  4. LCD/motion detection routine

1. Libraries and Global Variables

This section will discuss the libraries and global variables needed to implement the motion detection routine.
#include
#include <Robomart_MCP23017.h>
#include
The Wire.h library comes with the Arduino IDE and does not need to be implemented. This library allows the Arduino to access the analog inputs needed to read the accelerometer. The other two libraries are there to provide the functions needed to use the Robomart RGB LCD.
Next one, we will discuss the global variables and objects declared to implement the code.
Robomart_RGBLCDShield LCD = Robomart_RGBLCDShield (); //define the LCD object as LCD
#define GREEN 0x2 //define the color green for the LCD
The above creates an object called LCD. This object will be used to call specific functions concerning the LCD device. In addition, the definition of GREEN in this case is a hex number used to tell the LCD what color to display the next in. This can be changed by using different hex numbers.
//Declare input pins
const int xInput = A0; const int yInput = A1; const int zInput = A2; int idleX = 0;
The above declares the analog input pins for the accelerometer.
int idleY = 0; int idleZ = 0; int idlemaxX = 0; int idlemaxY = 0;
int idlemaxZ = 0; int idleminX = 0; int idleminY = 0; int idleminZ = 0;
The above initializes the idle variables for the accelerometer. These must be defined as global variables because they are used in both the setup and loop routines. Later, one will see that the idle state is redefined each time the controller is turned on. This prevents errors should the environment conditions change the idle state values.
// Take multiple samples to reduce noise
const int sampleSize = 10;
int dir = 0;
Sample size is declared to reduce noise in the accelerometer measurements. Each time the values are read, 10 samples are taken and then averaged. The variable dir is used to communicate what button on the LCD has been pressed. This tells us the LCD what information to display.

2. Set-up Routine

In this section, we will discuss the setup routine used in the control unit.
analogReference(EXTERNAL);
The first step in this set-up routine is set the analogue reference voltage. This step helps to give a baseline for the amount of noise in the sensor readings. The analogue pins wouldn't read any change in reading, without it.
The LCD needs to be set up and a welcome message displayed.

lcd.begin(16, 2);
lcd.print("Welcome to the ");
lcd.setCursor(0,1);
lcd.print("HCRP");
lcd.setBacklight(GREEN);
delay(3000);
The set-up routine enters into the calibration phase of the code. Here, the idle state of the controlled is initialized. The inactive state is defined as laying flat. This is needed because motion is defined by deviations from the inactive state. The default state is inactive.
lcd.clear();
lcd.setCursor(0,0); lcd.print("Calibrating ");
lcd.setCursor(0,1); lcd.print("Lay flat");
delay(5000);
idleX = ReadAxis(xInput); idleY = ReadAxis(yInput); idleZ = ReadAxis(zInput);
idlemaxX = idleX+15; idlemaxY = idleY+15; idlemaxZ = idleZ+15;
idleminX = idleX-15; idleminY = idleY-15; idleminZ = idleZ-15;
lcd.clear();
lcd.setCursor(0,0); lcd.print("All done! ");
lcd.setCursor(0,1); lcd.print("Begin Control");
delay(3000);
In order to detect motion, the accelerometer values will have to exceed the maximum or minimum value for the idle state. Finally, the code tells the user that the calibration is finished and control of the rover is about to begin.

3. Button Detection

This Section describes the different actions to be taken by Arduino given different button presses on the LCD.
if (buttons)
{
lcd.clear();
lcd.setCursor(0,0);
if (buttons & BUTTON_UP)
  {
 lcd.print("Move "); dir = 0;
 }
if (buttons & BUTTON_DOWN)
{
lcd.print("Z accel "); lcd.setCursor(0, 1);
lcd.print(zRaw); dir = 1;
}
if (buttons & BUTTON_LEFT) {
lcd.print("Y accel "); lcd.setCursor(0, 1);
lcd.print(yRaw); dir = 2;
}
if (buttons & BUTTON_RIGHT) {
lcd.print("X accel "); lcd.setCursor(0, 1);
lcd.print(xRaw); dir = 3;
}
When the UP button on the LCD is pressed, then the Movement detected by the control unit is printed to the screen. This is the default display of the LCD. The variable dir global variable used to define the button that was pressed. It is used later in a switch/case statement to determine what information to continuously display. When the DOWN button is pressed, the raw Z acceleration data is shown. If the RIGHT button is pressed, the raw X acceleration data is shown. And if the LEFT button is pressed, the raw Y acceleration is displayed.

4. Motion Detection

This section describes how the controller decides what kind of motion is happening. Through testing, is determined that, as referenced from the idle state, this is the pattern that the motion of the controller follows. 
(G=greater, L=less, S=same)
Ideal: 510, 497, 627
Right 611, 492, 521.....G,S,L
Left 408, 496, 530.....L,S,L
Forward 512, 598, 526.....S,G,L
Reverse 514, 395, 536.....S,L,L
What this is saying is that, for an example, in order for there to be motion to the right, the X reading must be greater than inactive, the Y reading must be about the same, and the Z reading needs to be less than inactive. The same kind of logic follows for the other kinds of motion.
In the following code, the switch/case statement uses simple logic to determine the motion.
case 0:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Move");
lcd.setCursor(0, 1);
if (xRaw > idleX && yRaw > idleminY && yRaw < idlemaxY && zRaw < idleZ)
{
lcd.print("Right");
}
else if (xRaw < idleX && yRaw > idleminY && yRaw < idlemaxY && zRaw < idleZ)
{
lcd.print("Left");
}
else if (xRaw > idleminX && xRaw < idlemaxX && yRaw > idleY && zRaw < idleZ)
{
lcd.print("Forward");
}
else if (xRaw > idleminX && xRaw < idlemaxX && yRaw < idleY && zRaw < idleZ)
{
lcd.print("Reverse");
}
else {
lcd.print("Idle");
}

Covering Up and Future Scope:

In conclusion, it provided some information to set up the blog and to explore the different types of motion using an accelerometer that is my hope. In this blog, for the installation process and various sensors such as accelerometers and LCD displays and discussions were using.
Finally, the blog of accelerometer measurements to map the proposal provided access to write code you've gone through.
In addition, a follow-up on the blog to move around in the environment of the device is able to use motion to discuss how to build a rover will be written to. 
Thank you so much for pay attention for this post. If you have any bug or comment or any update feel free to post here.