Difference between revisions of "Project:Arduino Rotary Encoder Menu System"
m (Fowkc moved page Arduino Rotary Encoder Menu System to Project:Arduino Rotary Encoder Menu System) |
|||
(4 intermediate revisions by one other user not shown) | |||
Line 1: | Line 1: | ||
I have recovered a number of ALPS rotary encoders from discarded industrial CRT monitors. I'm working on building a user interface menu system that makes use of the rotary encoders as the sole input technique. | I have recovered a number of ALPS rotary encoders from discarded industrial CRT monitors. I'm working on building a user interface menu system that makes use of the rotary encoders as the sole input technique. | ||
− | <div style ="height: | + | <div style ="height:300px;overflow-x:hidden;overflow-y:auto;border: 4px solid green;"> |
'''Rotary Encoder Test Sketch With Interrupts (non-PWM)''' | '''Rotary Encoder Test Sketch With Interrupts (non-PWM)''' | ||
<syntaxhighlight lang="cpp" line="GESHI_FANCY_LINE_NUMBERS" enclose="div"> | <syntaxhighlight lang="cpp" line="GESHI_FANCY_LINE_NUMBERS" enclose="div"> | ||
Line 112: | Line 112: | ||
See if it can cope with two encoders at rapid rate usage. | See if it can cope with two encoders at rapid rate usage. | ||
+ | |||
+ | OK, working well --[[User:Msemtd|Michael Erskine]] 18:10, 29 July 2012 (EST) | ||
+ | |||
+ | == Raspberry Pi menu for rotary encoder == | ||
+ | When using the Raspberry Pi as the menu display system we need to do a few things to a stock raspbian install... | ||
+ | * auto login and start X: use option in raspi-config | ||
+ | * switch off screen blanking: /etc/lightdm/lightdm.conf in SeatDefaults section "xserver-command=X -s 0 -dpms" | ||
+ | * auto start application | ||
+ | |||
+ | Here I'm building a Perl Tk menu application prototype using Tk::Canvas. I haven't yet wired up the serial as I'm just trying out some graphic styles on the small PAL LCD screen. | ||
+ | |||
+ | <div style ="height:300px;overflow-x:hidden;overflow-y:auto;border: 4px solid green;"> | ||
+ | '''Raspberry Pi menu for rotary encoder''' | ||
+ | <syntaxhighlight lang="perl" line="GESHI_FANCY_LINE_NUMBERS" enclose="div"> | ||
+ | #!/usr/bin/perl -w | ||
+ | use strict; | ||
+ | use IO::Handle; | ||
+ | autoflush STDOUT 1; | ||
+ | autoflush STDERR 1; | ||
+ | use tmstub; | ||
+ | use Tk; | ||
+ | #use Tk::FontDialog; | ||
+ | my $title = 'piduino menu'; | ||
+ | my $version = "v0.2 2012-07-29"; | ||
+ | |||
+ | my $mw = new MainWindow(); | ||
+ | # PAL resolution 656x512@16 | ||
+ | $mw->overrideredirect(1); | ||
+ | my ($scr_w, $scr_h) = $mw->maxsize(); | ||
+ | t "maxsize says: $scr_w x $scr_h"; | ||
+ | #~ $mw->geometry("656x512+0+0"); | ||
+ | $mw->geometry("680x540+0+0"); | ||
+ | #~ $mw->FullScreen; | ||
+ | #~ $mw->geometry(($mw->maxsize())[0] .'x'.($mw->maxsize())[1] . "+0+0"); | ||
+ | my $c = $mw->Canvas(-bg => "yellow", -width => 680, -height => 540)->pack; | ||
+ | # in theory we should be able to scroll infinitely but let's stick to something reasonable | ||
+ | #$c->configure(-scrollregion => [0,0, 600, 400]); | ||
+ | my $font = $mw->fontCreate('menufont', -family => 'Village', -size => 38, -weight=>'bold'); | ||
+ | |||
+ | my $menu_w = 400; | ||
+ | my $menu_h = 100; | ||
+ | |||
+ | # it don't work! | ||
+ | #~ invisible_cursor(); | ||
+ | |||
+ | # warp pointer tests... | ||
+ | $mw->after(100, sub {warp(20,20)}); | ||
+ | |||
+ | sub warp { | ||
+ | my($x, $y) = @_; | ||
+ | t "warp pointer to $x $y"; | ||
+ | $c->focus; | ||
+ | $mw->eventGenerate("<Motion>", | ||
+ | -when => 'head', | ||
+ | -x => $x, -y => $y, -warp => 1 | ||
+ | ); | ||
+ | } | ||
+ | |||
+ | # keybinding tests... | ||
+ | $mw->bind('<KeyPress>' => \&print_keysym); | ||
+ | |||
+ | sub print_keysym { | ||
+ | my($widget) = @_; | ||
+ | my $e = $widget->XEvent; # get event object | ||
+ | my($keysym_text, $keysym_decimal) = ($e->K, $e->N); | ||
+ | print "keysym=$keysym_text, numeric=$keysym_decimal\n"; | ||
+ | } | ||
+ | |||
+ | # hide cursor | ||
+ | sub invisible_cursor { | ||
+ | my $bitmapfile = Tk->findINC('trans_cur.xbm'); | ||
+ | my $maskfile = Tk->findINC('trans_cur.mask'); | ||
+ | $mw->configure(-cursor => [ '@' . $bitmapfile, $maskfile, 'black', 'white' ] ); | ||
+ | } | ||
+ | |||
+ | # handy font chooser | ||
+ | #~ $mw->Button( | ||
+ | #~ -font => $font, | ||
+ | #~ -text => "Font", | ||
+ | #~ -command => sub{choose_font()}, | ||
+ | #~ )->pack(); | ||
+ | |||
+ | # debug grid... | ||
+ | $c->createGrid(0, 0, 10, 10); | ||
+ | $c->createGrid(0, 0, 50, 50, -lines => 1, -dash => '-.'); | ||
+ | $c->createGrid(0, 0, 100, 100, -width => 3, -lines => 1); | ||
+ | |||
+ | # TODO - load settings from file | ||
+ | menubox("Music", 0, 0); | ||
+ | menubox("Controls", 0, 1); | ||
+ | menubox("Vehicle", 0, 2); | ||
+ | menubox("System", 0, 3); | ||
+ | menubox("Settings", 0, 3); | ||
+ | # menubox("More...", 1, 0); | ||
+ | |||
+ | #~ music selection | ||
+ | #~ playlists | ||
+ | #~ artists by name | ||
+ | #~ albums | ||
+ | #~ directories | ||
+ | |||
+ | #~ controls | ||
+ | #~ volume | ||
+ | #~ bass | ||
+ | #~ treble | ||
+ | #~ balance | ||
+ | #~ system reboot | ||
+ | #~ system shutdown | ||
+ | #~ app quit | ||
+ | #~ app restart | ||
+ | |||
+ | |||
+ | |||
+ | sub menubox { | ||
+ | my($t, $mx, $my) = @_; | ||
+ | my $x1 = $mx * $menu_w; | ||
+ | my $y1 = $my * $menu_h; | ||
+ | my $x2 = $x1 + $menu_w; | ||
+ | my $y2 = $y1 + $menu_h; | ||
+ | |||
+ | $c->createRectangle($x1, $y1, $x2, $y2, | ||
+ | -fill => "blue", | ||
+ | -activefill => "green", | ||
+ | -outline => "green", | ||
+ | -activeoutline => "orange", | ||
+ | ); | ||
+ | $c->createText($x1 + ($menu_w/2), $y1+ ($menu_h/2), | ||
+ | -text => "$t", | ||
+ | -font => $font, | ||
+ | -fill => "black", | ||
+ | ); | ||
+ | } | ||
+ | |||
+ | |||
+ | =for docs | ||
+ | |||
+ | options: | ||
+ | |||
+ | * canvas width and height to cover the whole menu system | ||
+ | * sub-menus can't all be visible simultaneously so we'd have to hide them | ||
+ | * group items together | ||
+ | |||
+ | do top level menu first | ||
+ | |||
+ | menu level zero at 0,0 | ||
+ | menu level one appears at 1*menu_w, selected item * menu_h | ||
+ | |||
+ | |||
+ | |||
+ | =cut | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | sub choose_font | ||
+ | { | ||
+ | # t $mw->GetDescriptiveFontName($font); | ||
+ | |||
+ | # my $f = $mw->FontDialog->Show( | ||
+ | #-initfont => $font, | ||
+ | #-nicefont => 1 | ||
+ | # ); | ||
+ | # return unless defined $f; | ||
+ | # $mw->RefontTree(-font => $f, -canvas => 1); | ||
+ | # my $d = $mw->GetDescriptiveFontName($f); | ||
+ | # t $d; | ||
+ | # $font = $f; | ||
+ | |||
+ | } | ||
+ | |||
+ | |||
+ | MainLoop(); | ||
+ | |||
+ | </syntaxhighlight> | ||
+ | </div> | ||
+ | |||
+ | |||
+ | OK, using adaencoder on the Pi-arduino bridge! The Arduino is just saying what it sees over serial. | ||
+ | |||
+ | <div style ="height:300px;overflow-x:hidden;overflow-y:auto;border: 4px solid green;"> | ||
+ | '''Raspberry Pi menu for rotary encoder''' | ||
+ | <syntaxhighlight lang="cpp" line="GESHI_FANCY_LINE_NUMBERS" enclose="div"> | ||
+ | #include <PinChangeInt.h> // necessary otherwise we get undefined reference errors. | ||
+ | #include <AdaEncoder.h> | ||
+ | |||
+ | #define a_PINA 10 | ||
+ | #define a_PINB 11 | ||
+ | #define BTN 9 | ||
+ | #define LED 13 | ||
+ | #define b_PINA A3 | ||
+ | #define b_PINB A4 | ||
+ | |||
+ | int8_t clicks=0; | ||
+ | char id=0; | ||
+ | |||
+ | void setup() | ||
+ | { | ||
+ | Serial.begin(9600); | ||
+ | Serial.println("---------------------------------------"); | ||
+ | pinMode(BTN, INPUT); | ||
+ | pinMode(LED, OUTPUT); | ||
+ | digitalWrite(BTN, HIGH); | ||
+ | AdaEncoder::addEncoder('a', a_PINA, a_PINB); | ||
+ | // AdaEncoder::addEncoder('b', b_PINA, b_PINB); | ||
+ | } | ||
+ | |||
+ | void loop() | ||
+ | { | ||
+ | static unsigned long btnHeld = 0; | ||
+ | encoder *thisEncoder; | ||
+ | thisEncoder=AdaEncoder::genie(&clicks, &id); | ||
+ | if (thisEncoder != NULL) { | ||
+ | thisEncoder=AdaEncoder::getFirstEncoder(); | ||
+ | |||
+ | Serial.print(id); | ||
+ | Serial.print(':'); | ||
+ | Serial.print(clicks, DEC); | ||
+ | if (clicks > 0) { | ||
+ | Serial.println(" UP"); | ||
+ | } | ||
+ | if (clicks < 0) { | ||
+ | Serial.println(" DOWN"); | ||
+ | } | ||
+ | } | ||
+ | // Upon button press... | ||
+ | if((digitalRead(BTN) == LOW) && !btnHeld){ | ||
+ | btnHeld = millis(); | ||
+ | digitalWrite(LED, HIGH); | ||
+ | Serial.println("pressed"); | ||
+ | |||
+ | } | ||
+ | // Upon button release... | ||
+ | if((digitalRead(BTN) == HIGH) && btnHeld){ | ||
+ | long t = millis(); | ||
+ | digitalWrite(LED, LOW); | ||
+ | Serial.print("released: (after "); | ||
+ | t -= btnHeld; | ||
+ | Serial.print(t, DEC); | ||
+ | Serial.println(" ms)"); | ||
+ | |||
+ | btnHeld = 0; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | </syntaxhighlight> | ||
+ | </div> |
Latest revision as of 00:51, 12 June 2014
I have recovered a number of ALPS rotary encoders from discarded industrial CRT monitors. I'm working on building a user interface menu system that makes use of the rotary encoders as the sole input technique.
multiple encoders
Try out http://code.google.com/p/adaencoder/ and PinChangeInt library (http://code.google.com/p/arduino-pinchangeint/) see...
http://arduino.cc/playground/Main/RotaryEncoders#Example14
See if it can cope with two encoders at rapid rate usage.
OK, working well --Michael Erskine 18:10, 29 July 2012 (EST)
When using the Raspberry Pi as the menu display system we need to do a few things to a stock raspbian install...
- auto login and start X: use option in raspi-config
- switch off screen blanking: /etc/lightdm/lightdm.conf in SeatDefaults section "xserver-command=X -s 0 -dpms"
- auto start application
Here I'm building a Perl Tk menu application prototype using Tk::Canvas. I haven't yet wired up the serial as I'm just trying out some graphic styles on the small PAL LCD screen.
OK, using adaencoder on the Pi-arduino bridge! The Arduino is just saying what it sees over serial.