Logitech steering wheel controlled stroker

This is the place for all suggestions, releases and feedback regarding Milovana Hardware efforts.
Post Reply
lackis
Explorer
Explorer
Posts: 6
Joined: Thu Oct 29, 2015 8:04 am
Gender: Male
Sexual Orientation: Straight

Logitech steering wheel controlled stroker

Post by lackis »

Made a node.js script to control movement of a Logitech G29 steering wheel.

Requires node.js and the package logitech-g29.

Working surprisingly well. Moves less sporadic when in use and friction is higher.

Image

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()
Install

Code: Select all

npm init
npm install logitech-g29
Run

Code: Select all

npm start
Roblsforbobls
Explorer At Heart
Explorer At Heart
Posts: 260
Joined: Tue May 21, 2019 2:27 am
Gender: Male
Sexual Orientation: Asexual
I am a: Switch

Re: Logitech steering wheel controlled stroker

Post by Roblsforbobls »

lmao what an absolute madman, hope it works well for you! :lol:
lackis
Explorer
Explorer
Posts: 6
Joined: Thu Oct 29, 2015 8:04 am
Gender: Male
Sexual Orientation: Straight

Re: Logitech steering wheel controlled stroker

Post by lackis »

I take that as a compliment :-D

I have been seeing FunScripts being mentioned on this site and decided to try to use that. With MultiFunPlayer sending commands over a local network connection I managed to filter them enough for my script to understood. Far from perfect as I can not control fixed positions, but at least intervals increasing and decreasing in length and stopping for sections.
Post Reply

Who is online

Users browsing this forum: No registered users and 38 guests