Still on XYZ and RGB
It should come as no surprise that I am still somewhat obsessed with my accelerometer. I've stated earlier that I'd like to create a lighted juggling ball that changes color as it rotates. This should be a simple task with an accelerometer - three axis, three colors, mix 'em and you're done, right? Maybe not so much.
The video starts out with me selecting read. From that point onward it's taking values in from the Arduino and doing the following:
I think for my first "throwable" prototype I'll just stick with the basic 6 colors. I intend to get a Really Bare Bones Board kit from Modern Device for this. It's small and really cheap. If I eventually figure out fading and I think I've got something like a real product on my hands I may consider creating a custom PCB that puts the accelerometer and the smaller form-factor ATmega328 directly on board along with LEDs. Possible a circular PCB that could be bolted directly into a ball, though some shock absorption of some sort may be in order.
I won't rehash previous posts, but I will say I am really close. I should, however, explain my criteria:
- Rotation should change color of the light, obviously
- At a minimum, there should be shifting between the 3 basic colors: red, green, blue
- I'd prefer 6 colors total, with the other 3 being mixes: yellow (red/green), aqua (green/blue), and purple (blue/red)
- I'd like to get some nice fading as it switches between colors, but as I'll point out later, this is somewhat hard
- The light intensity should never change - all on, and never off
- I'd prefer it if there wasn't much white - all colors on - showing
I already have code on the Arduino that'll produce 6 distinct colors. Based on the above criteria, I've succeeded. I've wired up the prototyping shield, the accelerometer, an RBG LED, and a seven segment display. The last is so I can display the digit of the color currently showing.
That setup (shown left) is seriously prototype. It's nothing I'd really use in an actual juggling ball. It's too big, it only has one LED, I probably wouldn't include the 7-seg display - but it helped me understand what I was up against.
It was a bit of a stretch to come up with the 6 basic colors out of 3 axis. Here's how I did it:
- The accelerometer produces values from 0 to 692 (roughly)
- There are 3 values coming from the X, Y, and Z axis
- To get 6 distinct numbers I split each axis down the middle and then checked which side of middle it was on
- If the value was lower than the mid-point it was one number, if higher than the mid-point it was another number
- Two colors were assigned to each axis, and as such only one color could show at a time, again if less than mid-point one color, higher, another color
- For example, the X axis lower than 346 is red, higher than that its aqua
- At any given time the position of the three axis indicates 3 numbers and colors at once - to pick only one, we take the highest of the three
- The axis values are split in half so they are from 0 to 346 and altered so they always increase the more the accelerometer is leaned in a particular direction, i.e. from 0 to 346 is actually flipped so at the zero value we'd be returning 346 and vice versa as we approach middle. From 346 to 692 we just subtract 346.
- These "half" values are shoved into an array and bubble sorted so we know which one is highest. The array is multidimensional and also contains the index we assigned to that number. When we know which value is highest, we also know which index is highest.
- Since we know which color is assigned to that index, we show that color.
The code in this situation might make more sense than that explanation. As usual you will find that code at the bottom of the post. Before that, though, I have a few more things to mention.
One is another notion I introduced with this code: smoothing. The values that come streaming out of the accelerometer are... not consistent. The sort of jump all over the place. If you were to watch the values on the serial output you'd see something like this:
373, 349, 536
372, 348, 532
371, 347, 548
378, 355, 554
372, 352, 539
365, 346, 531
371, 351, 542
371, 348, 541
371, 352, 544
374, 352, 544
And so on...
The first value is X, the second Y, and the third Z. X and Y are roughly middle, i.e. there's little pulling them one way or another. Z is pointing down, so it's higher than the other two. At it's current setting the accelerometer is measuring 1.5 g's, so at rest the Z values is somewhere lower than it's max. I'd have to shake it a bit to see it hit 692.
I started trying to figure out how fast the Arduino could sample the output of the accelerometer and between running at 16 mhz and returning those values out of serial at 9600 baud I gave up. It's pretty fast - there's a lot of sampling going on each second. And as you can see above, there's a lot of variation going on in a really short period of time.
That variation is not due to vibration. I'm not sure whether it's noise on the analog inputs (likely) or inaccuracy on the accelerometer (possible) or something else I don't know (also likely). Whatever the case, it's annoying and it causes the light of the LED to blink between colors when it's at a boundary between them.
So I figured out smoothing. What this is basically is shoving the values coming off the accelerometer into an array and then taking the average of a set of values (like 30) and using that value instead. It worked fairly well, though if I made the array too large it had some interesting effects.
I actually went back to some old .NET code I'd written in April of '09 (that post here) to test it. The app was designed to that just the X and Y and paint dots on a screen. Without smoothing the dots scatter and draw something that looks a bit like spray paint. With the smoothing it draws something closer to lines.
It was actually kind of pretty and fun to play with. I updated the app to use the Z axis to determine color. I ended up spending a lot of time with the kids playing with it. If I ever get into wireless I may consider creating a hardware interface that's a bit more user friendly that my current rig. I'm not sure how practical it'd be as a drawing interface, but still - fun to play with.
So I had smoothing. What I didn't have was fading between the 6 colors. I spent some time trying to figure this out on the Arduino, but this was frustrating at best. There's no debugger and using Serial.println has it's limits. So I took that job into .NET and wrote a simple Arduino sketch that'd just dump out to serial the values it fetches from the Accelerometer.
What I came up with was what you see in this video:
Before I move on I want to mention the software I used to get that video: CamStudio. It's got a free version that does well getting the basic AVI I have above.
- Showing them on the sliders that depict the full range of 0 to 692
- Splitting the values in half and showing the top 3
- Showing the dominant color on a visual representation of three axis split
- Showing the RGB value it came up with, both in numbers and in color
The mixing is achieved by determining how close the second and third picks are to the first. The first pick is always the dominant color, but if the second pick is within a certain percentage (as determined by the tolerance slider - usually 30%) then how large that second pick is in relation to the first will determine how much of that color bleeds into the primary color. The same calculation is used with the third pick in relation to the first.
Once I got all that sorted out it worked really well. In the video I am rolling the unit one way slowly, then the other, and finally all over the place quickly. It's fairly responsive and kind of cool to watch.
It was this idea, how this mixing worked, that had me wondering whether I'd post anything about any of this. I have scoured the web on several occasions looking for whether anyone else has figured this out. I've found little or no examples. Where I did find examples either they made no sense to me, or they didn't have enough information. When I eventually did come up with a solution - and I'm not saying this is the best/only way of doing this - I honestly didn't want to share it. Partially because no one else did and I felt a little like I wanted to hold onto this secret, but also partially because I'm not sure whether I want to build and sell juggling balls (or other products) using this technology.
Eventually - and obviously - I gave in and posted everything. What I came up with isn't really all that complicated or hard to figure out, though it did take me a while. I also feel like I need to pay some of this forward. I've gotten so many other good ideas and just raw reference - how to - from the inter-toobz that I think I should put some quasi-useful stuff out there myself. This is one of the reasons why I almost ALWAYS post code - and put lots of comments in said code.
Anyway, as usual, I'm not going to post all the .NET code here, though. It's fairly big and I'm feeling somewhat lazy at this point. The core of what you'd need to see is in the MainForm.cs, which is posted below:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Text;
using System.Windows.Forms;
namespace XYZtoRGB_PointFade
{
public partial class MainForm : Form
{
#region Members
// full length of each axis
private const int conMax = 692;
// mid point of the axis
private const int conMid = 346;
// points picked - can only be 3 of 6 at a time
private int[,] picks = { { 0, 0 }, { 0, 0 }, { 0, 0 } };
// blue, red, violet, green, yellow, aqua
private int[,] colors = {
{ 255, 255, 0 },
{ 255, 0, 0 },
{ 0, 255, 0 },
{ 0, 255, 255 },
{ 255, 0, 255 },
{ 0, 0, 255 }
};
// the serial port we'll read from
private SerialPort arduino = null;
// read from the serial input - by default, don't
private bool readSerial = false;
// places to put port and rate
string comPort = string.Empty;
int baudRate = 0;
// smoothing arrays
int[] xList = new int[50];
int[] yList = new int[50];
int[] zList = new int[50];
// watch values of the smooth loops
int wsx = 0, wsy = 0, wsz = 0;
#endregion Members
#region Events
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load(object sender, EventArgs e)
{
// init our smoothing arrays?
for (int i = 0; i < comport =" ConfigurationManager.AppSettings[" baudrate =" int.Parse(ConfigurationManager.AppSettings[" text =" tbSmoothing.Value" text =" tbTolerance.Value" readserial =" false;" text = "Read" readserial =" true;" text = "Stop">
/// What to do when one or all of the axis are changed,
/// namely update the color displayed.
///
private void AxisUpdate()
{
// fetch and display the axis values
txtXaxis.Text = tbXaxis.Value + "";
txtYaxis.Text = tbYaxis.Value + "";
txtZaxis.Text = tbZaxis.Value + "";
// mix these values into colors
MixPicks(tbXaxis.Value, tbYaxis.Value, tbZaxis.Value);
// then draw the map
DrawAxisMap();
}
///
/// More complicated color computation based on three
/// points of dominance, ranked in order
///
///
///
///
private void MixPicks(int xVal, int yVal, int zVal)
{
FindPicks(xVal, yVal, zVal);
//txtPoint1.Text = picks[0, 0] + "";
txtStep1.Text = picks[0, 1] + "";
//txtPoint2.Text = picks[1, 0] + "";
txtStep2.Text = picks[1, 1] + "";
//txtPoint3.Text = picks[2, 0] + "";
txtStep3.Text = picks[2, 1] + "";
// an array to hold the chosen color
int[] choice = { 0, 0, 0 };
int idx = picks[0, 0];
// set the primary color
choice[0] = colors[idx, 0];
choice[1] = colors[idx, 1];
choice[2] = colors[idx, 2];
if (tbTolerance.Value < perf =" ((float)tbTolerance.Value" per2 =" ((float)picks[1," per3 =" ((float)picks[2,"> perF)
{
idx = picks[1, 0];
choice[0] = AdjustColor(choice[0], colors[idx, 0], per2);
choice[1] = AdjustColor(choice[1], colors[idx, 1], per2);
choice[2] = AdjustColor(choice[2], colors[idx, 2], per2);
}
// if color 3 is above tolerance
if (per3 > perF)
{
idx = picks[2, 0];
choice[0] = AdjustColor(choice[0], colors[idx, 0], per3);
choice[1] = AdjustColor(choice[1], colors[idx, 1], per3);
choice[2] = AdjustColor(choice[2], colors[idx, 2], per3);
}
}
ShowColor(choice[0], choice[1], choice[2]);
}
///
/// More compact method that returns a multidimensional
/// array of the accelerometer values along with the points
/// they represent.
///
///
///
///
///
private void FindPicks(int xVal, int yVal, int zVal)
{
// supporting cast
int pnt = 0, val = 0;
// clear the text boxes
//txtXplus.Text = "0";
//txtXminus.Text = "0";
//txtYplus.Text = "0";
//txtYminus.Text = "0";
//txtZplus.Text = "0";
//txtZminus.Text = "0";
// blue, red, violet, green, yellow, aqua
// x plus/minus or red/green
if (xVal < text =" picks[0,"> conMax) { xVal = conMax; }
picks[0, 1] = xVal - conMid;
//txtXminus.Text = picks[0, 1] + "";
}
// y plus/minus or violet/yellow
if (yVal < text =" picks[1,"> conMax) { yVal = conMax; }
picks[1, 1] = yVal - conMid;
//txtYminus.Text = picks[1, 1] + "";
}
// z plus/minus or aqua/blue
if (zVal < text =" picks[2,"> conMax) { zVal = conMax; }
picks[2, 1] = zVal - conMid;
//txtZminus.Text = picks[2, 1] + "";
}
int limit = 2;
do
{
int last = 0;
for (int i = 0; i < j =" i" pnt =" picks[i," val =" picks[i," last =" i;" limit =" last;"> 0);
}
///
/// Separate method to make the determination of whether to
/// use a new possible color or to keep the current color.
///
/// This is core to the whole method because it allows us to
/// first put in a core color and then later to introduce seconday
/// and tertiary colors if they do not over power the dominant
/// color.
///
///
///
///
///
private static int AdjustColor(int current, int possible, float percent)
{
// reduce the possible color by the given percent
int test = (int)(possible * percent);
// default our adjusted color to the current
int adjusted = current;
// if the test color is larger, use it
if (test > adjusted) { adjusted = test; }
// return the adjusted color
return adjusted;
}
///
/// Display RGB value to view panel
///
///
///
///
private void ShowColor(int rVal, int gVal, int bVal)
{
// first show the numeric values in text boxes
txtRed.Text = rVal + "";
txtGreen.Text = gVal + "";
txtBlue.Text = bVal + "";
// then set the color
pnlColor.BackColor = Color.FromArgb(rVal, gVal, bVal);
}
///
/// Does the work of fetching serial data from the Arduino
/// and displaying it - in various ways - to the form.
///
private void ReadArduino()
{
// working variables
char[] delim = { ',' };
string line = "";
string[] axis = null;
int tmpX = -1, tmpY = -1, tmpZ = -1;
int count = 0;
// if we haven't already connected
if (arduino == null)
{
// connect to the Arduino
arduino = new SerialPort(comPort, baudRate);
arduino.ReadTimeout = 5000;
arduino.WriteTimeout = 5000;
arduino.Open();
}
// while flagged to read
while (readSerial)
{
count++;
// fetch one line of serial data from the Arduino
line = arduino.ReadLine();
// remove the return at the end of the line
if (line.LastIndexOf("\r") > -1)
{
line = line.Substring(0, line.Length - 1);
}
// if there was nothing read, just skip this iteration
if (string.IsNullOrEmpty(line.Trim())) { continue; }
// implicit else - split the line to an array of strings
axis = line.Split(delim);
// if we got an array
if (axis != null && axis.Length == 3)
{
// if we can't parse the values, set them low
if (!int.TryParse(axis[0], out tmpX)) { tmpX = -1; }
if (!int.TryParse(axis[1], out tmpY)) { tmpY = -1; }
if (!int.TryParse(axis[2], out tmpZ)) { tmpZ = -1; }
// if values are good, smooth them
if (tmpX > -1) { tmpX = SmoothVal(tmpX, ref wsx, xList); }
if (tmpY > -1) { tmpY = SmoothVal(tmpY, ref wsy, yList); }
if (tmpZ > -1) { tmpZ = SmoothVal(tmpZ, ref wsz, zList); }
// finally try and set the value
tbXaxis.Value = (tmpX > conMax) ? conMax : tmpX;
tbYaxis.Value = (tmpY > conMax) ? conMax : tmpY;
tbZaxis.Value = (tmpZ > conMax) ? conMax : tmpZ;
AxisUpdate();
}
// pump the windows message loop
Application.DoEvents();
}
}
///
/// Chucks a value into one of the lists and then
/// sends back out the caller an averaged value.
///
///
///
private int SmoothVal(int value, ref int ws, int[] axList)
{
int smax = tbSmoothing.Value;
int avg = 0;
// if no smoothing, return what ya got
if (smax <= 0) { return value; } // add to our watch index ws++; // shift index back to zero if greater than smoothing limit if (ws >= smax) { ws = 0; }
// put it in the array
axList[ws] = value;
// next, get the average
for (int i = 0; i < value =" ((int)avg" value =" (value"> conMax) ? conMax : value;
// return the average
return value;
}
///
/// Draw the axis map with emphasis on given axis that are
/// currently influencing the colors
///
private void DrawAxisMap()
{
// clear what was there first
Graphics gfx = pbAxisMap.CreateGraphics();
gfx.Clear(Color.DimGray);
gfx.Dispose();
// get some numbers
int w = pbAxisMap.Width;
int h = pbAxisMap.Height;
int cx = ((int)w / 2);
int cy = ((int)h / 2);
// blue, red, violet, green, yellow, aqua
// draw the lines
DrawLine(0, PickWidth(0), cx, cy, cx, h);
DrawLine(1, PickWidth(1), cx, cy, 0, cy + cy / 2);
DrawLine(2, PickWidth(2), cx, cy, w, cy + cy / 2);
DrawLine(3, PickWidth(3), cx, cy, w, cy / 2);
DrawLine(4, PickWidth(4), cx, cy, 0, cy / 2);
DrawLine(5, PickWidth(5), cx, cy, cx, 0);
}
///
/// Picks the width of a given color line.
///
///
///
private int PickWidth(int idx)
{
int g = 1;
if (idx == picks[0, 0]) { g = 9; }
else if (idx == picks[1, 0]) { g = 6; }
else if (idx == picks[2, 0]) { g = 3; }
return g;
}
///
/// Draw a single line of a given color
///
///
///
///
///
///
///
private void DrawLine(int idx, int girth, int x1, int y1, int x2, int y2)
{
Color color = Color.FromArgb(colors[idx,0], colors[idx, 1], colors[idx, 2]);
Point point1 = new Point(x1, y1);
Point point2 = new Point(x2, y2);
Pen pen = new Pen(color, girth);
Graphics gfx = pbAxisMap.CreateGraphics();
gfx.DrawLine(pen, point1, point2);
pen.Dispose();
gfx.Dispose();
}
#endregion Supporting
}
}
Once I got this working SO well in .NET I thought it'd be a cinch to get it working the same in the Arduino, right? Not so much. The language is MUCH simpler and has less to support what I wanted to do. I tried in .NET to use simple concepts and "do the work" where I should. For example I sorted the top 3 values myself using a bubble sort instead of just calling the "sort" on a collection.
What I got in the Arduino sort of worked, but not nearly as well. Here's a video I hope will help explain what I mean:
It's not smooth like the .NET app. For that matter there's not really much distinct "mid" color at all. It's like there's one middle color between the two major colors. I do have a BlinkM somewhere that I should really consider trying before I dismantle this whole thing. It may simplify the handling of colors, but it does have one considerable drawback - it's expensive. The RGB LED's cost about $2, and the BlinkM was $12.
I fiddled with this set up for a bit before deciding to post. It's close, but I'm kind of out of patience for it at this stage. My first juggle-able prototype will probably be just the 6 basic colors. This is easy to achieve and, to be honest, when juggling no one is going to notice the lack of fades as much. Here's a similar video with no fading:
I think for my first "throwable" prototype I'll just stick with the basic 6 colors. I intend to get a Really Bare Bones Board kit from Modern Device for this. It's small and really cheap. If I eventually figure out fading and I think I've got something like a real product on my hands I may consider creating a custom PCB that puts the accelerometer and the smaller form-factor ATmega328 directly on board along with LEDs. Possible a circular PCB that could be bolted directly into a ball, though some shock absorption of some sort may be in order.
Now that I've got this project in the cloud and off my chest, as it were, I can move on to another idea. I want to use the Arduino, a web cam, and a servo along with (yet another) custom .NET app to create a panning web cam app. I'll probably point it at my fish tank for now, but this is something I have a practical application for - watching the utility room at my folk's cabin. More on that later...
/*
* PointFade3.pde
*
* Third versiom of fading colors between 6 points
* of the accelerometer cross. This should be a
* conversion of the .NET code that I'd got working.
*/
// axis analog pins
int xPin = 0, yPin = 1, zPin = 2;
// axis value mid and max
int axMax = 692, axMid = 346;
// pins controlling red/green/blue
int rPin = 3, gPin = 6, bPin = 5;
// values from those pins
int xVal = 0, yVal = 0, zVal = 0;
// smoothing
int xLst[50], yLst[50], zLst[50];
int sTrk = 0, sMax = 10;
boolean full = false;
// array to store top 3 picks
int picks[][3] = {{ 0, 0 }, { 0, 0 }, { 0, 0 }};
// array to store positions and values of colors
int colors[][6] = {
{ 102, 163, 0 },
{ 102, 0, 0 },
{ 0, 163, 0 },
{ 0, 163, 163 },
{ 102, 0, 163 },
{ 0, 0, 163 }
};
// tolerance - or how much fade
float tol = 1.00;
// maximum PWM allowed for each LED
int rMax = 102, gMax = 163, bMax = 163;
// power for the 7-segment LED
int segPow = 11;
// establish an array for our LED pins
int segLed[7] = { 4, 7, 8, 9, 10, 12, 13 };
// array to store settings for numbers
int numbers[][11] = {
{ LOW, LOW, LOW, LOW, HIGH, LOW, LOW }, // 0
{ LOW, LOW, HIGH, HIGH, HIGH, HIGH, HIGH }, // 1
{ HIGH, LOW, LOW, HIGH, LOW, LOW, LOW }, // 2
{ LOW, LOW, LOW, HIGH, LOW, LOW, HIGH }, // 3
{ LOW, LOW, HIGH, LOW, LOW, HIGH, HIGH }, // 4
{ LOW, HIGH, LOW, LOW, LOW, LOW, HIGH }, // 5
{ LOW, HIGH, LOW, LOW, LOW, LOW, LOW }, // 6
{ LOW, LOW, LOW, HIGH, HIGH, HIGH, HIGH }, // 7
{ LOW, LOW, LOW, LOW, LOW, LOW, LOW }, // 8
{ LOW, LOW, LOW, LOW, LOW, HIGH, HIGH }, // 9
{ HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH } // off
};
/*
* The "run once" setup method
*/
void setup()
{
// set up to communication with serial
Serial.begin(9600);
// set axis/analog pins to input
pinMode(xPin, INPUT);
pinMode(yPin, INPUT);
pinMode(zPin, INPUT);
// turn on power for the 7-segment display
analogWrite(segPow, 102);
// initialize all 7 segment LED pins
for (int idx = 0; idx < xval =" getListVal(xLst);" yval =" getListVal(yLst);" zval =" getListVal(zLst);" xrv =" analogRead(xPin);" yrv =" analogRead(yPin);" zrv =" analogRead(zPin);" strk =" sTrk">= sMax)
{
// reset to beginning
sTrk = 0;
// and track that we've filled the arrays at least once
full = true;
}
}
/*
* Get a smoothed value from given array
*/
int getListVal(int aLst[50])
{
int idx = 0;
long sum = 0;
for (idx = 0; idx < idx =" idx" sum =" sum" ret =" sum" pnt =" 0," val =" 0;"> axMax) { xVal = axMax; }
picks[0][1] = xVal - axMid;
}
// y plus/minus
if (yVal <> axMax) { yVal = axMax; }
picks[1][1] = yVal - axMid;
}
// z plus/minus
if (zVal <> axMax) { zVal = axMax; }
picks[2][1] = zVal - axMid;
}
// now sort 'em
int limit = 2;
do
{
int last = 0;
for (int i = 0; i < j =" i" pnt =" picks[i][0];" val =" picks[i][1];" last =" i;" limit =" last;"> 0);
//showPicks(picks[0][0], picks[0][1],
//picks[1][0], picks[1][1], picks[2][0], picks[2][1]);
}
/*
* We should have our top 3 colors. Now
* we need to mix them in relation to each
* other based on the tolerance.
*/
void MixColors()
{
// create an array to hold the chosen color
int choice[3] = { 0, 0, 0 };
// get the percentages of the other two colors
float per2 = ((float)picks[1][1] / (float)picks[0][1]);
float per3 = ((float)picks[2][1] / (float)picks[0][1]);
// find the primary index
int idx = picks[0][0];
// show the number on the 7-segment
showDigit(idx);
// set the primary color
choice[0] = colors[idx][0];
choice[1] = colors[idx][1];
choice[2] = colors[idx][2];
//showChoice(idx, choice[0], choice[1], choice[2]);
// if we set a usable tolerance
if (tol <> tol)
{
//Serial.println("In per2 adjust");
int i2 = picks[1][0];
if (colors[i2][0] > 0) { choice[0] = AdjustColor(choice[0], colors[i2][0], per2); }
if (colors[i2][1] > 0) { choice[1] = AdjustColor(choice[1], colors[i2][1], per2); }
if (colors[i2][2] > 0) { choice[2] = AdjustColor(choice[2], colors[i2][2], per2); }
}
// if color 3 is above tolerance
if (per3 > tol)
{
int i3 = picks[2][0];
if (colors[i3][0] > 0) { choice[0] = AdjustColor(choice[0], colors[i3][0], per3); }
if (colors[i3][1] > 0) { choice[1] = AdjustColor(choice[1], colors[i3][1], per3); }
if (colors[i3][2] > 0) { choice[2] = AdjustColor(choice[2], colors[i3][2], per3); }
}
}
// show the color on the RGB LEDs
ShowColor(choice[0], choice[1], choice[2]);
}
/*
* A separate method dedicated to making the determination of whether
* to use a new possible color or to keep the current color. This is
* the core to color mixing because it allows us to first put in a
* core color and then alter to introduce secondary and tertiary colors
* if they do not overpower the dominant color.
*/
int AdjustColor(int current, int possible, float percent)
{
// default our adjusted color to the current
int adjusted = current;
// if the percent and possible are useful
if (possible > 0 && percent > 0)
{
// reduce the possible color by the given percent
int test = possible * percent;
// if the test color is larger, use it
if (test > adjusted) { adjusted = test; }
/*
Serial.print("Adjust - curr: ");
Serial.print(current);
Serial.print(", poss: ");
Serial.print(possible, DEC);
Serial.print(", perc: ");
Serial.print(percent, 4);
Serial.print(", test: ");
Serial.print(test, DEC);
Serial.println("");
*/
}
else
{
Serial.println("POSSIBLE IS ZERO!!");
}
// return the adjusted color
return adjusted;
}
/*
* Finally, after all that, light 'em.
*/
void ShowColor(float rPer, float gPer, float bPer)
{
//showAxis(rPer, gPer, bPer);
// calulate percentages lit
int rVal = rMax * rPer;
int gVal = gMax * gPer;
int bVal = bMax * bPer;
// light the LEDs to these percents
analogWrite(rPin, rVal);
analogWrite(gPin, gVal);
analogWrite(bPin, bVal);
}
/*
* Given specific number pluck out that
* row in the multi-dimensional array to
* show that combination of LOW/HIGH vals
*/
void showDigit(int digit)
{
// loop through LED pins
for (int idx = 0; idx <>
Comments
Post a Comment