Re my calculations sound?

Everything in my 5-prop airboat working well...except...the rockets.
They didn't ignite. There may be a few reasons for this; however, I'm here to ask if there's something off with my calculations.
Firstly, I know the code to fire the rockets works as intended, just to get that out of the way.

Rocket specs:
Estes B6-0 * 2 rockets
Maximum no fire current: 500mA
Minimum all-fire current: 2A
Starter resistance: 0.6904Ω

RC switches:
3.7-28V range, max continuous load current 8A.
Voltage out = voltage in when switch is on.
-100% is off; +100% is on with these switches (servo signal travel).

Batteries for just the rocket engines:
2 * 3.7V 150mAh 25C (0.5Wh) Lipo batteries used in
beginner hobby-grade RC airplanes (EFlite for ex) (one battery each, fully charged to 4.2V each)

My calculation:
I = V/R
4.2 or 3.7V/0.6904Ω = 6.083 or 5.359A each depending on whether battery is fully charged or running at nominal charge. Still under 8A spec for the switch.

My reasoning:
This is not a parallel current circuit to fire the rockets because:
each igniter is independently powered with its own 3.7V battery.
So no need to divide the Amperage value by two in the Ohm's Law calculation.

Another concern is that, at 0.6904Ω, across the rocket igniter, that I have essentially a dead short. In hindsight, I might have installed a small resistor in series with the igniter but is that even relevant in this instance?

Thanks for any critique or confirmation so I can focus my troubleshooting effort.

So

0.6904Ω

and 3.7 volts figures out to 5.4 amps, which should blow the igniters just fine unless there is such a thing as doing that so fast the rocket won't start. a real igniter circuit might be a controlled current source as opposed to a voltage.

Not a dead short at all, those small lipo cells can easily push 6 amps.

Please post a link to the switch that controls the igniter current, and links or data sheets for anything else in the circuit.

Pleas post a schematic diagram. Hand drawn is easiest, just show all the parts and how they are wired to each others, with attention to sources of power and how that power gets to the components that need it.

Pleasee post the code, or a reduced test sketch, that you expect will fire the igniter.

And what to you observe after the failure? Anything to see with the igniter or the romket that did not fire?

a7

  • That’s the cold resistance.

From my experience with the Estes launch system it uses 4 AA batteries in series with about 20 feet of maybe 24 gauge wire (doubled). I just looked up the system and it looks identical to what I use 30 years ago and still uses 4 AA cells.

I would think that a 3.7 volt cell would provide sufficient current to the igniter to ignite it given the shorter length of more robust wire most likely used with the lower internal resistance of the cell.

The igniter consists of a small piece of fine wire encased in a bead of a chemical that looks and acts like a match head. Once it ignites it produces enough heat for a long enough time to light the engine.

So the only unknown quantity is the switch used, the integrity of the connections to the igniter and the proper insertion of the igniter into the engine.

Is the igniter burning when it is triggered?

Would poring a cup of brine water or vinegar into your glass of beer be relevant? That would make the beer taste lousy and cause the igniter not to get hot enough. Try without the resistor and post a link to the switch.

hard to tell. One looked like maybe it did. Maybe it just broke as they don't seem robust enough for disassembly and there isn't a lot of igniter stuff on the tip. I am fairly certain I didn't let the leads touch each other, either.

Here's the link to the switch, although there isn't much more to be learned I think other than what I pasted from the spec details. Maybe youse guys see something I don't though .
amazon.ca/Remote-Controlled-Electronic-Switch-Relay/dp/B08FLVGTXQ
@LarryD

if you would, could you please elaborate on what you're driving at. I suspect that as it gets hot and before the ignition linkage burns off, the hot resistance would be less and that could be a problem? FWIW, I did test the voltage on the output before and after the launch attempt and it tested at the voltage I expected.

If i was unclear, I did not put a resistor in series. The box thingies that model rocketeers use are unfamiliar to me. What I have with an RC switch where the output voltage matches the input voltage is really just a switch in the form of a MOSFET. I have no idea if there's anything else in those rocket battery boxes than just a battery tray and a mechanical switch.

@alto777 c'mon, man.

It's literally those batteries on the input side of the RC switch, + and - voltage (tested) on the output side that matches the input, and a typical Futaba "J" connector controlling whether current flows between the input and output based on the pulse width.

The voltage going into the RC receiver is higher than the voltage on the switch side, but I don't see why that would matter.

The rocket circuit is isolated from the rest of the airboat, but everything grounds together through the receiver. I tested all the voltages to be exactly as expected, within spec.

@alto777 here you go, bro, tear my code to shreds again :face_with_peeking_eye: (just kidding, I always appreciate your improvements on code I write). Code tests exactly as I expect.

#include <ESP32Servo.h>

// 5 pins IN from RC Rx: Throttle; Elevator; Aileron; Rudder; Aux1
// Recommended pins include 2,4,12-19,21-23,25-27,32-33
// first number listed in comments is where it was no Nano Every
static const int throttleSignalPin = 21;  // throttle channel to pin d7/gpio 21
static const int aileronSignalPin = 22;   // aileron channel to pin d9/gpio 22
static const int elevatorSignalPin = 23;  // elevator channel to pin A2/gpio 23
static const int rudderSignalPin = 25;    //rudder channel to gpio 25
static const int aux1SignalPin = 26;      // Aux1 channel to gpio 26
                                          //static const int aux1SignalPin = 6;           // Aux1 channel to pin d6
                                          //static const int rudderSignalPin = 17;         // rudder channel to pin A3(alias 17 on Uno)

// 6 pins OUT to ESCs and RC (rocket) switches (if Nano Every/ if ESP32)
Servo starboardRocketSignalOut;  // pin 5/15
Servo portRocketSignalOut;       // pin 6/14
Servo starboardSignalOut;        // pin 8/16 - drives all starboard side motors
Servo portSignalOut;             // pin 10/17 - drives all portside motors
Servo sternSignalOut;            // pin 11/19 - use elevator raw sig
Servo bowSignalOut;              // pin 12/18 - N/C

// Recommended pins include 2,4,12-19,21-23,25-27,32-33
static const int portRocketSignalOutPin = 32;
static const int starboardRocketSignalOutPin = 33;
static const int starboardSignalOutPin = 16;
static const int portSignalOutPin = 17;
static const int bowSignalOutPin = 18;
static const int sternSignalOutPin = 19;
// general timer interval
const long interval = 1000;
// rocket countdown timing variables
int timer = 3;  // 3 seconds to ignition after switch flipped - Adios, Joes!
unsigned long previousLaunchTimer;
// heartbeat LED
const int heartbeatLED = 2;
unsigned long heartbeatTime;
const unsigned long rocketOnInterval = 200;  // blink interval for rockets on
const unsigned long rocketOffInterval = 600;

ESP32PWM pwm;
uint32_t spektrumTimeout = 22000;

// to store values for raw radio signals
uint32_t bowThrottleVal, sternThrottleVal, steerStarboardTrim, steerPortsideTrim, turnPortVal, turnStarVal = 0;
// to store modified values to go out to the ESCs
uint32_t bowValOut, sternValOut, steerPortOut, steerStarboardOut = 0;
// to read in Aux1 (flaps) channel
uint32_t rocketVal, rocketValOut = 0;
uint32_t rocketValMin = 400;   // from RC switch datasheet
uint32_t rocketValMax = 2600;  // from RC switch datasheet
int shouldFire = 0;
int ledFire = 0;

void setup() {  // Allow allocation of all timers
  ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);
  Serial.begin(115200);
  starboardSignalOut.setPeriodHertz(50);
  portSignalOut.setPeriodHertz(50);
  sternSignalOut.setPeriodHertz(50);
  bowSignalOut.setPeriodHertz(50);
  pinMode(throttleSignalPin, INPUT);
  pinMode(elevatorSignalPin, INPUT);
  pinMode(rudderSignalPin, INPUT);
  pinMode(aileronSignalPin, INPUT);
  pinMode(aux1SignalPin, INPUT);
  pinMode(heartbeatLED, OUTPUT);
  attachMotors();  // just the propulsion ESCs
  portSignalOut.writeMicroseconds(900);
  starboardSignalOut.writeMicroseconds(900);
  sternSignalOut.writeMicroseconds(900);
  bowSignalOut.writeMicroseconds(900);
  Serial.println("\nwaterMoccasinFiveMotor\n");
  previousLaunchTimer = 0;
}

void loop() {
  readPWMValues();
  updateMotorValues();
  setMotors();
 // printRealTimeMotorData();
  printRealTimeRocketData();
  switch (ledFire) {
    case 0:
      if (millis() - heartbeatTime >= rocketOffInterval) {
        heartbeatTime = millis();
        digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));
      }
      break;
    case 1:
      if (millis() - heartbeatTime >= rocketOnInterval) {
        heartbeatTime = millis();
        digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));
      }
      break;
    default:
      break;
  }
}


void readPWMValues() {
  bowThrottleVal = pulseIn(elevatorSignalPin, HIGH, spektrumTimeout);    // motors toward the bow
  sternThrottleVal = pulseIn(throttleSignalPin, HIGH, spektrumTimeout);  // the one mid stern motors, signal attached to throttle cut
  steerStarboardTrim = pulseIn(rudderSignalPin, HIGH, spektrumTimeout);  // not wired to anything, these are trim values as a feature of the transmitter settings
  steerPortsideTrim = pulseIn(aileronSignalPin, HIGH, spektrumTimeout);  // not wired to anything, these are trim values as a feature of the transmitter settings
  rocketVal = pulseIn(aux1SignalPin, HIGH, spektrumTimeout);
}

void printPWMValues() {
  Serial.print("bowThrottleVal: ");
  Serial.print(bowThrottleVal);
  // stern motors
  Serial.print("\tsternThrottleVal: ");
  Serial.print(sternThrottleVal);
  // steering offsets
  Serial.print("\tsteerStarboardTrim: ");
  Serial.print(steerStarboardTrim);
  Serial.print("\tsteerPortsideTrim: ");
  Serial.println(steerPortsideTrim);
}

void updateMotorValues() {
  /* 
Use Throttle signal in for two main motors up to its max
Use Elevator signal for other two aux motors up to THR max
Then use difference between Elev max and Thr max to drive top speed all motors

Ail and Rud should init about 1200 or so. (1283)
pushing right stick LEFT increases Ail val up to about 1800 while decreasing Rud val to stall
pushing right stick RIGHT increases Rud val up to about 1800 while decreasing Ail val to stall
bowValOut, sternValOut, steerPortOut, steerStarboardOut = 0;
Servo starboardSignalOut;        // pin 16 - drives all starboard side motors
Servo portSignalOut;             // pin 17 - drives all portside motors
Servo sternSignalOut;            // pin 19 - use throttle raw sig, just one rear mid motor
Servo bowSignalOut;              // pin 18 - N/C
*/

  // handle the motors
  sternValOut = sternThrottleVal;  // just stern large prop mid motor
                                   // port and star pairs, untrimmed to give max range
  if (steerStarboardTrim > 1300 && steerPortsideTrim < 1260) {
    steerStarboardOut = steerStarboardTrim * 0.90;
    steerPortOut = steerPortsideTrim * 0.90;
  } else if (steerPortsideTrim > 1300 && steerStarboardTrim < 1260) {
    steerStarboardOut = steerStarboardTrim * 0.90;
    steerPortOut = steerPortsideTrim * 0.90;
  }

  else {
    steerStarboardOut = sternValOut;
    steerPortOut = sternValOut;
    bowValOut = sternThrottleVal;
  }

  // handle the rockets
  switch (rocketVal) {
    case 900 ... 1699:
      shouldFire = 0;
      ledFire = 0;
      break;
    case 1700 ... 2000:
      shouldFire = 1;
      ledFire = 1;
      break;
    default:
      shouldFire = 0;
      ledFire = 0;
      break;
  }
  switch (shouldFire) {
    case 0:
      rocketValOut = rocketValMin;
      coolRockets();
      break;
    case 1:
      {
        starboardRocketSignalOut.attach(starboardRocketSignalOutPin);
        portRocketSignalOut.attach(portRocketSignalOutPin);
        // set countdown timer
        unsigned long thisLaunchTimer = millis();
        if (thisLaunchTimer - previousLaunchTimer >= interval) {
          previousLaunchTimer = thisLaunchTimer;
          timer--;
          if (timer == 0) {
            fireRockets();
          }
          if (timer == -1) {
            timer = 3;
          }
        }
      }
      break;
    default:
      rocketValOut = rocketValMin;
      coolRockets();
      break;
  }
}

void setMotors() {
  bowSignalOut.writeMicroseconds(bowValOut);
  sternSignalOut.writeMicroseconds(sternValOut);
  starboardSignalOut.writeMicroseconds(steerStarboardOut);
  portSignalOut.writeMicroseconds(steerPortOut);
}
void coolRockets() {
  starboardRocketSignalOut.detach();
  portRocketSignalOut.detach();
}
void fireRockets() {
  rocketValOut = rocketValMax;
  starboardRocketSignalOut.writeMicroseconds(rocketValOut);
  portRocketSignalOut.writeMicroseconds(rocketValOut);
}
void printRealTimeMotorData() {
  // bow motors
  Serial.print("bowValOut: ");
  Serial.print(bowValOut);
  // stern motors
  Serial.print("\tsternValOut: ");
  Serial.print(sternValOut);
  // steering offsets
  Serial.print("\tsteerStarboardOut: ");
  Serial.print(steerStarboardOut);
  Serial.print("\tsteerPortOut: ");
  Serial.println(steerPortOut);
}
void printRealTimeRocketData() {
  if (shouldFire == 0) {
    Serial.print(F("\n\trocketVal: "));
    Serial.print(rocketVal);
    Serial.print(F("\trocketValOut: "));
    Serial.print(rocketValOut);
    Serial.println(F("\t\tRockets Cool\n"));
  } else if (shouldFire == 1) {
    Serial.print(F("\n\trocketVal: "));
    Serial.print(rocketVal);
    Serial.print(F("\trocketValOut: "));
    Serial.print(rocketValOut);
    Serial.println(F("\t\tRockets Ignite!\n"));
  }
}

void attachMotors() {
  starboardSignalOut.attach(starboardSignalOutPin);
  bowSignalOut.attach(sternSignalOutPin);
  portSignalOut.attach(portSignalOutPin);
  sternSignalOut.attach(bowSignalOutPin);
}
void detachMotors() {
  starboardSignalOut.detach();
  portSignalOut.detach();
  bowSignalOut.detach();
  sternSignalOut.detach();
}

Everything connected like these pics.

In summary, kindly recall that I was mostly looking to see if my Ohm's Law math was sound. I sincerely appreciate all of you taking the time; however, every part of this project tested perfectly as expected in action, by Serial and by DMM.

I still wonder though what @LarryD meant, "cold resistance". Is that where I screwed up?

  • As the igniter gets hot, the resistance will increase, probably significantly. :thinking:
  • Hence the initial current will be 4.2v ÷ 0.6904Ω ≈ 6.1A
    After-witch, less than 6.1A as the igniter heats.

I did a quick flight over the code.

I would work backwards or up from

  1. a real switch and the lipo battery and the igniter.

  2. a simple sketch writing an ignition value to the RC switch.

Both using the same wires and connectors and so forth.

Both those should fire the rocket. I did not carefully reread the thread, you may have already tried.

a7

but still within this range, is your estimation?

So do you agree with @alto777 ? Two separate idential 3.7V batteries, two separate identical RC switches. Two separate signals trimmed and duplicated in the ESP32 from the RC AUX1 input signal.

That's really what I'm after, sorry if I wasn't perfectly clear. I just want to rule out the possibility that such a low resistance is going to short the RC switches and let the magic blue smoke out.

"Receiver signal input port (3.9 ~ 15V)"
What voltage are you applying here?

5.2V, regulated with Castle Creations 10A BEC, fed from a 4s lipo (14.8V, nominal).

OK. :grin:

  • Yes, the current draw only gets less (better).
    The batteries are stressed for just the first instance in time.

Thank you. Went to test by placing the boat in the road on my son's long skateboard, then the sky opened up to a downpour.
Cameras will be ready. This will either be epic or hilarious and either way is totally worth the price of admission!

Thanks, all for your input. I'll mark @LarryD with the solution.