Skip to content

Commit

Permalink
Update calibaration
Browse files Browse the repository at this point in the history
Added aux warning screen, automatic switching
  • Loading branch information
tomcourt authored and tomcourt committed Jul 22, 2017
1 parent 81efe23 commit 70a126b
Show file tree
Hide file tree
Showing 9 changed files with 497 additions and 273 deletions.
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

## General Description

Enguino (a portmanteau of engine and Arduino) is an inexpensive _(about $100)_, lightweight _(2 ounces w/o case or cables)_, small _(about the size of cigarette pack)_, [open source] engine monitor for experimental aircraft. The engine monitor is displayed on a tablet as a web page. Here is an [example] of a typical Enguino display. The tablet can be an iPad, an Android or any other tablet that includes a modern web browser and has wifi.
Enguino (a portmanteau of engine and Arduino) is an inexpensive _(about $100)_, lightweight _(2 ounces w/o case or cables)_, small _(about the size of a bar of bath soap)_, [open source] engine monitor for experimental aircraft. The engine monitor is displayed on a tablet as a web page. Here is an [example] of a typical Enguino display. The tablet can be an iPad, an Android or any other tablet that includes a modern web browser and has wifi.

Enguino is intended to work with the [Stratux] ADS-B receiver which is also open source. The Stratux acts as a Wifi router for Enguino. For airplanes not equipped with a Stratux it is still possible to create an Enguino system with slightly different hardware and a small change to the configuration.

The hardware consists of a tiny single board computer called an [Arduino]. This board is similar to the Raspberry Pi used in the Stratux, although the Arduino has a much simpler computer on it. Despite being a simple computer, the Arduino is much better at connecting to the real world.

Because Enguino is experimental, it is recommended that you don't replace your legally required gauges with Enguino until you've confirmed yourself that its readings are accurate and reliable. Also tablets and and wifi communication alone shouldn't be counted upon for critical flight information. Furthermore you may not have a dedicated tablet for Enguino. For these reasons an auxiliary display is an optional part of Enguino. It consists of a simple LED display that normally displays tachometer and fuel gauges but can also display engine alerts and warnings.
Because Enguino is experimental, it is recommended that you don't replace your legally required gauges with Enguino until you've confirmed to yourself that its readings are accurate and reliable. Also tablets and and wifi communication alone shouldn't be counted upon for critical flight information. Furthermore you may not have a dedicated tablet for Enguino. For these reasons an auxiliary display is an optional part of Enguino. It consists of a simple LED display that normally displays tachometer and fuel gauges but can also display engine alerts and warnings.

## Hardware

Expand All @@ -32,6 +32,7 @@ Due to hardware limitations all calculations are done using integers. A decimal

The engine sensors themselves are fairly generic. The default configuration uses Vans Aircraft engine sensors. At this time the only major non-supported sensor type is millivolt sensors such as an amp-meter, although this could be easily added by using 2 analog inputs in 'differential mode' or another chip.

Good calibration data for sensors can be hard to find. One way to determine configurations for sensors is to disconnect a sensor from its gauge and replace it with a *resistance decade box* (assuming the sensor is resistive). The *calibration.xls* spreadsheet can then be used to find the configuration settings.

### Layout
During design and testing of the layout it may be helpful to connect the Enguino to your local network instead of the Stratux. You may need to update the IP address in the Enguino.ino file. If you do do so, remember to change it back after finalizing the layout. To see values on the gauges while testing, uncomment out the line `#define RANDOM_SENSORS 1`
Expand All @@ -46,8 +47,8 @@ The Stratux is configured to route network traffic between the wired ethernet to
* Boot the Stratux. For first boot, wait 3 minutes, for rebooting wait 30 seconds.
* Either connect a monitor and keyboard to the Rapberry Pi and login with un: `pi`, pw: `raspberry` then skip ahead in these instructions to sudo nano...
* Or connect to the Stratux wifi network (this will need to be repeated when rebooting)
* On the Mac, start terminal. On a PC, run PuTTY.
* Once connected type `ssh [email protected]`
* On the Mac, start terminal. On a Windows PC, run PuTTY.
* To connected type `ssh [email protected]`
* You may get a message "Are you sure you want to continue connecting (yes/no)?" `yes`
* Password: `raspberry`

Expand Down Expand Up @@ -112,7 +113,7 @@ The supply is rated for 1000 ma. The Leonardo uses 82 mA (confirmed by testing).

The SD card on the Leonardo can not be used with the thermocouple board attached as they both use pin D4. The thermocouple board also interferes with 4 of the analog inputs. The Leonardo also interferes with one of the analog inputs.

The D6 and D12 pins support counters which would be useful for the tach and fuel flow. But the thermocouple board also conflicts with this. Interrupt pins will be used instead. With the tach, assume 2 pulses per revolution at 2700RPM the tach will max out at 90/cps so as long as IRQ disable time is <11ms no error should be expected. For the fuel flow with a k-factor of 68,000 and 13GPH it will max out at 250/cps so IRQ disable time must be <4ms.
The D6 and D12 pins support counters which would be useful for the tach and fuel flow. But the thermocouple board also conflicts with this. Interrupt pins will be used instead. With the tach, assume 2 pulses per revolution at 2700 RPM the tach will max out at 90/cps so as long as IRQ disable time is <11ms no error should be expected. For the fuel flow with a k-factor of 68,000 and 13GPH it will max out at 250/cps so IRQ disable time must be <4ms.

### Software

Expand All @@ -127,7 +128,7 @@ The main webpage has a timer running in Javascript on the tablet that invokes a

The sensor system is fairly generic but currently only Van's Aircraft engine sensors have predefined configurations. The resistive sensors will have a 240 ohm(1%) pull up to +5V. This will require up to 18 ma per sensor, or for the typical 5 sensors (fuel x 2, oil-p, oil-t, fuel-p) 90 ma total. This provides a good compromise between power usage, heat and loss of resolution. This provides 9 bits of resolution. To limit resistor heating to reasonable levels, .5 watt resistors should be used. Resistor temp. rise should be no more than 100 deg. C in free air. A resistance significantly out of range will mark the sensor inoperative. To convert from ADC units to ohms use this formula `ohms = 240 * (adc / (1024-adc))`, this will require long divided by long division unfortunately or a lookup/interpolation table.

Many of the sensors are 240-33.5 ohm sensors similar to Stewart Warner. These usually scale linearly by resistance. For those that don't, a custom interpolation table may be required. The oil temperature sensor (for a Rochester 3080-37) as follows (degF=ohms): 100=497, 150=179, 200=72, 250=34. This is a thermistor. Westach has different values: http:https://www.acro.co.uk/html/westach_calibration.htm Using a Steinhar-Hart calculator the conversion formula becomes `degrees Kelvin = 1 / (0.0016207535760566691 + 0.0002609330007304247 * log(R) + -1.0278556187396396e-7 * log(R)^3)`. An interpolation table is used to convert this.
Many of the sensors are 240-33.5 ohm sensors similar to Stewart Warner. These usually scale linearly by resistance. For those that don't, a custom interpolation table may be required. The oil temperature sensor is also resistive (its a *thermistor*) but it has a larger range. Using a Steinhar-Hart calculator the conversion formula becomes `degrees Kelvin = 1 / (0.0016207535760566691 + 0.0002609330007304247 * log(R) + -1.0278556187396396e-7 * log(R)^3)`. An interpolation table is used to convert this.

For resistive sensors still attached to the gauge, the gauge itself provides the pull up resistance and voltage. For Vans Aircraft engine instruments the pull up is 5 volts and the resistor is about 227 ohms(measured externally, internally the resistor appears to be 240 ohms, 5%). The pin can be directly connected if the voltage can't exceed Vcc by more than .5v. Otherwise a 15K series resistor could be attached to help isolate the pin.

Expand Down Expand Up @@ -204,8 +205,8 @@ To prevent having to re-acknowledge warnings there would be both temporal and ra
### Future stuff
* Record engine data by having the Engiuno pipe text to a port on the Stratux. The startup script on the stratux starts netcat (nc) in the background to record the text to a file. The script would also truncate the file at on powerup to limit its growth.
* It may be possible to support 2 (or maybe more) thermocouples without the thermocouple multiplexer shield by using the differential mode ADC, 40x gain and a CJC sensor(Analog TMP36). Only 8 bits are usable with 40x, the noisy lower bits help with oversampling though. 488 uV per count works out to 21.5 deg. F resolution with a K type thermocouple. The 2.56 volt internal reference would double the resolution and oversampling could probably quadruple it (16x oversample). ADC0 and ADC1 are the negative side, any other ADC pin may be positive. With a filtering cap (10nF) several thermocouples could share a pin. The internal ATMEGA temperature sensor needs both offset and gain calibration, a 10 deg-C rise is typical as well, 2 point calibration may be much to expect for users. **TBD** - move the voltage divider sensor to ADC5 to allow future use of thermocouples.
* A custom shield might be helpful particularly if it were populated. Jumpers would select resistors and maybe filter caps. This would eliminate most to all of the soldering involved. A 4 bit latch on the thermocouple mux would free up 4 more analog pins on the Leanardo.
* A custom aux display board would also help. A single LED drive chip could be used as one chip can support 8 LED digits, one display on the high 8 rows, the second on the low 8 on rows, even numbered columns. A bright master caution/warning LED would be easy (cathode would have skottky diodes to odd numbered columns so lit 50% of the time). And a smaller 7 segment LED module could be used to allow fitting the display in a 2.5" hole.
* A custom shield might be helpful particularly if it were populated. Jumpers would select resistors and maybe filter caps. This would eliminate most to all of the soldering involved. A 4 bit shift register on the thermocouple mux would free up 4 more analog pins on the Leanardo.
* A custom aux display board would also help. A single LED drive chip could be used as one chip can support 8 LED digits, one display on the high 8 rows, the second on the low 8 on rows, even numbered columns. A bright master caution/warning LED would be easy using the empty rows. And a smaller 7 segment LED modules could be used to allow fitting the display in a 2.25" hole. The switch could be a long post pushbutton on the board that would go through a small hole on the display.
* The Arduino Yun would support airplanes lacking a Stratux. The code would need to use the 'bridge' objects instead of the ethernet objects. Use #ifdef AVR_YUN to flex the code.
* Themes - a dark theme could be created easily enough by adjusting the styles. A larger text theme for the gauges would involve more defines and stringizing them for the SVG.
* Warning lights instead of auxiliary display? A board with 4 caution/warning LEDs (red/green common cathode [bicolor LED]). Turning red and green on produces yellow. Alternatively use a module like the [BOB-13884] to provide 3 RGB LED's.
Expand Down
69 changes: 40 additions & 29 deletions enguino/config.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
// Uncommenting the following line shows a box around each instrumment and around the viewable area of the page. Use to help arrange gauges.
// #define BOUNDING_BOX

// !!! Add conditional code to support a single fuel tank, find all instances of fuelS
#define DUAL_FUEL_TANK 1

#define TACH_DIVIDER 4

// Exceed any of these and engine will be considered 'running'. Hobbs time will accumulate and engine alerts will appear. Setting to 0 will ignore that sensor
#define RUN_VOLT 130
#define RUN_OILP 10
#define RUN_TACH 200

const char *green = "green";
const char *yellow = "yellow";
const char *red = "red";
Expand All @@ -11,6 +19,7 @@ const char *red = "red";

#define SCALE(factor) (int)((factor)*(1<<divisor) + 0.5) // Converts a floating point factor to integer
#define GRNG(range) SCALE(1000.0/(range)) // Used for gfactor, given range returns gfactor that will result in 0-1000
#define GARNG(range) SCALE(1024.0/(range)) // Used for gfactor, given range returns gfactor that will result in 0-1000
#define GMIN(low) (int)(-((low) + 0.5))
#define ADCtoV (5.0/1024.0) // multiply this by adc input to get DC volts
#define toV (40 * ADCtoV) // 1:4 voltage divider, V/10 = adc*toV
Expand All @@ -28,6 +37,7 @@ const char *red = "red";
// Some numeric values are multipled by 10 and then have a decimal point added when displayed.
// SCALE(1.) returns the raw values (ADC, RPM's). SCALE(range/full_scale) returns a value from 0 to range.
// The gauge pointers vary from 0 to 1000. Use GMIN() and GRNG to set the graphs b and m values based on lowest input and input range (hi-low) respectively.
// Manifold pressure sensor = P(inch) = V(full) * 32.811 + 3.117 or V = (P-3.117)/32.811

// sensor-type range
// -------------- --------
Expand All @@ -42,16 +52,16 @@ const char *red = "red";
// st_tachometer
// st_fuel_flow

// sensor-type, pin, decimal, voffset, vfactor, goffset, gfactor, lowAlarm, lowAlert, highAlert, highAlarm
const Sensor vtS = { st_volts, 0, 1, 0, SCALE(200/1024.0), GMIN(100*fromV), GRNG(60*fromV), 110, 130, 9999, 160 };
const Sensor opS = { st_volts, 1, 0, RVoff, RVRNG(100), RVoff, RVSCALE(1.), 25, 55, 9999, 95 };
const Sensor otS = { st_thermistorF, 2, 0, 0, SCALE(.1), GMIN(50*10), GRNG(200*10), -1, 140, 9999, 250 };
const Sensor fpS = { st_volts, 3, 1, RVoff, RVRNG(150), RVoff, RVSCALE(1.5), 5, 20, 60, 80 };
const Sensor flS = { st_volts, 4, 1, RVoff, RVRNG(160), RVoff, RVSCALE(1.), 25, 50, 9999, 999 };
const Sensor taS = { st_tachometer, 15, 0, 0, SCALE(1.), 0, GRNG(3000), -1, 500, 9999, 2700 };
const Sensor maS = { st_volts, -1, 1, 100, 2000, 0, SCALE(1.), -1, -1, 9999, 9999 };
const Sensor chS = { st_k_type_tcF, 16, 0, 0, SCALE(.25), GMIN(100*4), GRNG(400*4), -1, 150, 400, 500 };
const Sensor egS = { st_k_type_tcF, 20, 0, 0, SCALE(.25), GMIN(1000*4), GRNG(600*4), -1, -1, 9999, 9999 };
// sensor-type, pin, decimal, voffset, vfactor, goffset, gfactor, lowAlarm, lowAlert, highAlert, highAlarm
const Sensor voltS = { st_volts, 0, 1, 0, SCALE(200/1024.0), GMIN(100*fromV), GRNG(60*fromV), 110, 130, 9999, 160 };
const Sensor oilpS = { st_volts, 1, 0, RVoff, RVRNG(100), RVoff, RVSCALE(1.), 25, 55, 9999, 95 };
const Sensor oiltS = { st_thermistorF, 2, 0, 0, SCALE(.1), GMIN(50*10), GRNG(200*10), -1, 140, 9999, 250 };
const Sensor fuelpS = { st_volts, 3, 1, RVoff, RVRNG(150), RVoff, RVSCALE(1.5), 5, 20, 60, 80 };
const Sensor fuellS = { st_volts, 4, 1, RVoff, RVRNG(160), RVoff, RVSCALE(1.), 25, 50, 9999, 999 };
const Sensor tachS = { st_tachometer, 15, 0, 0, SCALE(1.), 0, GRNG(3000), -1, 500, 9999, 2700 };
const Sensor mapS = { st_volts, -1, 1, 31,SCALE(328.11/1024), GMIN(.21*1024), GARNG(25/32.811), -1, -1, 9999, 9999 };
const Sensor chtS = { st_k_type_tcF, 16, 0, 0, SCALE(.25), GMIN(100*4), GRNG(400*4), -1, 150, 400, 500 };
const Sensor egtS = { st_k_type_tcF, 20, 0, 0, SCALE(.25), GMIN(1000*4), GRNG(600*4), -1, -1, 9999, 9999 };

// Labels
// ------
Expand Down Expand Up @@ -98,28 +108,29 @@ int chRP[] = { 1000, 6000, 7940, 8000 };
#define bank 3500 // bank of misc vertical gauges
const Gauge gauges[] = {
// x, y, style, label1, label2, units, labVal, labPt, num, regClr, regPt, num, sensor
{bank+0, 0, gs_vert, "OIL", "PRES", "psi", opLV, opLP, N(opLV), opRC, opRP, N(opRC), &opS},
{bank+1750, 0, gs_vert, "OIL", "TEMP", "&deg;F", otLV, otLP, N(otLV), otRC, otRP, N(otRC), &otS},
{bank+3500, 0, gs_vert, "", "VOLT", "volt", vtLV, vtLP, N(vtLV), vtRC, vtRP, N(vtRC), &vtS},
{bank+5250, 0, gs_vert, "FUEL", "PRES", "psi", fpLV, fpLP, N(fpLV), fpRC, fpRP, N(fpRC), &fpS},
{bank+7000, 0, gs_pair, "FUEL", "", "gal", flLV, flLP, N(flLV), flRC, flRP, N(flRC), &flS},
{100, 0, gs_round, "TACH", "", "rpm", 0, 0, 0, taRC, taRP, N(taRC), &taS},
{100, 3200, gs_round, "MP", "", "in-hg", 0, 0, 0, maRC, maRP, N(maRC), &maS},
{2950, 6150, gs_horiz, "CHT", "", "", chLV, chLP, N(chLV), chRC, chRP, N(chRC), &chS},
{2950, 6150, gs_aux, "EGT", "", "", egLV, egLP, N(egLV), 0, 0, 0, &egS},
{bank+0, 0, gs_vert, "OIL", "PRES", "psi", opLV, opLP, N(opLV), opRC, opRP, N(opRC), &oilpS},
{bank+1750, 0, gs_vert, "OIL", "TEMP", "&deg;F", otLV, otLP, N(otLV), otRC, otRP, N(otRC), &oiltS},
{bank+3500, 0, gs_vert, "", "VOLT", "volt", vtLV, vtLP, N(vtLV), vtRC, vtRP, N(vtRC), &voltS},
{bank+5250, 0, gs_vert, "FUEL", "PRES", "psi", fpLV, fpLP, N(fpLV), fpRC, fpRP, N(fpRC), &fuelpS},
{bank+7000, 0, gs_pair, "FUEL", "", "gal", flLV, flLP, N(flLV), flRC, flRP, N(flRC), &fuellS},
{100, 0, gs_round, "TACH", "", "rpm", 0, 0, 0, taRC, taRP, N(taRC), &tachS},
{100, 3200, gs_round, "MP", "", "in-hg", 0, 0, 0, maRC, maRP, N(maRC), &mapS},
{2950, 6150, gs_horiz, "CHT", "", "", chLV, chLP, N(chLV), chRC, chRP, N(chRC), &chtS},
{2950, 6150, gs_aux, "EGT", "", "", egLV, egLP, N(egLV), 0, 0, 0, &egtS},
{800, 6650, gs_infobox,"", "", "", 0, 0, 0, 0, 0, 0, 0}
};

// Guage layout for aux display
// Change layout to literal, sensor, sensor. Where a sensor value is displayed in the top line if literal is blank, otherwise sensor is used for alarm state of top line
#define XTEXT(a,b,c,d) { .literal = {LED_TEXT(a,b,c,d)} } // literals must have characters in one of the last 2 letters
#define XSENSOR(x) { .sensor = {&x, 0} }
const AuxDisplay auxdisplay[] = {
XTEXT( ,b,A,t), XSENSOR(vtS),
XSENSOR(taS), XSENSOR(flS),
XTEXT( , ,O,P), XSENSOR(opS),
XTEXT( , ,O,t), XSENSOR(otS),
XTEXT( , ,F,P), XSENSOR(fpS),
XTEXT( ,A,L,t), XSENSOR(vtS),
// Layout is literal, top-sensor, bottom-sensor. Sensor value is displayed in the top line if literal is blank, otherwise sensor is used for alarm state of top line
#define AUX(a,b,c,d,top,bottom) {{LED_TEXT(a,b,c,d)},{&top,&bottom}}
AuxDisplay auxDisplay[] = {
AUX(b,A,t, , voltS, voltS),
AUX( , , , , tachS, fuellS),
AUX(O,P, , , oilpS, oilpS),
AUX(O,t, , , oiltS, oiltS),
AUX(F,P, , , fuelpS, fuelpS),
AUX(A,L,t, , voltS, voltS),
};

#define AUX_STARTUP_PAGES 1

Loading

0 comments on commit 70a126b

Please sign in to comment.