moves rower configuration into a config file and adds rower presets

This commit is contained in:
Lars Berning 2021-04-20 21:48:34 +02:00
parent 0586fc11d8
commit 55cde69ce6
14 changed files with 206 additions and 64 deletions

View File

@ -11,7 +11,7 @@
"ecmaVersion": 12,
"sourceType": "module"
},
"ignorePatterns": ["**/*.min.js"],
"ignorePatterns": ["**/*.min.js", "**/tools/ConfigManager.js"],
"rules": {
"camelcase": 0
}

1
.gitignore vendored
View File

@ -77,3 +77,4 @@ node_modules
._*
tmp/
build/
config/config.js

View File

@ -4,12 +4,10 @@
Starts the central manager in a forked thread since noble does not like
to run in the same thread as bleno
todo: check if noble would also work if we move this into a worker thread
(would save some ressources)
*/
import { createCentralManager } from './CentralManager.js'
import process from 'process'
import config from '../config.js'
import config from '../tools/ConfigManager.js'
import log from 'loglevel'
log.setLevel(config.loglevel.default)

View File

@ -5,7 +5,7 @@
This manager creates the different Bluetooth Low Energy (BLE) Peripherals and allows
switching between them
*/
import config from '../config.js'
import config from '../tools/ConfigManager.js'
import { createFtmsPeripheral } from './FtmsPeripheral.js'
import { createPm5Peripheral } from './Pm5Peripheral.js'
import log from 'loglevel'

View File

@ -1,19 +0,0 @@
'use strict'
/*
Open Rowing Monitor, https://github.com/laberning/openrowingmonitor
This file contains the app specific configuration.
Modify it to your needs.
*/
import log from 'loglevel'
export default {
loglevel: {
// the default loglevel
default: log.levels.INFO,
// the log level of some modules can be set individually to filter noise
RowingEngine: log.levels.WARN
},
// selects the Bluetooth Low Energy Profile
// supported modes: FTMS, FTMSBIKE, PM5
bluetoothMode: 'FTMS'
}

View File

@ -16,51 +16,45 @@ import { createTimer } from './Timer.js'
const log = loglevel.getLogger('RowingEngine')
// *****************************************************
// These constants are specific to your Rowing Machine
// *****************************************************
function createRowingEngine (rowerSettings) {
// How many impulses are triggered per revolution of the flywheel
// i.e. the number of magnets if used with a reed sensor
const numOfImpulsesPerRevolution = rowerSettings.numOfImpulsesPerRevolution
// How many impulses are triggered per revolution of the flywheel
// i.e. the number of magnets if used with a reed sensor
const numOfImpulsesPerRevolution = 2
// Needed to determine the damping constant of the rowing machine. This value can be measured in the recovery phase
// of the stroke (some ergometers do this constantly).
// However I still keep it constant here, as I still have to figure out the damping physics of a water rower (see below)
// To measure it for your rowing machine, comment in the logging at the end of "startDrivePhase" function. Then do some
// strokes on the rower and estimate a value.
const omegaDotDivOmegaSquare = rowerSettings.omegaDotDivOmegaSquare
// Needed to determine the damping constant of the rowing machine. This value can be measured in the recovery phase
// of the stroke (some ergometers do this constantly).
// However I still keep it constant here, as I still have to figure out the damping physics of a water rower (see below)
// To measure it for your rowing machine, comment in the logging at the end of "startDrivePhase" function. Then do some
// strokes on the rower and estimate a value.
const omegaDotDivOmegaSquare = 0.046
// The moment of inertia of the flywheel kg*m^2
// A way to measure it is outlined here: https://dvernooy.github.io/projects/ergware/, "Flywheel moment of inertia"
// You could also roughly estimate it by just doing some strokes and the comparing the calculated power values for
// plausibility. Note that the power also depends on omegaDotDivOmegaSquare (see above).
const jMoment = rowerSettings.jMoment
// The moment of inertia of the flywheel kg*m^2
// A way to measure it is outlined here: https://dvernooy.github.io/projects/ergware/, "Flywheel moment of inertia"
// You could also roughly estimate it by just doing some strokes and the comparing the calculated power values for
// plausibility. Note that the power also depends on omegaDotDivOmegaSquare (see above).
const jMoment = 0.49
// Set this to true if you are using a water rower
// The mass of the water starts rotating, when you pull the handle, and therefore acts
// like a massive flywheel
// Liquids are a tricky thing and therefore the dumping constant does not seem to be
// that constant on water rowers...
// This is WIP, but for now this setting is used to figure out the drive and recovery phases
// differently on water rowers
const liquidFlywheel = rowerSettings.liquidFlywheel
// Set this to true if you are using a water rower
// The mass of the water starts rotating, when you pull the handle, and therefore acts
// like a massive flywheel
// Liquids are a tricky thing and therefore the dumping constant does not seem to be
// that constant on water rowers...
// This is WIP, but for now this setting is used to figure out the drive and recovery phases
// differently on water rowers
const liquidFlywheel = true
// A constant that is commonly used to convert flywheel revolutions to a rowed distance
// see here: http://eodg.atm.ox.ac.uk/user/dudhia/rowing/physics/ergometer.html#section9
const c = 2.8
// A constant that is commonly used to convert flywheel revolutions to a rowed distance
// see here: http://eodg.atm.ox.ac.uk/user/dudhia/rowing/physics/ergometer.html#section9
const c = 2.8
// jMoment * ωdot = -kDamp * ω^2 during non-power part of stroke
const kDamp = jMoment * omegaDotDivOmegaSquare
// jMoment * ωdot = -kDamp * ω^2 during non-power part of stroke
const kDamp = jMoment * omegaDotDivOmegaSquare
// s = (k/c)^(1/3)*θ
const distancePerRevolution = 2.0 * Math.PI * Math.pow((kDamp / c), 1.0 / 3.0)
// s = (k/c)^(1/3)*θ
const distancePerRevolution = 2.0 * Math.PI * Math.pow((kDamp / c), 1.0 / 3.0)
function createRowingEngine () {
let workoutHandler
const kDampEstimatorAverager = createWeightedAverager(3)
let kPower = 0.0
let jPower = 0.0
let kDampEstimator = 0.0

View File

@ -10,7 +10,7 @@ import { fork } from 'child_process'
import log from 'loglevel'
// eslint-disable-next-line no-unused-vars
import fs from 'fs'
import config from './config.js'
import config from './tools/ConfigManager.js'
import { createRowingEngine } from './engine/RowingEngine.js'
import { createRowingStatistics } from './engine/RowingStatistics.js'
import { createWebServer } from './WebServer.js'
@ -65,7 +65,7 @@ gpioTimerService.on('message', (dataPoint) => {
// fs.appendFile('recordings/wrx700_2magnets_long.csv', `${dataPoint}\n`, (err) => { if (err) log.error(err) })
})
const rowingEngine = createRowingEngine()
const rowingEngine = createRowingEngine(config.rowerSettings)
const rowingStatistics = createRowingStatistics()
rowingEngine.notify(rowingStatistics)

View File

@ -0,0 +1,41 @@
'use strict'
/*
Open Rowing Monitor, https://github.com/laberning/openrowingmonitor
Merges the different config files and presents the configuration to the application
*/
import defaultConfig from '../../config/default.config.js'
async function getConfig () {
let customConfig
try {
customConfig = await import('../../config/config.js')
} catch (exception) {}
return customConfig !== undefined ? deepMerge(defaultConfig, customConfig.default) : defaultConfig
}
function deepMerge (...objects) {
const isObject = obj => obj && typeof obj === 'object'
return objects.reduce((prev, obj) => {
Object.keys(obj).forEach(key => {
const pVal = prev[key]
const oVal = obj[key]
if (Array.isArray(pVal) && Array.isArray(oVal)) {
prev[key] = pVal.concat(...oVal)
} else if (isObject(pVal) && isObject(oVal)) {
prev[key] = deepMerge(pVal, oVal)
} else {
prev[key] = oVal
}
})
return prev
}, {})
}
const config = await getConfig()
export default config

33
config/default.config.js Normal file
View File

@ -0,0 +1,33 @@
'use strict'
/*
Open Rowing Monitor, https://github.com/laberning/openrowingmonitor
This file contains the default configuration of the Open Rowing Monitor.
!!! Note that changes to this file will be OVERWRITTEN when you update to a new version
of Open Rowing Monitor. !!!
To change the settings you should modify the 'config.js' in this folder. If 'config.js' does not
exist, you can use the example file from the 'install' folder.
*/
import rowerProfiles from './rowerProfiles.js'
export default {
// available log levels: trace, debug, info, warn, error, silent
loglevel: {
// the default loglevel
default: 'info',
// the log level of of the rowing engine (stroke detection and physics model)
RowingEngine: 'warn'
},
// selects the Bluetooth Low Energy Profile
// supported modes: FTMS, FTMSBIKE, PM5
bluetoothMode: 'FTMS',
// the rower specific settings. Either choose a profile from config/rowerProfiles.js or
// define the settings individually. If you find good settings for a new rowing device
// please send them to us (together with a raw recording of 10 strokes) so we can add
// the device to the profiles.
rowerSettings: rowerProfiles.DEFAULT
}

57
config/rowerProfiles.js Normal file
View File

@ -0,0 +1,57 @@
'use strict'
/*
Open Rowing Monitor, https://github.com/laberning/openrowingmonitor
This file contains the rower specific settings for different models of ergometers.
These have been generated by the community. If your rower is not listed here and you did find
good settings for your rowing device please send them to us (together with a raw recording of
10 strokes) so we can add the device here.
*/
export default {
// Profile for an example rower
DEFAULT: {
// How many impulses are triggered per revolution of the flywheel
// i.e. the number of magnets if used with a reed sensor
numOfImpulsesPerRevolution: 1,
// Needed to determine the damping constant of the rowing machine. This value can be measured in the recovery phase
// of the stroke (some ergometers do this constantly).
// However I still keep it constant here, as I still have to figure out the damping physics of a water rower (see below)
// To measure it for your rowing machine, comment in the logging at the end of "startDrivePhase" function. Then do some
// strokes on the rower and estimate a value.
omegaDotDivOmegaSquare: 0.02,
// The moment of inertia of the flywheel kg*m^2
// A way to measure it is outlined here: https://dvernooy.github.io/projects/ergware/, "Flywheel moment of inertia"
// You could also roughly estimate it by just doing some strokes and the comparing the calculated power values for
// plausibility. Note that the power also depends on omegaDotDivOmegaSquare (see above).
jMoment: 0.49,
// Set this to true if you are using a water rower
// The mass of the water starts rotating, when you pull the handle, and therefore acts
// like a massive flywheel
// Liquids are a tricky thing and therefore the dumping constant does not seem to be
// that constant on water rowers...
// This is WIP, but for now this setting is used to figure out the drive and recovery phases
// differently on water rowers
liquidFlywheel: false
},
// Sportstech WRX700
WRX700: {
numOfImpulsesPerRevolution: 2,
omegaDotDivOmegaSquare: 0.046,
jMoment: 0.49,
liquidFlywheel: true
},
// DKN R-320 Air Rower
DKNR320: {
numOfImpulsesPerRevolution: 1,
omegaDotDivOmegaSquare: 0.019,
jMoment: 0.4,
liquidFlywheel: true
}
}

View File

@ -60,4 +60,4 @@ If your machine does not have something like this or if the sensor is not access
* PAS sensor (i.e. from an E-bike)
* Optical chopper wheel
You should now adjust the rower specific parameters in `app/engine/RowingEngine.js` to suit your rowing machine.
You should now adjust the rower specific parameters in `config/config.js` to suit your rowing machine.

34
install/config.js Normal file
View File

@ -0,0 +1,34 @@
'use strict'
/*
Open Rowing Monitor, https://github.com/laberning/openrowingmonitor
You can modify this file to configure Open Rowing Monitor to your needs.
This file should be placed in the 'config' folder of Open Rowing Monitor.
All available configuration parameters are visible in config/config.default.js
To modify a parameter, copy it to this file and modify the value.
Changes to this file are persisted when you update to new versions.
*/
// eslint-disable-next-line no-unused-vars
import rowerProfiles from './rowerProfiles.js'
export default {
/*
// example: change the default log level:
loglevel: {
default: 'debug'
},
// example: set a rower profile:
rowerSettings: rowerProfiles.DKNR320
// example: set custom rower settings:
rowerSettings: {
numOfImpulsesPerRevolution: 1,
omegaDotDivOmegaSquare: 0.03,
jMoment: 0.3,
liquidFlywheel: false
}
*/
}

View File

@ -76,6 +76,9 @@ print
print "Downloading and compiling Runtime dependencies..."
sudo npm install
sudo npm run build
if ! [[ -f "config/config.js" ]]; then
cp install/config.js config/
fi
print
print "Setting up Open Rowing Monitor as autostarting system service..."

View File

@ -1,6 +1,6 @@
{
"name": "openrowingmonitor",
"version": "0.7.0",
"version": "0.7.1",
"description": "A rowing monitor for rowing exercise machines",
"main": "app/server.js",
"author": "Lars Berning",