From a9d61fb01df3a533c64f6507b841da28a7b54330 Mon Sep 17 00:00:00 2001 From: Josh Stewart Date: Wed, 24 Apr 2024 17:32:47 +1000 Subject: [PATCH] Initial work on compression waves feature Not all configuration options are working for this yet --- UI/assets/css/main.css | 2 + UI/index.html | 24 ++++++++++ UI/renderer.js | 20 ++++---- ardustim/ardustim/ardustim.h | 2 + ardustim/ardustim/ardustim.ino | 86 +++++++++++++++++++++++++--------- ardustim/ardustim/comms.cpp | 4 +- ardustim/ardustim/globals.h | 68 +++++++++++++++++++++++++-- ardustim/ardustim/storage.h | 3 ++ ardustim/ardustim/storage.ino | 25 ++++++++-- 9 files changed, 195 insertions(+), 39 deletions(-) diff --git a/UI/assets/css/main.css b/UI/assets/css/main.css index 7002140..c6b12b9 100644 --- a/UI/assets/css/main.css +++ b/UI/assets/css/main.css @@ -66,12 +66,14 @@ input::-moz-focus-inner { padding: 0; } +/* input, select, textarea { -moz-appearance: none; -webkit-appearance: none; -ms-appearance: none; appearance: none; } +*/ /* Colummn */ diff --git a/UI/index.html b/UI/index.html index cab8a8c..837624d 100644 --- a/UI/index.html +++ b/UI/index.html @@ -80,6 +80,30 @@ +
+
Enable compression:
+
+ +
+
+
+
Configuration:
+
+ +
+
+
+
Compression RPM:
+
+ +
+
+

diff --git a/UI/renderer.js b/UI/renderer.js index aa56ede..a06d17b 100644 --- a/UI/renderer.js +++ b/UI/renderer.js @@ -6,7 +6,7 @@ const ByteLengthParser = require('@serialport/parser-byte-length') const {ipcRenderer} = require("electron") var port = new serialport('/dev/tty-usbserial1', { autoOpen: false }) -var CONFIG_SIZE = 13; +var CONFIG_SIZE = 15; var onConnectIntervalConfig; var onConnectIntervalWheels; var isConnected=false; @@ -215,13 +215,16 @@ function requestConfig() function receiveConfig(data) { console.log("Received config: " + data); - console.log("Mode: " + data[0]); - - document.getElementById("rpmSelect").value = data[4]; - document.getElementById("fixedRPM").value = (((data[6] & 0xff) << 8) | (data[5] & 0xff)); - document.getElementById("rpmSweepMin").value = (((data[8] & 0xff) << 8) | (data[7] & 0xff)); - document.getElementById("rpmSweepMax").value = (((data[10] & 0xff) << 8) | (data[9] & 0xff)); - document.getElementById("rpmSweepSpeed").value = (((data[12] & 0xff) << 8) | (data[11] & 0xff)); + console.log("Mode: " + data[2]); + + document.getElementById("rpmSelect").value = data[2]; + document.getElementById("fixedRPM").value = (((data[4] & 0xff) << 8) | (data[3] & 0xff)); + document.getElementById("rpmSweepMin").value = (((data[6] & 0xff) << 8) | (data[5] & 0xff)); + document.getElementById("rpmSweepMax").value = (((data[8] & 0xff) << 8) | (data[7] & 0xff)); + document.getElementById("rpmSweepSpeed").value = (((data[10] & 0xff) << 8) | (data[9] & 0xff)); + document.getElementById("compressionEnable").value = data[11]; + document.getElementById("compressionMode").value = data[12]; + document.getElementById("compressionRPM").value = (((data[14] & 0xff) << 8) | (data[13] & 0xff)); port.unpipe(); @@ -623,6 +626,7 @@ window.onload = function () refreshSerialPorts(); redrawGears(toothPatterns[0]); window.location.hash = '#connect'; + //window.location.hash = '#live'; checkForUpdates(); //animateGauges(); diff --git a/ardustim/ardustim/ardustim.h b/ardustim/ardustim/ardustim.h index 97dc509..292a95d 100644 --- a/ardustim/ardustim/ardustim.h +++ b/ardustim/ardustim/ardustim.h @@ -29,6 +29,8 @@ void reset_new_OCR1A(uint32_t); uint8_t get_bitshift_from_prescaler(uint8_t *); void get_prescaler_bits(uint32_t *, uint8_t *, uint8_t *); void setRPM(uint16_t); +uint16_t calculateCompressionModifier(); +uint16_t calculateCurrentCrankAngle(); /* Prototypes */ diff --git a/ardustim/ardustim/ardustim.ino b/ardustim/ardustim/ardustim.ino index 101c6d1..b10bc09 100644 --- a/ardustim/ardustim/ardustim.ino +++ b/ardustim/ardustim/ardustim.ino @@ -29,6 +29,7 @@ #include struct configTable config; +struct status currentStatus; /* Sensistive stuff used in ISR's */ volatile uint16_t adc0; /* POT RPM */ @@ -39,12 +40,13 @@ volatile uint8_t analog_port = 0; volatile bool adc0_read_complete = false; volatile bool adc1_read_complete = false; volatile bool reset_prescaler = false; -volatile bool normal = true; volatile uint8_t output_invert_mask = 0x00; /* Don't invert anything */ volatile uint8_t prescaler_bits = 0; volatile uint8_t last_prescaler_bits = 0; volatile uint16_t new_OCR1A = 5000; /* sane default */ volatile uint16_t edge_counter = 0; +volatile uint32_t cycleStartTime = micros(); +volatile uint32_t cycleDuration = 0; uint32_t sweep_time_counter = 0; uint8_t sweep_direction = ASCENDING; @@ -213,7 +215,7 @@ void setup() { // Set ADSC in ADCSRA (0x7A) to start the ADC conversion ADCSRA |= B01000000; /* Make sure we are using the DEFAULT RPM on startup */ - reset_new_OCR1A(config.rpm); + reset_new_OCR1A(currentStatus.rpm); } // End setup @@ -252,22 +254,17 @@ ISR(ADC_vect){ /* Pumps the pattern out of flash to the port * The rate at which this runs is dependent on what OCR1A is set to */ -ISR(TIMER1_COMPA_vect) { +ISR(TIMER1_COMPA_vect) +{ /* This is VERY simple, just walk the array and wrap when we hit the limit */ PORTB = output_invert_mask ^ pgm_read_byte(&Wheels[config.wheel].edge_states_ptr[edge_counter]); /* Write it to the port */ - /* Normal direction overflow handling */ - if (normal) - { - edge_counter++; - if (edge_counter == Wheels[config.wheel].wheel_max_edges) { - edge_counter = 0; - } - } - else + + edge_counter++; + if (edge_counter == Wheels[config.wheel].wheel_max_edges) { - if (edge_counter == 0) - edge_counter = Wheels[config.wheel].wheel_max_edges; - edge_counter--; + edge_counter = 0; + cycleDuration = micros() - cycleStartTime; + cycleStartTime = micros(); } /* The tables are in flash so we need pgm_read_byte() */ @@ -301,18 +298,17 @@ void loop() } else if (config.mode == LINEAR_SWEPT_RPM) { - //if(millis() > (sweep_time_counter + sweep_interval_ms)) if(micros() > (sweep_time_counter + config.sweep_interval)) { sweep_time_counter = micros(); if(sweep_direction == ASCENDING) { - tmp_rpm = config.rpm + 1; + tmp_rpm = currentStatus.rpm + 1; if(tmp_rpm >= config.sweep_high_rpm) { sweep_direction = DESCENDING; } } else { - tmp_rpm = config.rpm - 1; + tmp_rpm = currentStatus.rpm - 1; if(tmp_rpm <= config.sweep_low_rpm) { sweep_direction = ASCENDING; } } } @@ -321,7 +317,55 @@ void loop() { tmp_rpm = config.fixed_rpm; } - setRPM(tmp_rpm); + currentStatus.base_rpm = tmp_rpm; + currentStatus.compressionModifier = calculateCompressionModifier(); + + if(currentStatus.compressionModifier >= currentStatus.base_rpm ) { currentStatus.compressionModifier = 0; } + setRPM( (currentStatus.base_rpm - currentStatus.compressionModifier) ); +} + +uint16_t calculateCompressionModifier() +{ + if( (currentStatus.rpm > config.compressionRPM) || (config.useCompression != true) ) { return 0; } + //if( currentStatus.base_rpm > 400 ) { return 0;} + + uint16_t crankAngle = calculateCurrentCrankAngle(); + uint16_t modAngle = crankAngle; + + uint16_t compressionModifier = 0; + switch(config.compressionType) + { + case COMPRESSION_TYPE_2CYL_4STROKE: + modAngle = modAngle / 2; + compressionModifier = pgm_read_byte(&sin_100_180[modAngle]); + case COMPRESSION_TYPE_4CYL_4STROKE: + modAngle = (crankAngle % 180) ; + compressionModifier = pgm_read_byte(&sin_100_180[modAngle]); + break; + case COMPRESSION_TYPE_6CYL_4STROKE: + modAngle = crankAngle % 120; + compressionModifier = pgm_read_byte(&sin_100_120[modAngle]); + break; + case COMPRESSION_TYPE_8CYL_4STROKE: + modAngle = crankAngle % 90; + compressionModifier = pgm_read_byte(&sin_100_90[modAngle]); + break; + } + + return compressionModifier; +} + +uint16_t calculateCurrentCrankAngle() +{ + if(cycleDuration == 0) { return 0; } + + uint32_t cycleTime = micros() - cycleStartTime; + if( pgm_read_byte(&Wheels[config.wheel].wheel_degrees) == 720 ) { cycleTime = cycleTime / 2; } + + uint16_t tmpCrankAngle = ((cycleTime * 360U) / cycleDuration); + while(tmpCrankAngle > 360) { tmpCrankAngle -= 360; } + + return tmpCrankAngle; } /*! @@ -331,8 +375,8 @@ void setRPM(uint16_t newRPM) { if (newRPM < 10) { return; } - if(config.rpm != newRPM) { reset_new_OCR1A(newRPM); } - config.rpm = newRPM; + if(currentStatus.rpm != newRPM) { reset_new_OCR1A( newRPM ); } + currentStatus.rpm = newRPM; } diff --git a/ardustim/ardustim/comms.cpp b/ardustim/ardustim/comms.cpp index 3020ce0..d37e026 100644 --- a/ardustim/ardustim/comms.cpp +++ b/ardustim/ardustim/comms.cpp @@ -132,7 +132,7 @@ void commandParser() break; case 'R': //Send the current RPM - Serial.println(config.rpm); + Serial.println(currentStatus.rpm); break; case 's': //Set the high and low RPM for sweep mode @@ -199,7 +199,7 @@ void toggle_invert_secondary_cb() void display_new_wheel() { - reset_new_OCR1A(config.rpm); + reset_new_OCR1A(currentStatus.rpm); edge_counter = 0; // Reset to beginning of the wheel pattern */ } diff --git a/ardustim/ardustim/globals.h b/ardustim/ardustim/globals.h index f8eb1c0..cd812fc 100644 --- a/ardustim/ardustim/globals.h +++ b/ardustim/ardustim/globals.h @@ -28,18 +28,37 @@ #define TMP_RPM_CAP 9000 /* MAX RPM via pot control. Adjusted to 9,000rpm max from 16,384rpm to match the GUI */ #define EEPROM_LAST_MODE 100 -struct configTable { - uint8_t version; - uint16_t rpm = 6000; +#define COMPRESSION_TYPE_1CYL_4STROKE 0 //Not initiallity supported +#define COMPRESSION_TYPE_2CYL_4STROKE 1 +#define COMPRESSION_TYPE_3CYL_4STROKE 2 //Not initiallity supported +#define COMPRESSION_TYPE_4CYL_4STROKE 3 +#define COMPRESSION_TYPE_6CYL_4STROKE 4 +#define COMPRESSION_TYPE_8CYL_4STROKE 5 + +struct configTable +{ + uint8_t version; uint8_t wheel = FOUR_TWENTY_A; uint8_t mode; uint16_t fixed_rpm = 2500; uint16_t sweep_low_rpm = 250; uint16_t sweep_high_rpm = 4000; uint16_t sweep_interval = 1000; + + bool useCompression = false; + uint8_t compressionType = 0; + uint16_t compressionRPM = 400; }; extern struct configTable config; +struct status +{ + uint16_t base_rpm; //RPM excluding compression modifier + uint16_t compressionModifier; + uint16_t rpm; //Final RPM +}; +extern struct status currentStatus; + /* Tie things wheel related into one nicer structure ... */ typedef struct _wheels wheels; struct _wheels { @@ -51,4 +70,47 @@ struct _wheels { const uint16_t wheel_degrees; }; +//A sin wave of amplitude 100 with a complete cycle in 180 degrees (1 entry per degree). +const uint8_t sin_100_180[] PROGMEM = +{ + 0,0,0,0,0,1,1,1,2,2,3,4,4,5,6,7,8,9,10,11, + 12,13,14,15,17,18,19,21,22,24,25,27,28,30, + 31,33,35,36,38,40,41,43,45,47,48,50,52,53, + 55,57,59,60,62,64,65,67,69,70,72,73,75,76, + 78,79,81,82,83,85,86,87,88,89,90,91,92,93, + 94,95,96,96,97,98,98,99,99,99,100,100,100, + 100,100,100,100,100,100,99,99,99,98,98,97, + 96,96,95,94,93,92,91,90,89,88,87,86,85,83, + 82,81,79,78,76,75,73,72,70,69,67,65,64,62, + 60,59,57,55,53,52,50,48,47,45,43,41,40,38, + 36,35,33,31,30,28,27,25,24,22,21,19,18,17, + 15,14,13,12,11,10,9,8,7,6,5,4,4,3,2,2,1,1, + 1,0,0,0,0 +}; + +//A sin wave of amplitude 100 with a complete cycle in 90 degrees (1 entry per degree). +const uint8_t sin_100_90[] PROGMEM = +{ + 0,0,0,1,2,3,4,6,8,10,12,14,17,19,22,25,28, + 31,35,38,41,45,48,52,55,59,62,65,69,72,75, + 78,81,83,86,88,90,92,94,96,97,98,99,100,100, + 100,100,100,99,98,97,96,94,92,90,88,86,83,81, + 78,75,72,69,65,62,59,55,52,48,45,41,38,35,31, + 28,25,22,19,17,14,12,10,8,6,4,3,2,1,0,0 +}; + +//A sin wave of amplitude 100 with a complete cycle in 120 degrees + +const uint8_t sin_100_120[] PROGMEM = +{ + 0,0,0,1,1,2,2,3,4,5,7,8,10,11,13,15,17,19, + 21,23,25,27,30,32,35,37,40,42,45,47,50,53, + 55,58,60,63,65,68,70,73,75,77,79,81,83,85, + 87,89,90,92,93,95,96,97,98,98,99,99,100,100, + 100,100,100,99,99,98,98,97,96,95,93,92,90,89, + 87,85,83,81,79,77,75,73,70,68,65,63,60,58,55, + 53,50,47,45,42,40,37,35,32,30,27,25,23,21,19, + 17,15,13,11,10,8,7,5,4,3,2,2,1,1,0,0 +}; + #endif diff --git a/ardustim/ardustim/storage.h b/ardustim/ardustim/storage.h index f5880ed..0a8fecc 100644 --- a/ardustim/ardustim/storage.h +++ b/ardustim/ardustim/storage.h @@ -9,6 +9,9 @@ #define EEPROM_SWEEP_RPM_MAX 8 //Note this is 2 bytes #define EEPROM_SWEEP_RPM_INT 10 //Note this is 2 bytes #define EEPROM_FIXED_RPM 12 //Note this is 2 bytes +#define EEPROM_USE_COMPRESSION 14 +#define EEPROM_COMPRESSION_TYPE 15 +#define EEPROM_COMPRESSION_RPM 16 //Note this is 2 bytes void loadConfig(); void saveConfig(); diff --git a/ardustim/ardustim/storage.ino b/ardustim/ardustim/storage.ino index 7ab964f..a4799b6 100644 --- a/ardustim/ardustim/storage.ino +++ b/ardustim/ardustim/storage.ino @@ -11,7 +11,7 @@ void loadConfig() { //New arduino config.wheel = 5; //36-1 - config.rpm = 3000; + currentStatus.rpm = 3000; config.mode = POT_RPM; config.fixed_rpm = 3500; @@ -28,7 +28,7 @@ void loadConfig() byte highByte = EEPROM.read(EEPROM_CURRENT_RPM); byte lowByte = EEPROM.read(EEPROM_CURRENT_RPM+1); - config.rpm = word(highByte, lowByte); + currentStatus.rpm = word(highByte, lowByte); highByte = EEPROM.read(EEPROM_FIXED_RPM); lowByte = EEPROM.read(EEPROM_FIXED_RPM+1); @@ -52,10 +52,19 @@ void loadConfig() if(config.sweep_low_rpm >= config.sweep_high_rpm) { config.sweep_low_rpm = config.sweep_high_rpm - 100; } + config.useCompression = EEPROM.read(EEPROM_USE_COMPRESSION); + config.compressionType = EEPROM.read(EEPROM_COMPRESSION_TYPE); + highByte = EEPROM.read(EEPROM_COMPRESSION_RPM); + lowByte = EEPROM.read(EEPROM_COMPRESSION_RPM+1); + config.compressionRPM = word(highByte, lowByte); + //config.compressionType = COMPRESSION_TYPE_6CYL_4STROKE; + //Error checking if(config.wheel >= MAX_WHEELS) { config.wheel = 5; } if(config.mode >= MAX_MODES) { config.mode = FIXED_RPM; } - if(config.rpm > 15000) { config.rpm = 4000; } + if(currentStatus.rpm > 15000) { currentStatus.rpm = 4000; } + if(config.compressionType > COMPRESSION_TYPE_8CYL_4STROKE) { config.compressionType = COMPRESSION_TYPE_4CYL_4STROKE; } + if(config.compressionRPM > 1000) { config.compressionRPM = 400; } } } @@ -65,8 +74,8 @@ void saveConfig() EEPROM.update(EEPROM_RPM_MODE, config.mode); EEPROM.update(EEPROM_VERSION, EEPROM_CURRENT_VERSION); - byte highByte = highByte(config.rpm); - byte lowByte = lowByte(config.rpm); + byte highByte = highByte(currentStatus.rpm); + byte lowByte = lowByte(currentStatus.rpm); EEPROM.update(EEPROM_CURRENT_RPM, highByte); EEPROM.update(EEPROM_CURRENT_RPM+1, lowByte); @@ -90,4 +99,10 @@ void saveConfig() EEPROM.update(EEPROM_SWEEP_RPM_INT, highByte); EEPROM.update(EEPROM_SWEEP_RPM_INT+1, lowByte); + EEPROM.update(EEPROM_USE_COMPRESSION, config.useCompression); + EEPROM.update(EEPROM_COMPRESSION_TYPE, config.compressionType); + highByte = highByte(config.compressionRPM); + lowByte = lowByte(config.compressionRPM); + EEPROM.update(EEPROM_COMPRESSION_RPM, highByte); + EEPROM.update(EEPROM_COMPRESSION_RPM+1, lowByte); } \ No newline at end of file