2023年11月10日 星期五

XBOX joystick modification with ESP32

Purpose:
This topic uses ESP32 to modify the broken XBOX Joystick and analyze the operating actions of two Joysticks and four Buttons (A, B, X, Y)! This topic is also about learning the parts of Joystick and Button!
這個專題是使用ESP32將壞掉的XBOX Joystick改裝, 把兩個Joystick和四個Button(A,B,X,Y)的操作動作解析出來! 這專題是另類的Joystick和Button零件的學習!

Tools: 

圖一: MutilMeter
Use MutilMeter to find the contact location of the Joystick and button, then spot weld it to the header connector and connect it to the designated pin of the ESP32.
利用MutilMeter來找出Joystick和button的接點位置, 然後將其點焊接到header接頭並連接至ESP32的指定腳位.

Fundamental:
Joystick
Dual-axis button rocker module, the rocker can move along the X-axis and Y-axis in two directions (VRx and VRy). Because of its internal variable resistance, it outputs a signal of 0-1023 when moving.
雙軸按鍵搖桿模組,搖桿可沿著 X軸 和 Y軸 兩個方向移動 (VRx 和 VRy)。因其內部的可變電阻,移動時,對外輸出 0-1023 的訊號。



YouTube Demo:

ESP32 Code:

#include <ezButton.h>
//-----Global variable---------------------------------------
#define LED_BUILTIN 2
//--------joystick------------------------------------------
#define VRX_PIN_L  33 // ESP32 pin GPIO33 (ADC)
#define VRY_PIN_L  32 // ESP32 pin GPIO32 (ADC)
#define VRX_PIN_R  35 // ESP32 pin GPIO35 (ADC)
#define VRY_PIN_R  34 // ESP32 pin GPIO34 (ADC)
#define SW_X       18
#define SW_Y       16
#define SW_A       17
#define SW_B       19

#define LEFT_THRESHOLD_L  2200  
#define RIGHT_THRESHOLD_L 900
#define UP_THRESHOLD_L    2200  
#define DOWN_THRESHOLD_L  900  

#define LEFT_THRESHOLD_R  2200  
#define RIGHT_THRESHOLD_R 900
#define UP_THRESHOLD_R    2200  
#define DOWN_THRESHOLD_R  900  

#define COMMAND_NO_L     0x00
#define COMMAND_LEFT_L   0x01
#define COMMAND_RIGHT_L  0x02
#define COMMAND_UP_L     0x04
#define COMMAND_DOWN_L   0x08

#define COMMAND_NO_R     0x00
#define COMMAND_LEFT_R   0x01
#define COMMAND_RIGHT_R  0x02
#define COMMAND_UP_R     0x04
#define COMMAND_DOWN_R   0x08

int valueX_L = 0 ; // to store the X-axis value
int valueY_L = 0 ; // to store the Y-axis value
int command_L = COMMAND_NO_R;
int valueX_R = 0 ; // to store the X-axis value
int valueY_R = 0 ; // to store the Y-axis value
int command_R = COMMAND_NO_R;
//----------------------------------------------

int bValue_A = 0; // To store value of the button
int bValue_B = 0; // To store value of the button
int bValue_X = 0; // To store value of the button
int bValue_Y = 0; // To store value of the button
ezButton buttonA(SW_A);
ezButton buttonB(SW_B);
ezButton buttonX(SW_X);
ezButton buttonY(SW_Y);
//------------------------------------------------------------

//--------- Flag structure --------------------------------------
//----------------------------------------------------------
#define LINE_BUFFER_LENGTH 1024
typedef struct _vFlag
{
  uint8_t LEDFlag=0;
  uint8_t BTFlag=0;
}vFlag;
vFlag *flag_Ptr;
vFlag flag;
//--------- uart structure --------------------------------------
//----------uart--------------
typedef struct _vUart
{
  char c;
  int lineIndex = 0;
  int line1Index = 0;
  int BTlineIndex = 0;
  bool lineIsComment;
  bool lineSemiColon;
  char line[128];
  char BTline[20];
  String inputString;
  String BTinputString;
} vUart;
vUart *Uart_Ptr;
vUart Uart;
//-------------------------------------
TaskHandle_t hled;
TaskHandle_t huart;

void vLEDFlashTask(void *pvParameters);
void vUARTTask(void *pvParameters);

void initial()
{
  Serial.println(F("Create Task"));
  //----------------------------------------------------------------------
  // Now set up two tasks to run independently.
  xTaskCreatePinnedToCore(
    vLEDFlashTask, "LEDTask" // A name just for humans
    ,
    1024 // This stack size can be checked & adjusted by reading the Stack Highwater
    ,
    NULL, 2 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
    ,
    &hled //handle
    ,
    0);

  xTaskCreatePinnedToCore(
    vUARTTask, "UARTTask" // A name just for humans
    ,
    1024 // This stack size can be checked & adjusted by reading the Stack Highwater
    ,
    NULL, 3 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
    ,
    &huart //handle
    ,
    0);

  //----------------------------------------------------------------------
}


void setup() {
  Serial.begin(9600);
  /**240(default 240 160 80 40 20 and 10Mhz)***/
  setCpuFrequencyMhz(160);
  initial();
  //-----------------------------------------------------------------
  buttonA.setDebounceTime(50); // set debounce time to 50 milliseconds
  buttonB.setDebounceTime(50); // set debounce time to 50 milliseconds
  buttonX.setDebounceTime(50); // set debounce time to 50 milliseconds
  buttonY.setDebounceTime(50); // set debounce time to 50 milliseconds
  //------------------------------------------------
  Serial.println(F("System On!"));
  //-------------------------------------------
}

void loop()
{
  Serial.print(F("Main at core:"));
  Serial.println(xPortGetCoreID());
  while (1)
  {
    buttonA.loop(); // MUST call the loop() function first
    buttonB.loop(); // MUST call the loop() function first
    buttonX.loop(); // MUST call the loop() function first
    buttonY.loop(); // MUST call the loop() function first
    // Read the button value
    bValue_A = buttonA.getState();
    bValue_B = buttonB.getState();
    bValue_X = buttonX.getState();
    bValue_Y = buttonY.getState();

    if (buttonA.isPressed()) {
      Serial.println("The buttonA is pressed");
      // TODO do something here
    }
    if (buttonA.isReleased()) {
      Serial.println("The buttonA is released");
      // TODO do something here
    }
    if (buttonB.isPressed()) {
      Serial.println("The buttonB is pressed");
      // TODO do something here
    }
    if (buttonB.isReleased()) {
      Serial.println("The buttonB is released");
      // TODO do something here
    }
    if (buttonX.isPressed()) {
      Serial.println("The buttonX is pressed");
      // TODO do something here
    }
    if (buttonX.isReleased()) {
      Serial.println("The buttonX is released");
      // TODO do something here
    }
    if (buttonY.isPressed()) {
      Serial.println("The buttonY is pressed");
      // TODO do something here
    }
    if (buttonY.isReleased()) {
      Serial.println("The buttonY is released");
      // TODO do something here
    }
    //--------------------------------------------------------
    valueX_L = analogRead(VRX_PIN_L);
    valueY_L = analogRead(VRY_PIN_L);
    valueX_R = analogRead(VRX_PIN_R);
    valueY_R = analogRead(VRY_PIN_R);
    // converts the analog value to commands
    // reset commands
    command_L = COMMAND_NO_L;
    command_R = COMMAND_NO_R;
    // check left/right commands
   
    if (valueX_L > LEFT_THRESHOLD_L)
      command_L = command_L | COMMAND_LEFT_L;
    else if (valueX_L < RIGHT_THRESHOLD_L)
      command_L = command_L | COMMAND_RIGHT_L;
   
    // check up/down commands
    if (valueY_L > UP_THRESHOLD_L)
      command_L = command_L | COMMAND_UP_L;
    else if (valueY_L < DOWN_THRESHOLD_L)
      command_L = command_L | COMMAND_DOWN_L;


    // print command to serial and process command
   
    if (command_L & COMMAND_LEFT_L) {
      Serial.println("COMMAND LEFT_L");
      // TODO: add your task here
    }

    if (command_L & COMMAND_RIGHT_L) {
      Serial.println("COMMAND RIGHT_L");
      // TODO: add your task here
    }

    if (command_L & COMMAND_UP_L) {
      Serial.println("COMMAND UP_L");
      // TODO: add your task here
    }

    if (command_L & COMMAND_DOWN_L) {
      Serial.println("COMMAND DOWN_L");
      // TODO: add your task here
    }
   
    //-----------------------------------------------------
    if (valueX_R > LEFT_THRESHOLD_R)
      command_R = command_R | COMMAND_LEFT_R;
    else if (valueX_R < RIGHT_THRESHOLD_R)
      command_R = command_R | COMMAND_RIGHT_R;
   
    // check up/down commands
    if (valueY_R > UP_THRESHOLD_R)
      command_R = command_R | COMMAND_UP_R;
    else if (valueY_R < DOWN_THRESHOLD_R)
      command_R = command_R | COMMAND_DOWN_R;


    // print command to serial and process command
   
    if (command_R & COMMAND_LEFT_R) {
      Serial.println("COMMAND LEFT_R");
      // TODO: add your task here
    }

    if (command_R & COMMAND_RIGHT_R) {
      Serial.println("COMMAND RIGHT_R");
      // TODO: add your task here
    }

    if (command_R & COMMAND_UP_R) {
      Serial.println("COMMAND UP_R");
      // TODO: add your task here
    }

    if (command_R & COMMAND_DOWN_R) {
      Serial.println("COMMAND DOWN_R");
      // TODO: add your task here
    }
    //-----------------------------------------------------
  }//----while(1)-------------------------------------------

}
//--------------------------------------------------------
/*--------------------------------------------------*/
void vLEDFlashTask(void *pvParameters) // This is a task.
{
  (void)pvParameters;
 
  Serial.print(F("LEDTask at core:"));
  Serial.println(xPortGetCoreID());
  pinMode(LED_BUILTIN, OUTPUT);
  for (;;) // A Task shall never return or exit.
  {
    digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
    vTaskDelay(200);
    digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
    vTaskDelay(200);
  }
}

//-------------------------------------------
void vUARTTask(void *pvParameters)
{
  (void)pvParameters;

  Serial.print(F("UARTTask at core:"));
  Serial.println(xPortGetCoreID());
  for (;;)
  {
    while (Serial.available() > 0)
    {
      Uart.c = Serial.read();
 
      if ((Uart.c == '\n') || (Uart.c == '\r'))
      { // End of line reached
        if (Uart.lineIndex > 0)
        { // Line is complete. Then execute!
          Uart.line[Uart.lineIndex] = '\0'; // Terminate string
          //Serial.println( F("Debug") );
          //Serial.println( Uart.inputString );
          processCommand(Uart.line); // do something with the command
          Uart.lineIndex = 0;
          Uart.inputString = "";
        }
        else
        {
          // Empty or comment line. Skip block.
        }
        Uart.lineIsComment = false;
        Uart.lineSemiColon = false;
        Serial.println(F("ok>"));
      }
      else
      {
        //Serial.println( c );
        if ((Uart.lineIsComment) || (Uart.lineSemiColon))
        {
          if (Uart.c == ')')
            Uart.lineIsComment = false; // End of comment. Resume line.
        }
        else
        {
          if (Uart.c == '/')
          { // Block delete not supported. Ignore character.
          }
          else if (Uart.c == '~')
          { // Enable comments flag and ignore all characters until ')' or EOL.
            Uart.lineIsComment = true;
          }
          else if (Uart.c == ';')
          {
            Uart.lineSemiColon = true;
          }
          else if (Uart.lineIndex >= LINE_BUFFER_LENGTH - 1)
          {
            Serial.println("ERROR - lineBuffer overflow");
            Uart.lineIsComment = false;
            Uart.lineSemiColon = false;
          }
          else if (Uart.c >= 'a' && Uart.c <= 'z')
          { // Upcase lowercase
            Uart.line[Uart.lineIndex] = Uart.c - 'a' + 'A';
            Uart.lineIndex = Uart.lineIndex + 1;
            Uart.inputString += (char)(Uart.c - 'a' + 'A');
          }
          else
          {
            Uart.line[Uart.lineIndex] = Uart.c;
            Uart.lineIndex = Uart.lineIndex + 1;
            Uart.inputString += Uart.c;
          }
        }
      }
    } //while (Serial.available() > 0)
    vTaskDelay(10);
  }
}
//------------------------------------------------------------
void processCommand(char *data)
{
  int len, xlen, ylen, zlen, alen;
  char ctemp[20];

  len = Uart.inputString.length();
  if (strstr(data, "VER") != NULL)
  {
    Serial.println(F("W_ATE_Board_20231109"));
  }

}




沒有留言:

張貼留言