User Input Options

 

Getting User Input into your MotorVator

Many of the models that we build are self-sufficient: they take input
from sensors within the model and make decisions accordingly.

Some models however need to interact with Humans. An example is my
TicTaeToe Player.

The MotorVator software is programmed to decide which moves to make, and draw the
symbol on the board, but [obviously] needs to be told about my moves.

Here are three options for getting User Input:

Meccanisms Director

Rotary
Encoder

Keypad

 

Director

The simplest way is to use the Meccanisms Director to input my moves.
The READ BUTTON command lets you check whether any of the Director Buttons
are being pressed. So we use one button to cycle the Square_Number Up,
another to Cycle it Down, and a third to "Lock In" our move.

In MeccCode II:


......
' Get Move Routine

do
    If Joystick1Button2 = 1 then        ' 

Left Front Button Goes Up
        Increment Square_Number
        
If Square_Number 10 then        ' Wrap from 9 to 1
            Square_Number = 1
        End if
    End if

    If Joystick2Button2 = 1 then        ' 

Right front  Button Goes Down
        Decrement Square_Number
        
If Square_Number 0 then
            Square_Number 
9    ' Wrap from 1 to 9
        End if
    End if
Until (Joystick1Button1 = 1)    ' 
keep looking at the director buttons  
                                                 until the 
"Lock In Move" button is pressed
.....

Rotary Encoder

The Meccanisms Director is easy to implement, but you might prefer to
not need to have it attached. Next option is to use a rotary encoder. This
looks like a volume knob, but can rotate either way and can be pressed.
Some rotary encoders can tell you at which angle they are set: this one
simply tells you how many 'clicks' it has turned, and in which direction.
We've left the knob off so you can see the rotary encode itself. The piece
of matrix board is drilled to match Meccano spacing for mounting in a
frame.

So we set it up to Increment the Square_number when turned Clockwise,
Decrement when turned the Counter-Clockwise, and "lock in" the move when
pressed.

This rotary encoder has two "channels" that give pulses as
the knob is turned. The timing diagram looks like this (the dotted lines
show the position where the knob "clicks" and stays put"):

So to work out which way the knob has turned, we do the following:

1. When the level of channel A (Digital Input 3) changes, we firstly
check to see if it has changed to LOW. If not then we ignore the change,
because it is the "Falling edge" that we need to check. Note
that we use an EVENT to make sure that we can immediately catch when
Channel A changes.

2. If it is a falling edge, then we check the level of Channel B (Digital
Input 4). From the diagram we can see that if Channel B is LOW at the
point where Channel 1 goes from High to Low (the "falling edge")
then we are turning Clockwise, otherwise we are turning
CounterClockWise. 

So the Rotary Encoder takes up three of our Digital Inputs: 1 for
ChannelA, 1 for ChannelB and 1 for the "Lock In Move" press. If
we didn't need to check for direction then we could get away without
Channel B. You might say use a Ratchet Wheel to limit the possible
direction of rotation to Clockwise only.

In MeccCodeII, it will something like this:


SetEvent CheckEncoderOnOff3Event    the CheckEncoder Routine will run with any change of OnOff3 Event

......
' Get Move Section

do 
    Square_Number = Square_Number + Ce_CW
    Ce_CW = 0            ; clear any ClockWise Pulses, now that we'

ve used them
    
If Square_Number 10 Then
        Square_Number 
1        ; and cycle around from 9 to 1 if required
    End 
If

    

Square_Number Square_Number Ce_CCW
    Ce_CW 
0            clear any CounterClockWise Pulsesnow that weve used them
    
If Square_Number 0 Then
        Square_Number 
9        ; and cycle around from 1 to 9 if required
    End 
If

Until ReadOnOff(1) = 1    ; do until the Lock In Move Button is pressed
Now we have a move in Square_Number

....
.....

Declare EventHandler CheckEncoder()

If ReadOnOff(3) <> 0 Then      we are only interested if the Channel A (OnOff3has gone to 1

    If ReadOnOff(4) = 1    Then    ; If Channel B is 1then 
        Ce_CCW 
Ce_CCW 1    Counter Clockwise turn
    
Else
        
Ce_CW Ce_CW 1    Clockwise Turn
    
Endif
Endif

Keypad

The rotary encoder is compact, but not that intuitive for kids. So a
better alternative is a keypad that maps to the tictactoe board.

The keypad is about $US5, from Jaycar (www.jaycar.com.au catalogue
SP0770). It is wired as a simple 4 rows by 3 columns matrix. As purchased,
there is no logic built in - it is a simple collection of switches.

By wiring it as above, we can use Analog Inputs 3 to 6 to determine
when a key is pressed.

We connect each column to ground via a different value resistor. The
values of the resistors used are not critical - we chose 19K, 47K and 82K
to give a reasonable separation.

Now the cunning part: 

When no key is pressed, all of the Analog Inputs
will have a reading of 250+.  

When a key is pressed, one of the
Analog ports will be connected to ground via one of the resistors:


  • If it is connected via the 82K resistor, then the reading will be about
    150. 

  • If it is connected via the 47K resistor, then the reading will be about
    90. 

  • If it is connected via the 19K resistor, then the reading will be about
    50.

    (You need to find these readings by trial and error, using the CLI READ
    Status Command. Just start the rolling status read, then press each key in
    turn and see the corresponding reading).

All the keys from the same column (e.g. 1, 4, 7 and *) will give the
same reading.

Which key it is depends on which Analog Port has this reading.

In the Diagram above, 

- Keys 1, 2 and 3 are connected to analogue Input 4. 

- Keys 4, 5 and 6 are connected to analogue Input 3. 

- Keys 7, 8 and 9 are connected to analogue Input 6. 

- Keys *, 0 and # are connected to analogue Input 5. 

So if we get a reading of 90 from Analog Input 6, we know that the key
pressed is an 8 (middle column, row 3).

(This system has the advantage of not requiring debouncing, but can't cope
with more than one key pressed at a time. (Debouncing can be needed when
you connect a simple press-switch to an input. As the switch closes it
often generates a momentary contact, then goes open before settling down
to closed. Therefore to make the detection reliable it is normal to check
the status more than once before confirming that the switch is indeed
closed. There is more to debouncing that this, but we will leave that for
another day ). 

In MeccCode II, this routine will look like


Declare Function Keypad () Returns Byte
Keypress 
0
Keyadc 
ReadAnalog(4)

if 

KeyAdc 80 then
    
Return 1
end 
if
if 
KeyAdc 120 then
    
Return 2
end 
if
If 
keyAdc <180 then
    
Return 3
end 
if

KeyAdc ReadAnalog (3)<br>
if 
KeyAdc 80 then
    
Return 4
end 
if
if 
KeyAdc 120 then
    
Return 5
end 
if
If 
keyAdc <180 then
    
Return 6
end 
if

Keyadc ReadAnalog(6)
if 
KeyAdc 80 then
    
Return 7
end 
if
if 
KeyAdc 120 then
    
Return 8
end 
if
If 
keyAdc <180 then
    
Return 9
end 
if

return 

0
End 
Function