Wednesday, March 19, 2014

RC navigation lights

Someone on LinkedIn asked me for some help with some lights on his RC plane. Since I had an evening to spare anyway I was happy to help. There were just a few requirements:
  • Use an Arduino Nano
  • Control 5 LEDs
  • Each LED should be controllable using just one switch on a remote control
  • Flipping the switch X times will toggle LED X
That's just your basic programmable RC navigation/landing light system you'll find on quite a few scale model airplanes and helicopters. You can find these kind of systems in most stores that sell RC equipment, some for as little as $12, but most for $25 and up (and up up up). But where's the fun in that?

So after a bit of programming and testing this is what I came up with:
Total cost: less than $10. You can pick up a Nano on eBay for as little as $6 and resistors and LEDs should be in your parts bin anyway ;)

Here's the breadboard layout (doesn't match the one from the movie exactly, but you get the idea)
 The servo represents the receiver, I used it since it has the same connectors (signal, 5V, gnd)

And the schematics:

And of course, the code!

Let's cover the reading of the switch on the remote first. By connecting the signal wire (usually the white one) from the receiver to pin 9 on the Arduino we can read the state of the switch. There will be a pulse coming from the receiver about 50 times per second. This pulse will be between 1000 and 2000 microseconds in length depending on the position of the switch. We can assume that anything above 1500 is the up position, and below 1500 the down position. So it's simply a matter of detecting the pulse and measuring its length. Normally I'd use interrupts to handle this, but I wanted to keep this one simple so I used the pulseIn() function instead.

Let's define a few variables first:


1:  uint8_t cfg_inputPin;  
2:  bool     loop_lastSwitchPosition;  
3:  uint8_t    loop_switchCount;  
4:  unsigned long loop_lastSwitchTime;  
cfg_inputPin holds which pin the receiver is connected to. loop_lastSwitchPosition holds the last read state of the switch, loop_switchCount holds how often it has been flipped up and loop_lastSwitchTime holds when the switch was flipped up.

Now for the setup:
1:  void setup()  
2:  {  
3:      cfg_inputPin = 9;  
4:    
5:      loop_lastSwitchPosition = pulseIn(cfg_inputPin, HIGH) > 1500;  
6:  }  

First we set the input pin. Pins are already in INPUT mode initially so no need to set that here. Furthermore we initialize the loop variable here with some default value.

1:  void loop()  
2:  {  
3:      unsigned long duration = pulseIn(cfg_inputPin, HIGH);  
4:      while ( duration == 0 )  
5:      {  
6:          duration = pulseIn(cfg_inputPin, HIGH);  
7:      }  
8:        
9:      bool newSwitchPosition = duration > 1500;  
10:      if ( newSwitchPosition != loop_lastSwitchPosition )  
11:      {  
12:          loop_lastSwitchPosition = newSwitchPosition;  
13:          if ( newSwitchPosition )  
14:          {  
15:              ++loop_switchCount;  
16:              loop_lastSwitchTime = millis();  
17:          }  
18:      }  
19:      else  
20:      {  
21:          if ( loop_lastSwitchTime != 0 && millis() - loop_lastSwitchTime > 1000 )  
22:          {  
23:              uint8_t channel = loop_switchCount - 1;  
24:              if ( channel < CHANNELS )  
25:              {  
26:                  // do something  
27:              }  
28:              loop_switchCount = 0;  
29:              loop_lastSwitchTime = 0;  
30:          }  
31:      }  
32:  }  
That's more like it :)
In lines 3-7 we wait for a valid pulse.
Line 9 converts the pulse duration to a switch position.
Line 10 checks if there's a change in switch position since the last loop. If so, we update the stored switch position on line 12.
Lines 13-17 handle the transition of the switch from down to up. If that happens we increment the switch counter and update the "last switch" timestamp.
The rest of the lines handle the situation where the switch did not change.
Line 21 checks if there was a switch change in one of the previous loops (loop_lastSwitchTime != 0) and if more than a second has passed since. So this expression will evaluate to true when you've flipped the switch up a second ago. That basically means you've stopped flipping the switch.
Lines 23 to 29 convert the switch counter to a channel index, check if that's not out of bounds (flipped the switch more than there are channels to control) and line 26 is where you put your actual code. The remaining two lines reset the loop variables.

Let's add some LEDs!
1:  #define CHANNELS 5  
2:  uint8_t cfg_pins[CHANNELS];  
3:  bool   state_switch[CHANNELS];  
4:    
5:  void setChannelPin(uint8_t p_channel, uint8_t p_pin)  
6:  {  
7:      digitalWrite(p_pin, LOW);  
8:      pinMode(p_pin, OUTPUT);  
9:      cfg_pins[p_channel] = p_pin;  
10:  }  
11:    
12:  void setChannelSwitch(uint8_t p_channel, bool p_on)  
13:  {  
14:      state_switch[p_channel] = p_on;  
15:      if ( p_on == false )  
16:      {  
17:          digitalWrite(cfg_pins[p_channel], LOW);  
18:      }  
19:      else  
20:      {  
21:          digitalWrite(cfg_pins[p_channel], HIGH);  
22:      }  
23:  }  
24:    
25:    
26:  void toggleChannelSwitch(uint8_t p_channel)  
27:  {  
28:      setChannelSwitch(p_channel, !state_switch[p_channel]);  
29:  }  
30:    
The define is used to define how many channels we'll be able to control. cfg_pins holds the pin for each channel. state_switch holds the state of the "virtual" switch for each channel. setChannelPin can be used to configure the pin for a channel. It'll set the pin in output mode and make sure it's off. The setChannelSwitch function allows you to set the state of the "virtual" switch for the channel and turns the LED on or off. toggleChannelSwitch toggles the state of the switch.

Now we need to update our setup function and add a few lines:
1:      setChannelPin(0, 4);  
2:      setChannelPin(1, 5);  
3:      setChannelPin(2, 6);  
4:      setChannelPin(3, 7);  
5:      setChannelPin(4, 8);  
So our five channels are connected to pins 4 - 8.

In our loop function we need to replace the "// do something " comment with
1:  toggleChannelSwitch( channel );  

Tadaaah! We can now turn channels on and off with the switch on the remote.

Hmm, that's a bit boring though... Let's add some blinking and flashing! For this we need some sort of update function that updates all the "animations". We need to keep track of time as well. The easiest way to handle this is by giving the update function a parameter that holds the number of milliseconds passed since the last update.

1:  unsigned long loop_lastMillis;  
2:    
3:  void setup()  
4:  {  
5:      // previous code here  
6:      loop_lastMillis = millis();  
7:  }  
8:    
9:  void loop()  
10:  {  
11:      // previous code here  
12:    
13:      unsigned long now = millis();  
14:      uint16_t deltaMillis = now - loop_lastMillis);  
15:      loop_lastMillis = now;  
16:    
17:      if ( deltaMillis > 0 )  
18:      {  
19:          update( deltaMillis );  
20:      }  
21:  }  
22:    
23:  void update(uint16_t p_delta)  
24:  {  
25:      // animation code here  
26:  }  
Pretty self explanatory I guess? We calculate the difference between the current and last timestamp and pass that to the update function.

For the animations I want to be able to specify how often an LED should blink, how long it should blink, how much time should be between blinks and how much time should be between the last blink in a sequence and the first one of the next sequence. I want to be able to create a strobe that flashes two times rapidly and then waits for a second or so, but I also want to be able to have a LED that blinks at a constant rate. And of course, I want some LEDs to be on all of the time.

We'll need a few more variables...
1:  uint8_t cfg_blinks[CHANNELS];  
2:  uint16_t cfg_onDuration[CHANNELS];  
3:  uint16_t cfg_offDuration[CHANNELS];  
4:  uint16_t cfg_pauseDuration[CHANNELS];  
5:    
6:  bool   state_onOff[CHANNELS];  
7:  uint8_t state_currentBlink[CHANNELS];  
8:  uint16_t state_nextChange[CHANNELS];  
So we have our variable that specify how often a channel should blink (0 being constantly on), how long it should be on, how long it should be off between blinks and how long it should pause between blink sequences.
Then we have our variable to hold the state of the channels while the animation is running. We need to know whether it's currently on or off, which blink we're at and how many milliseconds remain until the next state change.

We'll want some convenience functions to configure the channels:
1:  void configureChannelBlink(uint8_t p_channel, uint8_t p_blinks, uint16_t p_onDuration, uint16_t p_offDuration, uint16_t p_pauseDuration)  
2:  {  
3:      cfg_blinks[p_channel]    = p_blinks;  
4:      cfg_onDuration[p_channel]  = p_onDuration;  
5:      cfg_offDuration[p_channel]  = p_offDuration;  
6:      cfg_pauseDuration[p_channel] = p_pauseDuration;  
7:      setChannelSwitch(p_channel, true);  
8:  }  
9:    
10:    
11:  void configureChannelConstant(uint8_t p_channel)  
12:  {  
13:      cfg_blinks[p_channel] = 0;  
14:      setChannelSwitch(p_channel, true);  
15:  }  
And we can call this from our setup function:
1:      configureChannelConstant(0);  
2:      configureChannelConstant(1);  
3:      configureChannelConstant(2);  
4:        
5:      configureChannelBlink(3, 1, 50, 0, 950);  
6:      configureChannelBlink(4, 2, 50, 50, 1850);  
So channels 0-2 are constantly on, channel 3 blinks constantly and channel 4 is a strobe (double flash).

We need to update our setChannelSwitch function so it will reset the animation when the channel is turned on:
1:  void setChannelSwitch(uint8_t p_channel, bool p_on)  
2:  {  
3:      state_switch[p_channel] = p_on;  
4:      if ( p_on == false )  
5:      {  
6:          digitalWrite(cfg_pins[p_channel], LOW);  
7:      }  
8:      else  
9:      {  
10:          state_onOff[p_channel]    = true;  
11:          state_currentBlink[p_channel] = 0;  
12:          state_nextChange[p_channel]  = cfg_onDuration[p_channel];  
13:          digitalWrite(cfg_pins[p_channel], HIGH);  
14:      }  
15:  }  
Lines 10-12 are new.

And lastly, our blinky code:
1:  void update(uint16_t p_delta)  
2:  {  
3:      for ( uint8_t channel = 0; channel < CHANNELS; ++channel )  
4:      {  
5:          if ( cfg_blinks[channel] == 0 )  
6:          {  
7:              continue;  
8:          }  
9:          if ( state_switch[channel] == false )  
10:          {  
11:              continue;  
12:          }  
13:            
14:          if ( p_delta >= state_nextChange[channel] )  
15:          {  
16:              state_onOff[channel] = ! state_onOff[channel];  
17:                
18:              if ( state_onOff[channel] )  
19:              {  
20:                  state_nextChange[channel] = cfg_onDuration[channel];  
21:                  digitalWrite(cfg_pins[channel], HIGH);  
22:              }  
23:              else  
24:              {  
25:                  state_currentBlink[channel]++;  
26:                  if ( state_currentBlink[channel] == cfg_blinks[channel] )  
27:                  {  
28:                      state_nextChange[channel] = cfg_pauseDuration[channel];  
29:                      state_currentBlink[channel] = 0;  
30:                  }  
31:                  else  
32:                  {  
33:                      state_nextChange[channel] = cfg_offDuration[channel];  
34:                  }  
35:                  digitalWrite(cfg_pins[channel], LOW);  
36:              }  
37:          }  
38:          else  
39:          {  
40:              state_nextChange[channel] = state_nextChange[channel] - p_delta;  
41:          }  
42:      }  
43:  }  
Lines 5-8 test if the channel should be constantly on, if so then we skip the rest of the loop and move to the next channel
Lines 9-12 test if the channel is switched off, if so we can again skip this channel.
Line 14 checks whether it's time to toggle the channel.
Line 15 toggles the state of the channel; from on to off and vice versa.
Lines 18-22 turn the LED on and update the "next change" counter.
Lines 23-37 turn the LED off, increment the blink counter and check if this was the last blink. If so then we use the pauseDuration, else we use the offDuration. Don't forget to reset the blink counter ( line 29).
Lines 38-41 handle the situation where a channel does not need to change state yet, all we need to do is decrement the amount of time remaining until the next state change.

That's all there's to it.
Here's the final complete code for your convenience:
1:  // NavLights.ino  
2:  // Arduino based remote controlled navigation lights  
3:  //  
4:  // By Daniel van den Ouden, 2014  
5:  //  
6:    
7:  // configuration for input  
8:  uint8_t cfg_inputPin;  
9:    
10:  // 5 output channels  
11:  #define CHANNELS 5  
12:    
13:  uint8_t cfg_blinks[CHANNELS];            // how often a channel will blink in a sequence, 8 bit, so value is 0 - 255, 0 means no blinking  
14:  uint16_t cfg_onDuration[CHANNELS];        // how long the channel will be on in milliseconds, 16 bit, so value is 0 - 65535  
15:  uint16_t cfg_offDuration[CHANNELS];        // how long the channel will be off between blinks in milliseconds, 16 bit  
16:  uint16_t cfg_pauseDuration[CHANNELS];    // how long the channel will be off between the last and first blink of a sequence, 16 bit  
17:  uint8_t cfg_pins[CHANNELS];            // which pin to use for which channel  
18:    
19:  bool   state_switch[CHANNELS];        // state of the channel's "switch" (true = on, false = off)  
20:  bool   state_onOff[CHANNELS];            // the output state of the channel (true = high, false = low)  
21:  uint8_t state_currentBlink[CHANNELS];    // how often this channel has blinked in the current sequence  
22:  uint16_t state_nextChange[CHANNELS];    // number of milliseconds until next change  
23:    
24:  unsigned long loop_lastMillis;            // time of last update  
25:  bool     loop_lastSwitchPosition;    // last measured switch position  
26:  uint8_t    loop_switchCount;            // number of switches in current sequence  
27:  unsigned long loop_lastSwitchTime;        // time at which the switch was flipped last  
28:    
29:  void setChannelPin(uint8_t p_channel, uint8_t p_pin)  
30:  {  
31:      digitalWrite(p_pin, LOW);  
32:      pinMode(p_pin, OUTPUT);  
33:      cfg_pins[p_channel] = p_pin;  
34:  }  
35:    
36:    
37:  void configureChannelBlink(uint8_t p_channel, uint8_t p_blinks, uint16_t p_onDuration, uint16_t p_offDuration, uint16_t p_pauseDuration)  
38:  {  
39:      cfg_blinks[p_channel]    = p_blinks;  
40:      cfg_onDuration[p_channel]  = p_onDuration;  
41:      cfg_offDuration[p_channel]  = p_offDuration;  
42:      cfg_pauseDuration[p_channel] = p_pauseDuration;  
43:      setChannelSwitch(p_channel, true);  
44:  }  
45:    
46:    
47:  void configureChannelConstant(uint8_t p_channel)  
48:  {  
49:      cfg_blinks[p_channel] = 0;  
50:      setChannelSwitch(p_channel, true);  
51:  }  
52:    
53:    
54:  void setup()  
55:  {  
56:      cfg_inputPin = 9;  
57:        
58:      setChannelPin(0, 4);  
59:      setChannelPin(1, 5);  
60:      setChannelPin(2, 6);  
61:      setChannelPin(3, 7);  
62:      setChannelPin(4, 8);  
63:        
64:      configureChannelConstant(0);  
65:      configureChannelConstant(1);  
66:      configureChannelConstant(2);  
67:        
68:      configureChannelBlink(3, 1, 50, 0, 950);  
69:      configureChannelBlink(4, 2, 50, 50, 1850);  
70:        
71:      loop_lastMillis = millis();  
72:      loop_lastSwitchPosition = pulseIn(cfg_inputPin, HIGH) > 1500;  
73:  }  
74:    
75:    
76:  void loop()  
77:  {  
78:      unsigned long duration = pulseIn(cfg_inputPin, HIGH);  
79:      while ( duration == 0 )  
80:      {  
81:          duration = pulseIn(cfg_inputPin, HIGH);  
82:      }  
83:        
84:      bool newSwitchPosition = duration > 1500;  
85:      if ( newSwitchPosition != loop_lastSwitchPosition )  
86:      {  
87:          loop_lastSwitchPosition = newSwitchPosition;  
88:          if ( newSwitchPosition )  
89:          {  
90:              ++loop_switchCount;  
91:              loop_lastSwitchTime = millis();  
92:          }  
93:      }  
94:      else  
95:      {  
96:          if ( loop_lastSwitchTime != 0 && millis() - loop_lastSwitchTime > 1000 )  
97:          {  
98:              uint8_t channel = loop_switchCount - 1;  
99:              if ( channel < CHANNELS )  
100:              {  
101:                  toggleChannelSwitch( channel );  
102:              }  
103:              loop_switchCount = 0;  
104:              loop_lastSwitchTime = 0;  
105:          }  
106:      }  
107:        
108:      unsigned long now = millis();  
109:      uint16_t deltaMillis = now - loop_lastMillis;  
110:      loop_lastMillis = now;  
111:        
112:      if ( deltaMillis > 0 )  
113:      {  
114:          update( deltaMillis );  
115:      }  
116:  }  
117:    
118:    
119:  void update(uint16_t p_delta)  
120:  {  
121:      for ( uint8_t channel = 0; channel < CHANNELS; ++channel )  
122:      {  
123:          if ( cfg_blinks[channel] == 0 )  
124:          {  
125:              continue;  
126:          }  
127:          if ( state_switch[channel] == false )  
128:          {  
129:              continue;  
130:          }  
131:            
132:          if ( p_delta >= state_nextChange[channel] )  
133:          {  
134:              state_onOff[channel] = ! state_onOff[channel];  
135:                
136:              if ( state_onOff[channel] )  
137:              {  
138:                  state_nextChange[channel] = cfg_onDuration[channel];  
139:                  digitalWrite(cfg_pins[channel], HIGH);  
140:              }  
141:              else  
142:              {  
143:                  state_currentBlink[channel]++;  
144:                  if ( state_currentBlink[channel] == cfg_blinks[channel] )  
145:                  {  
146:                      state_nextChange[channel] = cfg_pauseDuration[channel];  
147:                      state_currentBlink[channel] = 0;  
148:                  }  
149:                  else  
150:                  {  
151:                      state_nextChange[channel] = cfg_offDuration[channel];  
152:                  }  
153:                  digitalWrite(cfg_pins[channel], LOW);  
154:              }  
155:          }  
156:          else  
157:          {  
158:              state_nextChange[channel] = state_nextChange[channel] - p_delta;  
159:          }  
160:      }  
161:  }  
162:    
163:    
164:  void setChannelSwitch(uint8_t p_channel, bool p_on)  
165:  {  
166:      state_switch[p_channel] = p_on;  
167:      if ( p_on == false )  
168:      {  
169:          digitalWrite(cfg_pins[p_channel], LOW);  
170:      }  
171:      else  
172:      {  
173:          state_onOff[p_channel]    = true;  
174:          state_currentBlink[p_channel] = 0;  
175:          state_nextChange[p_channel]  = cfg_onDuration[p_channel];  
176:          digitalWrite(cfg_pins[p_channel], HIGH);  
177:      }  
178:  }  
179:    
180:    
181:  void toggleChannelSwitch(uint8_t p_channel)  
182:  {  
183:      setChannelSwitch(p_channel, !state_switch[p_channel]);  
184:  }  
185:    
186:    

25 comments:

  1. This is just awesome and you are awesome daniel

    ReplyDelete
  2. Hello
    Great project. Just cannot get the switch to work, it seems to behave strangely, using Channel 5 of my receiver and I want to be able to turn the Landing lights on and off. Can you help

    ReplyDelete
    Replies
    1. I can give it a try :) First things first: check if your channel 5 is working correctly by connecting a servo to CH5 on your receiver. Flipping the switch should move the servo between one end and the other. The code will only work if the servo travels past the center point.
      If you've verified that that works, then it's time to make sure the code registers the switch correctly. The easiest way to do this is by turning the little LED on the Arduino on and off based on the switch position. You'll need to slightly modify the code for that.
      In the setup function, add the following line (doesn't matter where, as long as it's in the setup function):

      pinMode(13, OUTPUT);

      The on-board LED is connected to pin 13, so we need to set that to output mode.

      In the loop function, under the line that says
      bool newSwitchPosition = duration > 1500;
      add the following:
      digitalWrite(13, newSwitchPosition ? HIGH : LOW );

      This will turn the LED on when the switch is in the up position, and off when it's in the down position. If this action is reversed, then you'll either have to invert the channel in your transmitter, or you can replace
      duration > 1500;
      with
      duration <= 1500;

      If the LED is blinking or behaving erratically, then there's probably something wrong with your connections.

      Good luck, and let me know if this was of any help or not :)

      Delete
  3. Hi. this looks awesome. :D
    i am new to the rc world. just got myself a planes, and its flying pretty good now. the next project is installing lights, however there is only 1 ch left on my receiver (RX) i have a turnigy 9xr transmitter (TX). so i can offset a servo to many positions using different switches.
    But i know little to nothing about arduion and and programming.
    but just enought to get me started, could you tell me the parts list (led size and wattage and what resistor your using) and if i could archive the same result with a ATtiny 45/85? (a smaller chip would fit better than the nano)
    my email is jon.poulsen.89@gmail.com (in case i don't get notification on your response.

    ReplyDelete
    Replies
    1. Hi Jon (I guess that's your name),

      The compiled sketch is just 2314 bytes large, so that should fit in a ATtiny 45/85. The RAM usage should be within the restrictions of those devices as well. Just keep in mind that you can only use 4 "channels"; the tiny has 6 IO pins, one of those is the RESET pin which you cannot use as an I/O pin (well, you can, but then you can no longer upload new software). You need one pin to connect to the receiver, so that leaves just 4 pins to drive the LEDs.

      As for the LEDs and resistors themselves. I just used generic 3mm LEDs and standard 1/4 watt resistors (190/240 ohm, depending on the color of the LED, there's plenty of resources online to figure out the correct value).

      If you want to drive larger or multiple LEDs from a single I/O pin, then I suggest you use a transistor like a 2N3904 to control more current. You can read more about that here: http://ledvdocube.blogspot.nl/2014/03/theory.html

      Delete
  4. DVDouden,
    On compilation of the code I get the following error message-

    Arduino: 1.6.8 (Windows 10), Board: "Arduino Pro or Pro Mini, ATmega328 (5V, 16 MHz)"

    rc-nav-led:11: error: stray '#' in program

    11: #define CHANNELS 5

    ^

    rc-nav-led:1: error: expected unqualified-id before numeric constant

    1: // NavLights.ino

    ^

    rc-nav-led:9: error: expected unqualified-id before numeric constant

    9:

    ^

    rc-nav-led:14: error: expected unqualified-id before numeric constant

    14: uint16_t cfg_onDuration[CHANNELS]; // how long the channel will be on in milliseconds, 16 bit, so value is 0 - 65535

    ^

    rc-nav-led:15: error: expected unqualified-id before numeric constant

    15: uint16_t cfg_offDuration[CHANNELS]; // how long the channel will be off between blinks in milliseconds, 16 bit

    ^

    rc-nav-led:16: error: expected unqualified-id before numeric constant

    16: uint16_t cfg_pauseDuration[CHANNELS]; // how long the channel will be off between the last and first blink of a sequence, 16 bit

    ^

    rc-nav-led:17: error: expected unqualified-id before numeric constant

    17: uint8_t cfg_pins[CHANNELS]; // which pin to use for which channel

    ^

    rc-nav-led:18: error: expected unqualified-id before numeric constant

    18:

    ^

    rc-nav-led:20: error: expected unqualified-id before numeric constant

    20: bool state_onOff[CHANNELS]; // the output state of the channel (true = high, false = low)

    ^

    rc-nav-led:21: error: expected unqualified-id before numeric constant

    21: uint8_t state_currentBlink[CHANNELS]; // how often this channel has blinked in the current sequence

    ^

    rc-nav-led:22: error: expected unqualified-id before numeric constant

    22: uint16_t state_nextChange[CHANNELS]; // number of milliseconds until next change

    ^

    rc-nav-led:23: error: expected unqualified-id before numeric constant

    23:

    ^

    rc-nav-led:25: error: expected unqualified-id before numeric constant

    25: bool loop_lastSwitchPosition; // last measured switch position

    ^

    rc-nav-led:26: error: expected unqualified-id before numeric constant

    26: uint8_t loop_switchCount; // number of switches in current sequence

    ^

    rc-nav-led:27: error: expected unqualified-id before numeric constant

    27: unsigned long loop_lastSwitchTime; // time at which the switch was flipped last

    ^

    rc-nav-led:28: error: expected unqualified-id before numeric constant

    28:

    ^

    rc-nav-led:29: error: expected unqualified-id before numeric constant

    29: void setChannelPin(uint8_t p_channel, uint8_t p_pin)

    ^

    rc-nav-led:35: error: expected unqualified-id before numeric constant

    35:

    ^

    rc-nav-led:45: error: expected unqualified-id before numeric constant

    45:

    ^

    rc-nav-led:52: error: expected unqualified-id before numeric constant

    52:

    ^

    rc-nav-led:74: error: expected unqualified-id before numeric constant

    74:

    ^

    exit status 1
    stray '#' in program

    This report would have more information with
    "Show verbose output during compilation"
    option enabled in File -> Preferences.

    What mistake I am doing?

    ReplyDelete
    Replies
    1. You've probably copy/pasted the code including all line numbers. Try this:
      http://pastebin.com/Sfd4g6WB

      Delete
  5. Wow!
    Comiled and Uploaded.
    Testing in an hour.

    ReplyDelete
  6. Thanks DVDOuden.
    Suuccessful. However, the TX only toggles the landing light. Is it possible to ensure that other lights are also switched on and off with the Transmitter?

    ReplyDelete
  7. Thanks DVDOuden.
    Suuccessful. However, the TX only toggles the landing light. Is it possible to ensure that other lights are also switched on and off with the Transmitter?

    ReplyDelete
    Replies
    1. Hi Pawan,

      What is it exactly that you're trying to achieve? The way the code is right now, it reads how often you flick the switch on and off repeatedly and turns a specific light on or off based on the number of times you flicked the switch.
      If you want multiple channels/lights to be turned off simultaneously then you'll have to modify some bits and pieces here and there. Let me know if you want/need some help with that.

      Delete
  8. Hello DVDOuden,
    I wish to switch on the navigation lights (Strobe, Beacon, Port and Starboard lights) with one flick and the landing lights with another. Yes, I wish to turn on and off multiple lights with flick of switch.
    Thanks for your patience to listen to me and helping me out. I am new to Arduino but I am just swept by your concept and hence the bother even on a weekend.
    Thanks again.

    ReplyDelete
  9. Thanks again DVDOuden,
    http://www.rcgroups.com/forums/showatt.php?attachmentid=8383435&d=1446290740 is the perfect code. Channel 5 switches navigation lights and next flick switches landing lights. Perfect. Thanks again for your help.

    ReplyDelete
    Replies
    1. Good to hear Pawan! I was about to modify my code so you could have multiple channels on a single switch action. But if that code works for you, great!

      Delete
    2. Hi DvdOuden,
      Is it possible to have the nav lights on all the time , and the switch just for the landing lights only?
      Also I may need some extra channels as I have
      2 x wing tip strobes
      2 wing tip nav lights
      1x tail strobe
      2 x landing lights
      Where would I need to alter the code for this?
      Regards

      Rob

      Delete
    3. Hi Rob,

      To only make the switch act on 1 channel, modify line 101 ( toggleChannelSwitch( channel ); ) by replacing 'channel' with the channel your landing lights are on (for example: toggleChannelSwitch( 2 ); )

      You don't necessarily need more channels I think. Since your wing tip strobes will both flash at the same time I guess? If your nav lights are always on, then you might as well wire them directly to the power supply. It's possible to control multiple LEDs from a single channel, but I suggest you add a transistor as a switch since the pins on the Arduino can only provide a small amount of current. There's plenty of examples of this available on the Internet.
      I hope this helps!

      gr.


      DvdOuden

      Delete
  10. Many thanks for the reply

    Regards

    Rob

    ReplyDelete
  11. Hi DvdOuden,
    Is it possible to have the beacon lights, That is to say that these lights are fade type and that its light fades away?

    ReplyDelete
    Replies
    1. Hi, it's possible, but not easy. You'd either have to use the analogWrite function, which is only available for a few specific pins) or you'd have to make the whole thing interrupt driven and do some PWM in software. Either way you need to do quite some refactoring of the program.

      Delete
  12. just a question can I define 6 CHANNELS instead of 5 ,use another pin and and associated code on an pro mini?
    would like to toggle camera for video but inflight.

    ReplyDelete
  13. Hi,
    Can i adapt this code to a static 1/144 model kit, whthout RC?
    Thanks

    ReplyDelete
    Replies
    1. Sure. Just remove the lines that deal with RC input (78 - 106) and you should be done.

      Delete
  14. This comment has been removed by the author.

    ReplyDelete
  15. Hello, I'm trying to contact you but I can't reach you.
    I would like to modify a bit this code to fit my needs but I don't have the knowledge. I tried but I failed :)
    I need to use a 3 position switch instead of reading pulse.
    Also (i love the blinking animation!) I need to add a fade in-out led to this animation.
    Plus, the starting position should be off. When my battery is connected it turns everything on (except channel1) consuming lot of Watts, but If I turn on the remote it switch to blinking animation.
    Can we fix this?
    Thank you :)

    ReplyDelete
    Replies
    1. Hi, it's been almost nine years since I wrote this, so I can't help you with everything. I no longer have the hardware to test this.

      Fading in and out is a matter of turning LEDs on and off hundreds of times per second for varying amounts of time. You should look into the "analogWrite" method of the Arduino for that.

      For turning the lights off at start, try replacing line 43 and 50
      setChannelSwitch(p_channel, true);
      with
      setChannelSwitch(p_channel, false);

      What do you mean with "3 position switch"? Is that a switch on your transmitter? Then you need to figure out which timing corresponds with which switch position. The pulse duration will vary with the switch position. My code assumes a two position switch and 1500 microseconds is the threshold between the on and off position. The actual value of the on and off position can vary depending on how the switch was programmed in the transmitter.

      Delete