Arduino Free Flight timer, an expensive lesson in programming

Arduino projects on the go
Post Reply
MaxZ
Posts: 330
Joined: 31 Jan 2019, 11:48
Location: Boskoop, Netherlands

Arduino Free Flight timer, an expensive lesson in programming

Post by MaxZ »

As I have mentioned in an earlier topic, I have been developing an Arduino based timer for electric free flight models. In particular, I needed it for an Ebenezer type FF plane, to be entered in an event we held last weekend. Here is my "Jetsonezer"
DSC04353.JPG
One of the features was a run time that can be set in 4 stages up to 30 seconds.

All went well, I tested the timer on the bench and in the air several times, and the motor cut at the set time every time. Just before the event, I decided that I wanted a 60s run time maximum, so I reprogrammed the Arduino accordingly.

So I travelled to Zwolle where the event was going to be held, an Old Warden style fun for all type of event. Weather was perfect, sunny skies, very little wind. There were a number of (untested) Ebenezer there, and we all had a ball trying them out and trimming. I kept the runs short to avoid having to walk a lot and jumping the water-filled ditches to recover the plane every time. I kept them to 25s max.

Then the mass fly-off was announced, and, eager to show off the steady circles my plane could fly, I raised the run time to 45s. Long story short: we spent 5-10 minutes with a group of people admiring the steady circling as the plane disappeared into the distance, never to be seen again (?).

So the motor did not cut, why? I think I now have found the mistake I made in the code. These are the essential lines:

Code: Select all

int readSwitch = 0;
unsigned long setTime;

void setup() {

  readSwitch = 30; // run time in seconds
  
  setTime = readSwitch * 1000; // run time in milliseconds

}

void loop() {
  // stop motor when setTime is exceeded
}
My reasoning was, I would never set a time that exceeds the int maximum, so I used that for "readSwitch". But to convert this to milliseconds and compare that with the current millis(), I used an unsigned long for "setTime".

It never occurred to me that the multiplication with 1000 would happen to readSwitch first, thereby potentially overflowing the limits of an int ( and causing a large negative number), and only then gets copied to "setTime". Unfortunately this happens somewhere between 30s and 45s input...... And to make things worse, setTime is an unsigned long, just a long would have prevented the motor to start in the first place.

In hindsight I wonder why I chose to use two different variables, a single unsigned long would have avoided all this.

As I said, an expensive lesson.......

Cheers,
Max.
Martin
Posts: 744
Joined: 16 Feb 2018, 14:11
Location: Warwickshire

Re: Arduino Free Flight timer, an expensive lesson in programming

Post by Martin »

You could add the letters UL (for unsigned long) to the 1000, so it reads 1000UL
The other way is to 'cast' a variable or constant to the larger size - by putting the type name in parentheses:

int a = 1000;
int b = 1000;

unsigned long c = (unsigned long)a * b;

This will give the correct answer, one million, even though only a has been cast. b is automatically cast to a long, so it matches the size of (the casted) a for the multiply operation.

When an arithmetic operation between mixed types occurs, the compiler promotes the smaller one to match the larger before the operation. So you can then multiply a char, byte, or int by a long, or unsigned long, and the result will be the correct 32-bit size.

Sorry you lost your plane. I suppose there is still some hope it may be found?

As you say, lesson is always to stress test your code, by supplying it with larger values than it will ever see in reality. Zero is also an edge case that should be tested if there is any remote chance that it could occur. Negative numbers likewise.
MaxZ
Posts: 330
Joined: 31 Jan 2019, 11:48
Location: Boskoop, Netherlands

Re: Arduino Free Flight timer, an expensive lesson in programming

Post by MaxZ »

Martin, thank you as always for your input.
Martin wrote: 17 Sep 2022, 15:13 When an arithmetic operation between mixed types occurs, the compiler promotes the smaller one to match the larger before the operation. So you can then multiply a char, byte, or int by a long, or unsigned long, and the result will be the correct 32-bit size.
I take it you are referring to (unsigned long)a @ 32bit and b @ 16bit as in your example. Unfortunately this does not extend to a copy command =, but there must be good reasons for that.
Martin wrote: 17 Sep 2022, 15:13 Sorry you lost your plane. I suppose there is still some hope it may be found?
Well, I omitted to write a phone number on it somewhere, or even my operator registration number (although not required as the weight is only some 160g, so well under the 250g limit). But the organizer of the event is well known in the area as an aeronut, so there still is a chance that someone delivers the remains to him, and he will know how to contact me. We are not talking big money though, I was more worried about the cause of the fly away, which I seem to have found now. Still, it was a nice little plane that flew very well once properly trimmed.

Cheers,
Max.
bluejets
Posts: 316
Joined: 19 Jun 2019, 04:09

Re: Arduino Free Flight timer, an expensive lesson in programming

Post by bluejets »

I used simple dip switches in some code in a timer set to count in binary.
Martin
Posts: 744
Joined: 16 Feb 2018, 14:11
Location: Warwickshire

Re: Arduino Free Flight timer, an expensive lesson in programming

Post by Martin »

Forth, which I've been playing with lately, doesn't have any operator overloading to deal with different sizes of integers. It has different operators to deal with different-sized quantities: for example * to multiply two 16-bit numbers (assuming that the result also fits in 16 bits) or D* to multiply two "double" 32-bit numbers. It's the programmer's responsibility to use the correct operator: what could be simpler? It also has some "mixed sized" operators that include an M in their names, and some operators with a U in their names, that work with unsigned quantities...

Forth is unusual in that it also allows you to easily add your own special operators to the language, if none of the standard ones do exactly what you want.

Forth's most impressive feature, for Arduinos and similar, is that the entire Forth operating system, including the compiler, assembler, and user interface actually runs on the Arduino itself - no need to compile your sketch on a PC, upload the resulting code, test and repeat. There are drawbacks, of course, so I'm not suggesting that Forth is ever going to replace C++ for the Arduino. Interesting to try though, if you like programming, and it teaches you to think about your programs in a new way.
Post Reply