Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ERG Mode first try #277

Merged
merged 45 commits into from
Dec 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
5c86403
Moved ERG to seperate task
Dec 4, 2021
6b35e29
Added TargetWatts and ERG Mode simulation
Dec 4, 2021
1bfcd56
skip erg comp if stepper is running
Dec 4, 2021
707cdd2
splitted settings to userSettings and RuntimeSettings
Dec 4, 2021
b1a8537
ERG Mode class variables and fix of Measurment access
Dec 4, 2021
50ffd60
Enabled FW update
Dec 4, 2021
65312ab
update rtSetting: added currentIncline.
Dec 5, 2021
7f5d4a1
Added ERG Mode to stepper driver.
Dec 5, 2021
992d26c
reordered parameters
Dec 6, 2021
ea71333
changed BLE Client delay, refactored ERG
Dec 6, 2021
e4020ba
ERG_Mode: added two steps
Dec 10, 2021
9345f35
added csv logging to erg_mode
Dec 12, 2021
9617ef4
reduced minor step to 1/4
Dec 13, 2021
27d461c
Merge branch 'doudar:develop' into develop
MarkusSchneider Dec 17, 2021
d4a93b5
changed minore steps to ergSensitivity/2
Dec 17, 2021
a9739c2
Merge branch 'ERG-Respin' into develop
doudar Dec 19, 2021
80adc83
Integrated Shifting WebPage and small testing fixes.
doudar Dec 19, 2021
77ca1c4
Inserted Licence for pre-commit checks
doudar Dec 19, 2021
98b0c87
Created framework for a power table
doudar Dec 19, 2021
683cb04
Added comments on suggestions for ergPowerTable
doudar Dec 19, 2021
32a2197
Initialized PowerEntry with 0's
doudar Dec 19, 2021
312ff57
Removed millis in powerEntry
doudar Dec 20, 2021
bfc183f
Expanded the PowerTable Class (untested)
doudar Dec 20, 2021
0a83fc9
Added more iteration to powertable lookup
doudar Dec 20, 2021
32be88e
PowerTable::lookup complete. Not tested.
doudar Dec 21, 2021
d165d68
1st Tests.
doudar Dec 21, 2021
5324e2d
Adjusted loop timing and logs for actual testing.
doudar Dec 21, 2021
fa9b423
Added Logging...This might actually work...
doudar Dec 21, 2021
dd0025f
moved isSpinning test earlier in erg
doudar Dec 22, 2021
cbfdae0
added comments
doudar Dec 22, 2021
6f85362
fixed typo
doudar Dec 22, 2021
e859191
fixed a bug
doudar Dec 22, 2021
3e0e5f8
added comment
doudar Dec 22, 2021
8cb092a
fixed bug in newEntry()
Dec 22, 2021
cbafef6
fixed buffer overflow in PowerTable::toLog()
Dec 22, 2021
f2a48e6
Cleaned up the formatting of the powerTable log.
doudar Dec 22, 2021
1e13f04
removed obsolete comments
doudar Dec 22, 2021
6e832df
fixed missing semi in test container
doudar Dec 22, 2021
99212ac
Added ArduinoFake for native unit testing
Dec 23, 2021
e88e053
ERG waits for knob to stop after powertab lookup
doudar Dec 23, 2021
8daf131
Merge branch 'develop' of https://github.com/markusschneider/smartspi…
doudar Dec 23, 2021
b82f2cc
added option to return log in rtConfig.returnJSON
doudar Dec 24, 2021
b0a754b
updates smartspin_parameters.h
doudar Dec 24, 2021
04f3403
Fixed erronious logging.
doudar Dec 24, 2021
6ee7192
Added additional cadence checks for delta correct
doudar Dec 24, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added
- Added Webpage for Shifting.
- Added /shift server on backend.
- Split userConfig into userConfig and rtConfig.
- Added ERG testing to btsimulator.html
- Broke out ERG computation into it's own task.
- Added image for wiki.

### Changed
- Adjusted the order of "Submit" "Reboot" and "Reset to Defaults" on the settings page.
- Adjusted the setting webpage so "reset to defaults" is harder to accidentally press.
- Increased the amount of free stack by removing the default Arduino loop();
- Updated /shift server on to rtConfig.
- Fixed redeclaring global targetposition in moveStepper().
- Renamed Settings page "Submit" button to "Save Setting"

### Hardware
- Increased hex head and nut size to 13mm.
Expand Down
142 changes: 111 additions & 31 deletions data/btsimulator.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,57 +23,88 @@ <h1>BLE Device Simulator</h1>

<h2>Sim Heart Rate</h2>
<p><span id="hrValue"></span></p>
<p><input type="range" onload="requestConfigValues()" onchange="updateHRSlider(this)" id="HRSlider" min="40"
<p><input type="range" onload="requestConfigValues()" onchange="updateHrSlider()" id="hrSlider" min="40"
max="250" value="0" step="1" class="slider2"></p>
<p><label class="switch"><input type="checkbox" onload="toggleHRCheckbox(this, true)"
onchange="toggleHRCheckbox(this,true)" id="hrOutput"><span class="slider"></span></label></p>

<h2>Sim Power Output</h2>
<p><span id="wattsValue"></span></p>
<p><input type="range" onload="requestConfigValues()" onchange="updateWattsSlider(this)" id="WattsSlider" min="0"
max="2000" value="0" step="1" class="slider2"></p>
<p><input type="range" onload="requestConfigValues()" onchange="updateWattsSlider()" id="wattsSlider" min="0"
max="600" value="0" step="1" class="slider2"></p>
<p><label class="switch"><input type="checkbox" onload="toggleWattsCheckbox(this,true)"
onchange="toggleWattsCheckbox(this,true)" id="wattsOutput"><span class="slider"></span></label></p>

<h2>Sim CAD Output</h2>
<p><span id="cadValue"></span></p>
<p><input type="range" onload="requestConfigValues()" onchange="updateCadSlider(this)" id="CadSlider" min="0"
<p><input type="range" onload="requestConfigValues()" onchange="updateCadSlider()" id="cadSlider" min="0"
max="180" value="0" step="1" class="slider2"></p>
<p><label class="switch"><input type="checkbox" onload="toggleCadCheckbox(this,true)"
onchange="toggleCadCheckbox(this,true)" id="cadOutput"><span class="slider"></span></label></p>

<h1>Trainer Simulator</h1>
<h2>Enable ERG</h2>
<p>
<label class="switch">
<input type="checkbox" onload="toggleEnableErgCheckbox(this)" onchange="toggleEnableErgCheckbox(this)"
id="enableErgCheckbox">
<span class="slider"></span>
</label>
</p>
<h2>ERG Target Watts</h2>
<p><span id="targetWattsValue"></span></p>
<p><input type="range" onload="requestConfigValues()" onchange="updateTargetWattsSlider()"
id="targetWattsSlider" min="0" max="600" value="0" step="1" class="slider2"></p>
<p>
<label class="switch">
<input type="checkbox" onload="toggleTargetWattsCheckbox(this,true)"
onchange="toggleTargetWattsCheckbox(this,true)" id="targetWattsOutput">
<span class="slider"></span>
</label>
</p>
</body>
<script>
//Update values on specified interval
setInterval(function () {
requestConfigValues();

}, 2000);

let pwrTimer;

function toggleHRCheckbox(element, updateServer) {
if (element.checked) {
document.getElementById("HRSlider").hidden = false;
document.getElementById("hrSlider").hidden = false;
document.getElementById("hrValue").hidden = false;
}
else {
document.getElementById("HRSlider").hidden = true;
document.getElementById("hrSlider").hidden = true;
document.getElementById("hrValue").hidden = true;
}
if (updateServer) {
var xhr = new XMLHttpRequest();
if (element.checked) {
xhr.open("GET", "/hrslider?value=enable", true);
xhr.open("GET", "/hrSlider?value=enable", true);
xhr.send();
}
else {
xhr.open("GET", "/hrslider?value=disable", true);
xhr.open("GET", "/hrSlider?value=disable", true);
xhr.send();
}
}
}

function toggleWattsCheckbox(element, updateServer) {
if (element.checked) {
document.getElementById("WattsSlider").hidden = false;
document.getElementById("wattsSlider").hidden = false;
document.getElementById("wattsValue").hidden = false;
}
else {
document.getElementById("WattsSlider").hidden = true;
document.getElementById("wattsSlider").hidden = true;
document.getElementById("wattsValue").hidden = true;
if (!!pwrTimer) {
clearInterval(pwrTimer);
}
}

if (updateServer) {
Expand All @@ -91,11 +122,11 @@ <h2>Sim CAD Output</h2>

function toggleCadCheckbox(element, updateServer) {
if (element.checked) {
document.getElementById("CadSlider").hidden = false;
document.getElementById("cadSlider").hidden = false;
document.getElementById("cadValue").hidden = false;
}
else {
document.getElementById("CadSlider").hidden = true;
document.getElementById("cadSlider").hidden = true;
document.getElementById("cadValue").hidden = true;
}

Expand All @@ -112,64 +143,113 @@ <h2>Sim CAD Output</h2>
}
}

function updateHRSlider(element) {
var sliderValue = document.getElementById("HRSlider").value;
function updateHrSlider() {
var sliderValue = document.getElementById("hrSlider").value;
document.getElementById("hrValue").innerHTML = sliderValue + " BPM";
var xhr = new XMLHttpRequest();
xhr.open("GET", "/hrslider?value=" + sliderValue, true);
xhr.open("GET", "/hrSlider?value=" + sliderValue, true);
xhr.send();
}

function updateWattsSlider(element) {
var sliderValue = document.getElementById("WattsSlider").value;
function updateWattsSlider() {
var sliderValue = document.getElementById("wattsSlider").value;
document.getElementById("wattsValue").innerHTML = sliderValue + " Watts";
var xhr = new XMLHttpRequest();
xhr.open("GET", "/wattsslider?value=" + sliderValue, true);
xhr.send();
}

function updateCadSlider(element) {
var sliderValue = document.getElementById("CadSlider").value;
function updateCadSlider() {
var sliderValue = document.getElementById("cadSlider").value;
document.getElementById("cadValue").innerHTML = sliderValue + " RPM";
var xhr = new XMLHttpRequest();
xhr.open("GET", "/cadslider?value=" + sliderValue, true);
xhr.send();
}

//Update values on specified interval
setInterval(function () {
function updateTargetWattsSlider() {
var sliderValue = document.getElementById("targetWattsSlider").value;
document.getElementById("targetWattsValue").innerHTML = sliderValue + " Watts";
var xhr = new XMLHttpRequest();
xhr.open("GET", "/targetwattsslider?value=" + sliderValue, true);
xhr.send();
}

requestConfigValues();
function toggleTargetWattsCheckbox(element, updateServer) {
if (element.checked) {
document.getElementById("targetWattsSlider").hidden = false;
document.getElementById("targetWattsValue").hidden = false;
}
else {
document.getElementById("targetWattsSlider").hidden = true;
document.getElementById("targetWattsValue").hidden = true;
}

}, 2000);
if (updateServer) {
var xhr = new XMLHttpRequest();
if (element.checked) {
xhr.open("GET", "/targetwattsslider?value=enable", true);
xhr.send();
}
else {
xhr.open("GET", "/targetwattsslider?value=disable", true);
xhr.send();
}
}
}

function toggleEnableErgCheckbox(element) {
var xhr = new XMLHttpRequest();
if (element.checked) {
xhr.open("GET", "/ergmode?value=enable", true);
xhr.send();
}
else {
xhr.open("GET", "/ergmode?value=disable", true);
xhr.send();
}
}

function requestConfigValues() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
var obj = JSON.parse(this.responseText);
document.getElementById("wattsValue").innerHTML = obj.simulatedWatts + " Watts";
document.getElementById("WattsSlider").value = obj.simulatedWatts;
document.getElementById("wattsSlider").value = obj.simulatedWatts;
document.getElementById("wattsOutput").checked = obj.simulateWatts;
document.getElementById("WattsSlider").hidden = !obj.simulateWatts;
document.getElementById("wattsSlider").hidden = !obj.simulateWatts;
document.getElementById("wattsValue").hidden = !obj.simulateWatts;

document.getElementById("hrValue").innerHTML = obj.simulatedHr + " BPM";
document.getElementById("HRSlider").value = obj.simulatedHr;
document.getElementById("hrSlider").value = obj.simulatedHr;
document.getElementById("hrOutput").checked = obj.simulateHr;
document.getElementById("HRSlider").hidden = !obj.simulateHr;
document.getElementById("hrSlider").hidden = !obj.simulateHr;
document.getElementById("hrValue").hidden = !obj.simulateHr;

document.getElementById("cadValue").innerHTML = obj.simulatedCad + " RPM";
document.getElementById("CadSlider").value = obj.simulatedCad;
document.getElementById("cadSlider").value = obj.simulatedCad;
document.getElementById("cadOutput").checked = obj.simulateCad;
document.getElementById("CadSlider").hidden = !obj.simulateCad;
document.getElementById("cadSlider").hidden = !obj.simulateCad;
document.getElementById("cadValue").hidden = !obj.simulateCad;

setTimeout(function () { document.getElementById("loadingWatermark").remove(); }, 1000);
document.getElementById("enableErgCheckbox").checked = obj.ERGMode;

document.getElementById("targetWattsValue").innerHTML = obj.targetWatts + " Watts";
document.getElementById("targetWattsSlider").value = obj.targetWatts == null ? 0 : obj.targetWatts;
document.getElementById("targetWattsOutput").checked = obj.simulateTargetWatts;
document.getElementById("targetWattsSlider").hidden = !obj.simulateTargetWatts;
document.getElementById("targetWattsValue").hidden = !obj.simulateTargetWatts;

setTimeout(function () {
const watermark = document.getElementById("loadingWatermark");
if (!!watermark) {
document.getElementById("loadingWatermark")?.remove();
}
}, 1000);
}
};
xhttp.open("GET", "/configJSON", true);
xhttp.open("GET", "/runtimeConfigJSON", true);
xhttp.send();
}

Expand Down
6 changes: 3 additions & 3 deletions data/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ <h2>
<input type='button' onclick="clickStep(document.getElementById('ERGSensitivity'), this.value)"
value="-">
<input style="width:50%; position: relative; top: 5px;" type="range" id="ERGSensitivity"
name="ERGSensitivity" value="1.0" min=".5" max="5" step=".1" class="slider1"
onchange="updateSlider(this, document.getElementById('ERGSensitivityValue'))" />
name="ERGSensitivity" value="1.0" min=".5" max="20" step=".1" class="slider1"
onchange="updateSlider(this.value, document.getElementById('ERGSensitivityValue'))" />
<input type='button' onclick="clickStep(document.getElementById('ERGSensitivity'), this.value)"
value="+">
</td>
Expand Down Expand Up @@ -140,7 +140,7 @@ <h2>
</tr>
</tbody>
</table>
<input type="submit" value="Submit" />
<input type="submit" value="Save Settings" />
</form>
<p></p>
<form action="/reboot.html">
Expand Down
2 changes: 1 addition & 1 deletion data/shift.html
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ <h1>Shift</h1>
}
}
};
xhttp.open("GET", "/configJSON", true);
xhttp.open("GET", "/runtimeConfigJSON", true);
xhttp.send();
}

Expand Down
2 changes: 1 addition & 1 deletion include/BLE_Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ extern SpinBLEServer spinBLEServer;

void startBLEServer();
bool spinDown();
void computeERG(int = 0);
// void computeERG(int = 0);
void computeCSC();
void logCharacteristic(char *buffer, const size_t bufferCapacity, const byte *data, const size_t dataLength, const NimBLEUUID serviceUUID, const NimBLEUUID charUUID,
const char *format, ...);
Expand Down
80 changes: 80 additions & 0 deletions include/ERG_Mode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright (C) 2020 Anthony Doud & Joel Baranick
* All rights reserved
*
* SPDX-License-Identifier: GPL-2.0-only
*/

#pragma once

#include "settings.h"
#include "SmartSpin_parameters.h"

#define ERG_MODE_LOG_TAG "ERG_Mode"
#define ERG_MODE_LOG_CSV_TAG "ERG_Mode_CSV"
#define POWERTABLE_LOG_TAG "PowTab"
#define ERG_MODE_DELAY 700

extern TaskHandle_t ErgTask;
void setupERG();
void ergTaskLoop(void *pvParameters);

class ErgMode {
public:
void computErg(int newSetpoint);
void _writeLogHeader();
void _writeLog(int cycles, float currentIncline, float newIncline, int currentSetPoint, int newSetPoint, int currentWatts, int newWatts, int currentCadence, int newCadence);

private:
bool engineStopped = false;
bool initialized = false;
int setPoint = 0;
int cycles = 0;
int offsetMuliplier = 0;
Measurement watts = Measurement(0);
int cadence = 0;

bool _userIsSpinning(int cadence, float incline);
};

class PowerEntry {
public:
int watts;
int32_t targetPosition;
int cad;
int readings;

PowerEntry() {
this->watts = 0;
this->targetPosition = 0;
this->cad = 0;
this->readings = 0;
}
};

class PowerBuffer {
public:
PowerEntry powerEntry[POWER_SAMPLES];
void set(int);
void reset();
};

class PowerTable {
public:
PowerEntry powerEntry[POWERTABLE_SIZE];

// Catalogs a new entry into the power table.
void newEntry(PowerBuffer powerBuffer);

// returns incline for wattTarget. Null if not found.
int32_t lookup(int watts, int cad);

// load power table from spiffs
bool load();

// save powertable from spiffs
bool save();

// Display power table in log
void toLog();
};
Loading