Show Posts
Pages: [1] 2 3
1  Using Arduino / LEDs and Multiplexing / Brightness/Luminance Map on: February 08, 2013, 08:01:19 pm
I believe I've seen these around the forum, but here's a PWM to brightness map for LEDs I came up with:

static byte lightPowerMap[256] = {
   0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,
   2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,
   4,4,4,4,4,4,5,5,5,5,5,6,6,6,6,6,
   7,7,7,7,8,8,8,8,9,9,9,10,10,10,10,11,
   11,11,12,12,12,13,13,13,14,14,15,15,15,16,16,17,
   17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,
   25,25,26,26,27,28,28,29,29,30,31,31,32,32,33,34,
   34,35,36,37,37,38,39,39,40,41,42,43,43,44,45,46,
   47,47,48,49,50,51,52,53,54,54,55,56,57,58,59,60,
   61,62,63,64,65,66,67,68,70,71,72,73,74,75,76,77,
   79,80,81,82,83,85,86,87,88,90,91,92,94,95,96,98,
   99,100,102,103,105,106,108,109,110,112,113,115,116,118,120,121,
   123,124,126,128,129,131,132,134,136,138,139,141,143,145,146,148,
   150,152,154,155,157,159,161,163,165,167,169,171,173,175,177,179,
   181,183,185,187,189,191,193,196,198,200,202,204,207,209,211,214,
   216,218,220,223,225,228,230,232,235,237,240,242,245,247,250,252
};

The point of this map is that human perception of brightness follows a roughly logarithmic response curve, except at very low levels. Actually, the CIE 1931 formula I came across relates the two as follows:

Brightness = 116 * Luminance ^ (1/3) - 16         for luminance levels above 0.008856 (0 to 1 scale)
Brightness = 903.3 * Luminance                        for luminance levels at or below 0.008856

If you solve for brightness you get:

Luminance = ((Brightness + 16) / 116) ^ 3         for brightness levels above 7.9996 (0 to 100 scale; I suspect they mean 8 smiley)

Luminance = Brightness / 903.3                       for brightness levels at or below 7.9996 (smiley-cool

If you want 50% brightness (8 bit value of 128) you'd use a pulse width modulation value of 47 (47.3874, rounded), lightPowerMap[128].

This doesn't adjust for different perceptions of brightness of different colors, so basically it's most applicable to a white LED. On my aquarium light controller, which has banks of red, white and blue LEDs, it seems to work tolerably well. There are a few "jumps" apparent when you ramp brightness from 0 to 255, but they're relatively minor.

Your mileage (and perception smiley) may vary, of course.
2  Using Arduino / Sensors / Re: MaxSonar Noise Problem? on: February 08, 2013, 01:10:31 pm
Thanx for the offer, Tom. But I think I've solved the problem. There's a more detailed discussion in a subsequent thread I opened, but this is the gist: I purchased a model with a wide detection envelope because I need to sense people standing anywhere along a five foot span four or so feet from the sensor. The sensor is mounted in a position where a hardwood floor is just at, or slightly beyond, the detection envelope.

When no observer is present the sensor occasionally senses the hardwood floor. Based on what I saw when I put the sensor output on my scope this happens once or twice out of every 10 scan cycles. For the other 8 or 9 cycles the distance reading is maxed out. Unfortunately, those one or two "spurious" results were enough to trip my detection algorithm.

I fixed the problem by angling the sensor up, away from the floor. I also changed the algorithm so that instead of reporting the median distance of a series of 7 or so observations, it reports the maximum distance observed. For my application that works better than the median approach.

- Mark
3  Using Arduino / Programming Questions / Re: Possible Serial Interaction? on: February 04, 2013, 04:05:09 pm
A quick update to record how I solved my problem.

Further testing showed that there was, in fact, no odd serial connection interaction (i.e., when I waited long enough, odd sonar triggering occurred whether or not the USB connection was established). I'm not sure why I had such a long run of observations implying there was a connection.

I finally did what I should have done earlier and slapped a scope on the variable pulse width signal coming out of the MaxSonar. What I found was that when there was no observer present I was getting spurious short distance readings. Most of the pulse widths would look normal (wide), but every second or so there would be a single narrower pulse. This was enough to falsely trip my detection algorithm, which was based on measuring the median distance of a set of 5 or 7 measurements.

These spurious narrow pulses may be a consequence of the physical placement of the MaxSonar sensor and the particular sensor model I'm using. There's a hardwood floor just "beyond" the detection horizon I've set for my sketch and it may have been creating the short distance readings when nothing is in the field of view. That's because the sensor model I picked has wide detection lobes. In retrospect I probably should have bought one with narrow lobes. Then again, I wanted to be able to detect anyone standing anywhere in front of the tank, which requires a wide field of view.

BTW, I did try putting a filter on the MaxSonar power supply. I didn't have the recommended 100uF capacitor, but with 47uF there was no change in the spurious short distance readings. That strengthens my belief that the hardwood floor is causing problems.

I've minimized the false triggers by doing two things. First, I've pointed the sensor up (i.e., away from the hardwood floor) as much as I can. Second, I changed the algorithm to look at the maximum distance detected within a series of 5 or 7 measurements. This ignores the spurious short measurements when nothing is in the field of view, but still works when an observer is in the target area.
4  Using Arduino / Programming Questions / Re: Receiving More than 64 Bytes of Data via Serial on: February 04, 2013, 03:55:20 pm
I understand that there's no guarantee that a serial communication "session" will deliver all its data. That's why on the receiving end (i.e., in my Windows configuration app) there's a timeout period. As well as a variety of other integrity checks, including a checksum validation.

I was finally able to get the serial communications working reliably. Thanks for the suggestions.
5  Using Arduino / Programming Questions / Re: Possible Serial Interaction? on: February 03, 2013, 04:53:33 pm
That's an interesting idea, thanx. The project is powered off of a 90W 15V wall wart. The 15V supply is connected directly to the buckpucks controlling the LED arrays, and connected to a 8V voltage regulator to produce power for the Arduino. There's another 5V regulator that is used to power various things including the MaxSonar sensor. I'd post a schematic but in the two years since I last worked on this project I seem to have cunningly deleted the schematic file from my computer. I have to pull some old backups and see if I can find it.
6  Using Arduino / Sensors / Re: MaxSonar Noise Problem? on: February 03, 2013, 04:49:32 pm
Thanks, I came across that power filter spec after I posted the question. However, it didn't help.

I was able to reduce the noise problem by using a shielded cable to connect the MaxSonar to the project. But there are still oddities.
7  Using Arduino / Programming Questions / Re: Possible Serial Interaction? on: February 03, 2013, 01:51:49 pm
Good point, thanks. I rewrote all the classes where I was doing hardware interaction in the constructor to have a begin() method instead.

FWIW, that did not change the behavior I'm seeing. Having a "live" USB connection has the sketch behave the way I want it to. Having an unconnected USB connection results in the sonar sensor not being able to determine when there's an empty field of view.

Maybe I'll just have to leave my laptop plugged into the project all the time... smiley
8  Using Arduino / Programming Questions / Possible Serial Interaction? (SOLVED) on: February 02, 2013, 06:30:11 pm
This is taking place on a Duemilanove with an ATMega328P.

My sketch polls a MaxSonar sensor to determine whether someone is standing in front of my aquarium and then adjusts the tank lights accordingly. Distance measurement is by way of pulse width detection (147 microseconds to the inch).

I'm playing around with the sketch and the hardware to eliminate spurious measurements. I've got a working solution...but only when the Arduino's USB port is plugged into the serial port of my laptop. When it's not plugged in, the sketch detects the presence of an observer and ramps the lights up, but it never detects the observer's departure so as to turn the lights down.

The effect of plugging in the USB connection is reproducible. Merely rebooting the Arduino, without the USB being connected, doesn't solve the problem.

Here's the portion of the code that interfaces to the MaxSonar. The entire sketch is pretty large (it compiles to around 20KB) so posting it probably wouldn't be too useful.

The header file:

Code:
// interface for sonar observation
#ifndef OBSERVATION_H
#define OBSERVATION_H

#include "Arduino.h"

#include <Time.h>

#define MICROSEC_PER_INCH 147.0
#define SONAR_READINGS 5
#define SENSE_WINDOW_MICROSEC 50000

class ObserverDetection;

typedef void (* DetectionCallback) ( ObserverDetection* );

class ObserverDetection
{
public:
ObserverDetection( byte pin );
int detect();
int detect( const time_t t );

byte freqSec;

private:
byte _pin;
unsigned long _pulseWidths[SONAR_READINGS];
unsigned long _sortedWidths[SONAR_READINGS];
int _lastDist;
time_t _lastTime;

void sortReadings();
};

#endif

The method definition file:

Code:
// implementation of sonar observation interface
#include "observation.h"

ObserverDetection::ObserverDetection( byte pin )
{
_pin = pin;
pinMode(_pin, INPUT);

freqSec = 5;
_lastTime = 0; // force reading on first detect
_lastDist = -1;
}

int ObserverDetection::detect()
{
return detect(now());
}

int ObserverDetection::detect( const time_t t )
{
if( (t - _lastTime) < freqSec ) return _lastDist;

for( byte idx = 0; idx < SONAR_READINGS; idx++ )
{
_pulseWidths[idx] = pulseIn(_pin, HIGH, SENSE_WINDOW_MICROSEC);
}

sortReadings();
_lastDist = (int) ((float) _sortedWidths[ SONAR_READINGS / 2 ] / MICROSEC_PER_INCH);

if( _lastDist <= 0 ) _lastDist = -1;

return _lastDist;
}

void ObserverDetection::sortReadings()
{
for( byte i = 0; i < SONAR_READINGS; i++ )
{
_sortedWidths[i] = _pulseWidths[i];
}

for( byte i=0; i< SONAR_READINGS- 1; i++ )
{
byte m = i;

for( byte j=i+1; j< SONAR_READINGS; j++ )
{
if (_sortedWidths[j] < _sortedWidths[m]) m = j;
}

if (m != i)
{
unsigned long t = _sortedWidths[m];
_sortedWidths[m] = _sortedWidths[i];
_sortedWidths[i] = t;
}
}
}

FYI, the basic algorithm is:
- wait 5 seconds between observations (this is adjustable)
- take 5 sonar readings (each one with a timeout window of 50000 microseconds)
- sort the readings by distance
- select the 3rd reading (median) as the observation

Elsewhere in the sketch the observed median distance value is used to determine whether the system is or is not under observation.

My question is this: are there side effects of the Arduino USB port being connected to a destination which alter the way the board works? Even to the extent of "just" inserting some timing delays in the looping?
9  Using Arduino / Sensors / MaxSonar Noise Problem? (SOLVED) on: February 01, 2013, 12:34:30 am
I'm trying to diagnose a problem with a MaxSonar sensor. I'm using pulse width detection, but in a free-running state (i.e., I don't toggle the RX line high/wait 25 microseconds/low/wait 25 microseconds each time I take a reading). That's because I don't have enough free pins on my Arduino to control the RX line.

When I run my project off of a laboratory/bench power supply everything works exactly as I expect. Objects are detected when they come within a defined horizon, and lost when they move beyond it.

When I run the project off a wall wart, an object will be detected successfully, but once it is, it's never seen to leave (i.e., the sonar sensor is reporting that something's within the horizon even when nothing is). If I cycle the RX line low/high manually (i.e., by pinning it to ground and then to +5V), and leave it pinned high, the lack of an object within the horizon gets detected. But once I try to repeat the object seen/object departed cycle, the sensor once again can't detect the departure.

This sounded like noise on the line. But putting a 0.1 uF capacitor across the MaxSonar board's power supply pins didn't solve the problem. Neither did putting a 1000 uF capacitor across the output from the wall wart.

Normally I'd conclude you have to cycle the MaxSonar's RX pin to use the sensor. But that doesn't square with everything working fine off of the laboratory power supply. Then again, neither does the persistence of the problem after putting a big capacitor across the wall wart output.

I'd be interested in thoughts or suggestions as to what might the problem, or what I might try to work around it.
10  Using Arduino / Project Guidance / Re: enum as function parameter on: January 30, 2013, 06:04:30 pm
It's something I came across while I flailing away at another problem. I was thinking I might be having some Windows 8 64 bit compatibility problems, and it might offer a solution.

As it turns out, my problem was not compatibility related, but I've left the "enhanced" IDE installed. I don't generally use the Arduino IDE anymore, opting instead for the Visual Micro Visual Studio add-in. That's because I do almost all of my programming in VS, and being able to do my Arduino work in that environment is a plus.

The Visual Micro add-in also gives me access to the beta of their Arduino debugger. It doesn't let me step through the code like what I'm used to doing in VS (not sure that's possible on a micro the size of the Arduino), and it has some quirks/oddities, but in many situations its more convenient than scattering a bunch of Serial.print() calls throughout my  Arduino code. Particularly if you're used to the way the VS debugging interface works.

The "enhanced" IDE is described at http://arduino.cc/forum/index.php/topic,118440.0.html. The Visual Micro VS add-in can be found at http://www.visualmicro.com/.

- Mark
11  Using Arduino / Project Guidance / Re: enum as function parameter on: January 29, 2013, 11:44:11 pm
By including the 'enum' keyword the forward declaration that the IDE puts at the top of your file isn't confused by the not-yet-defined "LightContext".  This also seems to work for 'struct'.

I'd tried that in my experimentation, and just tried it again using the following:

Code:
enum Junk
{
  One,
  Two,
  Three
} ralph = Two;

void setup()
{
  // This code will only run once, after each powerup or reset of the board
 
}

void loop()
{
  // This code will loops consecutively
 
}

void test( enum Junk a )
{
}

This throws the error "use of enum 'Junk' without previous declaration". At least under version 1.03 of the "enhanced" Arduino IDE (Arduino ERW 1.0.3)
12  Using Arduino / Project Guidance / enum as function parameter on: January 28, 2013, 05:22:26 pm
I stumbled into an interesting gap in my understanding of enums in c++ just now. I have a sketch which includes the following:

Code:
enum LightContext
{
    Normal,
    Fed,
    Sonar
} lightContext = Normal;

void startSpecials( LightContext newContext )
{
    // ...do something
}


This is not allowed. I found the article on the site that talked about the typical hack for working with enums as function parameters and return types in sketches (put them in a separate header file), but couldn't get the approach to work. As a workaround, I changed startSpecials() to accept an int (which is the underlying type for the enum LightContext) and cast it to a LightContext inside the function. That works, but is kludgy.

I'd like to understand what's causing this problem, and why putting the enum and their related functions in a separate header file is the recommended solution.

FWIW, I'm coming at this from a C# perspective. In that language you can use enums as parameters or return types without doing anything funky. The situation is obviously different in c++, but it's unclear to me why it is.
13  Using Arduino / Programming Questions / Re: Function Pointer in Class on: January 26, 2013, 09:31:25 pm
John & Nick,

Thanks for the quick feedback, and cross-compiling the code for me smiley.

I'm embarrassed to have to report the problem was, as is almost always the case, the boob behind the keyboard.

One of the things I didn't show in the code extract was that there is a private unsigned long array located immediately before the private callback pointer field. My program logic triggered an array overrun condition (i.e., I ended up writing past the end of the array). Which naturally caused all sorts of bizarre behavior, including changing the callback pointer value (plus some other private values, too).

I'm too used to programming in c#, where a mistake like that would cause the program to blow up when it executed.
14  Using Arduino / Programming Questions / Function Pointer in Class (SOLVED - array overrun!) on: January 26, 2013, 08:05:36 pm
I've got a question about classes that contain a function pointer. What is their initial value when the class is created? Here's an extract of my code:

Code:
typedef void (* DetectionCallback) ( ObserverDetection* );

class ObserverDetection
{
public:
ObserverDetection( byte pin );
    void Process();
void setDetectionCallback( DetectionCallback callback );

private:
byte _pin;
DetectionCallback _callback;
};

ObserverDetection::ObserverDetection( byte pin )
{
_pin = pin;
pinMode(_pin, INPUT);

_callback = NULL; // problem occurs whether this line is present or not
}

void ObserverDetection::Process()
{
// doCallback gets set by logic within Process which I'm not showing
// but the problem is in this next line, with the test for whether or
// not _callback is defined or NULL/0. Regardless of whether or not
// I call setDetectionCallback(), _callback is always nonzero.
//
        if( doCallback && (_callback != 0) ) _callback(this);
}

void ObserverDetection::setDetectionCallback( DetectionCallback callback )
{
_callback = callback;
}

It's easy enough to put another field in the class (e.g., _callbackDefined) to flag whether or not one has been defined, and then test for that. But the approach of testing the value of _callback directly was something I saw in the Time library, and it works perfectly there. However, in the Time library the function pointer is a static variable within the cpp file, not a class field.

What's the reason for the difference in behavior?

Moderator edit: [code] ... [/code] tags added. (Nick Gammon)
15  Using Arduino / Programming Questions / Re: Receiving More than 64 Bytes of Data via Serial on: January 25, 2013, 10:31:05 pm
I'm not sending a string. I'm sending a 129 byte long array of bytes (the size is fixed, so the sketch knows it's received everything when it gets 129 bytes).
Pages: [1] 2 3