• Steel Soldiers now has a few new forums, read more about it at: New Munitions Forums!

  • Microsoft MSN, Live, Hotmail, Outlook email users may not be receiving emails. We are working to resolve this issue. Please add support@steelsoldiers.com to your trusted contacts.

Prototype 803a Autostart Proper Procedure Questions

Icesythe7

Active member
147
223
43
Location
Indiana, USA
So I design alot of pcbs/circuits for mods for retro systems like gameboys etc and have alot of MCU's laying around figured I would make some rudimentary autostart, I did manage to get an autostart made for about $7 in parts that works but was curious if I am going about it properly and if I should change anything.

Currently I am more or less electronically emulating the master switch with the thought process that if there is an error of some sort (oil pressure, coolant temp, etc) it will still shutdown the engine as it overrides the master switch which I am emulating. I have yet to hook up any of the gauges for monitoring (I do plan too) but my thought process is as follows:

User presses start on touchscreen/bluetooth device/wifi device
1. Ensure motor is not already running by reading HZ (if HZ greater than x motor running)
2. Read coolant temp if temp less than x start preheat for y time
3. Set proper mode (run or aux run) and let pressure build for ~3 seconds
4. Crank motor until oil pressure is higher than 35 (assume we started here) then hold for 2 seconds
5. If we don't see a start after cranking for 5 seconds or we had a start but died reset and start again at step 2 until 3 attempts are made and then notify user of a non start
6. If we start and are running monitor all data for user and display it including faults

Does anyone see a better way to know if the engine is running? Am I missing any critical steps or can anything be improved?

For the people that like code I am currently just testing with an arduino but plan to use a pico w or esp32 for the final product so don't judge the 15 mins it took to make this lol
C++:
class MepAutoStart
{
    enum state: uint8_t {
        off,
        preheat,
        start,
        running
    };

    enum mode: uint8_t {
        aux_run,
        run
    };

    static constexpr uint8_t num_states = 4;
    static constexpr uint8_t num_modes = 2;
    const char* const state_strings_[num_states] = { "Off", "Preheat", "Start", "Running" };
    const char* const mode_strings_[num_modes] = { "Aux run", "Run" };

    using callback_function_t = void(*)(uint8_t);
    callback_function_t callback_ = nullptr;

    uint8_t preheat_start_pin_;
    uint8_t aux_run_pin_;
    uint8_t run_pin_;

    uint8_t current_state_ = off;
    uint8_t last_state_ = 0xFF;
    uint8_t current_mode_ = run;
    bool has_preheated_ = false;

    MepAutoStart(const uint8_t preheat_start, const uint8_t aux, const uint8_t run) {
        preheat_start_pin_ = preheat_start;
        aux_run_pin_ = aux;
        run_pin_ = run;

        pinMode(preheat_start_pin_, OUTPUT);
        pinMode(aux_run_pin_, OUTPUT);
        pinMode(run_pin_, OUTPUT);
    }

    // forbid more than 1 instance or copies of class
    MepAutoStart(const MepAutoStart&) = delete;
    MepAutoStart& operator=(MepAutoStart const&) = delete;

public:
    static MepAutoStart& init(const uint8_t preheat_start, const uint8_t aux, const uint8_t run) {
        static MepAutoStart res(preheat_start, aux, run);
        return res;
    }

    void registerCallback(const callback_function_t f) {
        callback_ = f;
    }

    void setState(const uint8_t new_state) {
        current_state_ = new_state;
    }

    uint8_t getState() const {
        return current_state_;
    }

    const char* stateToString(const uint8_t state) {
        return (state < num_states) ? state_strings_[state] : "Unknown";
    }

    void setMode(const uint8_t new_mode) {
        current_mode_ = new_mode;
    }

    uint8_t getMode() const {
        return current_mode_;
    }

    const char* modeToString(const uint8_t mode) {
        return (mode < num_modes) ? mode_strings_[mode] : "Unknown";
    }

    bool preHeat(const bool test) {
        static bool pre_heat_running = false;
        static uint32_t start_time = 0;
        // todo: if engine temp < 55c preheat for x time based on temp else skip state
        if (pre_heat_running) {
            constexpr uint32_t preheat_time = 5000;
            const uint32_t elapsed_time = millis() - start_time;
            if (preheat_time > elapsed_time) {
                return true;
            }
            pre_heat_running = false;
            has_preheated_ = true;
            digitalWrite(preheat_start_pin_, LOW);
            return false;
        }
        if (test) { // fake simulation of cold start since no temp yet
            pre_heat_running = true;
            start_time = millis();
            digitalWrite(preheat_start_pin_, HIGH);
            return true;
        }
        return false;
    }

    void update() {
        const uint8_t current_state = getState();

        if (current_state != last_state_) {
            last_state_ = current_state;
            if (callback_)
                callback_(current_state);
        }

        switch (current_state) {
            case off: {
                digitalWrite(preheat_start_pin_, LOW);
                digitalWrite(aux_run_pin_, LOW);
                digitalWrite(run_pin_, LOW);
                has_preheated_ = false;
                break;
            }
            case preheat: {
                digitalWrite(aux_run_pin_, LOW);
                digitalWrite(run_pin_, LOW);
                if (!preHeat(true))
                    setState(start);
                break;
            }
            case start: {
                digitalWrite(getMode() ? run_pin_ : aux_run_pin_, HIGH);
                delay(3000);
                digitalWrite(preheat_start_pin_, HIGH);
                delay(3000);
                digitalWrite(preheat_start_pin_, LOW);
                setState(running);
                break;
            }
            case running: {
                //if (errors)
                //{
                //    // report errors and shutdown engine
                //    setState(off);
                //}
                break;
            }
        default:
            break;
        }
    }
};

inline void OnStateChange(uint8_t state);

MepAutoStart& gen_set = MepAutoStart::init(2, 4, 3);
uint32_t last_time = millis();

void setup() {
    Serial.begin(9600);
    gen_set.registerCallback(OnStateChange);
    Serial.println("AutoStart Controller v0.1 by Icesythe7");
    // test code until touchscreen gets here from china
    delay(5000);
    gen_set.setState(1);
}


void loop() {
    const uint32_t current_time = millis();
    static uint32_t times = 0;

    // simulate a button press of touchscreen every 2 mins
    if (current_time - last_time >= 120000) {
        last_time = current_time;
        gen_set.setState(times % 2);
        times++;
    }

    gen_set.update();
}

void OnStateChange(const uint8_t state) {
    Serial.print("Current machine state changed to ");
    Serial.println(gen_set.stateToString(state));
}
 
Last edited:

Scoobyshep

Well-known member
1,137
1,511
113
Location
Florida
So I design alot of pcbs/circuits for mods for retro systems like gameboys etc and have alot of MCU's laying around figured I would make some rudimentary autostart, I did manage to get an autostart made for about $7 in parts that works but was curious if I am going about it properly and if I should change anything.

Currently I am more or less electronically emulating the master switch with the thought process that if there is an error of some sort (oil pressure, coolant temp, etc) it will still shutdown the engine as it overrides the master switch which I am emulating. I have yet to hook up any of the gauges for monitoring (I do plan too) but my thought process is as follows:

User presses start on touchscreen/bluetooth device/wifi device
1. Ensure motor is not already running by reading HZ (if HZ greater than x motor running)
2. Read coolant temp if temp less than x start preheat for y time
3. Set proper mode (run or aux run) and let pressure build for ~3 seconds
4. Crank motor until oil pressure is higher than 35 (assume we started here) then hold for 2 seconds
5. If we don't see a start after cranking for 5 seconds or we had a start but died reset and start again at step 2 until 3 attempts are made and then notify user of a non start
6. If we start and are running monitor all data for user and display it including faults

Does anyone see a better way to know if the engine is running? Am I missing any critical steps or can anything be improved?

For the people that like code I am currently just testing with an arduino but plan to use a pico w or esp32 for the final product so don't judge the 15 mins it took to make this lol
C++:
class MepAutoStart
{
typedef enum : uint8_t {
off,
preheat,
start,
running
} state;

typedef enum : uint8_t {
aux_run,
run
} mode;

uint8_t preheat_start_pin;
uint8_t aux_run_pin;
uint8_t run_pin;

uint8_t current_state_ = off;
uint8_t last_state_ = 0xFF;
uint8_t current_mode_ = run;
bool has_preheated_ = false;

public:
MepAutoStart(const uint8_t preheat_start, const uint8_t aux, const uint8_t run) {
preheat_start_pin = preheat_start;
aux_run_pin = aux;
run_pin = run;

pinMode(preheat_start_pin, OUTPUT);
pinMode(aux_run_pin, OUTPUT);
pinMode(run_pin, OUTPUT);
};

void setState(const uint8_t new_state) {
current_state_ = new_state;
}

uint8_t getState() const {
return current_state_;
}

void setMode(const uint8_t new_mode) {
current_mode_ = new_mode;
}

uint8_t getMode() const {
return current_mode_;
}

bool preHeat(const bool test) {
static bool pre_heat_running = false;
static uint32_t start_time = 0;
// todo: if engine temp < 55c preheat for x time based on temp else skip state
if (pre_heat_running) {
constexpr uint32_t preheat_time = 5000;
const uint32_t elapsed_time = millis() - start_time;
if (preheat_time > elapsed_time) {
return true;
}
pre_heat_running = false;
has_preheated_ = true;
digitalWrite(preheat_start_pin, LOW);
Serial.println("Preheating done!");
return false;
}
if (test) { // fake simulation of cold start since no temp yet
pre_heat_running = true;
start_time = millis();
digitalWrite(preheat_start_pin, HIGH);
Serial.println("Preheating...");
return true;
}
return false;
}

void update() {
switch (getState()) {
case off: {
Serial.println("Shutdown");
digitalWrite(preheat_start_pin, LOW);
digitalWrite(aux_run_pin, LOW);
digitalWrite(run_pin, LOW);
has_preheated_ = false;
break;
}
case preheat: {
digitalWrite(aux_run_pin, LOW);
digitalWrite(run_pin, LOW);
if (!preHeat(true))
setState(start);
break;
}
case start: {
digitalWrite(getMode() ? run_pin : aux_run_pin, HIGH);
Serial.println("Priming...");
delay(3000);
digitalWrite(preheat_start_pin, HIGH);
Serial.println("Starting...");
delay(3000);
digitalWrite(preheat_start_pin, LOW);
Serial.println("Running...");
setState(running);
break;
}
case running: {
//if (errors)
//{
// // report errors and shutdown engine
// setState(off);
//}
break;
}
default:
break;
}
}
};

MepAutoStart gen_set = MepAutoStart(2, 4, 3);
uint32_t last_time = millis();

void setup() {
Serial.begin(9600);
Serial.println("AutoStart Controller v0.1 by Icesythe7");
// test code until touchscreen gets here from china
delay(5000);
gen_set.setState(1);
}


void loop() {
const uint32_t current_time = millis();
static uint32_t times = 0;

// simulate a button press of touchscreen every 2 mins
if (current_time - last_time >= 120000) {
last_time = current_time;
gen_set.setState(times % 2);
times++;
}

gen_set.update();
}
I did this on a 004 and in the simplest of terms I am emulating switch flips. Specifically the stop/run/start and circuit breaker. (Run, start, close, and not open)

Id imagine as long as you aren't manipulating the battle short circuit the safeties will still work (mine do).

In addition to commands my controller watches: voltage present( 240v relay across l1l3 providing a dry contact), fuel solenoid powered (controller interprets this as an automatic e stop), frequency (as a 4-20 ma signal, this is more for my homebrew governor), 2 DC buss volt monitors (battery ok and alt ok) right now my system just assumes if the fuel solenoid is off unexpectedly its high heat or low oil (or loss of fuel)

Sent from my SM-S908U using Tapatalk
 

Icesythe7

Active member
147
223
43
Location
Indiana, USA
I did this on a 004 and in the simplest of terms I am emulating switch flips. Specifically the stop/run/start and circuit breaker. (Run, start, close, and not open)

Id imagine as long as you aren't manipulating the battle short circuit the safeties will still work (mine do).

In addition to commands my controller watches: voltage present( 240v relay across l1l3 providing a dry contact), fuel solenoid powered (controller interprets this as an automatic e stop), frequency (as a 4-20 ma signal, this is more for my homebrew governor), 2 DC buss volt monitors (battery ok and alt ok) right now my system just assumes if the fuel solenoid is off unexpectedly its high heat or low oil (or loss of fuel)

Sent from my SM-S908U using Tapatalk
Thanks ya that is essentially what I am doing aswell figured it would be safe since all safeties should remain intact, how are you handling the switch flips? solid state relays?
 

Scoobyshep

Well-known member
1,137
1,511
113
Location
Florida
Thanks ya that is essentially what I am doing aswell figured it would be safe since all safeties should remain intact, how are you handling the switch flips? solid state relays?
Dry contact relays, coil is sourced from controller and Contacts from generator battery. Most are just paralleled, contactor open (breaker trip) is normally closed so I had to put that one in series.

Sent from my SM-S908U using Tapatalk
 
Top