Skip to content

Commit

Permalink
Add AnalogIO::Joystick
Browse files Browse the repository at this point in the history
  • Loading branch information
vickash authored and vickash committed Oct 31, 2024
1 parent aae2005 commit 02b0f47
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 0 deletions.
31 changes: 31 additions & 0 deletions examples/analog_io/joystick.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#
# Use a generic 2-axis (double potentiometer) joystick.
#
require 'bundler/setup'
require 'denko'

X_PIN = :A1
Y_PIN = :A2

board = Denko::Board.new(Denko::Connection::Serial.new)
joystick = Denko::AnalogIO::Joystick.new board: board,
pins: {x: X_PIN, y: Y_PIN},
invert_x: true,
invert_y: true,
# maxzone: 98, # as percentage
deadzone: 2 # as percentage

# Listen to both analog inputs at 250 Hz.
# joystick.listen(4)

# Simple 60Hz game loop.
loop do
last_tick = Time.now

# If listening, joystick.state is constantly updated in the background.
# Otherwise, #read must be called each tick to update it.
joystick.read
puts joystick.state.inspect

sleep(0.0001) while (Time.now - last_tick < 0.0166)
end
1 change: 1 addition & 0 deletions lib/denko/analog_io.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module AnalogIO
autoload :Input, "#{__dir__}/analog_io/input"
autoload :Output, "#{__dir__}/analog_io/output"
autoload :Potentiometer, "#{__dir__}/analog_io/potentiometer"
autoload :Joystick, "#{__dir__}/analog_io/joystick"
autoload :ADS111X, "#{__dir__}/analog_io/ads111x"
autoload :ADS1100, "#{__dir__}/analog_io/ads1100"
autoload :ADS1115, "#{__dir__}/analog_io/ads1115"
Expand Down
65 changes: 65 additions & 0 deletions lib/denko/analog_io/joystick.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
module Denko
module AnalogIO
class Joystick
include Behaviors::MultiPin
include Behaviors::Lifecycle

def initialize_pins(options={})
proxy_pin(:x, AnalogIO::Input)
proxy_pin(:y, AnalogIO::Input)
end

after_initialize do
# Midpoint as float
@mid = board.adc_high / 2.0

# Invert settings as +1 or -1 multipliers
@invert_x = params[:invert_x] ? -1 : 1
@invert_y = params[:invert_y] ? -1 : 1

# Deadzones as percentages
@deadzone = 0
@maxzone = @mid
@deadzone = ((params[:deadzone] * @mid) / 100).round if params[:deadzone]
@maxzone = ((params[:maxzone] * @mid) / 100).round if params[:maxzone]

# Per axis callbacks
x.on_data { |value| state[:x] = raw_to_percent(value, @invert_x) }
y.on_data { |value| state[:y] = raw_to_percent(value, @invert_y) }
end

def state
@state ||= { x: nil, y: nil }
end

def raw_to_percent(value, invert)
float = (value - @mid) * invert
abs = float.abs
if abs < @deadzone
return 0
elsif abs > @maxzone
return (float > 0) ? 100 : -100
else
return ((float * 100) / @mid).round
end
end

def read
# Blocking read only for last axis read.
x._read
y.read
state
end

def listen(divider=16)
x.listen(divider)
y.listen(divider)
end

def stop
x.stop
y.stop
end
end
end
end

0 comments on commit 02b0f47

Please sign in to comment.