Show Posts
Pages: [1] 2 3 ... 13
1  Using Arduino / Project Guidance / Re: How To Get A Robot To Exit ANY Room It Has Explored on: August 12, 2013, 02:17:14 pm

You don't have to use the EEPROM to save the path data.  If there's RAM available, save it to a string or array. Normally EEPROM is used to save data that you need across resets or power-cycles.  Of course, if the path gets really complicated you might run out of space to store it.

The problem with the type of 'dead reckoning' navigation that you are using to retrace the paths is that it is terribly imprecise.  If your wheels slip, or the floor is uneven or you run over an obstacle, it gets off course.  Plus there is just a certain amount of error in encoders and gear trains.  I'm not saying it can't be done, but you have to take the errors into account.
To see how big those errors can get, have your bot map a path, and then do it in reverse.  It won't end up exactly where it started.  You can use the saved path as a general guide on which way to go, but be prepared to do some searching along the way.

One thing you can do, depending on how smart the mindstorms bot is, is to use the obstacles as part of the navigation.  "Go forward until you hit something, then turn right." might be more accurate than trying to say "go forward exactly 29 inches, then turn 98 degress".  That is if the obstacles don't move.

Sounds like a fun project.
2  Using Arduino / Project Guidance / Re: RC Car DC Motor Controller on: August 12, 2013, 01:52:29 pm
   You can use either digital or PWM (analog) output to the motor controller.  If you want to control the speed,
then yes, you will need to use PWM (analogWrite()) functions on the HIGH pin.  Without knowing more about the RC car and what you are trying to do, I can't tell you how many PWM outputs you'll need.  A minimum of 1, possibly as many as 4.  Check the information on your arduino to see which pins support PWM and how many there are.

   Depending on what kind of RC car it is, you might be able to get away without a motor controller by using the circuits already inside the car.  I have done with with simple RC vehicles by identifying the inputs to the h-bridge that drives the motors, and tapping into them from the arduino.  That allowed me to use either the arduino or the remote to drive the vehicle.  In one case I also intercepted the remote outputs so I could use the remote as input to the arduino.

Have fun,
3  Using Arduino / Programming Questions / Re: Does the PS/2 keyboard lib returns key release events? on: August 08, 2013, 10:04:50 am
The library you are using does not give you key presses, it returns the ASCII code (characters). It does the interpretation from scan codes to characters for you.  So you will not see the key down/ key up events.

You are correct in that the library does not pass on the key up events. It only tracks key up events in order to properly handle the shift keys.  It also masks out many of the "special" keys that have an E0 prefix.

Either use a different keyboard library, or modify this one.  You could tap into the get_scan_code() function
to get the raw scan code and do your own handling of the F0 events.  Or extend the read function to include a flag for make/break.

4  Using Arduino / Sensors / Re: detecting rotary switch position change through interrupt on: June 18, 2013, 12:56:20 pm
Don't forget debouncing.

In general, attaching switches to an interrupt is a Bad Idea because of the noisy nature of the input.  You'll get lots of overlapping and back-to-back interrupts for each turn of the switch.  Polling is actually the preferred method to handle switches.

You could try to do something externally with a comparator and a latch, but it would probably be more complicated than it's worth.  Use a pull-down resistor so that the output goes to gnd when the wiper is not connected to a pole, and set the comparator to signal when its input goes lower than the lowest value of the switch.  Feed that into a latch, and the output of that can go to an interrupt pin.  You'd need to reset the latch after each read, though.
5  Using Arduino / Programming Questions / Re: Difference between attachInterrupt() and ISR() on: June 18, 2013, 12:44:08 pm
Here's the scoop:

ISR() is how you tell the compiler to associate a function with a specific interrupt source.  You can use it on any source of interrupts. You can only associate ONE function with each interrupt source, at compile time.

AttachInterrupt() is the arduino "language" function that allows you to associate a function with an external interrupt.  You can only use it on external interrupts.  You can change the function associated with the interrupt while the sketch is running.

AttachInterrupt() is implemented using ISR().  It is a layer on top of the raw C code that makes it easier and more convenient to use in a sketch.

If you try to use ISR() on one of the external interrupts in your sketch, you will get an error because the arduino core library already associates a function with those interrupt sources.  If you want to do the equivalent of AttachInterrupt() on something besides an external interrupt, you will need to use ISR().  See the PCint library in the playground for an example.

A requested feature for arduino is to allow more sources of interrupts to be used with AttachInterrupt, such as the millis timer and the ADC completion interrupt.  So far this hasn't happened.

6  Using Arduino / Programming Questions / Re: What is wrong with this code and how do I fix it on: June 05, 2013, 01:18:32 pm
Tons of things wrong with the code.  You really should look at more examples before trying to write a sketch.  In particular you'll need to look at the blink without delay example.

Rather than enumerating everything wrong, here's how I would do it:
#include <Servo.h>

#define HEAD_DELAY      15
#define MOUTH_DELAY     1000

Servo myhead;
Servo mouth;
int pos = 0;
int dir = 1;
int mouth_state = 0;
unsigned long head_time;
unsigned long mouth_time;

void setup()
        myhead.attach(9); // attaches the servo on pin 9 to the servo object
        // start at a known position.
        head_time = mouth_time = millis();

void loop()
        unsigned long now = millis();

        if ((now - head_time) > HEAD_DELAY)
                pos += dir;
                if (pos <= 0)
                        dir = 1;
                } else if (pos >= 100) {
                        dir = -1;
                head_time = now;
        if ((now - mouth_time) > MOUTH_DELAY)
                if (mouth_state = 0) {
                        mouth_state = 1;
                } else {
                        mouth_state = 0;
                mouth_time = now;
7  Using Arduino / Programming Questions / Re: ****What is wrong or problematic with this Function**** on: June 05, 2013, 12:53:57 pm
Without the whole sketch, can only offer suggestions.

For memory saving:
- L_estimate is not used in the function, so it can be removed.

- There is a direct relationship between TC_test value and the index. Therefore it can be computed instead of stored.  TC_value = (11.0 + (float)n)/10.0;

- Since S_estimate and h_estimate are const, you can use PROGMEM to store them, saving some ram there. Note that float is not directly supported, but you can use longs and fake it.

- Since mag_vector is only referenced once, you can compute it on the fly instead of storing it as well, thus eliminating yet another array.

Other possible problems:
- the function rgb2hsl() doesn't look correct.  SInce you didn't include the code, I can't tell.  If the h, s, l variables are really going to be changed, then they should be passed by reference: rgb2hsl(&h, &s, &l);

- The whole function's only purpose as written is to print out the TC value.  It doesn't change any globals, doesn't modify any of its parameters and doesn't return anything.  That doesn't seem very useful.

- I think you may have an off-by-one error in your second for loop.  You should use n<est_size. As written it will skip the last element of the array.

Other optimizations/changes:
- You don't need the max value of a float, just start with the first element of the array.

Here's a quick cut at an improved function. WARNING: haven't tested or even compiled it. The PROGMEM stuff may be wrong.  This is just to give you an idea.

#define EST_SIZE        20

PROGMEM prog_uint32_t h_est_store[EST_SIZE] = { 4233, 3781, 3305, 2805, 2282, 2011, 1729, 1132, 1007,  879,  748,  654,  558,  462,  414,  366,  317,   52, 62611, 62333 };

PROGMEM prog_uint32_t S_est_store[EST_SIZE] = { 5054, 4921, 4798, 4687, 4588, 4499, 4413, 4253, 4207, 4162, 4118, 4094, 4071, 4048, 4024, 4000, 3976, 3928, 3883, 3841 };

//pass RGB valves that will be converted to HSL and matched to ?estimate?
float TC_colormatch(int red, int green, int blue)

        float h = red; float s = green; float l = blue;
        int n;
        float minval;
        float curval;
        int min_location;
        float S_estimate, h_estimate;
        float TC_value;

        rgb2hsl(&h,&s,&l); //this replace the current hsl address values with real HSL
        Serial.print("hue "); Serial.println(h); Serial.print("sat "); Serial.println(s); Serial.print("lum "); Serial.println(l);  Serial.print("\n");
        h = h*6.2832; //convert h from 0-1 to 0-2pi  (h*2pi)

        // these estimates are being used to find where the measured color sample(h,s,l) match.

        S_estimate = (float)pgm_read_dword_near(S_est_stor) / 10000.0;
        h_estimate = (float)pgm_read_dword_near(h_est_stor) / 10000.0;
        minval = sqrt(S_estimate*S_estimate+s*s - 2*S_estimate*s*cos(h_estimate-h));
        min_location = 0;

        for(n=1; n < EST_SIZE; n++){
                S_estimate = (float)pgm_read_dword_near(S_est_stor + n) / 10000.0;
                h_estimate = (float)pgm_read_dword_near(h_est_stor + n) / 10000.0;
                curval = sqrt(S_estimate*S_estimate+s*s - 2*S_estimate*s*cos(h_estimate-h));
                if(curval < minval){
                        minval = curval;
                        min_location = n;  // capture the location of the minium value
        TC_value =  (11.0 + (float)n)/ 10.0
        Serial.print("Value = ");Serial.println(TC_value);Serial.print("\n\n");
        return TC_value;

8  Using Arduino / Project Guidance / Re: Help me with my code, double loop if possible on: May 31, 2013, 11:00:11 am
I am using arduino UNO v3, my code should do the following, read 10 sensor values, make an average, turn one of the 3 leds according to the value. The average sum should be displayed once per second so that means I need to read the input value once every 0.1 seconds.

The code you have posted does not do what the above description says.  Why do you need a double loop at all?

Your code is taking one hundred sensor readings, in groups of 10. It then divides the sum by ten.  I don't think this is what you want.  Also you are really mis-using the variable v.
It is an array, and you should use a sub-script when assigning elements to it.
   v[j] = a;

Before using the double loop, the min value was 0 and max value was around 600, using the double loop the read value from the sensor has gone haywire
Do you mean the actual values from analogRead are now bad, or the "average"?

A much simpler thing to do:
void loop()
    long sum;
    int reading, avg;

    for (int i = 0; i < 10; i++)
        reading = analogRead(A0);
        sum += reading;
    avg = reading / 10;
    delay(900);  /* most of a second. */

Please use code tags, like this:

int leda = 2;
int ledb = 4;
int ledc = 6;

void setup() {
  pinMode(leda, OUTPUT);
  pinMode(ledb, OUTPUT);
  pinMode(ledc, OUTPUT);

void loop()

  int a;
int v[10], i, s=0, j;
double m;

for (j=0; j < 10 ; j++){

for (i=1; i<=10; i++)
{a = analogRead(A0);
v[i] = a;

  if (m < 200 )
   digitalWrite(leda, HIGH);
  digitalWrite(ledb, LOW);
  digitalWrite(ledc, LOW);
 else if (m > 400 )
   digitalWrite(leda, LOW);
  digitalWrite(ledc, HIGH);
  digitalWrite(ledb, LOW);
   digitalWrite(leda, LOW);
  digitalWrite(ledc, LOW);
  digitalWrite(ledb, HIGH);
9  Using Arduino / Project Guidance / Re: How to make the keypad work for multiple variables on: May 31, 2013, 10:36:15 am
Post the code.  Use code tags. Can't help you without details.

It might also help to know what kind of keypad you are using, and how it is wired up.

Unless you have more than one keypad, you don't need multiple instances of KeypadEvent.  I don't know what library you are using, so that's about all I can help with now.
10  Topics / Device Hacking / Re: Interrupts on: May 30, 2013, 11:06:53 am

I understand what you want to do.  You need a different approach, however.

Let's talk about "main" first.  The actual main() function of an arduino sketch is in the arduino core library.  It sets up the arduino board, calls your setup() function and then calls your loop() function over and over again, forever.  To really re-do main() would be the equivalent of a reset. Changing the PC or stack to jump there is not a good idea.  Things will get left on the stack, globals and static variables will not get initialized, and memory will have junk in it.

You can try to do a hardware reset (there are threads in the forum on this) but it is slow and could leave any devices attached to the arduino in an unknown or dangerous state.

What you really need to do is carefully structure your loop() function so that it puts your robot into a known good inactive state when an flag (set by the interrupt function) is in the right state.
#define NO_INTERRUPT 0

volatile int flag;
    while (flag == INTERRUPTED)
    if (flag == INTERRUPT_ENDED)
   rest of loop function

Where reinitialize() will stop whatever the sketch is doing, put any attached hardware into a good state (turn off motors and sensors, etc), reset all global variables to their initial values, and make sure the arduino is ready to run the rest of loop() again (fix timers and stuff).
This is really the only safe way to do what you want.  It may involve re-writing some of your sketch.  You may have to add additional code to check for the interrupt flag if any of the code in loop() takes a long time, or has loops in it.

Hope this helps,
11  Using Arduino / Project Guidance / Re: Spinning Goal Red Light on: May 30, 2013, 10:34:29 am
Get creative!

Don't spin the LED, shine it on a mirror and spin the mirror.

If not, what you want to do a spinning light is called a slip ring, which allows electricity to go to a rotating part.  You could probably make one or salvage one from something else that spins.

If you can't get the right color LED, use a white one, and filter it through colored plastic wrap, or other translucent material to get the color you want.

Don't have to 3D print, just salvage something already close to what you want.  Look for cheap toys with spinning lights on them, and hack that.  Check the dollar store.

You could get a mechanics work light and
use it for parts.  Maybe there's one at a thrift store or at a garage sale.

Half the fun of projects like this is figuring out inventive ways to get the parts you need without having to buy custom (expensive) parts.  Unless you happen to already own a 3D printer, of course.

Have fun,
12  Using Arduino / Project Guidance / Re: Interrupt causing crash? on: May 30, 2013, 10:17:04 am
Where to start....

What's probably happening is that you are getting an interrupt cascade: several interrupts that come in while you are still executing the interrupt function.  This can cause some crazy errors with code that is not designed to be re-entrant, especially if the interrupts are really close together, as they would be with noisy input like a non-debounced button.

You are calling both delay() and Serial.print from interrupt context. Don't Do That.  Interrupt routines should be as short as possible, do as little as possible and return immediately.

Your "debounce" routine is a bit primitive, and it's possible that you are still seeing noise from the
button after the debounce period.  There are many better debounce algorithms. See this for some ideas.

Since the debounce period is in milliseconds, why not use millis() instead of micros()?  Much less chance of roll-over problems that way.

In general it is a Bad Idea to attach a non-debounced input to an interrupt.  You really want to
go with polling on this.  Even if your loop takes several milliseconds, it will still seem to respond very quickly to human reactions.

There are several pieces of code in the playground that deal with debouncing, you could use one
of those and not have to write your own.

13  Using Arduino / Programming Questions / Re: using more than one loop on: April 26, 2013, 10:41:13 am

Sorry I meant to add the code.  Here it is.  I want the PID to work simultaniously with the serial.println(TempIn) and work with the digitalWrite(pump,HIGH), DELAY, LOW, DELAY.  Thank you.

Please use code tags when posting code. Also, if you don't have a good
preferred coding style, use the format button before you post code, to make it more readable. And posting some sample output would be helpful in diagnosing the problem as well.  You say the value printed is the same: is it always 0? -12343464332? 5000? How long do you wait to see if it changes?  Do you print out the Output value as well?

A few over-all problems to start with.

First thing is the way you set this up.  You want to control the temperature by turning a heater
on and off, from what I can tell.  Have you considered using a PWM output on the heat pin?  PWM basically turns a pin on and off rapidly, in a specific ratio. It has the effect of "dimming" the
power output.  That would make the code and PID implementation considerably easier.  See analogWrite() in the reference links.

Secondly, I'm not sure you understand how to get the most out of PID algorithm.  Your input
is the temperature, and your output is how long to turn on the heater.  But, every time you Compute you are going to get a different time value.  So the amount of time you wait changes during the waiting period.  This will make your program act a bit irregularly.  Either only do Compute after each window (but the window is too long) or use PWM as suggested above.

Then the problem with the pump code is that you are waiting 127 seconds in your loop function. That causes everything else to wait over two minutes to update.  It's also much greater than your window value, which probably means that the heater is probably either always on or always off.

Lets look at the code.
#include <PID_v1.h>

int heat = 8;                                        //initialize heat
int pump = 13;                                       //initialize pump
heat and pump don't change, so you can make them either const or #defines.

int Input;                                           //digital read from rtd
double TempSet, Output, TempIn;                      //Define Variables for PID
double gap;                                          //Help in agressivness level of PID
double aggKp=4, aggKi=0.2, aggKd=1;
double consKp=1, consKi=0.05, consKd=0.25;           //Define the aggressive and conservative Tuning Parameters

PID myPID(&TempIn, &Output, &TempSet, consKp, consKi, consKd, DIRECT); //Specify the links and initial tuning parameters

int WindowSize = 5000;
If you are going to compare WindowSize to other milllis() values, it should also be an unsigned long. Apples to apples and all that.  Sometimes integer type conversions will bite you when you least expect it.

unsigned long windowStartTime;
void setup()
  pinMode(pump,OUTPUT);                              //initialize pump as output
  pinMode(heat,OUTPUT);                              //initialize heater as output
  Serial.begin(9600);                                //initialize serial communication at 9600 bits per second
  analogReference(INTERNAL);                         //set ref voltage 0 - 1.1 V
  windowStartTime = millis();
  TempSet = 700;                                     //insert desired temp
  myPID.SetOutputLimits(0, WindowSize);              //tell the PID to range between 0 and the full window size
  myPID.SetMode(AUTOMATIC);                          //turn the PID on automatically

void loop()
  Input = analogRead(A0);                            //reads in digital value
  //TempIn = 5*Input + 6;                            //converts digital value to temperature
OK so far.

  gap = abs(TempSet-TempIn);                         //distance away from setpoint
  {                                                  //we're close to setpoint, use conservative tuning parameters
    myPID.SetTunings(consKp, consKi, consKd);
  {                                                 //we're far from setpoint, use aggressive tuning parameters
     myPID.SetTunings(aggKp, aggKi, aggKd);
If you choose your tuning parameters correctly, there should be no need to switch from conservative to aggressive settings.  PID is supposed to do that for you.  It will either aggressively or conservatively change the output depending on how far from the set point you are (that's the P part of PID).  I would delete all the code for agg versus cons settings and just try to find one set of tuning parameters that works.  Tuning PID parameters is tricky, so you should read up on it.

  myPID.Compute();                                  //Turns relay on/off based on temp read in
  unsigned long now = millis();
  if(now - windowStartTime>WindowSize)
  {                                                 //time to shift the Relay Window
    windowStartTime += WindowSize;
This clause is kind of a problem.  What you want to do is start a new "window" every time the current window expires.  But consider the case where now is 127000 and windowStartTime is 15000 (which might happen with the long delays below).  It will never catch up.  What you want to do is set windowStartTime to now.

  if(Output > now - windowStartTime) {
  } else {
As mentioned above, the long window time is going to cause weird effects with your Output computations.  If Output is set to say 1000 the first time through the loop, and then you call Compute and it might get set to 3000, then the heat may be turned on or off depending on where you are in the window.  If you used PWM then you would set your output range to 0-255 and simply do an analogWrite() with the output value.  No need for windows at all.

If that's not feasible (since we don't know your hardware setup), then I would still suggest abandoning these windows and just turn the heat on or off depending on whether the Output is over or under the halfway mark.  Then make the loop fairly tight, delaying no more than a second anywhere in it.

  digitalWrite(pump,HIGH);                           //turn pump on
This is the biggest problem.  Long delays are a Bad Thing.  Most single purpose sketches, like the blink() example, use delays because the program isn't doing anything else, so it can afford to waste time.  In general this is a bad example.  This code will turn the pump on for 7 seconds and off for two minutes.  To do this without delay(), the idea is to use millis() instead.  You keep track of the current state of the pump and the last time it changed state.  Then using the current time (now) you can figure out if you need to turn the pump on or off.  When you change the pump state, update the saved state and timestamp.

It would also be a good idea to print the Output value, the time values and maybe the gap.  More information is better.

I hope this gives you some ideas to improve the code.
14  Using Arduino / Programming Questions / Re: 3 digit file numbers giving me grief! on: April 26, 2013, 09:19:03 am
Hi guys,
this is a basic problem but is giving me a headache trying to solve it. If I want a file to increment, I can do it for single and also double digit numbers. When I try to implement it for 3 or higher digit numbers I can't get it to work.
// ////////////////////////////////////////////////////////////////////////
//For files called file0 -> file999
char filename[] = "file000.CSV";
  for (uint8_t i = 0; i < 1000; i++)
      filename[4] = i/100 + '0';   //???
      filename[5] = i/10 + '0';    //???
      filename[6] = i%10 + '0';    //???

This is a code fragment (or fragments), not working code.  When asking for help, post the full
code, as you don't know what is relevant to the question.

That being said, the problem is with the 10's place value.
      filename[5] = ((i/10) % 10) + '0';    //???

Another solution would be to use snprintf(), although that will add to the size of your sketch.
15  Using Arduino / Motors, Mechanics, and Power / Re: speed measurement of dc motor with encoder on: April 04, 2013, 04:34:11 pm
   First, use the CODE tags when posting code to the forum. It is much more readable, and polite.

   The number of pulses per rotation should not effect the code.  At the most, you'd just have to change a couple of numbers to 255 to make it work.  The code you posted doesn't care, it just reports the number of encoder ticks per second.

The proper declaration for the encoder position is:
volatile long encoder0Pos=0;
The 'volatile' keyword informs the compiler that the value could change behind its back (due to an interrupt in this case).  Long instead of int because int is only 16 bits and that doesn't give you a lot of rotations before it rolls over.  Also we want a signed number to handle roll over. What if your current encoder reading was 4, and then you moved 8 ticks back? Your delta would be 16K-4, which would give a huge velocity.  OTOH, 4 - -4 is 8, which is what you want.

Likewise newposition and oldposition should be of type long.

The millis() function returns unsigned long, so newtime and oldtime should also be of that type.

As for velocity, you are calculating encoder ticks per second. Do you really need to know the fractional part of that?  An int (or long) would do just as well, if we do the calculations right.

The setup function looks good. 
The only thing to worry about in your main loop is the calculation of velocity.  First of all, instead of multiplying by a fraction, use a little algebra and convert that to dividing by an integer.  But you probably don't want to do that yet anyway, because it makes the calculation less accurate.  You went to all the trouble of gathering the time in milliseconds, and then throw away 3 orders of magnitude of accuracy.  The trick is to calculate value in high precision, and then convert to convenient units on the display. Also, I'm thinking that whatever this winds up in final form as, that delay statement won't always be there. Even if you leave it in, it decreases the response time of the velocity calculation. Plus the sketch isn't doing anything else while calling delay.  But if you don't delay by at least 1 second, your velocity calculation is going to hit a divide by 0 situation.  So use milliseconds to calculate the velocity.  But dividing by milliseconds also loses significant digits from the velocity calculation. This can be fixed by doing the multiply before the division, which neatly gives us ticks per second again.  Except this way we can handle sample intervals that are not exact multiples of 1 second.

Finally, do not put Serial print statements in your interrupt service routine (ISR).  An ISR should be as short as possible. You are pushing it with two digitalRead statements as it is.

Leaving it looking something like this:
#define encoder0PinA  2
#define encoder0PinB  4

volatile long encoder0Pos=0;
long newposition;
long oldposition = 0;
unsigned long newtime;
unsigned long oldtime = 0;
long vel;

void setup()
  pinMode(encoder0PinA, INPUT);
  digitalWrite(encoder0PinA, HIGH);       // turn on pullup resistor
  pinMode(encoder0PinB, INPUT);
  digitalWrite(encoder0PinB, HIGH);       // turn on pullup resistor
  attachInterrupt(0, doEncoder, RISING);  // encoDER ON PIN 2
  Serial.begin (9600);
  Serial.println("start");                // a personal quirk

void loop()
 newposition = encoder0Pos;
 newtime = millis();
 vel = (newposition-oldposition) * 1000 /(newtime-oldtime);
 Serial.print ("speed = ");
 Serial.println (vel);
 oldposition = newposition;
 oldtime = newtime;

void doEncoder()
  if (digitalRead(encoder0PinA) == digitalRead(encoder0PinB)) {
  } else {

Pages: [1] 2 3 ... 13