|
Post by turboron on Jan 30, 2018 9:57:54 GMT -5
Note that I downloaded and installed the latest Arduino Integrated Development Environment (IDE) software version 1.8.5 before compiling my code and uploading it to the Arduino Uno's firmware.
|
|
|
Post by turboron on Jan 30, 2018 14:34:59 GMT -5
I remembered that not everyone is familiar with the Arduino and how easy it is to use for our projects. After you install the IDE and input your code to your PC and compile it you must upload it to the Arduino firmware which runs every time you power it up. The photo below shows how this is accomplished. You can see the IDE running on the PC, the Arduino and the USB cable that connects the two computers. When you select the IDE upload tag on the PC it transmits the complied code to the Arduino. The cable is mini-USB connector on the Arduino and regular USB connector on the PC. And now on to the Tachometer code.
|
|
|
Post by turboron on Feb 10, 2018 16:11:47 GMT -5
All, I believe I now understand KU's tachometer code. They use a separate Arduino Uno with interrupts to send an rpm to the main FADEC control. The reason is to avoid interrupts in the main control. I have studied the code and added comments to help understand how it works. The pseudo code is below:
/*********************************************************
February 3, 2018
Tachometer Pseudo Code
The Kansas University team’s report explains the tachometer’s function in their control system. It is not a closed loop system where the tachometer output controls the fuel system achieve a set rpm. It is an open loop system since the tachometer simply informs the kart driver what the rpm is and he adjusts a throttle as required to achieve his goal. The code uses interrupts which are useful for making things happen automatically in microcontroller programs. Also, the code uses the volatile data type to make sure that the data passed between the ISR and the main program are updated correctly. An Arduino ATMEGA 328 Uno is used for the microcontroller.
**************************************************/ #define ledpin 5
#define tachpin 1 // Arduino says to use pins 2 and 3 for Uno interrupts to avoid compatibility problems with other boards
volatile byte revolutions;
volatile boolean led;
/************************************************
The volatile data type is needed here because it will be used in an interrupt. Specifically, it directs the compiler to load the variable from RAM and not from a storage register, which is a temporary memory location where program variables are stored and manipulated. Under certain conditions, the value for a variable stored in registers can be inaccurate.
A variable should be declared volatile whenever its value can be changed by something beyond the control of the code section in which it appears, such as a concurrently executing thread. In the Arduino, the only place that this is likely to occur is in sections of code associated with interrupts, called an interrupt service routine.
*************************************************/
unsigned int rpm;
unsigned long timeold;
void rev_int() // Interrupt Service Routine (ISR)
{
revolutions++; //interrupt increments revolutions for every rotation
}
void setup()
{
revolutions = 0;
rpm = 0;
timeold = 0;
pinMode(ledpin, OUTPUT);
digitalWrite(ledpin, LOW);
Serial.begin(9600);
attachInterrupt(tachpin, rev_int, FALLING); //attach interrupt before loop starts.
/*******************************************************The last argument in this function is the Mode. Four constants are predefined as valid values. They are LOW, CHANGE, RISING, FALLING. Some boards such as the MKR1000 also allow HIGH. FALLING is for when the pin goes from high to low.
******************************************************/
}
void loop() // program starts
{
delay(100); //update approximately every 100ms, interrupt active for 100ms
detachInterrupt(tachpin); //stop interrupt
rpm = (60000/(millis() - timeold))*revolutions;
/****************************************************
calculate millisecond-revolution value, calculate rpm. millis() is a function that returns the amount of milliseconds that have passed since program start.
My understanding is that the 60000 used in the calculation comes from the fact that the Arduino uses timer(0) for external interrupts. timer(0) is an 8 bit timer so it counts form 0 to 255 and generates an interrupt when it overflows. Since the Arduino has a 15MHz system clock the timer overflows at 16,000,000/255 = 62,745 < 60,000.
**********************************************/
//Serial.write(rpm/312);
Serial.write(rpm/312); // Tell the operator the current rpm per step (loop?)
// Serial.write(357 / 256);
// Serial.write(357 % 256);
revolutions = 0; //reset interrupt counter
/****************************************************
The code section is confusing. What is the purpose of this code? My investigation stated with the main FADEC code which provides some insight into what the code does. One line of code is as follows;
long RPM = 0; //max ~ 80,000 RPM, precision = whatever necessary, currently 312 RPM per step.
Since Serial.write can only write a byte with a value of 0 to 256 we must shift rpm to something the function can handle such as 80,000 rpm / 312 equals 256.4 rounded to 256. We then convert it in the FADEC program by multiplying by 312.
RPM = (RPM*312);
*************************************************/
if(led == HIGH)
{
led = LOW;
digitalWrite(ledpin, LOW);
}
else
{
led = HIGH;
digitalWrite(ledpin, HIGH);
}
timeold = millis();
/***************************************************
after other loop functions occur, update timeold (millis expires in 50 days, careful). The KU comment means that the millis() operator overflows and returns to zero after 49 days. Can your code execute if millis() goes to zero?
**************************************************/
attachInterrupt(tachpin, rev_int, FALLING); //restart interrupt
}
|
|
|
Post by turboron on Feb 11, 2018 7:46:17 GMT -5
The Tachometer code was compiled and uploaded to firmware on an Arduino Uno this morning without any problems. Be sure to select the correct Com Port.
Thanks, Ron
|
|
|
Post by turboron on Feb 25, 2018 16:34:28 GMT -5
All, shown below is my Agricultural version of the KU digital control. It features 4 Arduinos. There are two Megas and two Unos Arduino boards. I have arranged the components so that the simulate shelves in a future enclosure. postimg.org/image/er8da12nd/Thanks, Ron
|
|
|
Post by turboron on Feb 26, 2018 21:37:58 GMT -5
I spent several hours today trying to understand the following comment in the KU teams FADEC code:
We never use hardware pin numbers at all in the software because they differ between different packages of the very same chip. The Arduino software uses virtual pin numbers for everything, including the analog pins which have two distinct numbering schemes, from zero (just for analogRead()), and A0..A7 (which are #defines for 14..21 in fact) which work with all pin-related calls
I finally went to the Arduino forum for help. What the guys there seem to say is the each microcontroller chip assigns virtual pin numbers internally when it sees the hardware pin numbers in the code since not all boards have the same pin assignments. The code will not compile without a hardware (board) pin number assigned.
Watch this space.
|
|
|
Post by madrocketscientist on Feb 27, 2018 0:02:36 GMT -5
Looks like you have your work cut out for you!
|
|
|
Post by turboron on Feb 27, 2018 16:41:45 GMT -5
After some more discussions with the Arduino forum guys and gals it turns out the my previous statement is ass backwards. The virtual pin numbers are the board (hardware) numbers which do not change from board to board. However, the microcontroller chip pin number, for board pin 10 for example, varys from chip to chip. In other words, board pin 10 may be connect to chip pin 48 on an Uno and 34 on a Mega. The core of the chip is mapped to the board pins to keep everything straight in the real world.
In any case, when I assigned Mega board digital and analog pin numbers to the KU FADEC code it compiled and uploaded successful. Now it is time to start populating the board and wiring the components.
|
|
Feathers
Veteran Member
Joined: August 2010
Posts: 169
|
Post by Feathers on Feb 27, 2018 18:03:25 GMT -5
Hi Ron,
Sorry I haven't been more active on the forum lately.
We send tach data to the main microcontroller, which uses it for several closed-loop functions such as idle regulation and mapping throttle slew rate limits to engine operating conditions. Driver input is very detached from executed throttle and fuel pump speed.
Cheers,
- Feathers
|
|
|
Post by Johansson on Mar 1, 2018 16:45:29 GMT -5
This is very interesting stuff Ron, as you know I am planning to make a closed loop PWM controller for my turbine bike oil pump and use a micro potentiometer to set the desired oil pressure.
For my fuel pump I use a throttle grip from an electric motorcycle and an Arduino Nano PWM controller designed by my friend Olov, so perhaps the same Nano could be used for controlling the oil pump? That would make for a compact system for sure! (I am no Arduino skilled guy so I´ll be asking Olov for help with it, poor guy...)
Cheers! /Anders
|
|
|
Post by turboron on Mar 1, 2018 17:59:48 GMT -5
Anders, my post on pages 1 and 2 go into a lot of detail on the code and testing the pressure sensor to get the pressure versus voltage relationship. I also posted the pressure sensor I bought which was fairly inexpensive. Olov still owes me a report on his International Farmall Cub.
Thanks, Ron
|
|
|
Post by olovselander on Mar 2, 2018 5:09:31 GMT -5
Nice project! I also bought a pressure sensor like that a few years ago to evaluate for the plans of a big Arduino based datalogger for our turbines. But as usual the time isn´t enough for all projects and it´s probably in the bottom of one of all the "good to have" boxes.. BELOW IS A BIG TIME OFF TOPIC POST, sorry! Sorry about the cub report.. All time went to making as much as possible on the ice yacht before speedweekend. Don´t know what to say about it or where to start. It´s my fathers project, he has been farming for about forty years and as the company grew he got more and more land to take hay on (swenglish . The cub has been sitting in a barn on one of all these fields for many many years before he deared to ask the owner if it was for sale but it wasn´t. BUT!! He was able to trade it for a horse wagon! The cub was in terrible condition so he´s doing a complete overhaul, done is rear and front end is disassembled and inspected and put together with new bearings and seals where needed. Engine also torn appart and put together with new bearings, gaskets, piston rings, valve job etc etc. left is fuel system, ingition and all electrics. The funny thing is that almost all parts is available new through the local case-new holland delaer. It´s produced in US and is a 47 i think, (first year). The goal is to have it in perfect driving condition but keep the patina.
|
|
|
Post by turboron on Mar 2, 2018 7:43:50 GMT -5
Olov, thanks. All things Farmall are close to my heart.
Thanks again, Ron
|
|
|
Post by turboron on Mar 23, 2018 13:29:52 GMT -5
I finished my review and comment of the KS main FADEC code. I am ready to proceed to the hardware step of assembling the control. I use individual components where the KS team create on one printed circuit board solution. The review follows:
/*
KU comments are common font. Turboron comments are italicized and tagged with a TR. The comments are in Times New Roman 16 font. February 26, 2018 Pseudo Fadec Main Firmware 623 lines (568 sloc) 17.6 KB
----------------------------------------------------------------- Gas Turbine Full Authority Digital Engine Controller ----------------------------------------------------------------- Main Controller - ATMEGA2560 So we've been making some progress on the "brain" of the jet kart. It will be a FADEC unit, firmware and hardware written, designed, and produced in-house.
It consists of three microcontrollers, and a host of IC's and drivers.
The first microcontroller is the one you guys are going to worry about. It will be running closed-loop oil pressure regulation (in a manner similar to in the post above). We're taking every precaution to protect it, and make its operation as solid as possible. It has its own dedicated controller running simple code with coded contingencies for sensor failure, hardware failure, etc. It will be on its own separate, filtered power from the rest of the controller, and will communicate with the rest of the controller in an electrically isolated manner. The pump comes online as soon as the kart is switched on, and the rest of the controller won't operate unless pressure is good. This controller has a "dead-man's pedal" to the rest of the system. It will run the oil pump via PWM speed control with one of the (white) motor driver IC's toward the edge of the board.
The second microcontroller will serve as a tachometer, taking pulses from an omron optical sensor and feeding the master controller engine speed, and driving a bar-graph LED display on the steering wheel.
The third, large microcontroller will be listening to both smaller controllers, as well as several sensors for access to engine speed, oil pressure, P2, T3, and T4 (via thermocouples and transducers) in order to sequence startup, running, and shutdown based on present engine state, control input, and a set of boundary conditions. This controller will also be in charge of fuel flow, via PWM speed control using the second motor driver IC. It will take input from either a twist-grip, or thumb-throttle with a potentiometer.
Of course, there will also be a gigantic emergency stop button controlling power to the non-critical side of the controller. (Oil pressure regulating controller will continue running)
The control firmware basically has five states:
Idle - Just hanging out waiting for a start command, default state if engine is cold. If any other state reaches an out-of-bounds condition and cannot correct it, and the engine is still cold, we return to idle. TR -I disagree with this title as it conflicts with common usage. My definition of idle is that the gas turbine is running without a load at minimum speed (rpm) to sustain operation. My term for this condition is STOPPED.
Heating - If a start is requested, but EGT is less than 800*F and oil temperature is less than 100*F, engage the starter motor and burn propane. A minimum heating period of 30 seconds is enforced to ensure ignition, starter engagement, and evaporator heating. TR – see HEATING while statement in the code
Starting - After the heating period is finished, begin stepping up fuel flow and starter speed by conditional "milestones" of engine speed. Disengage starter when above 22000 RPM, and abort if EGT is too high or any step takes too long. TR – see STARTING while statement in the code
Running - Pretty simple. Just monitor for out-of-bounds conditions and respond to requested throttle position. TR – see RUNNING while statement in the code
Cooling - If EGT is greater than 250*F or oil temperature is greater than 130*F, engage the starter and run cold air through. Otherwise, return to idle. If any state is aborted or stopped, and the engine is hot, it will return to cooling before idle. TR- see COOLDOWN in the code. This means that when the gas turbine is shut down by turning off the fuel valve the oil pump continues to run and the starter is engaged to reduce the EGT to less than 250 degrees F or the oil temperature is less than 130 degrees F.
We use a raspberry pi with a touchscreen and an Xbee wireless module to communicate with the FADEC on the kart. Just type "start" and it starts . Type anything else, and it returns to idle or cooling. The rest of the time we use this "telemetry station" to monitor telemetry packets transmitted by the FADEC in real-time. Its very handy. We never use hardware pin numbers at all in the software because they differ between different packages of the very same chip. The Arduino software uses virtual pin numbers for everything, including the analog pins which have two distinct numbering schemes, from zero (just for analogRead()), and A0..A7 (which are #defines for 14..21 in fact) which work with all pin-related calls. TR - I finally went to the Arduino forum for help. What the guys there seem to say is the each microcontroller chip assigns virtual pin numbers internally when it sees the hardware pin numbers in the code since not all boards have the same pin assignments. The code will not compile without a hardware (board) pin number assigned.
pins default to INPUT, so no need to set them as inputs. You can if you want to "declare" their use as inputs using pinMode() - it helps document your project in fact - but normally the #defines you use to give your symbolic names to the pins are enough for that
*/ #include <max6675.h> #include <Servo.h> // TR-Note that you can have PWM and Servo at the same time on the Arduino Mega. If you are using the Arduino UNO the use of Servo disables PWM. #define estopsig_pin 4 // TR-Emergency stop signal pin #define fuelpwmout_pin 44 // TR-Pulse Width Modulation digital output to fuel control pump #define FADECwhite_pin 5 // TR-Boolean digital output to follow startup ? #define FADECorange_pin 6 // TR-Boolean digital output to follow acceleration to idle? #define FADECgreen_pin 7 // TR-Boolean digital output to show oil pressure okay // TR-pin 8 is not assigned at present #define escsigout_pin 18 // TR-Starter servo interrupt pin. The Arduino interrupt pins available are 2 and 3. The Mega available interrupt pins are 2, 3, 18, 19, 20 and 21 #define startswled_pin 9 // TR-Not used in code? #define startswsig_pin 10 // TR-Not used in code? #define oilokay_pin 11 // TR-Where is this pin set? #define ignctl_pin 12 // TR-Turns ignitor on and off #define startfuelsol_pin 22 // TR-Start fuel solenoid? #define startengsol_pin 24 // TR-Engine starter solenoid pin #define genrlyctl_1_pin 26 // TR-Not used in code? #define genrlyctl_2_pin 28 // TR-Not used in code? #define throttlein_pin A6 // TR-analog input from throttle potentiometer Servo STARTER; //name servo //initialize max6675 thermocouple A #define AthermoDO A0 //TR-assigned pin #define AthermoCS A1 //TR-assigned pin #define AthermoCLK A2 //TR-assigned pin MAX6675 Athermocouple(AthermoCLK, AthermoCS, AthermoDO); //initialize max6675 thermocouple B #define BthermoDO A3 //TR-assigned pin #define BthermoCS A4 //TR-assigned pin #define BthermoCLK A5 //TR-assigned pin MAX6675 Bthermocouple(BthermoCLK, BthermoCS, BthermoDO); boolean oilokay = LOW; boolean requeststart = LOW; boolean wantstart = LOW; boolean wantrun = LOW; boolean oiltemp = LOW; boolean estop = LOW; boolean hot = LOW; boolean ignstate = LOW; const int ignhigh = 5; // duration of ignition dwell const int ignlow = 250; // ignition low period unsigned long lastigntime = 0; // ignition counter const int temptime = 250; // temperature sample interval unsigned long lasttemptime = 0; // temperature sample counter const int oilreadtime = 50; // oil pressure sample interval unsigned long lastoilreadtime = 0; // oil pressure sample counter const int tachreadtime = 50; // tachometer sample interval unsigned long lasttachreadtime = 0; // tachometer sample counter const int telemetrytime = 250; // telemetry transmission interval unsigned long lasttelemetrytime = 0; // telemetry transmission counter const int requesttime = 250; // start request polling interval unsigned long lastrequesttime = 0; // start request polling counter const int throttlereadtime = 50; // throttle read interval unsigned long lastthrottlereadtime = 0; // throttle read counter int throttlediff = 0; // Instantaneous difference between throttle input and fuel speed int idle = 90; // Default idle setting const int idlesettime = 1000; // idle adjust interval - should be high, on the order of seconds, for stable idle unsigned long lastidlesettime = 0; // idle adjust counter unsigned long preheattimer = 0; // variable for timing preheat unsigned long starttimer = 0; // variable for timing start sequence unsigned long runtimer = 0; // variable for timing events while running unsigned long cooltimer = 0; // variable for timing cooldown cycle byte oilpsi = 0; //1 PSI precision to max of 100 PSI long RPM = 0; //max ~80,000 RPM, precision = whatever necessary, currently 312 RPM per step int throttlesetting = 0; int fuelspeed = 0; int startspeed = 0; int startswLED_val = 0; boolean FADECwhiteLED_val = LOW; boolean FADECorangeLED_val = LOW; boolean FADECgreenLED_val = LOW; //TESTING ONLY boolean NOchill = LOW; //TESTING ONLY //temperature initialization - inconsequential as of current version int temperatureoil = 0; int temperatureegt = 0; int ambienttempoil = 0; int ambienttempegt = 0; byte state = 0; void setup() { pinMode(FADECwhite_pin,OUTPUT); pinMode(FADECorange_pin,OUTPUT); pinMode(FADECgreen_pin,OUTPUT); pinMode(escsigout_pin, OUTPUT); pinMode(startswled_pin, OUTPUT); pinMode(startswsig_pin, INPUT); pinMode(oilokay_pin, INPUT); pinMode(ignctl_pin, OUTPUT); pinMode(startfuelsol_pin, OUTPUT); pinMode(startengsol_pin, OUTPUT); // Set engine starter solenoid pin as output pinMode(genrlyctl_1_pin, OUTPUT); pinMode(genrlyctl_2_pin, OUTPUT); pinMode(throttlein_pin, INPUT); // read fuel pump speed pinMode(fuelpwmout_pin, OUTPUT); // change fuel pump speed? digitalWrite(FADECgreen_pin,LOW); STARTER.attach(escsigout_pin); // Starter interrupt STARTER.write(85); // TR-The number of 85 indicates a continuously rotating servo motor with the speed set at 0 when the motor is full speed in one direction and 180 if rotation is in the opposite direction. The speed is 90 when the motor is at rest. Serial3.begin(9600); Serial2.begin(9600); Serial1.begin(9600); Serial.begin(9600); delay(500); Serial.print("CONNECTED\n"); ambienttempoil = int(Athermocouple.readFarenheit()); ambienttempegt = int(Bthermocouple.readFarenheit()); if((ambienttempoil || ambienttempegt) > 110) { ambienttempoil = 80; ambienttempegt = 80; } delay(5000); } void loop() // TR-Start FADEC control program { //------------------------------------------------------------------- Default startup state - wait for oil pressure estop = digitalRead(estopsig_pin); // check emergency stop status oilokay = digitalRead(oilokay_pin); // check oil status wantstart = LOW; requeststart = LOW; wantrun = LOW; digitalWrite(startengsol_pin, LOW); // Turn off starter solenoid digitalWrite(startfuelsol_pin, LOW); analogWrite(fuelpwmout_pin, 0); STARTER.write(84); request(); oilread(); tachread(); temp(); telemetry(); throttleread(); state = 0; preheattimer = millis(); //--------------------------------------------------------------------------------------------------------- while // HEATING - this loop runs when a start requested. It runs for at least 30s, and until oil and combustor are hot. ((oilokay == HIGH) // TR-first right facing (RF) parenthesis starts multiline comparison statement. && (requeststart == HIGH) // TR-&& is the logical comparison operator that evaluates true if the conditions on both sides of the && are true. Also, the == is the Equal to operator. /* TR-This while comparison state was a source of confusion as the newlines are in somewhat unusual places since the statement is so long. Newlines are ignored as far as the compiler syntax is considered, so this is the same as:
while ( (oilokay == HIGH) && (requeststart == LOW)
Since our statement includes four comparisons the closing parenthesis in an unexpected place.
*/ && (wantstart == LOW) && (wantrun == LOW) && (estop == HIGH)) // 2nd left facing (LF) parenthesis ends comparison statement { // TR-Start HEATING while - left facing (LF) french brace #1 estop = digitalRead(estopsig_pin); // Check for emergency stop signal oilokay = digitalRead(oilokay_pin); // Check oil pressure status digitalWrite(startengsol_pin, HIGH); // Engage starter solenoid oilread(); tachread(); temp(); telemetry(); state = 1; // State? analogWrite(fuelpwmout_pin, 0); if(temperatureegt < 800) // Run ignition for low EGT { // TR-LF french brace #2 ignition(); // Ignition function } // TR-RF french brace #1 if(millis()-preheattimer < 300) { // TR-LF french brace #3 STARTER.write(82); } // TR-RF french brace #2 else if(millis()-preheattimer >= 300 && millis()-preheattimer < 5000) { // TR-LF french brace #4 STARTER.write(75); } // TR-RF french brace #3 else if(millis()-preheattimer >= 5000 && millis()-preheattimer < 300000) { // TR-LF french brace #5 digitalWrite(startfuelsol_pin, HIGH); // Engage fuel solenoid to provide fuel to engine } // TR-RF french brace #4 else // Timeout - Return to idle (running on butane?) { // TR-LF french brace #6 wantstart = LOW; requeststart = LOW; wantrun = LOW; cooltimer = millis(); digitalWrite(startengsol_pin, LOW); // Turn off starter solenoid STARTER.write(84); } // TR-RF french brace #5 if(temperatureegt > 1400) // Overtemp - Return to idle { // TR-LF french brace #7 wantstart = LOW; requeststart = LOW; wantrun = LOW; cooltimer = millis(); digitalWrite(startengsol_pin, LOW); // Turn off starter solenoid STARTER.write(84); } // TR-RF french brace #6 if((temperatureegt > 750) && (oiltemp == HIGH) && ((millis()-preheattimer) > 30000)) // Proceed to start { // TR-LF french brace #8 requeststart = LOW; wantstart = HIGH; wantrun = LOW; starttimer = millis(); idle = 90; //Re-initialize idle value in case previous run idleset function set it too low (hot vs cold oil) } // TR-RF french brace #7 request(); } // TR-RF french brace #8 – end HEATING while //--------------------------------------------------------------------------------------------------------- while // STARTING ((oilokay == HIGH) && (requeststart == LOW) && (wantstart == HIGH) && (wantrun == LOW) && (estop == HIGH)) { estop = digitalRead(estopsig_pin); // Read emergency stop pin oilokay = digitalRead(oilokay_pin); // Read oil pressure okay pin oilread(); tachread(); temp(); telemetry(); state = 2; if(millis()-starttimer < 3000) { STARTER.write(45); analogWrite(fuelpwmout_pin, 60); } else if (millis()-starttimer >= 3000 && millis()-starttimer < 15000 && RPM < 15000) { digitalWrite(FADECorange_pin, HIGH); STARTER.write(30); analogWrite(fuelpwmout_pin, 75); } else if (millis()-starttimer < 15000 && RPM >= 15000 && RPM < 22000) { digitalWrite(FADECorange_pin, LOW); STARTER.write(25); analogWrite(fuelpwmout_pin, 85); } else if (millis()-starttimer < 20000 && RPM >= 22000 && RPM < 30000) { digitalWrite(FADECorange_pin, HIGH); digitalWrite(startengsol_pin, LOW); // Turn off starter solenoid STARTER.write(85); analogWrite(fuelpwmout_pin, 95); } else if (millis()-starttimer < 20000 && RPM >= 30000) // Started - Proceed to run { digitalWrite(FADECorange_pin, LOW); digitalWrite(startengsol_pin, LOW); // Turn off starter solenoid STARTER.write(85); analogWrite(fuelpwmout_pin, 100); wantstart = LOW; requeststart = LOW; wantrun = HIGH; runtimer = millis(); } else // Timeout - Return to idle or cooldown { wantstart = LOW; requeststart = LOW; wantrun = LOW; cooltimer = millis(); digitalWrite(startengsol_pin, LOW); // Turn off starter solenoid STARTER.write(84); } if((temperatureegt > 1500) || (temperatureegt < 500)) // Overtemp - Return to idle or cooldown { wantstart = LOW; requeststart = LOW; wantrun = LOW; cooltimer = millis(); digitalWrite(startengsol_pin, LOW); // Turn off starter solenoid STARTER.write(84); } request(); } // end while STARTING //--------------------------------------------------------------------------------------------------------- while // RUNNING ((oilokay == HIGH) && (requeststart == LOW) && (wantstart == LOW) && (wantrun == HIGH) && (estop == HIGH) && (RPM > 25000)) { estop = digitalRead(estopsig_pin); oilokay = digitalRead(oilokay_pin); //Check oil pressure status digitalWrite(startengsol_pin, LOW); // Turn off starter solenoid digitalWrite(startfuelsol_pin, LOW); STARTER.write(85); throttleread(); oilread(); tachread(); temp(); telemetry(); state = 3; if(millis()-runtimer < 600000) { if(fuelspeed < 20) { idleset(); analogWrite(fuelpwmout_pin, idle); } else if(fuelspeed >= 20) { analogWrite(fuelpwmout_pin, map(fuelspeed, 20, 255, idle, 255)); } } else { wantstart = LOW; requeststart = LOW; wantrun = LOW; cooltimer = millis(); digitalWrite(startengsol_pin, LOW); // Turn off starter solenoid digitalWrite(startfuelsol_pin, LOW); analogWrite(fuelpwmout_pin, 0); STARTER.write(84); } if((temperatureegt > 1500) || (temperatureegt < 600)) // Overtemp/undertemp - Return to passive or cooldown { wantstart = LOW; requeststart = LOW; wantrun = LOW; cooltimer = millis(); digitalWrite(startengsol_pin, LOW); // Turn off starter solenoid digitalWrite(startfuelsol_pin, LOW); analogWrite(fuelpwmout_pin, 0); STARTER.write(84); } request(); } // end while RUNNING //--------------------------------------------------------------------------------------------------------- while // COOLDOWN ((oilokay == HIGH) && (requeststart == LOW) && (wantstart == LOW) && (wantrun == LOW) && (estop == HIGH) && (hot == HIGH) && (NOchill == LOW)) { estop = digitalRead(estopsig_pin); oilokay = digitalRead(oilokay_pin); request(); oilread(); tachread(); temp(); telemetry(); analogWrite(fuelpwmout_pin, 0); digitalWrite(startfuelsol_pin, LOW); state = 4; if(RPM < 2000) { if(millis()-cooltimer > 10000 && millis()-cooltimer < 10300) { digitalWrite(startengsol_pin, HIGH); // Engage starter solenoid STARTER.write(82); } else if(millis()-cooltimer >= 10300 && millis()-cooltimer < 300000) { digitalWrite(startengsol_pin, HIGH); // Engage starter solenoid STARTER.write(75); } } } } // end while COOLDOWN //---------------------------------------------------------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------------------------------------------------------------
// TR start of function definitions for the code void request() // TR – start of request() function definition { if(millis() - lastrequesttime >= requesttime) { if( Serial.available()>0) { if(Serial.readString() == "start") { requeststart = HIGH; // TR – I think this is where the word “start” is entered on the Xbee touch screen to start the gas turbine } else { requeststart = LOW; wantstart = LOW; wantrun = LOW; cooltimer = millis(); digitalWrite(startengsol_pin, LOW); // Turn off starter solenoid digitalWrite(startfuelsol_pin, LOW); analogWrite(fuelpwmout_pin, 0); digitalWrite(ignctl_pin, LOW); STARTER.write(84); } Serial.readString(); Serial.readString(); } lastrequesttime = millis(); } } // TR- end of request() function void idleset() // this function maintains idle speed at ~30,000 RPM. This accommodates for oil temperature fluctuations and different fuels. TR – start of idleset() function definition { if(((millis() - lastidlesettime) >= idlesettime) && (fuelspeed < 20)) //adjust idle speed only when in idle state and at the specified interval { if((idle >= 105) || (idle <= 65)) //if idle setting unreasonably high or low, step it back to default { idle = 90; } else if(RPM < 30000) //if idle is low, increment idle { idle++; } else if(RPM >= 30000) //if idle is high, decrement idle { idle--; } lastidlesettime = millis(); } } // TR - end of idleset() function definition void ignition() // TR – start of ignition() function definition { if(ignstate == LOW) { if(millis() - lastigntime >= ignlow) { digitalWrite(ignctl_pin, HIGH); ignstate = HIGH; lastigntime = millis(); } } else { if(millis() - lastigntime >= ignhigh) { digitalWrite(ignctl_pin, LOW); ignstate = LOW; lastigntime = millis(); } } } // TR - end of ignition() function definition void temp() // TR – start of temp() function definition { if(millis()- lasttemptime >= temptime) { temperatureoil = Athermocouple.readFarenheit(); temperatureegt = Bthermocouple.readFarenheit(); if(temperatureoil > 100) { oiltemp = HIGH; } else if(temperatureoil < 95) { oiltemp = LOW; } if(temperatureegt > 350) { // digitalWrite(FADECorange_pin, HIGH); hot = HIGH; } else if(temperatureegt < 250) { // digitalWrite(FADECorange_pin, LOW); hot = LOW; } lasttemptime = millis(); } } // TR- end of temp() function void oilread() // TR – start of oilread() function definition { if(millis() - lastoilreadtime >= oilreadtime) { if( Serial3.available() > 0 ) // read oil pressure { oilpsi = Serial3.read(); } lastoilreadtime = millis(); } if(oilokay == HIGH) // Set green LED according to "oil pressure okay/not okay" { digitalWrite(FADECgreen_pin, HIGH); } else { digitalWrite(FADECgreen_pin, LOW); } } // TR- end of oilread() function void throttleread() // TR – start of throttleread() function definition { if(millis()-lastthrottlereadtime >= throttlereadtime) //If it is time to read the throttle (50ms interval - THIS INTERVAL AFFECTS THROTTLE SLEW RATE LIMIT) { throttlesetting = (analogRead(throttlein_pin)/4); //Compute and rescale 10-bit throttle in to 8-bit value throttlediff = throttlesetting - fuelspeed; //Calculate difference between desired throttle setting and current fuel setting if(throttlesetting < 15) //Prevent jitter-related bugs by defining thresholds for "high" and "low" potentiometer settings { fuelspeed = 0; } else if(throttlesetting > 245) { fuelspeed = 255; } else if(throttlediff > 0) //If throttle setting is higher than fuel setting { if(abs(throttlediff) < 20) //and the difference is less than 20 { fuelspeed += ((abs(throttlediff))/3); //Increment fuel pump speed proportionally (max rate of 6 units/function call) } else { fuelspeed += 7; //Otherwise obey throttle-up slew rate limit (> 1.5sec from idle to full throttle) } } else if(throttlediff < 0) //If throttle setting is lower than fuel setting { if(abs(throttlediff) < 20) //and the difference is less than 20 { fuelspeed -= ((abs(throttlediff))/5); //Decrement fuel pump speed proportionally (max rate of 4 units/function call) } else { fuelspeed -= 3; //Otherwise obey throttle-down slew rate limit (> 4sec from full throttle to idle) } } lastthrottlereadtime = millis(); //Reset throttleread function counter } } // TR- end of throttleread() function void tachread() // TR – start of tachread() function definition { if(millis() - lasttachreadtime >= tachreadtime) { if( Serial2.available()>0) { RPM = (Serial2.read()); // RPM = (int)RPM1*256+(int)RPM2; RPM = (RPM*312); } lasttachreadtime = millis(); } } // TR- end of request() function void telemetry() // TR – start of telemetry() function definition { if(millis() - lasttelemetrytime >= telemetrytime) { digitalWrite(FADECwhite_pin, HIGH); switch(state) { case 0: Serial.println("PASS"); break; case 1: Serial.println("HEAT"); break; case 2: Serial.println("START"); break; case 3: Serial.println("RUN"); break; case 4: Serial.println("COOL"); break; } Serial.println(temperatureoil); Serial.println((int)oilpsi); Serial.println(temperatureegt); Serial.println(RPM); Serial.println(fuelspeed); Serial.println("#"); Serial1.write((byte)RPM); digitalWrite(FADECwhite_pin, LOW); lasttelemetrytime = millis(); } } // TR- end of telemetry() function
|
|
|
Post by turboron on Mar 30, 2018 14:48:26 GMT -5
I wanted to post my latest thinking on the Agriculture FADEC control approach. The key is I found a breadboard with a Molex ribbon cable connector, ribbon cables and a Molex connector to screw terminal adapter. I plan on using two of each component to create the control. The screw terminal adapters will be mounted on the DIY gas turbine. The control will be connect by the use on the ribbon cables when it is under test. This approach will allow be to go back and forth between the gas turbine and the work bench. Images of the components are below:
Sorry, I can not post the images for some reason. I am selecting BBCode and the images are JPEG. Any ideas?
|
|