Posts with «accelerometer» label

Taming Robot Arm Jump with Accelerometers

Last fall, I grabbed a robot arm from Robot Geeks when they were on sale at Thanksgiving. The arm uses servos to rotate the base and move the joints and gripper. These work well enough but I found one aspect of the arm frustrating. When you apply power, the software commands the servos to move to home position. The movement is sufficiently violent it can cause the entire arm to jump.

This jump occurs because there is no position feedback to the Arduino controller leaving it unable to know the positions of the arm’s servos and move them slowly to home. I pondered how to add this feedback using sensors, imposing the limitation that they couldn’t be large or require replacing existing parts. I decided to try adding accelerometers on each arm section.

Accelerometers, being affected by gravity when on a planet, provide an absolute reference because they always report the direction of down. With an accelerometer I can calculate the angle of an arm section with respect to the direction of gravitational acceleration.

Before discussing the accelerometers, take a look at the picture of the arm. An accelerometer would be added to each section of the arm between the controlling servos.

Accelerometers

Gravity tugs everything toward the center of the mass of the Earth. It is a force that creates an acceleration exactly just like what you feel when a vehicle begins to move or stop. The force of gravity creates an acceleration of 1 g which is 9.8 m/s2 or 32.15 ft/s2. An accelerometer measures this force.

Integrated circuit accelerometers are inexpensive and small devices readily usable by hackers. One reason they are inexpensive is the high demand for them in smart phones. These small devices are based on etching mechanical structures within the integrated circuit using a technology called MEMS (Microelectromechanical systems).

One design for a MEMS accelerometer is basically a variable capacitor. One plate is fixed and the other mounted some distance away on a spring suspension. When the device is accelerated the suspended plate moves closer or further away from the fixed plate, changing the capacitance. Another uses piezo-resistive material to measure the stress on an arm caused by acceleration.

A single axis accelerometer measures acceleration in only one direction. If positioned so the direction is up and down it will measure the force of gravity but will not detect horizontal acceleration. When the device is tilted between horizontal and vertical the force of gravity is only partially affecting the measurement. This provides the ability to measure the angle of the device with the direction of gravity. The acceleration felt along the tilted axis, for a tilt angle can be calculated by:

Knowing the output of the accelerometer we can determine the angle by taking the inverse sine, the arc sine, of the output:

If you rotate a single axis device through 360° the output is a sine wave. Start with the device outputting zero and consider that 0°. As it rotates, the output is 1 when the angle is 90° and back to zero at 180°. Continuing the rotation, the output becomes -1 at 270°, or -90°, degrees and back to zero at 360°, or 0°.

Notice on the chart that between -60° and 60° the output is nearly linear. This is the best orientation for measuring inclination. Increases in inclination are not as accurate on the other portions of the curve. Also notice that the same output is generated for 45° and 135° (90° + 45°) creating an ambiguity. With a single axis you cannot determine which of those angles is measured.

Putting two accelerometers at a right angle to one another creates a 2-axis device which solves the ambiguity problem. As the device is rotated through 360° the outputs are 90° out of phase, the same relationship as the sine and cosine. By combining the measurements there is a unique solution for every angle throughout 360°. The acceleration due to gravity at each angle is given by:

which leads to calculating the angle by:

Actually, one more step is needed to determine the sign of the angle. This requires examining the sign of the values for the X and Y axis. It isn’t necessary to go into this here because a standard programming function handles this automatically.

The orientation of a quadcopter requires a 3-axis accelerometer. The calculations for the three spherical angles combine all three inputs for their results. You’ll need to study this carefully because the standard trigonometric equations can cause anomalies when the quadcopter flips.

First Pass Solution

Accelerometers are easily obtained and relatively cheap. You can find them mounted on breakout boards with voltage regulators and all the supporting circuits from the usual vendors. They are available for 1 to 3 axis, various amounts of g force, and providing either analog or digital outputs. Analog devices need an analog input for each axis being measured. Digital outputs use I2C or SPI buses for communications. I decided to use analog devices because digital units typically only allow two addresses and the arm needs three devices, one for each section.

The robot arm uses an Arduino board so there are at least 6 analog inputs. The original board was a Robot Geek Geekduino, their version of the Arduino Duemilanove, with 8 analog inputs. Unfortunately, when working with the arm I broke the USB connector so switched to a Uno equivalent having only 6 inputs.

My choice for accelerometer is a 3-axis, ±3 g accelerometer breakout from Adafruit, their ADXL335. It has one analog output for each axis. Since I’m measuring three joints that means three boards which adds up to 9 analog outputs.

Because of the geometry of the arm, however, I only need 5 inputs for these three joints. The shoulder joint only moves from 0° to 180°. This can be handled by a single axis accelerometer by mounting it to read acceleration of 1 g for 0° and -1g for 180°. That provides a unique output for the necessary angles. The elbow and wrist joints each require two inputs. The third input is not needed because their motion is constrained to moving within the vertical plane of the arm.

Frame of Reference

The next issue is the frame of reference. This is a standard problem in robotics work. Early in a project, a global frame of reference is decided upon. This sets the origin for the coordinate system that the robot will follow and the direction of the three axes, usually specified as X, Y, and Z. For the arm, X is straight forward, Y is to the left, and Z is straight up. The zero point is the base of the shoulder. This also defines a global frame for rotation of the arms limbs with zero degrees also toward the front.

Sensors and controllers each have their own frame of reference. Any differences among these devices and the global frame need to be resolved in software. The shoulder servo’s frame of reference is 0° at the back of the arm and 180° at the front, a clockwise rotation. This is the reverse of the global frame. The elbow servo worked the opposite with a counter-clockwise rotation putting 180° straight up and 90° straight out when the shoulder was vertical. It is 90° off from the global frame of reference.

Sensors also have their own frame of reference. The Y-axis accelerometer measuring the shoulder orientation worked counter-clockwise. Both axis on the accelerometers measuring the elbow worked in the clock-wise direction. This may seem strange but it’s because of the different mounting orientations of the sensors.

Software

The actual code is straightforward once the frame of references are sorted out. A single axis is read from the analog input and its angle calculated with:

const int shouldery = shoulderAnalogY.read();
float shoulder_angle = degrees(asin(shouldery_value / 100.0));

The read() method scales the raw analog input values so ±1g is represented as ±100. The input to asin() is divided by 100.0 to convert to the actual g value. That suffices for the shoulder angle.

The elbow and wrist angles use values from two axis and the calculation is:

const int elbowx = elbowAnalogX.read();
const int elbowy = elbowAnalogY.read();
float elbow_angle = degrees(atan2(-elbowy, elbowx));

The atan2() function is a special version of the arc tangent calculation. It examines the signs of the input value to determine the quadrant of the angle to set the appropriate sign on its result. The negative sign on the elbowy is needed to set the appropriate quadrant. There’s the frame of reference issue, again.

Wrap Up

Adding the accelerometers solved the startup lurching problem well enough. Whether the accelerometers can be used for other purposes remains to be seen.

The accuracy of the angle measurements is not good. In part this is due to using a device that with a +/- 3 g range to measure 1/3 of the devices range, 1 g. The device outputs 0 to 3.3 volts while the Arduino is sampling for 5 volts, again losing accuracy. This might be improved by using an Arduino based on 3.3 volts. I have a couple Dues on hand so might try them. The Uno also provides for adjusting the reference voltage for analog inputs so setting it to 3.3 volts might help.

The analog values need to be calibrated with some care. Each accelerometer outputs slightly different values. Calibration requires measuring the outputs for 1 and -1 g for each axis, recording the values, and using them to scale the voltage input to acceleration. This calibration is not accurate given the other problems with the analog inputs.

Another problem is the mounting of the accelerometers on the arm’s sections. The alignment of the boards with the sections of the arm is not perfect. When the servo is positioned at 90° the accelerometer doesn’t necessarily sit at 90° with respect to the center of the earth. Of course, the servos are not that precise, either. They do not always arrive at the same position, especially when approaching from different directions. Another goal for this project was to use the accelerometer information to more precisely position the servos.

I guess I have to think about this project a bit more, including deciding what I actually want to accomplish with the arm. But then, just saying you have a robotic arm is a terrific hacking cred.


Filed under: Arduino Hacks, robots hacks

Teach your drone what is up and down with an Arduino

Gyroscopes and accelerometers are the primary sensors at the heart of an IMU, also known as an internal measurement unit — an electronic sensor device that measures the orientation, gravitational forces and velocity of a multicopter, and help you keep it in the air using Arduino.

Two videos made by Joop Brokking, a Maker with passion for RC model ‘copters, clearly explain how to program your own IMU so that it can be used for self-balancing your drone without Kalman filters,  libraries, or complex calculations.

Auto leveling a multicopter is pretty challenging. It means that when you release the pitch and roll controls on your transmitter the multicopter levels itself. To get this to work the flight controller of the multicopter needs to know exactly which way is down. Like a spirit level that is on top of the multicopter for the pitch and roll axis.

Very often people ask me how to make an auto level feature for their multicopter. The answer to a question like this is pretty involved and cannot be explained in one email. And that is why I made this video series.

You can find the bill of materials and code here.

Machine learning for the maker community

At Arduino Day, I talked about a project I and my collaborators have been working on to bring machine learning to the maker community. Machine learning is a technique for teaching software to recognize patterns using data, e.g. for recognizing spam emails or recommending related products. Our ESP (Example-based Sensor Predictions) software recognizes patterns in real-time sensor data, like gestures made with an accelerometer or sounds recorded by a microphone. The machine learning algorithms that power this pattern recognition are specified in Arduino-like code, while the recording and tuning of example sensor data is done in an interactive graphical interface. We’re working on building up a library of code examples for different applications so that Arduino users can easily apply machine learning to a broad range of problems.

The project is a part of my research at the University of California, Berkeley and is being done in collaboration with Ben Zhang, Audrey Leung, and my advisor Björn Hartmann. We’re building on the Gesture Recognition Toolkit (GRT) and openFrameworks. The software is still rough (and Mac only for now) but we’d welcome your feedback. Installations instructions are on our GitHub project page. Please report issues on GitHub.

Our project is part of a broader wave of projects aimed at helping electronics hobbyists make more sophisticated use of sensors in their interactive projects. Also building on the GRT is ml-lib, a machine learning toolkit for Max and Pure Data. Another project in a similar vein is the Wekinator, which is featured in a free online course on machine learning for musicians and artists. Rebecca Fiebrink, the creator of Wekinator, recently participated in a panel on machine learning in the arts and taught a workshop (with Phoenix Perry) at Resonate ’16. For non-real time applications, many people use scikit-learn, a set of Python tools. There’s also a wide range of related research from the academic community, which we survey on our project wiki.

For a high-level overview, check out this visual introduction to machine learning. For a thorough introduction, there are courses on machine learning from coursera and from udacity, among others. If you’re interested in a more arts- and design-focused approach, check out alt-AI, happening in NYC next month.

If you’d like to start experimenting with machine learning and sensors, an excellent place to get started is the built-in accelerometer and gyroscope on the Arduino or Genuino 101. With our ESP system, you can use these sensors to detect gestures and incorporate them into your interactive projects!

Hackaday Prize Entry: Project Dekoboko 凸凹 Maps Bumpy Roads On A Bike

If you live in New England (like me) you know that the roads take a pounding in the winter. Combine this with haphazard maintenance and you get a recipe for biking disaster: bumpy, potholed roads that can send you flying over the handlebars. Project Dekoboko 凸凹 aims to help a little with this, by helping you map and avoid the bumpiest roads and could be a godsend in this area.

The 2015 Hackaday Prize entry from [Benjamin Shih], [Daniel Rojas], and [Maxim Lapis] is a device that clips onto your bike and maps how bumpy the ride is as you pedal around. It does this by measuring the vibration of the bike frame with an accelerometer. Combine this with a GPS log and you get a map of the quality of the roads that helps you plan a smooth ride, or which could help the city figure out which roads need fixing the most.

The project is currently on its  third version, built around an Arduino, Adafruit Ultimate GPS Logger shield, and a protoboard that holds the accelerometer (an Analog ADXL345). The team has also set up a first version of their web site, which contains live data from a few trips around Berlin. This does show one of the issues they will need to figure out, though: the GPS data has them widely veering off the road, which means that the data was slightly off, or they were cycling through buildings on the Prinzenstrasse, including a house music club. I’ll assume that it was the GPS being inaccurate and not them stopping for a rave, but they will need to figure out ways to tie this data down to a specific street before they can start really analyzing it. Google Maps does offer a way to do this, but it is not always accurate, especially on city streets. Still, the project has made good progress and could be useful for those who are looking for a smooth ride around town.

The 2015 Hackaday Prize is sponsored by:


Filed under: The Hackaday Prize, transportation hacks

Hand Controlled Robot uses Accelerometer

What do orchestra conductors, wizards, and Leap controller users have in common? They all control things by just waving their hands. [Saddam] must have wanted the same effect, so he created a robot that he controls over wireless using hand gestures.

An accelerometer reads hand motions and sends them via an RF module to an Arduino. This is a bit of a trick, because the device produces an analog value and [Saddam] uses some comparators to digitize the signal for the RF transmitter. There is no Arduino or other CPU on the transmit side (other than whatever is in the RF module).

From the video, it looks like a natural way to control a robot as long as you don’t mind duct taping the transmitter to your hand. Of course, if you are a real hacking geek, you might even consider that an advantage as you can pretend you are working on becoming a cyborg.

[Saddam] spends some time talking about how the accelerometer works internally, and we’ve covered that before if you are curious. It turns out the devices aren’t as much electronic as we usually think of them, but mechanical.


Filed under: Android Hacks, robots hacks

It’s Time to Roll Your Own Smartwatch

Giant wristwatches are so hot right now. This is a good thing, because it means they’re available at many price points. Aim just low enough on the scale and you can have a pre-constructed chassis for building your own smartwatch. That’s exactly what [benhur] did, combining a GY-87 10-DOF module, an I²C OLED display, and an Arduino Pro Mini.

The watch uses one button to cycle through its different modes. Date and time are up first, naturally. The next screen shows the current temperature, altitude, and barometric pressure. Compass mode is after that, and then a readout showing your step count and kilocalories burned.

In previous iterations, the watch communicated over Bluetooth to Windows Phone, but it drew too much power. With each new hardware rev, [benhur] made significant strides in battery life, going from one hour to fourteen to a full twenty-fours.

Take the full tour of [benhur]’s smartwatch after the break. He’s open to ideas for the next generation, so share your insight with him in the comments. We’d like to see some kind of feedback system that tells us when we’ve been pounding away at the Model M for too long. 

[via Embedded Lab]


Filed under: Arduino Hacks, wearable hacks

NeoPixel Playground


The NeoPixel Digital RGB LED Strip (144 LED/m) is a really impressive product that will have you lighting up your room in next to no time. The 144 individually addressable LEDs packed onto a 1 metre flexible water resistant strip, enables a world of luminescent creativity that will blow your blinking Arduino friends away. The following tutorial will show you how to create an immersive and interactive LED display using an Arduino UNO, a potentiometer and an accelerometer. There will be a total of FIVE LED sequences to keep you entertained or you can create your own !
 
This tutorial was specifically designed to work with the 144 Neopixel Digital RGB LED strip with the ws2812B chipset.

 

Parts Required:

Power Requirements

Before you start any LED strip project, the first thing you will need to think about is POWER. According to the Adafruit website, each individual NeoPixel LED can draw up to 60 milliamps at maximum brightness - white. Therefore the amount of current required for the entire strip will be way more than your Arduino can handle. If you try to power this LED strip directly from your Arduino, you run the risk of damaging not only your Arduino, but your USB port as well. The Arduino will be used to control the LED strip, but the LED strip will need to be powered by a separate power supply. The power supply you choose to use is important. It must provide the correct voltage, and must able to supply sufficient current.
 

Operating Voltage(5V)

The operating voltage of the NeoPixel strip is 5 volts DC. Excessive voltage will damage/destroy your NeoPixels.

Current requirements (8.6 Amps)

OpenLab recommend the use of a 5V 10A power supply. Having more Amps is OK, providing the output voltage is 5V DC. The LEDs will only draw as much current as they need. To calculate the amount of current this 1m strip can draw with all LEDs turned on at full brightness - white:

144 NeoPixel LEDs x 60 mA x 1 m = 8640 mA = 8.64 Amps for a 1 metre strip.

Therefore a 5V 10A power supply would be able to handle the maximum current (8.6 Amps) demanded by a single 1m NeoPixel strip of 144 LEDs.
 
 

Arduino Libraries and IDE


Before you start to hook up any components, upload the following sketch to the Arduino microcontroller. I am assuming that you already have the Arduino IDE installed on your computer. If not, the IDE can be downloaded from here.
 
The FastLED library is useful for simplifying the code for programming the NeoPixels. The latest "FastLED library" can be downloaded from here. I used FastLED library version 3.0.3 in this project.
 
If you have a different LED strip or your NeoPixels have a different chipset, make sure to change the relevant lines of code to accomodate your hardware. I would suggest you try out a few of the FastLED library examples before using the code below, so that you become more familiar with the library, and will be better equipped to make the necessary changes. If you have a single 144 NeoPixel LED/m strip with the ws2812B chipset, then you will not have to make any modifications below (unless you want to).
 

ARDUINO CODE:


 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318



/* ==================================================================================================================================================
         Project: NeoPixel Playground
Neopixel chipset: ws2812B  (144 LED/m strip)
          Author: Scott C
         Created: 12th June 2015
     Arduino IDE: 1.6.4
         Website: http://arduinobasics.blogspot.com/p/arduino-basics-projects-page.html
     Description: This project will allow you to cycle through and control five LED
                  animation sequences using a potentiometer and an accelerometer
                     Sequence 1:   Cylon with Hue Control                                       Control: Potentiometer only
                     Sequence 2:   Cylon with Brightness Control                                Control: Potentiometer only
                     Sequence 3:   Comet effect with Hue and direction control                  Control: Potentiometer and Accelerometer (Y axis only)
                     Sequence 4:   FireStarter / Rainbow effect with Hue and Direction control  Control: Potentiometer and Accelerometer (Y axis only)
                     Sequence 5:   Digital Spirit Level                                         Control: Accelerometer only (Y axis)
            
                  This project makes use of the FastLED library. Some of the code below was adapted from the FastLED library examples (eg. Cylon routine).
                  The Comet, FireStarter and Digital Spirit Level sequence was designed by ScottC.
                  The FastLED library can be found here: http://fastled.io/
                  You may need to modify the code below to accomodate your specific LED strip. See the FastLED library site for more details.
===================================================================================================================================================== */

//This project needs the FastLED library - link in the description.
#include "FastLED.h"

//The total number of LEDs being used is 144
#define NUM_LEDS 144

// The data pin for the NeoPixel strip is connected to digital Pin 6 on the Arduino
#define DATA_PIN 6

//Initialise the LED array, the LED Hue (ledh) array, and the LED Brightness (ledb) array.
CRGB leds[NUM_LEDS];
byte ledh[NUM_LEDS];
byte ledb[NUM_LEDS];

//Pin connections
const int potPin = A0; // The potentiometer signal pin is connected to Arduino's Analog Pin 0
const int yPin = A4; // Y pin on accelerometer is connected to Arduino's Analog Pin 4
                            // The accelerometer's X Pin and the Z Pin were not used in this sketch

//Global Variables ---------------------------------------------------------------------------------
byte potVal; // potVal: stores the potentiometer signal value
byte prevPotVal=0; // prevPotVal: stores the previous potentiometer value
int LEDSpeed=1; // LEDSpeed: stores the "speed" of the LED animation sequence
int maxLEDSpeed = 50; // maxLEDSpeed: identifies the maximum speed of the LED animation sequence
int LEDAccel=0; // LEDAccel: stores the acceleration value of the LED animation sequence (to speed it up or slow it down)
int LEDPosition=72; // LEDPosition: identifies the LED within the strip to modify (leading LED). The number will be between 0-143. (Zero to NUM_LEDS-1)
int oldPos=0; // oldPos: holds the previous position of the leading LED
byte hue = 0; // hue: stores the leading LED's hue value
byte intensity = 150; // intensity: the default brightness of the leading LED
byte bright = 80; // bright: this variable is used to modify the brightness of the trailing LEDs
int animationDelay = 0; // animationDelay: is used in the animation Speed calculation. The greater the animationDelay, the slower the LED sequence.
int effect = 0; // effect: is used to differentiate and select one out of the four effects
int sparkTest = 0; // sparkTest: variable used in the "sparkle" LED animation sequence
boolean constSpeed = false; // constSpeed: toggle between constant and variable speed.


//===================================================================================================================================================
// setup() : Is used to initialise the LED strip
//===================================================================================================================================================
void setup() {
    delay(2000); //Delay for two seconds to power the LEDS before starting the data signal on the Arduino
    FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS); //initialise the LED strip
}


//===================================================================================================================================================
// loop() : The Arduino will take readings from the potentiometer and accelerometer to control the LED strip
//===================================================================================================================================================
void loop(){
  readPotentiometer();           
  adjustSpeed();
  constrainLEDs();
 
  switch(effect){
    case 0: // 1st effect : Cylon with Hue control - using Potentiometer
      cylonWithHueControl();
      break;
      
    case 1: // 2nd effect : Cylon with Brightness control - using Potentiometer
      cylonWithBrightnessControl();
      break;
      
    case 2: // 3rd effect : Comet effect. Hue controlled by potentiometer, direction by accelerometer
      cometEffect();
      break;
      
    case 3: // 4th effect : FireStarter / Rainbow Sparkle effect. Direction controlled by accelerometer, sparkle by potentiometer.
      fireStarter(); 
      break;
    
    case 4:
      levelSense();                                        // 5th effect : LevelSense - uses the accelerometer to create a digital "spirit" level.
      break;
  }
}


//===================================================================================================================================================
// readPotentiometer() : Take a potentiometer reading. This value will be used to control various LED animations, and to choose the animation sequence to display.
//===================================================================================================================================================
void readPotentiometer(){
  //Take a reading from the potentiometer and convert the value into a number between 0 and 255
  potVal = map(analogRead(potPin), 0, 1023 , 0, 255);
  
  // If the potentiometer reading is equal to zero, then move to the next effect in the list.
  if(potVal==0){
    if(prevPotVal>0){ // This allows us to switch effects only when the potentiometer reading has changed to zero (from a positive number). Multiple zero readings will be ignored.
      prevPotVal = 0;   // Set the prev pot value to zero in order to ignore replicate zero readings.
      effect++;         // Go to the next effect.
      if(effect>4){
        effect=0;       // Go back to the first effect after the fifth effect.
      }
    }
  }
  prevPotVal=potVal;    // Keep track of the previous potentiometer reading
}


//===================================================================================================================================================
// adjustSpeed() : use the Y axis value of the accelerometer to adjust the speed and the direction of the LED animation sequence
//===================================================================================================================================================
void adjustSpeed(){
  // Take a reading from the Y Pin of the accelerometer and adjust the value so that
  // positive numbers move in one direction, and negative numbers move in the opposite diraction.
  // We use the map function to convert the accelerometer readings, and the constrain function to ensure that it stays within the desired limits
  // The values of 230 and 640 were determined by trial and error and are specific to my accelerometer. You will need to adjust these numbers to suit your module.
  
  LEDAccel = constrain(map(analogRead(yPin), 230, 640 , maxLEDSpeed, -maxLEDSpeed),-maxLEDSpeed, maxLEDSpeed);
  
  
  // If the constSpeed variable is "true", then make sure that the speed of the animation is constant by modifying the LEDSpeed and LEDAccel variables.
  if(constSpeed){
    LEDAccel=0; 
    if(LEDSpeed>0){
      LEDSpeed = maxLEDSpeed/1.1;     // Adjust the LEDSpeed to half the maximum speed in the positive direction
    } 
    if (LEDSpeed<0){
      LEDSpeed = -maxLEDSpeed/1.1;    // Adjust the LEDSpeed to half the maximum speed in the negative direction
    }
  } 
 
  // The Speed of the LED animation sequence can increase (accelerate), decrease (decelerate) or stay the same (constant speed)
  LEDSpeed = LEDSpeed + LEDAccel;                        
  
  //The following lines of code are used to control the direction of the LED animation sequence, and limit the speed of that animation.
  if (LEDSpeed>0){
    LEDPosition++;                                       // Illuminate the LED in the Next position
    if (LEDSpeed>maxLEDSpeed){
      LEDSpeed=maxLEDSpeed;                              // Ensure that the speed does not go beyond the maximum speed in the positive direction
    }
  }
  
  if (LEDSpeed<0){
    LEDPosition--;                                       // Illuminate the LED in the Prior position
    if (LEDSpeed<-maxLEDSpeed){
      LEDSpeed = -maxLEDSpeed;                           // Ensure that the speed does not go beyond the maximum speed in the negative direction
    }
  }
}


//===================================================================================================================================================
// constrainLEDs() : This ensures that the LED animation sequence remains within the boundaries of the various arrays (and the LED strip)
//                   and it also creates a "bouncing" effect at both ends of the LED strip.
//===================================================================================================================================================
void constrainLEDs(){
  LEDPosition = constrain(LEDPosition, 0, NUM_LEDS-1); // Make sure that the LEDs stay within the boundaries of the LED strip
  if(LEDPosition == 0 || LEDPosition == NUM_LEDS-1) {
    LEDSpeed = (LEDSpeed * -0.9);                         // Reverse the direction of movement when LED gets to end of strip. This creates a bouncing ball effect.
  }
}



//===================================================================================================================================================
// cylonWithHueControl() :  This is the 1st LED effect. The cylon colour is controlled by the potentiometer. The speed is constant.
//===================================================================================================================================================
void cylonWithHueControl(){
      constSpeed = true; // Make the LED animation speed constant
      showLED(LEDPosition, potVal, 255, intensity);       // Illuminate the LED
      fadeLEDs(8);                                        // Fade LEDs by a value of 8. Higher numbers will create a shorter tail.
      setDelay(LEDSpeed);                                 // The LEDSpeed is constant, so the delay is constant
}


//===================================================================================================================================================
// cylonWithBrightnessControl() : This is the 2nd LED effect. The cylon colour is red (hue=0), and the brightness is controlled by the potentiometer
//===================================================================================================================================================
void cylonWithBrightnessControl(){
      constSpeed = true; // Make speed constant
      showLED(LEDPosition, 0, 255, potVal);               // Brightness is controlled by potentiometer.
      fadeLEDs(16);                                       // Fade LEDs by a value of 16
      setDelay(LEDSpeed);                                 // The LEDSpeed is constant, so the delay is constant
}


//===================================================================================================================================================
// cometEffect() :  This is the 3rd LED effect. The random brightness of the trailing LEDs produces an interesting comet-like effect.
//===================================================================================================================================================
void cometEffect(){
      constSpeed = false; // The speed will be controlled by the slope of the accelerometer (y-Axis)
      showLED(LEDPosition, potVal, 255, intensity);        // Hue will change with potentiometer.
      
      //The following lines create the comet effect
      bright = random(50, 100); // Randomly select a brightness between 50 and 100
      leds[LEDPosition] = CHSV((potVal+40),255, bright); // The trailing LEDs will have a different hue to the leading LED, and will have a random brightness
      fadeLEDs(8);                                         // This will affect the length of the Trailing LEDs
      setDelay(LEDSpeed);                                  // The LEDSpeed will be affected by the slope of the Accelerometer's y-Axis
}


//===================================================================================================================================================
// fireStarter() : This is the 4th LED effect. It starts off looking like a ball of fire, leaving a trail of little fires. But as you
//                 turn the potentiometer, it becomes more like a shooting star with a rainbow-sparkle trail.
//===================================================================================================================================================
void fireStarter(){
      constSpeed = false; // The speed will be controlled by the slope of the accelerometer (y-Axis)
      ledh[LEDPosition] = potVal;                          // Hue is controlled by potentiometer
      showLED(LEDPosition, ledh[LEDPosition], 255, intensity); 
      
      //The following lines create the fire starter effect
      bright = random(50, 100); // Randomly select a brightness between 50 and 100
      ledb[LEDPosition] = bright;                          // Assign this random brightness value to the trailing LEDs
      sparkle(potVal/5);                                   // Call the sparkle routine to create that sparkling effect. The potentiometer controls the difference in hue from LED to LED.
      fadeLEDs(1);                                         // A low number creates a longer tail
      setDelay(LEDSpeed);                                  // The LEDSpeed will be affected by the slope of the Accelerometer's y-Axis
}


//===================================================================================================================================================
// levelSense() : This is the 5th and final LED effect. The accelerometer is used in conjunction with the LED strip to create a digital "Spirit" Level.
//                You can use the illuminated LEDs to identify the angle of the LED strip
//===================================================================================================================================================
void levelSense(){
      constSpeed = true;
      LEDPosition = constrain(map(analogRead(yPin), 230, 640, 1, NUM_LEDS-1), 0 , NUM_LEDS-1);
      
      //Jitter correction: this will reduce the amount of jitter caused by the accelerometer reading variability
      if(abs(LEDPosition-oldPos) < 2){
        LEDPosition = oldPos;
      }
      
      //The following lines of code will ensure the colours remain within the red to green range, with green in the middle and red at the ends.
      hue = map(LEDPosition, 0, NUM_LEDS-1, 0, 200);
      if (hue>100){
         hue = 200 - hue;
      }
      
      //Illuminate 2 LEDs next to each other
      showLED(LEDPosition, hue, 255, intensity); 
      showLED(LEDPosition-1, hue, 255, intensity);              
      
      //If the position moves, then fade the old LED positions by a factor of 25 (high numbers mean shorter tail)
      fadeLEDs(25);                               
      oldPos = LEDPosition; 
}


//===================================================================================================================================================
// fadeLEDs(): This function is used to fade the LEDs back to black (OFF) 
//===================================================================================================================================================
void fadeLEDs(int fadeVal){
  for (int i = 0; i<NUM_LEDS; i++){
    leds[i].fadeToBlackBy( fadeVal );
  }
}



//===================================================================================================================================================
// showLED() : is used to illuminate the LEDs 
//===================================================================================================================================================
void showLED(int pos, byte LEDhue, byte LEDsat, byte LEDbright){
  leds[pos] = CHSV(LEDhue,LEDsat,LEDbright);
  FastLED.show();
}


//===================================================================================================================================================
// setDelay() : is where the speed of the LED animation sequence is controlled. The speed of the animation is controlled by the LEDSpeed variable.
//              and cannot go faster than the maxLEDSpeed variable.
//===================================================================================================================================================
void setDelay(int LSpeed){
  animationDelay = maxLEDSpeed - abs(LSpeed);
  delay(animationDelay);
}


//===================================================================================================================================================
// sparkle() : is used by the fireStarter routine to create a sparkling/fire-like effect
//             Each LED hue and brightness is monitored and modified using arrays  (ledh[]  and ledb[])
//===================================================================================================================================================
void sparkle(byte hDiff){
  for(int i = 0; i < NUM_LEDS; i++) {
    ledh[i] = ledh[i] + hDiff;                // hDiff controls the extent to which the hue changes along the trailing LEDs
    
    // This will prevent "negative" brightness.
    if(ledb[i]<3){
      ledb[i]=0;
    }
    
    // The probability of "re-igniting" an LED will decrease as you move along the tail
    // Once the brightness reaches zero, it cannot be re-ignited unless the leading LED passes over it again.
    if(ledb[i]>0){
      ledb[i]=ledb[i]-2;
      sparkTest = random(0,bright);
      if(sparkTest>(bright-(ledb[i]/1.1))){
        ledb[i] = bright;
      } else {
        ledb[i] = ledb[i] / 2;                  
      }
    }
    leds[i] = CHSV(ledh[i],255,ledb[i]);
  }
}


 

NeoPixel Strip connection

The NeoPixel strip is rolled up when you first get it. You will notice that there are wires on both sides of the strip. This allows you to chain LED strips together to make longer strips. The more LEDs you have, the more current you will need. Connect your Arduino and power supply to the left side of the strip, with the arrows pointing to the right side of the strip.
 

Follow the Arrows

The arrows are quite hard to see on this particular LED strip because they are so small, plus they are located right under the thicker part of the NeoPixel weatherproof sheath. I have circled the arrows in RED so that you know where to look:

 


NeoPixel Strip Wires

There are 4 wires coming from either side of the NeoPixel LED strip:
 
  One red wire, one white wire, and two black wires.
 
It doesn't matter which Black wire you use to connect to the power supply (or Arduino) GND. Both black wires appear to be going to the same pin on the LED strip anyway. Use the table below to make the necessary NeoPixel Strip connections to the Arduino and power supply.


Large Capacitor

Adafruit also recommend the use of a large capacitor across the + and - terminals of the LED strip to "prevent the initial onrush of current from damaging the pixels". Adafruit recommends a capacitor that is 1000uF, 6.3V or higher. I used a 4700uF 16V Electrolytic Capacitor.

Resistor on Data Pin

Another recommendation from Adafruit is to place a "300 to 500 Ohm resistor" between the Arduino's data pin and the data input on the first NeoPixel to prevent voltage spikes that can damage the first pixel. I used a 330 Ohm resistor.
 

Powering your Arduino (USB vs Power supply)

You can power your Arduino board via USB cable or via the LED strip power supply.
*** Please note: different power supplies will yield different accelerometer readings. I noticed this when changing the Arduino's power source from USB to LED power supply. My final sketch was designed to eliminate the USB/computer connection, hence I have chosen to power the Arduino via the power supply. The fritzing sketch below shows the Arduino being powered by a power supply only.

**WARNING: If you decide to power your Arduino UNO via a USB cable, please make sure to remove (or disconnect) the wire that goes to the the Arduino VIN pin. The GND connections remain unchanged.


Fritzing Sketch - NeoPixel strip connection


 

Potentiometer connection

The potentiometer will be used to switch between the different LED sequences. When it reads zero, it will switch to the next sequence in the list. It will jump right back to the beginning after the last sequence. The potentiometer is also used to interact with the LEDs (e.g. controlling hue, brightness etc etc).
See the fritzing sketch below to add the potentiometer to this project.



 

Accelerometer connection (Y-axis)

The accelerometer makes the LEDs much more fun and interactive. We will only be using the Y-axis of the accelerometer in this sketch. By tilting the accelerometer from one side to the other, the LEDs react and respond accordingly. The accelerometer is an essential component of the digital spirit level sequence. That's right ! You can use this sketch to create your own spirit level. This digital version can also be used to measure angles !
 
Have a look below to see how to hook up the accelerometer to the Arduino. The Y-axis is connected to the Arduino analog pin 4. If you wanted to use the X and Z axis, connect them to one of the other available analog pins (eg. A3 and A5).




 

Let the fun begin !!

Now that you have the Arduino code uploaded to the Arduino, and have made all of the necessary wire/component connections, it is time to turn on the power supply.
 

Sequence 1: Cylon with Hue control

The LEDs will move from one end of the strip to the other. It should start off as a RED cylon effect. As you turn the potentiometer clockwise, the colour of the LEDs will change and move through the various colours of the rainbow. If the potentiometer reading gets back to zero (fully anti-clockwise), it will move to sequence 2.
 

Sequence 2: Cylon with brightness control

You will see that the LEDs have turned off. The potentiometer readings correlate with the LED brightness. At the start of this sequence, the potentiometer readings will be zero, therefore the brightness will be zero (LEDs turned off). As you turn the potentiometer clockwise, the readings increase, and so will the brightness of the LEDs.
 

Sequence 3: Comet effect with Hue and direction control

This is where the real fun begins. You control the hue of the leading LED with the potentiometer, however the LED will move along the LED strip as though it were affected by gravity. As it hits the end of the LED strip, it will bounce for a while and eventually come to a stop. The more you tilt the accelerometer, the greater the acceleration of the leading LED. The trailing LEDs have an interesting randomised glow, which creates the "comet" effect.
 

Sequence 4: FireStarter / Rainbow effect : Hue and direction control

The initial colours of LEDs in this sequence creates a fire-like animation. As the leading LED moves along the LED strip, it appears to ignite the LEDs in its path, leaving a fire trail behind it. The fire effect is best when you turn the potentiometer clockwise slightly to introduce a small amount of yellow into the mix of colours. As you turn the potentiometer further clockwise, the fire trail turns into a pretty rainbow trail. The accelerometer affects the leading LED in the same way as the previous sequence.
 

Sequence 5: Digital spirit level

This sequence was my original idea for this project, however I thought it would be nice to share some of the other cool effects I created on my journey of discovery. The idea was to make a digital version of a spirit level. I originally wanted the LEDs to represent a spirit level bubble that would "float" according to the vertical/horizontal position of the LED strip. However, as I played around with this sketch, I discovered that it could potentially be used to measure the angle of the strip relative to the horizon. The angle can be determined by the illuminated LED. If the strip is horizontal, the illuminated LEDs will be close to the middle of the strip, and their colour will be green. If the strip is vertical, the illuminated LEDs will be close to end of the strip, and their colour will be red. The colour is just an additional visual indicator.
 


Concluding Comments

The NeoPixel Digital RGB LED strip is a lot of fun. The FastLED library makes for easy programming, and allows you to get up and running really quickly. 144 LEDs on a single strip means you have plenty of room for creative algorithms and lighting effects. Add a few sensors, and "pretty" quickly turns into "awesome" !!
 
This tutorial shows you how to control a "144 NeoPixel per metre Digital RGB LED strip" with an Arduino UNO. Feel free to share your own LED creations in the comments below.



If you like this page, please do me a favour and show your appreciation :

 
Visit my ArduinoBasics Google + page.
Follow me on Twitter by looking for ScottC @ArduinoBasics.
I can also be found on Pinterest and Instagram.
Have a look at my videos on my YouTube channel.


 
 
             

This project would not have been possible without the collaborative effort from OpenLab.
Please visit their site for more cool projects.



However, if you do not have a google profile...
Feel free to share this page with your friends in any way you see fit.

New Project: Coffee Cup Spy Cam

Take your cup of Joe from classic to classified with a tilt-triggered spy camera. The trick is to modify two paper coffee cups — install the device in one, slide it into the second, and align holes cut in the bottoms of each. Two LEDs can be seen through the […]

Read more on MAKE

IcosaLEDron: 20-Sided LED Ball

Bored with playing games with a non-glowing ball? Why not build your own IcosaLEDron, a programmable, LED-enabled glowing contraption about the size of a baseball. This ball, as seen on Instructables, features 20 sides that light up as different colors depending on the situation. An ATmega328p board, which is Arduino-compatible, […]
MAKE » Arduino 21 Nov 21:01

E-traces creates visual sensations from ballerinas

Electronic Traces is an interactive project designed to allow ballet dancers to recreate their movements in  digital pictures using a customizable mobile application. It was prototyped by product-designer Lesia Trubat mixing technological, artisanal skills and using Arduino Lilypad, force sensitive resistors and accelerometer:

The concept of Electronic Traces is based on capturing dance movements and transforming them into visual sensations through the use of new technologies. To do this we focused on the ballet shoes themselves, which through the contact with the ground, and thanks to Lilypad Arduino technology, record the pressure and movement of the dancer’s feet and send a signal to an electronic device. A special application will then allow us to show this data graphically and even customize it to suit each user, through the different functions of this app.

The user can then view all the moves made in video format, extract images and even print them. Dancers can interpret their own movements and correct them or compare them with the movements of other dancers, as graphs created with motion may be the same or different depending on the type of movements execute.