Arduino Scale, Problems with map()

Mar 25, 2012 12 Replies

I got my Arduino connected to an AD7730 chip for reading load cell with 24 bit A/D. I am trying to scale and offset for calibration and zero. Since I'm using 24 bit A/D all the math is done in long integers 32bit. My zero routine takes the average reading of 16 samples at zero and uses that as the input zero in the map() function. Then I put my calibration weight on and average 16 readings, subtract the zero number and am left with the in span. I am using fixed point with the 32bit longs, for example if I want to calibrate 60 lbs to .001 lb I enter 60000. Map doesn't work with the numbers I'm using if the out final number is too large. For example when I calibrate an object and enter that it weight 500 for a half pound, it displays 500 just fine. I can set it to read 5000 and it's still OK, but mostly noise. But if I set it to a large number, like maybe 20,000, the number will go negative or go to a smaller value. I'm guessing map with all



32 bit numbers is being messed up somehow.

Any ideas on how to work with larger numbers without getting the goofy numbers I'm getting from map()? Signed 16 bit numbers will go up to +32767 but I can't map to a number even that big using all longs. The A/D seems to have a few lsb's of noise, maybe I'll divide my readings by 32 or something and try again, I'm getting some 50,000 counts with a 1/2 lb on a 30kg load cell. I'm thinking the map function is overflowing the 32 bit longs that it's using and thought maybe someone has a better idea.



Thanks



RogerN


accordings to the arduino documentation

formatting link
this is map():

long map(long x, long in_min, long in_max, long out_min, long out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; }

which is obviously only good when (x - in_min) * (out_max - out_min) is less than LONG_MAX this basically limits the input to 16 bit input values

try this: (which will be about 4 times slower to execute) long lmap(long x, long in_min, long in_max, long out_min, long out_max) { return (x - in_min) * (long long)(out_max - out_min) / (long long)(in_max - in_min) + out_min; }

and send the folks at arduino a bug report so they can fix their documentation.

?? 100% natural --- Posted via news://freenews.netfront.net/ - Complaints to news@netfront.net

Or, since it's for a scale which can (presumably) be slow, do it all in double-precision floating point (after verifying that it's really 64 bits and not just 32-bit with a fancy name).

Using fixed-point math for calculations in embedded systems is only manly if you really do need to do it.

Tim Wescott Control system and signal processing consulting www.wescottdesign.com

Thanks! That works great, solved the problem, I was able to get numbers out over 100,000,000, that's more than I'll ever need in a scale.

But your solution brings up even more questions like how does (long long) work as a 64 bit data type? Where can I look for documentation to learn that something like (long long) would work for this?

I don't suppose (float float) works as 64 bit floating point?

RogerN

It depends very much on the system architecture and compiler. Different processors, and different compilers and runtime packages vary in what they mean by "int", "long int", and "long long int".

If you truly require integers of a specific width, you're better off using a length-specific type declaration - if your environment has the "stdint.h" include file, take a look at it and see what types it offers. If you use this file (or an equivalent) you can declare variables as (e.g.) int64_t, and the compiler will typedef this to a type such as "long long int" which gives the correct results.

"double" usually does that in C. Some systems even have a "long double" type for even greater precision, but that's not terribly common these days.

Dave Platt AE6EO Friends of Jade Warrior home page: http://www.radagast.org/jade-warrior I do _not_ wish to receive unsolicited commercial email, and I will boycott any company which has the gall to send me such ads!

Arduino uses GCC as the backend compiler, so take a look at the GCC documentation. long long (or better: long long int, because this the name as defined in ISO C99) is at least 64 bits, says the C standard.

No, it is "long double", "double" is sometimes the same as "float". But if you don't want to measure the weight of the Earth with one atom precision, and if there are no rounding problems, you can use just "float", because it has about 7 significant digits.

Frank Buss, http://www.frank-buss.de electronics and more: http://www.youtube.com/user/frankbuss

From Arduino's reference:

double Desciption

Double precision floating point number. Occupies 4 bytes.

The double implementation on the Arduino is currently exactly the same as the float, with no gain in precision.

The fixed point shouldn't be a problem I hope For example if I'm using 3 decimal places I think I can display weight /

1000 '.' weight % 1000

RogerN

Well, crud-buckets.

Actually, 32-bit floating point gives you an effective 25 bits of precision, so you may lose less with regular old floating point than you would with an ill-matched computation in 32-bit integers. Dunno why that didn't strike me in my earlier response.

And if it's in floating point, you can keep everything in engineering units (oz, grams, whatever), as well as easily displaying decimal points where you want them, etc.

Tim Wescott Control system and signal processing consulting www.wescottdesign.com

The file (as used with #include) it where it's spelled out. But knowing arduino compiler was avrgcc I just googled "avrgcc integer sizes"

"float float" isn't "C" ("double" and "long double" are.) double would do 64 bit if it could, but the AVR is just an 8 bit processor and 32 bit floats are slow enough, especially if you're using an AVR model that doesn't have hardware multiply.

?? 100% natural --- Posted via news://freenews.netfront.net/ - Complaints to news@netfront.net

I would suggest "C, a Reference Manual" by Harbison and Steel. It's my favorite because it _is_ a reference manual, not a textbook -- meaning that I can look something up in the index, and 90% of the time I just need to read a page or two and be reminded of that specific thing, then I can close the book and get back to work.

At any rate, "long long int" is to "long int" as "long int" is to "int"

-- it's a (probably) longer version of the same old thing, with which you can do all the integer operations, only slower and with a much higher maximum value to play with.

"double" is _supposed_ to be 64 bit (or, at least, it's supposed to be good to 10 decimal digits of precision, where ANSI-C only guarantees 6 for "float"), and "long double" is supposed to be at least the same as "double".

But I've used at least one tool chain (Code Composter for the TI TMS320F2812) that only gave you 32-bit "double" (with seven or eight decimal digits of precision, and thus in violation of ANSI C) but did give you a 64-bit "long double".

So if you really want 64 bit double-precision, you might try "long double". Or, as I noted in my retraction to my statement about not just using "float" -- "float" should be (barely) good enough.

My liberal friends think I'm a conservative kook. My conservative friends think I'm a liberal kook. Why am I not happy that they have found common ground? Tim Wescott, Communications, Control, Circuits & Software http://www.wescottdesign.com

out_max)

out_max)

numbers out=20

long)=20

learn=20

The last time i looked Arduinos are not AVRs.

?-)

That what you get for looking at Don's webdite :) Try the Arduino website.

?? 100% natural --- Posted via news://freenews.netfront.net/ - Complaints to news@netfront.net

Somebitch. I thought that they were ARMs.

?-)

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required