Go Down

Topic: map() not working as expected (Read 561 times) previous topic - next topic

thermalhound

Hi everyone,

I'm having a few issues using map in a sketch. It could well be my understanding of the way it works but I've used it before and got the exact result I was expecting.

The line I am having trouble with is (I'll post full sketch at the end of this post) is ...

Code: [Select]
int distMap = map(dist, 5, 125, 0, 24);

The variable "dist" is a distance returned from an ultrasonic sensor (SR04) and is working perfectly (and very accurately!). I am building a parking radar which takes the distance from the sensor and lights the appropriate number of lines on 3 8x8 matrix displays. The closer you get the less lines are displayed and when the final one goes out you stop. I have mapped the distance to the variable distMap from 0 - 24 so that I could easily read off how many lines on the displays I needed to light up.

I had set up if statements to evaluate the size of the distMap ...

distMap == 24 (turns on all display lines)
distMap < 24 && distMap > 16 (turns on top 2 displays and shows distMap-16 lines on last display)
distMap <= 16 && distMap > 8 (turns on top display, shows distMap-8 lines on second, and turns off last)
distMap <= 8 && dist > 5 (turns off bottom 2 displays and shows distMap lines on top display)
else (if dist is less than 5 flash all lights as an emergency stop)

When I first ran the sketch it displayed erroneous data on the display and I was getting the emergency stop signal even though I knew the sensor was about 150cm from a solid wall I was using to test. As I pushed it closer the displays then began to work correctly. I added a serial output so I could see what was going on and it showed that when dist was greater than 125 (and max value I had supplied) the map was generating figures above 24 (again the max value I had selected). The mapping still seemed to be working correctly, i.e. when I moved the sensor to 130cm I would get a reading of 25, 135cm / 26, etc, but my (maybe flawed) understanding of the way that map worked was that it also constrained the figure to the max selected.

I have obviously changed the first if statement from distMap == 24 to distMap >= 24 which now gives the intended functionality but I am still scratching my head as to why this didn't work as intended.

If someone could explain what I've done wrong, or where my understanding is lacking, I would most grateful. Also if you have any suggestions on how I could make the code more efficient that'd be great.

Many thanks!

TH

Code: [Select]
/*
Sketch to control 3 8x8 matrices in a bar graph
style using an SR04 split into functions
*/

const int dataPin = 6; // 595 pin 14
const int latchPin = 4; // 595 pin 12
const int clockPin = 2; // 595 pin 11

/*
On 595 connect pins 8 & 13 to GND and
pins 10 & 16 to 5v. Outputs are on pins
15 & 1-7. Flowthrough is out pin 9 which
connects to pin 14 (data) on the next 595
*/

const int trigPin = 8;
const int echoPin = 10;
byte dispValue[] = {0, 1, 3, 7, 15, 31, 63, 127, 255}; // byte array of values to be displayed

void setup() {
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  //Serial.begin(9600);
 
}

void loop() {
  int distance = getDist();
  updateBar(distance);
}

int getDist(){
  int duration, distance;
  digitalWrite(trigPin, HIGH); // sends pulse of ...
  delayMicroseconds(1000); // 1000 microseconds ...
  digitalWrite(trigPin, LOW); // and this ends the pulse
  duration = pulseIn(echoPin, HIGH); // listens for return pulse - sr04 output pulse length = time between send and receive
  distance = (duration/2) / 29.1; // converts time into distance
  return distance;
}

void updateBar(int dist){
  int distMap = map(dist, 5, 125, 0, 24); // sets the 0 distance to 10 cm as a safety margin
  //Serial.print("Distance = ");
  //Serial.print(dist);
  //Serial.print(" DistMap = ");
  //Serial.println(distMap);
  if (distMap >= 24) { // lights all displays
    digitalWrite(latchPin, LOW);// arms shift reg
    shiftOut(dataPin, clockPin, MSBFIRST, dispValue[8]);// output to 595
    shiftOut(dataPin, clockPin, MSBFIRST, dispValue[8]);// output to 595
    shiftOut(dataPin, clockPin, MSBFIRST, dispValue[8]);// output to 595
    digitalWrite(latchPin, HIGH);//tells 595 to output received data
    delay(50);// prevents flicker
  }
  else if (distMap < 24 && distMap > 16) { // lights top two displays, and shows distMap-16 lines on bottom
    digitalWrite(latchPin, LOW);// arms shift reg
    shiftOut(dataPin, clockPin, MSBFIRST, dispValue[distMap-16]);// output to 595
    shiftOut(dataPin, clockPin, MSBFIRST, dispValue[8]);
    shiftOut(dataPin, clockPin, MSBFIRST, dispValue[8]);
    digitalWrite(latchPin, HIGH);//tells 595 to output received data
    delay(50);// prevents flicker
  }
  else if (distMap <= 16 && distMap > 8) { // lights top display, shows distMap-8 lines on middle and turns off bottom
    digitalWrite(latchPin, LOW);// arms shift reg
    shiftOut(dataPin, clockPin, MSBFIRST, 0);
    shiftOut(dataPin, clockPin, MSBFIRST, dispValue[distMap-8]);// output to 595
    shiftOut(dataPin, clockPin, MSBFIRST, dispValue[8]);
    digitalWrite(latchPin, HIGH);//tells 595 to output received data
    delay(50);// prevents flicker
  }
  else if (distMap <= 8 && dist >= 5) { // turns off bottom two displays and shows distMap lines on top
    digitalWrite(latchPin, LOW);// arms shift reg
    shiftOut(dataPin, clockPin, MSBFIRST, 0);
    shiftOut(dataPin, clockPin, MSBFIRST, 0);
    shiftOut(dataPin, clockPin, MSBFIRST, dispValue[distMap]);// output to 595
    digitalWrite(latchPin, HIGH);//tells 595 to output received data
    delay(50);// prevents flicker
  }
  else { // distance less than 5 // flashes alternate lines as emergency stop signal
    digitalWrite(latchPin, LOW);// arms shift reg
    shiftOut(dataPin, clockPin, MSBFIRST, 85);// output to 595
    shiftOut(dataPin, clockPin, MSBFIRST, 85);// output to 595
    shiftOut(dataPin, clockPin, MSBFIRST, 85);// output to 595
    digitalWrite(latchPin, HIGH);//tells 595 to output received data
    delay(100);
    digitalWrite(latchPin, LOW);// arms shift reg
    shiftOut(dataPin, clockPin, MSBFIRST, 170);// output to 595
    shiftOut(dataPin, clockPin, MSBFIRST, 170);// output to 595
    shiftOut(dataPin, clockPin, MSBFIRST, 170);// output to 595
    digitalWrite(latchPin, HIGH);//tells 595 to output received data
    delay(100);
  }
}

johnwasser


Code: [Select]
int distMap = map(dist, 5, 125, 0, 24);
If someone could explain what I've done wrong, or where my understanding is lacking, I would most grateful.


I think the problem is that most people assume that the output of that map() call will always be a number from 0 to 24.  That is true ONLY if the input is in the range 5 to 125.  If the input is outside that range the output is likely to be outside the expected range as well.  For example:

Code: [Select]
map(300, 100, 200, 0, 1000);

This will return 2000 because 300 is 100% greater than the high end of the input range and 2000 is 100% greater than the high end of the output range.
Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

thermalhound

Hi John,

Thanks for that, makes perfect sense! I had a feeling it was my flawed understanding. I guess if I really needed it to only generate the maximum number (in this case 24) I could always just constrain the input value to a maximum of the maximum value (again in this case 125).

Thanks!

johnwasser

You could constrain the input:
Code: [Select]
int distMap = map(constrain(dist,5,125), 5, 125, 0, 24);

or constrain the output:
Code: [Select]
int distMap = constrain(map(dist, 5, 125, 0, 24),0,24);

or both, but that would be silly:
Code: [Select]
int distMap = constrain(map(constrain(dist,5,125), 5, 125, 0, 24),0,24);
Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy