Yeah here was the working code. I borrowed examples off the internet and didn't bother to even change the comments, so the comments generally aren't mine. I used this sketch to drive a robot toy using a Mindsensors shield for driving Lego motors (this shield also includes the ILI9341 screen). You can strip out all that code and print the joystick values to the serial (or, you could probably just find the original example I based this on, which probably does precisely that). Reminder, you must flash the Nina module first -- this requires loading a stub sketch to the Nano Connect so that you can use "esptool" to flash the Gamepad firmware to the Nina module -- the instructions for that are available elsewhere.
// Copyright 2021 - 2022, Ricardo Quesada
// SPDX-License-Identifier: Apache 2.0 or LGPL-2.1-or-later
/*
* This example shows how to use the Gamepad API.
*
* Supported on boards with NINA W10x like:
* - Arduino MKR WiFi 1010,
* - UNO WiFi Rev.2,
* - Nano RP2040 Connect,
* - Nano 33 IoT,
* - etc.
*/
#include <Bluepad32.h>
#include <Wire.h>
#include <EVShield.h>
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
// For the Adafruit shield, these are the default.
#define TFT_DC 8
#define TFT_CS 7
// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// setup for this example:
// attach external power to EVShield.
// attach 4 motors to motor ports
// Open the Serial terminal to view.
EVShield evshield(0x34,0x36);
GamepadPtr myGamepads[BP32_MAX_GAMEPADS] = {};
void setup() {
// Initialize serial
Serial.begin(115200);
delay(2000); // wait two seconds, allowing time to
// activate the serial monitor
long rotations = 2; // Define variable rotations and set
// equal to 90
char str[40];
tft.begin();
tft.setRotation(3);
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(0, 0);
tft.setTextColor(ILI9341_WHITE); tft.setTextSize(1);
tft.println("The Mindsensors shield isn't on.");
tft.println("Make sure the batteries are all in");
tft.print("Press the GO button then reset");
String fv = BP32.firmwareVersion();
Serial.print("Firmware version installed: ");
Serial.println(fv);
evshield.init( SH_HardwareI2C );
Wire.setClock(10000);
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(0, 0);
evshield.bank_a.motorStop(SH_Motor_1, SH_Next_Action_Float);
evshield.bank_a.motorStop(SH_Motor_2, SH_Next_Action_Float);
evshield.bank_b .motorStop(SH_Motor_1, SH_Next_Action_Float);
evshield.bank_b.motorStop(SH_Motor_2, SH_Next_Action_Float);
// BP32.pinMode(27, OUTPUT);
// BP32.digitalWrite(27, 0);
// This call is mandatory. It setups Bluepad32 and creates the callbacks.
BP32.setup(&onConnectedGamepad, &onDisconnectedGamepad);
// "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 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 onConnectedGamepad(GamepadPtr gp) {
bool foundEmptySlot = false;
for (int i = 0; i < BP32_MAX_GAMEPADS; i++) {
if (myGamepads[i] == nullptr) {
Serial.print("CALLBACK: Gamepad is connected, index=");
Serial.println(i);
myGamepads[i] = gp;
foundEmptySlot = true;
// Optional, once the gamepad is connected, request further info about the
// gamepad.
GamepadProperties properties = gp->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: Gamepad connected, but could not found empty slot");
}
}
void onDisconnectedGamepad(GamepadPtr gp) {
bool foundGamepad = false;
for (int i = 0; i < BP32_MAX_GAMEPADS; i++) {
if (myGamepads[i] == gp) {
Serial.print("CALLBACK: Gamepad is disconnected from index=");
Serial.println(i);
myGamepads[i] = nullptr;
foundGamepad = true;
break;
}
}
if (!foundGamepad) {
Serial.println(
"CALLBACK: Gamepad disconnected, but not found in myGamepads");
}
}
void loop() {
static bool blacked=false;
if (blacked==false) {
tft.fillScreen(ILI9341_BLACK);
blacked=true;
}
tft.setCursor(0, 0);
tft.print(" ");
tft.setCursor(0,0);
tft.setTextColor(ILI9341_WHITE); tft.setTextSize(1);
tft.print("1");
// This call fetches all the gamepad info from the NINA (ESP32) module.
// Just call this function in your main loop.
// The gamepad pointers (the ones received in the callbacks) gets updated
// automatically.
BP32.update();
tft.print("2");
// It is safe to always do this before using the gamepad API.
// This guarantees that the gamepad is valid and connected.
for (int i = 0; i < BP32_MAX_GAMEPADS; i++) {
GamepadPtr myGamepad = myGamepads[i];
if (myGamepad && myGamepad->isConnected()) {
// There are different ways to query whether a button is pressed.
// By query each button individually:
// a(), b(), x(), y(), l1(), etc...
if (myGamepad->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
myGamepad->setColorLED(255, 0, 0);
break;
case 1:
// Green
myGamepad->setColorLED(0, 255, 0);
break;
case 2:
// Blue
myGamepad->setColorLED(0, 0, 255);
break;
}
colorIdx++;
}
if (myGamepad->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:
myGamepad->setPlayerLEDs(led & 0x0f);
}
if (myGamepad->x()) {
// Duration: 255 is ~2 seconds
// force: intensity
// Some gamepads like DS3, DS4, DualSense, Switch, Xbox One S support
// force feedback.
// It is possible to set it by calling:
myGamepad->setRumble(0xc0 /* force */, 0x10 /* duration */);
}
if (myGamepad->y()) {
// Disable new gamepad connections
Serial.println("Bluetooth new connections disabled");
BP32.enableNewBluetoothConnections(false);
}
tft.print("3");
// 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 buffer[120];
snprintf(buffer, sizeof(buffer) - 1,
"idx=%d, dpad: 0x%02x, buttons: 0x%04x, axis L: %4li, %4li, axis "
"R: %4li, %4li, brake: %4ld, throttle: %4li, misc: 0x%02x",
i, // Gamepad Index
myGamepad->dpad(), // DPAD
myGamepad->buttons(), // bitmask of pressed buttons
myGamepad->axisX(), // (-511 - 512) left X Axis
myGamepad->axisY(), // (-511 - 512) left Y axis
myGamepad->axisRX(), // (-511 - 512) right X axis
myGamepad->axisRY(), // (-511 - 512) right Y axis
myGamepad->brake(), // (0 - 1023): brake button
myGamepad->throttle(), // (0 - 1023): throttle (AKA gas) button
myGamepad->miscButtons() // bitmak of pressed "misc" buttons
);
tft.print("4");
Serial.println(buffer);
static bool ledstate=false;
ledstate = !ledstate;
//pinMode(LED_BUILTIN, OUTPUT);
//digitalWrite(LED_BUILTIN, ledstate ? HIGH : LOW);
int fwdback, absfwdback, fwdbackpct;
fwdback = myGamepad->axisRY();
absfwdback = (fwdback < 0) ? -fwdback : fwdback;
if (absfwdback < 50) absfwdback = 0;
fwdbackpct = (absfwdback * 100) / 512;
if (fwdbackpct==0)
evshield.bank_a.motorStop(SH_Motor_1, SH_Next_Action_Float);
else evshield.bank_a.motorRunUnlimited(SH_Motor_1, (fwdback>=0) ? SH_Direction_Forward : SH_Direction_Reverse, fwdbackpct);
//else evshield.bank_a.motorSetSpeedTimeAndControl(SH_Motor_1, fwdbackpct * ((fwdback>=0) ? 1 : -1, );
fwdback = myGamepad->axisRX();
absfwdback = (fwdback < 0) ? -fwdback : fwdback;
if (absfwdback < 50) absfwdback = 0;
fwdbackpct = (absfwdback * 100) / 512;
if (fwdbackpct==0)
evshield.bank_b.motorStop(SH_Motor_1, SH_Next_Action_Brake);
else evshield.bank_b.motorRunUnlimited(SH_Motor_1, (fwdback<0) ? SH_Direction_Forward : SH_Direction_Reverse, fwdbackpct);
fwdback = myGamepad->axisY();
absfwdback = (fwdback < 0) ? -fwdback : fwdback;
if (absfwdback < 50) absfwdback = 0;
fwdbackpct = (absfwdback * 100) / 512;
if (fwdbackpct==0)
evshield.bank_b.motorStop(SH_Motor_2, SH_Next_Action_Float);
else evshield.bank_b.motorRunUnlimited(SH_Motor_2, (fwdback>=0) ? SH_Direction_Forward : SH_Direction_Reverse, fwdbackpct);
tft.print("5");
if (evshield.isTouched()) tft.print("6");
// You can query the axis and other properties as well. See Gamepad.h
// For all the available functions.
}
}
delay(50);
}