ricardoquesada / bluepad32

Bluetooth gamepad, mouse and keyboard support for ESP32 and PicoW
https://bluepad32.readthedocs.io/
Other
503 stars 53 forks source link

BluePad32 and RP2040 only working when connected to PC and arduino IDE open #72

Closed JclayArt closed 4 months ago

JclayArt commented 4 months ago

What happened?

I followed your instructions and Flashed Bluepad32 v4.0-beta1 onto an Arduino Nano RP2040 Connect and verified the install. While the RP2040 is connected to the PC and ArduinoIDE is open everything works as expected (the example code buttons all work to change the color and make the controller vibrate), I sync my PS4 controller to it and It will connect without any issues and run the example code as long as Arduino IDE is open. However when I try and power the Arduino RP2040 from an external source or Close ArduinoIDE the controller will no longer connect/loses connection.

Do you have any thoughts as to what could be causing this to only function when connected through USB and ArduinoIDE open? Maybe some sort of library issue that I'm not understanding?

I'm running the example controller code, maybe this is user error and I'm missing something here? Very excited to use your awesome Library to control a Nerf Dart Robot I've been building, very much hoping this is solvable.

Thanks for your time and efforts! -Joshua Clay

Bluepad32 Version

latest from develop branch

Bluepad32 version custom

Example: Using Git develop branch commit hash #xxxxxxx

Bluepad32 Platform

Arduino + NINA

Platform version

Arduino IDE 2.3.1

Controller

PlayStation4 controller

ESP32 chip

ESP32

ESP32 board

Arduino Nano RP2040 Connect

OS

None

Relevant log output

No response

Relevant sketch

// Copyright 2021 - 2023, Ricardo Quesada
// SPDX-License-Identifier: Apache 2.0 or LGPL-2.1-or-later

/*
 * This example shows how to use the Controller API.
 *
 * Supported on boards with NINA W10x. In particular, these boards:
 *  - Arduino MKR WiFi 1010,
 *  - UNO WiFi Rev.2,
 *  - Nano RP2040 Connect,
 *  - Nano 33 IoT,
 *  - Arduino MKR Vidor 4000
 */
#include <Bluepad32.h>

ControllerPtr myControllers[BP32_MAX_CONTROLLERS];

// Arduino setup function. Runs in CPU 1
void setup() {
  // Initialize serial
  Serial.begin(9600);
  while (!Serial) {
    // Wait for serial port to connect.
    // You don't have to do this in your game. This is only for debugging
    // purposes, so that you can see the output in the serial console.
    ;
  }

  String fv = BP32.firmwareVersion();
  Serial.print("Firmware version installed: ");
  Serial.println(fv);

  // To get the BD Address (MAC address) call:
  const uint8_t* addr = BP32.localBdAddress();
  Serial.print("BD Address: ");
  for (int i = 0; i < 6; i++) {
    Serial.print(addr[i], HEX);
    if (i < 5)
      Serial.print(":");
    else
      Serial.println();
  }

  // BP32.pinMode(27, OUTPUT);
  // BP32.digitalWrite(27, 0);

  // This call is mandatory. It sets up Bluepad32 and creates the callbacks.
  BP32.setup(&onConnectedController, &onDisconnectedController);

  // "forgetBluetoothKeys()" should be called when the user performs
  // a "device factory reset", or similar.
  // Calling "forgetBluetoothKeys" in setup() just as an example.
  // Forgetting Bluetooth keys prevents "paired" gamepads to reconnect.
  // But it might also fix some connection / re-connection issues.
  BP32.forgetBluetoothKeys();
}

// This callback gets called any time a new gamepad is connected.
// Up to 4 gamepads can be connected at the same time.
void onConnectedController(ControllerPtr ctl) {
  bool foundEmptySlot = false;
  for (int i = 0; i < BP32_MAX_GAMEPADS; i++) {
    if (myControllers[i] == nullptr) {
      Serial.print("CALLBACK: Controller is connected, index=");
      Serial.println(i);
      myControllers[i] = ctl;
      foundEmptySlot = true;

      // Optional, once the gamepad is connected, request further info about the
      // gamepad.
      ControllerProperties properties = ctl->getProperties();
      char buf[80];
      sprintf(buf,
              "BTAddr: %02x:%02x:%02x:%02x:%02x:%02x, VID/PID: %04x:%04x, "
              "flags: 0x%02x",
              properties.btaddr[0], properties.btaddr[1], properties.btaddr[2],
              properties.btaddr[3], properties.btaddr[4], properties.btaddr[5],
              properties.vendor_id, properties.product_id, properties.flags);
      Serial.println(buf);
      break;
    }
  }
  if (!foundEmptySlot) {
    Serial.println(
        "CALLBACK: Controller connected, but could not found empty slot");
  }
}

void onDisconnectedController(ControllerPtr ctl) {
  bool foundGamepad = false;

  for (int i = 0; i < BP32_MAX_GAMEPADS; i++) {
    if (myControllers[i] == ctl) {
      Serial.print("CALLBACK: Controller is disconnected from index=");
      Serial.println(i);
      myControllers[i] = nullptr;
      foundGamepad = true;
      break;
    }
  }

  if (!foundGamepad) {
    Serial.println(
        "CALLBACK: Controller disconnected, but not found in myControllers");
  }
}

void processGamepad(ControllerPtr gamepad) {
  // There are different ways to query whether a button is pressed.
  // By query each button individually:
  //  a(), b(), x(), y(), l1(), etc...

  if (gamepad->a()) {
    static int colorIdx = 0;
    // Some gamepads like DS4 and DualSense support changing the color LED.
    // It is possible to change it by calling:
    switch (colorIdx % 3) {
      case 0:
        // Red
        gamepad->setColorLED(255, 0, 0);
        break;
      case 1:
        // Green
        gamepad->setColorLED(0, 255, 0);
        break;
      case 2:
        // Blue
        gamepad->setColorLED(0, 0, 255);
        break;
    }
    colorIdx++;
  }

  if (gamepad->b()) {
    // Turn on the 4 LED. Each bit represents one LED.
    static int led = 0;
    led++;
    // Some gamepads like the DS3, DualSense, Nintendo Wii, Nintendo Switch
    // support changing the "Player LEDs": those 4 LEDs that usually indicate
    // the "gamepad seat".
    // It is possible to change them by calling:
    gamepad->setPlayerLEDs(led & 0x0f);
  }

  if (gamepad->x()) {
    // Duration: 255 is ~2 seconds
    // force: intensity
    // Some gamepads like DS3, DS4, DualSense, Switch, Xbox One S support
    // rumble.
    // It is possible to set it by calling:
    gamepad->setRumble(0xc0 /* force */, 0xc0 /* duration */);
  }

  // Another way to query the buttons, is by calling buttons(), or
  // miscButtons() which return a bitmask.
  // Some gamepads also have DPAD, axis and more.
  char buf[256];
  snprintf(buf, sizeof(buf) - 1,
           "idx=%d, dpad: 0x%02x, buttons: 0x%04x, "
           "axis L: %4li, %4li, axis R: %4li, %4li, "
           "brake: %4ld, throttle: %4li, misc: 0x%02x, "
           "gyro x:%6d y:%6d z:%6d, accel x:%6d y:%6d z:%6d, "
           "battery: %d",
           gamepad->index(),        // Gamepad Index
           gamepad->dpad(),         // DPad
           gamepad->buttons(),      // bitmask of pressed buttons
           gamepad->axisX(),        // (-511 - 512) left X Axis
           gamepad->axisY(),        // (-511 - 512) left Y axis
           gamepad->axisRX(),       // (-511 - 512) right X axis
           gamepad->axisRY(),       // (-511 - 512) right Y axis
           gamepad->brake(),        // (0 - 1023): brake button
           gamepad->throttle(),     // (0 - 1023): throttle (AKA gas) button
           gamepad->miscButtons(),  // bitmask of pressed "misc" buttons
           gamepad->gyroX(),        // Gyro X
           gamepad->gyroY(),        // Gyro Y
           gamepad->gyroZ(),        // Gyro Z
           gamepad->accelX(),       // Accelerometer X
           gamepad->accelY(),       // Accelerometer Y
           gamepad->accelZ(),       // Accelerometer Z
           gamepad->battery()       // 0=Unknown, 1=empty, 255=full
  );
  Serial.println(buf);

  // You can query the axis and other properties as well. See
  // Controller.h For all the available functions.
}

void processMouse(ControllerPtr mouse) {
  char buf[160];
  sprintf(buf,
          "idx=%d, deltaX:%4li, deltaY:%4li, buttons: 0x%04x, misc: 0x%02x, "
          "scrollWheel: %d, battery=%d",
          mouse->index(),        // Controller Index
          mouse->deltaX(),       // Mouse delta X
          mouse->deltaY(),       // Mouse delta Y
          mouse->buttons(),      // bitmask of pressed buttons
          mouse->miscButtons(),  // bitmask of pressed "misc" buttons
          mouse->scrollWheel(),  // Direction: 1=up, -1=down, 0=no movement
          mouse->battery()       // 0=Unk, 1=Empty, 255=full
  );
  Serial.println(buf);
}

void processBalanceBoard(ControllerPtr balance) {
  char buf[160];
  sprintf(buf,
          "idx=%d, tl:%4i, tr:%4i, bl: %4i, br: %4i, temperature=%d, "
          "battery=%d",
          balance->index(),  // Controller Index
          balance->topLeft(), balance->topRight(), balance->bottomLeft(),
          balance->bottomRight(), balance->temperature(),
          balance->battery()  // 0=Unk, 1=Empty, 255=full
  );
  Serial.println(buf);
}

// Arduino loop function. Runs in CPU 1
void loop() {
  // This call fetches all the controller info from the NINA (ESP32) module.
  // Call this function in your main loop.
  // The controllers' pointer (the ones received in the callbacks) gets updated
  // automatically.
  BP32.update();

  // It is safe to always do this before using the controller API.
  // This guarantees that the controller is valid and connected.
  for (int i = 0; i < BP32_MAX_CONTROLLERS; i++) {
    ControllerPtr myController = myControllers[i];

    if (myController && myController->isConnected()) {
      if (myController->isGamepad())
        processGamepad(myController);
      else if (myController->isMouse())
        processMouse(myController);
      else if (myController->isBalanceBoard())
        processBalanceBoard(myController);
    }
  }
  delay(150);
}
JclayArt commented 4 months ago

Ran through the installation steps again on a second Arduino Nano RP2040 and have the same results. Everything works as expected while ArduinoIDE is open, once I close ArduinoIDE the controller stops responding and eventually powers off and will not reconnect unless I open ArduinoIDE.

ricardoquesada commented 4 months ago

remove this part from the sketch:

  while (!Serial) {
    // Wait for serial port to connect.
    // You don't have to do this in your game. This is only for debugging
    // purposes, so that you can see the output in the serial console.
    ;
  }
ricardoquesada commented 4 months ago

reopen the issue if that doesn't fix it

JclayArt commented 4 months ago

Oh wow that worked perfectly, thank you for taking the time to respond to me so quickly! Is there anyway I could buy you dinner or something as a thank you? I could zelle or Venmo you or if there's another platform you'd prefer I could look into it. I'll definitely credit you for the awesome Bluepad32 library and support.

-Joshua Clay www.joshuaclayart.com

Get Outlook for Androidhttps://aka.ms/AAb9ysg


From: Ricardo Quesada @.> Sent: Wednesday, February 21, 2024 6:36:13 AM To: ricardoquesada/bluepad32 @.> Cc: Joshua Clay @.>; Author @.> Subject: Re: [ricardoquesada/bluepad32] BluePad32 and RP2040 only working when connected to PC and arduino IDE open (Issue #72)

remove this part from the sketch:

while (!Serial) { // Wait for serial port to connect. // You don't have to do this in your game. This is only for debugging // purposes, so that you can see the output in the serial console. ; }

— Reply to this email directly, view it on GitHubhttps://github.com/ricardoquesada/bluepad32/issues/72#issuecomment-1956557308, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AXEOBCGOOUGHMENBPAWLY6DYUXS33AVCNFSM6AAAAABDSA6WGCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNJWGU2TOMZQHA. You are receiving this because you authored the thread.Message ID: @.***>

ricardoquesada commented 4 months ago

thanks. donations are welcome. This page contains different forms to help the project: https://bluepad32.readthedocs.io/en/latest/contributing/

thanks

JclayArt commented 2 months ago

Hello there, I'm wondering if you'd possible be able to give me an example of how to use axisX and axisY within an Arduino RP2040 sketch similiar to how you give an example for using the B button:

if (gamepad->b()) { }

I tried using it like this but haven't had any luck and I'm not sure what I'm doing wrong:

if (gamepad->axisX() > 35) { }

if (gamepad->axisX() < -35) { }

Any help would be greatly appreciated!!! Love being able to use a PS4 controller with the RP2040, so cool!

Thanks for everything you do! -Joshua Clay www.joshuaclayart.comhttp://www.joshuaclayart.com


From: Ricardo Quesada @.> Sent: Wednesday, February 21, 2024 1:50 PM To: ricardoquesada/bluepad32 @.> Cc: Joshua Clay @.>; Author @.> Subject: Re: [ricardoquesada/bluepad32] BluePad32 and RP2040 only working when connected to PC and arduino IDE open (Issue #72)

thanks. donations are welcome. This page contains different forms to help the project: https://bluepad32.readthedocs.io/en/latest/contributing/

thanks

— Reply to this email directly, view it on GitHubhttps://github.com/ricardoquesada/bluepad32/issues/72#issuecomment-1957788525, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AXEOBCCDMP3FWXVO66GYWPDYUZF2DAVCNFSM6AAAAABDSA6WGCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNJXG44DQNJSGU. You are receiving this because you authored the thread.Message ID: @.***>

JclayArt commented 2 months ago

Hello there, I'm wondering if you'd possible be able to give me an example of how to use axisX and axisY within an Arduino RP2040 sketch similiar to how you give an example for using the B button:

if (gamepad->b()) { }

I tried using it like this but haven't had any luck and I'm not sure what I'm doing wrong:

if (gamepad->axisX() > 35) { }

if (gamepad->axisX() < -35) { }

Any help would be greatly appreciated!!! Love being able to use a PS4 controller with the RP2040, so cool!

Thanks for everything you do! -Joshua Clay www.joshuaclayart.com

ricardoquesada commented 2 months ago

that should work. what issues are you having ? which controller are you using ?

JclayArt commented 2 months ago

Ok interesting, well its good to know I'm on the correct path, thank you!

I'm using a PS4 controller and the issue I'm having is when the axisX portion is included (same as above) in the code the controller will connect however no button presses work, when I comment out the axisX portion everything works again leading me to believe I was somehow calling the axisX portion incorrectly. Everything compiles, it just stops working when I put that portion of code in.

Essentially when axisX is >35 I'm mapping the joystick value to a servos MID and MAX range and when the axisX value is <-35 I'm mapping the joystick value to the servos MID and MIN range. using 35 and -35 for some deadspace/wiggle room within the joystick axisX value.

ricardoquesada commented 2 months ago

weird... but what you can do is to print the value of axisX(). You should see a value between -512 to 511

JclayArt commented 2 months ago

Yeah that's true, I'll comment things out and print the value like you suggested and work from there. Thank you for the help! Helps to know the way I'm using axisX() is correct!