Requires node.js and the package logitech-g29.
Working surprisingly well. Moves less sporadic when in use and friction is higher.
Features
Change settings with keyboard
Drift left or right (a, q), helps it stay in place
Amplitude/length of move (left, right)
Interval of full move (up, down)
Presets (1-7) that sets both amplitude and interval
Sanity check on values
Video
https://new.reddit.com/r/diysextoys/com ... to_stroke/
Code
https://paste2.org/sCAsKeXx
https://pastebin.com/PV8XmEet
- Spoiler: show
-
Code: Select all
/* Control Logitech G29 wheel with intervals and amplitude # Install npm init npm install logitech-g29 # Run npm start */ const g = require('logitech-g29') const readline = require('readline'); const os = require('os') readline.emitKeypressEvents(process.stdin); process.stdin.setRawMode(true); // Initialization const options = { autocenter: false, range: 270 } const defaults = { forceFriction: 0 // 0 = no friction, 0.5 = half strength, 1 = full strength } let lastFriction = defaults.forceFriction const min_interval = 50; const max_interval = 4000; // Variables let interval = 500; let nextInterval = false; let frq = 25; let amplitude = 0.1 let nextAmplitude = false; let drift = 0.02 // Helper function function mathRound(number) { return Math.round(number * 100) / 100; } // Friction function setForceFriction(val) { if (val === 0) { lastFriction = 0 } else if (val > 0) { lastFriction += 0.1 } else { lastFriction -= 0.1 } lastFriction = mathRound(lastFriction) if (lastFriction < 0) lastFriction = 0 if (lastFriction > 1) lastFriction = 1 console.log('forceFriction(' + lastFriction + ')') g.forceFriction(lastFriction) } // Amplitude function setAmplitude(val) { if (amplitude == val) return if (val < 0) val = 0 else if ((interval > 400) && val > 0.2) val = 0.2 else if ((interval > 200) && val > 0.3) val = 0.3 else if (val > 0.4) val = 0.4 nextAmplitude = mathRound(val) } function increaseAmplitude() { setAmplitude(amplitude + 0.01) } function decreaseAmplitude() { setAmplitude(amplitude - 0.01) } // Drift function setDrift(val) { if (val < -0.5) val = -0.5 else if (val > 0.5) val = 0.5 drift = mathRound(val) console.log(color.cyan('drift'), drift) } function increaseDrift() { setDrift(drift + 0.01) } function decreaseDrift() { setDrift(drift - 0.01) } // Interval function updateInterval(val) { if ((val > max_interval) || (val < min_interval)) { console.log(color.red("WARN: Invalid interval ") + val) return } nextInterval = val // Sanity check for amplitued with the new interval setAmplitude(amplitude) } function increaseInterval() { let step = 500 if (interval < 300) step = 50 else if (interval < 1000) step = 100 let val = interval + step if (val > max_interval) return updateInterval(val) } function decreaseInterval() { let step = 50 if (interval > 1000) step = 500 else if (interval > 300) step = 100 let val = interval - step if (val < min_interval) return updateInterval(val) } // Position let increase = false; let extreme = false; let last = 0; // Wait until end position before changing amplitude and interval function delayChange(x) { if (x > last && !increase) { extreme = true increase = true } else if (x < last && increase) { extreme = true increase = false } if (extreme) { if (nextAmplitude) { amplitude = nextAmplitude nextAmplitude = false console.log(color.magenta('amplitude'), amplitude) } if (nextInterval) { interval = nextInterval nextInterval = false console.log(color.green('interval ') + interval) } extreme = false } last = x } function updatePosition() { let x = Math.cos(Math.PI * 2 * new Date().getTime() / interval); // Value between 0 and 1 x *= amplitude // Multiplied by amplitude to decrease movement x += 0.5 // Middle is 0.5 which is no movement x += drift // Add extra weight towards one side x = mathRound(x) //console.log(x) delayChange(x) g.forceConstant(x) } // Bind buttons g.connect(options, function(err) { g.on('wheel-button_plus', function(val) { if (val == 1) increaseInterval() }) g.on('wheel-button_minus', function(val) { if (val == 1) decreaseInterval() }) g.on('wheel-spinner', function(val) { if (val !== 0) { setForceFriction(val) } }) g.on('wheel-button_spinner', function(val) { if (val === 1) { setForceFriction(0) } }) process.stdin.on('keypress', (str, key) => { if (key.ctrl && key.name === 'c') { g.forceConstant(0.5) clearInterval(loop) process.exit(); } else { // console.log(`You pressed the "${str}" key`); // console.log(); //console.log(key); // console.log(); if (key.name == 'up') { decreaseInterval() } else if (key.name == 'down') { increaseInterval() } else if (key.name == 'left') { decreaseAmplitude() } else if (key.name == 'right') { increaseAmplitude() } else if (key.name == 'q') { increaseDrift() } else if (key.name == 'a') { decreaseDrift() } else if (key.name == '1') { updateInterval(4000) setAmplitude(0.13) } else if (key.name == '2') { updateInterval(2000) setAmplitude(0.16) } else if (key.name == '3') { updateInterval(1000) setAmplitude(0.18) } else if (key.name == '4') { updateInterval(500) setAmplitude(0.2) } else if (key.name == '5') { updateInterval(350) setAmplitude(0.25) } else if (key.name == '6') { updateInterval(250) setAmplitude(0.3) } else if (key.name == '7') { updateInterval(200) setAmplitude(0.4) } else if (key.name == 'escape') { setAmplitude(0.01) } } }); console.log(color.cyan('Wheel ready.')) console.log() console.log(color.green('Increase speed with up, decrease with down.')) console.log(color.magenta('Increase amplitude/movement with right, decrease with left.')) console.log(color.cyan('Increase drift/weight right with q, left with a.')) console.log(color.yellow('Number keys are quick settings, 1-7, slow to fast')) console.log() console.log(color.grey('Play with forceFriction() by using the Red Spinner. Rotate right for more, left for less, and press the spinner button to reset.')) console.log() console.log('Quit with Ctrl + C') // Start interval that changes wheel position let loop = setInterval(updatePosition, frq) }) // Terminal Colors let color = {} const colors = { black: [30, 39], red: [31, 39], green: [32, 39], yellow: [33, 39], blue: [34, 39], magenta: [35, 39], cyan: [36, 39], white: [37, 39], gray: [90, 39], grey: [90, 39], // bright colors redBright: [91, 39], greenBright: [92, 39], yellowBright: [93, 39], blueBright: [94, 39], magentaBright: [95, 39], cyanBright: [96, 39], whiteBright: [97, 39] } const platform = os.platform() function showColor(hue, info = '') { // ` signifies a template literal return `\u001B[${colors[hue][0]}m` + info + `\u001B[${colors[hue][1]}m` } // showColor function setupColors() { for (let item in colors) { const hue = item color[hue] = function (info) { return showColor(hue, info) } } if (platform === 'win32' || platform === 'win64') { // use brigher versions of these colors color.red = color.redBright color.green = color.greenBright color.yellow = color.yellowBright color.blue = color.blueBright color.magenta = color.magentaBright color.cyan = color.cyanBright color.white = color.whiteBright } } // setupColors setupColors()
Code: Select all
npm init
npm install logitech-g29
Code: Select all
npm start