Bit of a different topic to my last post, I'm currently building an 'afterburner' rc plane that'll be using an arduino pro micro to control the servo operating a fuel valve based on throttle input from a radio receiver.
As these things usually go, more and more got added on to the project and now it's sat in a nice little enclosure on a PCB next to a Rush F7 flight controller topped with 2 oled displays. It'll be up in the air hopefully so screens aren't useful except for ground testing. Looks cool though which is an excuse in itself right?.
At this point I've got the code pretty much ready for actual testing. I'll probably need to do something to scale the fuel servo output since I doubt it's going to be a linear increase that's needed as the rpm goes up, but that's for later.
The issue I've got is I can't run both screens at 128 x 64. I've got a graph on one screen (display1) and some status data on the other (display 2). At first the best I could get was 128 x 64 on one and 96 x 32 on the other, after removing a bunch of my initial Serial.print debugging lines I bumped that 2nd display up to 128 x 32 which now runs fine and stretches to fill the screen but could be better.
From some googling this seems to be due to the displays requiring 1024b of sram each at 128x64, with the pro micro having a total of 2560b available.
Are there any other libraries or differing methods to get both displays up to 128x64? Also any suggestions on bits where I've gone wrong or could write out better would be great, the only other arduino project I've done was a button box and that wasn't a pretty sketch either.
--
As a side note, once I arm the system and it starts processing throttle values to servo positions I can visibly see the runtime slows down probably 4-5x, is this a result of me using an incorrect or slow method? Or am I just asking too much of the system? The graph plots a new point once per loop which I can see takes much longer when armed vs disarmed.
for the #includes,
#include <OLED_SSD1306_Chart.h>
also contains all the Adafruit stuff for the other display so isn't added as a separate #include.
Memory Stats after uploading:
Sketch uses 25648 bytes (89%) of program storage space. Maximum is 28672 bytes.
Global variables use 807 bytes (31%) of dynamic memory, leaving 1753 bytes for local variables. Maximum is 2560 bytes.
Sketch:
//Servo Library
#include <Servo.h>
//display Stuff
#include <Arduino.h>
#include <Wire.h>
#include <OLED_SSD1306_Chart.h>
#define OLED_RESET -1
#define BAUDRATE 9600
#define SDA_PIN 2
#define SCL_PIN 3
OLED_SSD1306_Chart display1(128, 64, &Wire, OLED_RESET);
Adafruit_SSD1306 display2(128, 32, &Wire, OLED_RESET);
char actualThickness;
// RC Channels
int throttle = A6;
int safety = A2;
int ch;
int minValue;
int maxValue;
int defaultValue;
int rpm;
int KV = 2400;
int cellCount = 4;
int VCC = ((4.2 * cellCount));
// Fuel Management
Servo fuelValve;
int fuelServo = 10;
int fuelVal;
int throttleVal;
int throttlePercent;
int fuelFlow;
// Ignition
int arcPin = 8;
int flameSensor = A1;
int flameVal = 0;
int flameOut = 4;
int safetyVal = 0;
int armed = 0;
int idle = 80;
int purgeRequired = 1;
int ignitionRequired = 1;
int timeOut = 0;
int prevState = 0;
int i = 0;
//Channel Reading
int readChannel(int channelInput, int minLimit, int maxLimit, int defaultValue) {
int ch = pulseIn(channelInput, HIGH, 30000);
if (ch < 100) return defaultValue;
return map(ch, 1000, 2000, minLimit, maxLimit);
}
void setup() {
Serial.begin(BAUDRATE);
Wire.begin();
initialiseDisplay2();
delay(2000); // Boot Delay for FC
initialiseDisplay();
pinMode(throttle, INPUT);
pinMode(safety, INPUT);
pinMode(flameSensor, INPUT);;
fuelValve.attach(fuelServo);
}
void loop() {
genVals();
preFlight();
inFlight();
updateDisplay();
updateDisplay2();
}
void initialiseDisplay() {
display1.begin(SSD1306_SWITCHCAPVCC, 0x3c);
display1.clearDisplay();
display1.setChartCoordinates(0, 60);
display1.setChartWidthAndHeight(123, 40);
display1.setXIncrement(1);
display1.setYLimits(0, 100);
display1.setYLimitLabels("0", "100");
display1.setYLabelsVisible(true);
display1.setAxisDivisionsInc(8, 5);
display1.setPlotMode(SINGLE_PLOT_MODE);
actualThickness = NORMAL_LINE;
display1.setLineThickness(actualThickness);
display1.drawChart();
display1.setCursor(1, 0);
display1.setTextSize(2);
display1.println(F("FUEL FLOW"));
display1.display();
}
void initialiseDisplay2() {
display2.begin(SSD1306_SWITCHCAPVCC, 0x3d);
display2.clearDisplay();
display2.setTextSize(1);
display2.setTextColor(WHITE);
display2.setCursor(0, 0);
display2.println("FCM V1");
display2.println("DO NOT ARM");
display2.println("Booting up...");
display2.display();
}
void updateDisplay() {
if (!display1.updateChart(fuelFlow))
{
display1.clearDisplay();
if (actualThickness == NORMAL_LINE)
{
actualThickness = LIGHT_LINE;
}
else if (actualThickness == LIGHT_LINE)
{
actualThickness = NORMAL_LINE;
}
display1.setLineThickness(actualThickness);
display1.drawChart();
display1.setCursor(1, 0);
display1.setTextSize(2);
display1.println(F("FUEL FLOW"));
}
}
void updateDisplay2() {
display2.clearDisplay();
display2.setTextSize(1);
display2.setCursor(0, 0);
if (armed == 1) {
display2.print("ARMED");
}
else display2.print("DISARMED");
display2.setCursor(0, 8);
if (purgeRequired == 1) {
display2.print("Purge Required");
}
else display2.print("Purged");
display2.setCursor(0, 16);
if (ignitionRequired == 1) {
display2.print("Flameout");
}
else {
display2.print("Afterburner Active");
}
display2.setCursor(0, 24);
display2.print("RPM: ");
display2.setCursor(25, 24);
//display2.print(rpm);
display2.print(timeOut * 100); // Dummy rpm value
display2.display();
}
void genVals() {
throttleVal = readChannel(throttle, 0, 1000, 0);
safetyVal = readChannel(safety, 0, 1000, 0);
fuelVal = map(throttleVal, 0, 1000, 80, 50);
//fuelFlow = map(fuelVal, 80, 50, 0, 100);
fuelFlow = map(timeOut, 0, 180, 0, 100); // Dummy chart/rpm value
flameVal = analogRead(flameSensor);
throttlePercent = map(throttleVal, 0, 1000, 0, 100);
rpm = (((KV * VCC) / 100) * throttlePercent);
//Serial.print(rpmOut);
}
void preFlight() {
if (flameVal <= 1) {
ignitionRequired = 1;
}
if (safetyVal >= 100) {
armed = 1;
}
else if (safetyVal <= 100) {
armed = 0;
}
if (armed == 0) {
fuelValve.write(90);
digitalWrite(arcPin, LOW);
prevState = 0;
if (timeOut == 180) {
purgeRequired = 1;
timeOut = 0;
}
else timeOut++;
}
if (armed == 1) {
if (prevState == 0) {
prevState = 1;
}
if (purgeRequired == 1) {
purge();
purgeRequired = 0;
}
timeOut = 0;
}
}
void inFlight() {
if (ignitionRequired == 1 && armed == 1) {
ignite();
}
if (throttleVal <= 100 && armed == 1) {
fuelValve.write(idle);
}
if (throttleVal > 100 && armed == 1) {
fuelValve.write(fuelVal);
}
}
void purge() {
fuelValve.write(65);
delay(500);
fuelValve.write(90);
delay(500);
fuelValve.write(65);
delay(750);
fuelValve.write(90);
delay(1000);
}
void ignite() {
if (ignitionRequired = 1) {
for (int i = 0; i <= 4; i++) {
digitalWrite(arcPin, HIGH);
delay(100);
digitalWrite(arcPin, LOW);
delay(100);
}
}
}