Thread: Using State Pattern and Joystick

  1. #1
    Registered User
    Join Date
    Dec 2015
    Posts
    92

    Using State Pattern and Joystick

    Hello everyone,
    I am implement using joystick as Password Logger, where Joystick remembers 3 out of 4 UTTERMOST positions, and the combination of the THREE joystick positions represents a PASSWORD.

    Since I do not have any joystick, I connected two potentiometers with voltage divider to simulate the real Joystick since it reads voltage and converts it back to analog 10 bit value.


    Joystick uttermost position vs analog value:

    +X coordinate = 1023
    -X coordinate = 0
    +Y coordinate = 1023
    -Y coordinate = 0

    Idle position = (X, Y) ~= (511, 511)

    So basically how it works, In order to memorize any position, joystick needs to be first in the IDLE position, and after it moves to for example in RIGHT position it needs to get back to IDLE position in order for a position to be memorized.

    So this would be an example of a successful/unsuccessfully memorization:
    IDLE -> RIGHT -> IDLE (Memorized RIGHT Position Succesfully)
    IDLE -> IDLE -> IDLE (Unsuccessful Position Memorization)
    IDLE -> RIGHT -> LEFT (Unsuccesful Positition Memorization - after getting to RIGHT position it should get back to IDLE not to LEFT position)

    I also defined a DEADZONE
    https://s4.postimg.org/g4k4t1svh/Joystick.pngpic uploadcertificity.com

    With boundaries:
    Code:
    #define MAX_X_POSITION        1000
    #define MIN_X_POSITION        20
    #define MAX_Y_POSITION        1000
    #define MIN_Y_POSITION        20
    So Joystick method check whether Joystick is in DEAD_ZONE or not based on the current x and y coordinates:
    Code:
    int8_t Joystick::getZone(int nX, int nY)
    {
        if (nX < 0 && nX > 1023 || nY < 0 && nY > 1023)
        {
            return INVALID_PARAMETER;
        }
    
        if (nX > MAX_X_POSITION || nX < MIN_X_POSITION || nY > MAX_Y_POSITION || nY < MIN_Y_POSITION)
        {
            return NOT_IN_DEADZONE;
        }
        return IN_DEADZONE;
    }
    So if joystick is in DEADZONE than it's considered to be in an IDLE position.

    What I basically used is State pattern, where every Joystick Position is represented as a class,
    and class JoystickState is used as an interface, where every state implements that interface. Every concrete state is a Singleton:

    0. JoystickState (INTERFACE) Joystick/JoystickState.h at master * IvanAntunovic/Joystick * GitHub

    1. IdleJoystickState Joystick/IdleJoystickState.h at master * IvanAntunovic/Joystick * GitHub

    2. UpJoystickState https://github.com/IvanAntunovic/Joy...oystickState.h

    3. DownJoystickState https://github.com/IvanAntunovic/Joy...oystickState.h

    4. RightJoystickState https://github.com/IvanAntunovic/Joy...oystickState.h

    5. LeftJoystickState https://github.com/IvanAntunovic/Joy...oystickState.h


    every concrete state has a handleCoordinates method, where it changes it's next state based on the current x and y paramters, you can see that a CONTEXT which is Joystick is passed to the function.

    For example in RightJoystickState::handleCoordinates method

    Code:
    #define INVALID_PARAMETER   -1
    #define IN_DEADZONE          0
    #define NOT_IN_DEADZONE      1
    Code:
    void RightJoystickState::handleCoordinates(int nX, int nY, Joystick & joystick)
    {
        int8_t retVal = joystick.getZone(nX, nY);
            // If we are in DEADZONE change state to IDLE
        if (retVal == IN_DEADZONE)
        {
            joystick.changeState(IdleJoystickState::getInstance());
            if (joystick.isPasswordSet())
            {
                joystick.position_states[3] = IdleJoystickState::getInstance();
            }
            Serial.println("Joystick moved to Idle Position!");
        }
            // If we are NOT in DEADZONE, then we stay in the same state (RIGHT)
            // From Right State we can only get back to IDLE state in order to MEMORIZE a MOVEMENT
        else if (retVal == NOT_IN_DEADZONE)
        {
            Serial.println("Joystick is not in Deadzone! - Right");
        }
        else if (retVal == INVALID_PARAMETER)
        {
            Serial.println("Invalid parameters!");
        }
    }
    or a little more complicated IdleJoystickState

    Code:
    void IdleJoystickState::handleCoordinates(int nX, int nY, Joystick & joystick)
    {
        int8_t retVal = joystick.getZone(nX, nY);
        Serial.print("Ret Val: ");
        Serial.println(retVal);
        Serial.print( "MAX_X_POSITION: ");
        Serial.println( MAX_X_POSITION );
        Serial.print("MAX_Y_POSITION: ");
        Serial.println( MAX_Y_POSITION );
        
            // If we are NOT in DEADZONE that means we need to change our state from IDLE to one of the 4 
            // States based on the X and Y coordinates
        if (retVal == NOT_IN_DEADZONE)
        {
            int8_t bufferFreeIndexNum;
            if (nX > MAX_X_POSITION)
            {
                bufferFreeIndexNum = this->getBufferFreeIndex(joystick);
    
                if (bufferFreeIndexNum != NOK)
                {
                    joystick.changeState(RightJoystickState::getInstance());
                    joystick.position_states[bufferFreeIndexNum] = RightJoystickState::getInstance();
                    Serial.println( "Joystick moved to Right Position!");
                }
            }
            else if (nX < MIN_X_POSITION)
            {
                bufferFreeIndexNum = this->getBufferFreeIndex(joystick);
    
                if (bufferFreeIndexNum != NOK)
                {
                    joystick.changeState(LeftJoystickState::getInstance());
                    joystick.position_states[bufferFreeIndexNum] = RightJoystickState::getInstance();
                    Serial.println("Joystick moved to Left Position!");
                }
            }
            else if (nY > MAX_Y_POSITION)
            {
                bufferFreeIndexNum = this->getBufferFreeIndex(joystick);
    
                if (bufferFreeIndexNum != NOK)
                {
                    joystick.changeState(UpJoystickState::getInstance());
                    joystick.position_states[bufferFreeIndexNum] = UpJoystickState::getInstance();
                    Serial.println("Joystick moved to Up Position!" );
                }
            }
            else if (nY < MIN_Y_POSITION)
            {
                bufferFreeIndexNum = this->getBufferFreeIndex(joystick);
    
                if (bufferFreeIndexNum != NOK)
                {
                    joystick.changeState(DownJoystickState::getInstance());
                    joystick.position_states[bufferFreeIndexNum] = DownJoystickState::getInstance();
                    Serial.println( "Joystick moved to Down position!" );
                }
            }
        }
            // If we are in the DEADZONE that means we stay in the currentState = IDLE State
        else if (retVal == IN_DEADZONE)
        {
            Serial.println( "Joystick is in Deadzone! - Idle");
        }
        else if (retVal == INVALID_PARAMETER)
        {
            Serial.println("Invalid parameters!" );
        }
        
    }
    The problem happens with +X (RIGHT position) and +Y (UP position) uttermost positions. For example when I am in the IDLE state.

    Joystick Memorizing LEFT Position
    https://s15.postimg.org/hnnn0ixnf/Jo...t_Position.jpgimage uploading sitecertificity.com

    Unsuccessful UP Position
    https://s13.postimg.org/rk3dkmg37/Jo...p_Position.jpg

    Unsuccessful RIGHT Position
    https://s24.postimg.org/nzpyona51/Jo...t_Position.jpgimage uploadercertificity.com

    I tested the program in visual studio and it seemed to work:

    Successful memorization: (Enter key 'P' for Password memorziation)
    https://s24.postimg.org/tea92kbv5/Jo...Successful.jpg

    After Succesfull memorization I tried to enter the password and log in (Enter key 'K' for logging in), but I entered on purpose on wrong position and it showed the message that wrong password is entered
    https://s7.postimg.org/irzd3qo5z/Joystick_Invalid.jpg

    Whole code in VS C++:
    https://github.com/IvanAntunovic/Joy...ree/master/src



    Whole code for Arduino:

    https://github.com/IvanAntunovic/Joy...er/Arduino/src

    It took me an hour to write this post, I tried to be as clear as possible, so I hope someone could help me resolve my problem. I really do not see what I am doing wrong since logic works in Visual studio, but then it fails once it is connected to the microcontroller.

    Thanks in advance and sorry if this is a wrong place to post this kind of question.

  2. #2
    Registered User
    Join Date
    Dec 2015
    Posts
    92
    SOLVED:

    OK I got it working, The map function was the problem... somehow it didn't map the values right.

    Analog Refrence Voltage is 5V for reading the analog values. And guess what, pin that was reading X coordinate was reading 0 - 2.62 V,
    and pin that was reading Y coordinate was reading 0 - 2.58 V (because of the voltage dividor I used). And that means I could only get analog values from 0 to ~536. So I mapped these values to get a full range from 0 - 2^10 - 1 and passed them as an nX and nY arguments to the handleCoordinates method, and it seems like I was passing the wrong MAPPED values.

    Trecherous map function...

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. State design pattern - can't find an error
    By ZeroesAndOnes in forum C++ Programming
    Replies: 12
    Last Post: 03-28-2017, 03:26 AM
  2. directx: how use it for joystick?
    By joaquim in forum Game Programming
    Replies: 0
    Last Post: 03-21-2015, 09:42 AM
  3. [win32] - how use joystick?
    By joaquim in forum Windows Programming
    Replies: 3
    Last Post: 08-11-2014, 01:01 PM
  4. Raw input from a HID joystick
    By Cynic in forum Networking/Device Communication
    Replies: 0
    Last Post: 05-10-2012, 09:19 AM
  5. Joystick
    By merlin371 in forum C++ Programming
    Replies: 2
    Last Post: 09-02-2003, 07:15 PM

Tags for this Thread