BTS7960 and PS4 controller code issues

Apologies in advance, I only started this project a week ago and it's 10 years since I programmed in C and C++.

I a building my son a Wall E robot using a ESP32 board and a L298N board to control the head with a PS4 controller. So far I managed to get that working and can control 2 motors using the following code:

#include <Bluepad32.h>

//PIN CONNECTIONS

int ledPin = 2;

int ENApin = 14; //motor1 speed

int IN1pin = 27; //motor1 dir1

int IN2pin = 26; //motor1 dir2

int IN3pin = 25; //motor2 dir1

int IN4pin = 33; //motor2 dir2

int ENBpin = 32; //motor2 speed

ControllerPtr myControllers[BP32_MAX_GAMEPADS];


I use this code for the PS4:

// RIGHT JOYSTICK UP

if (ctl->axisRY() <= -25) {

    int motorSpeed = map(ctl->axisRY(), -25, -508, 50, 225);

    digitalWrite(IN1pin, HIGH);
    digitalWrite(IN2pin, LOW);
    analogWrite(ENApin, motorSpeed);
  
}

// RIGHT JOYSTICK DOWN
if (ctl->axisRY() >= 25) {

    int motorSpeed = map(ctl->axisRY(), 25, 512, 50, 225);

    digitalWrite(IN1pin, LOW);
    digitalWrite(IN2pin, HIGH);
    analogWrite(ENApin, motorSpeed);


    //LEFT JOYSTICK DEADZONE
    if (ctl->axisRY() > -25 && ctl->axisRY() < 25 && ctl->axisRX() > -25 && ctl->axisRX() < 25) {
        analogWrite(ENApin, 0);
        analogWrite(ENBpin, 0);
    }

// Arduino setup function. Runs in CPU 1
void setup() {
    pinMode(ledPin, OUTPUT);
    pinMode(IN1pin, OUTPUT);
    pinMode(IN2pin, OUTPUT);
    pinMode(ENApin, OUTPUT);
    pinMode(IN3pin, OUTPUT);
    pinMode(IN4pin, OUTPUT);
    pinMode(ENBpin, OUTPUT);


I now need to use two BTS7960 motor controller boards for the tracks. If i load the following sketch I can spin the motors from 0 to 255. How do i incorporate this code with the code above and get it to work with the ps4 controller?
I have tried many combinations without any success.

#include <BTS7960.h>
//BTS7960 works between +3v and +5v so you can use a uno, mega or a nano.
#define L_EN 2
#define R_EN 4
#define L_PWM 5                             //pin 5 supports 980hz pwm frequency
#define R_PWM 6                             //pin 6 supports 980hz pwm frequency

BTS7960 motor1(L_EN, R_EN, L_PWM, R_PWM);   //This method will create a object of the class BTS7960

void setup() {
  Serial.begin(9600);                       //begin the serial monitor for output
  motor1.begin();                           //This method will set the motor driver pins as output
  motor1.enable();                          //This method will set the L_EN and R_EN to HIGH or digitalWrite them to +5v/3v depending on your mcu
}

void loop() {
  
  for(int i=0; i<=255; i=i+10)
  {
    motor1.pwm = i;                         //Set the speed, by default the speed is set to 255 you can change it 
    motor1.front();                         //front functions should turn the motor in clockwise direction
    delay(500);
  }
  motor1.stop();                            //stop function should halt the motor by applying 0 pwm to both R_PWM and L_PWM
  delay(500);
  for(int i=0; i<=255; i=i+10)
  { 
    motor1.pwm = i;                         //Set the speed
    motor1.back();                          //back functions should turn the motor in anti-clockwise direction
    delay(500);
  }
  delay(500);
  motor1.disable();                         //This method will set the L_EN and R_EN to LOW or digitalWrite them to 0v
}

Any assistance would be appreciated.

Your topic does not indicate a problem with IDE 2.x and therefore has been moved to a more suitable location on the forum.

You have three individual programs by the looks of it but you have only one code block in this post. And it contains what is supposed to be shown as normal text.
Can you try to clean it up please.

this is the code that works:


#include <Bluepad32.h>

//PIN CONNECTIONS
int ledPin = 2;
int ENApin = 14; //motor1 speed
int IN1pin = 27; //motor1 dir1
int IN2pin = 26; //motor1 dir2
int IN3pin = 25; //motor2 dir1
int IN4pin = 33; //motor2 dir2
int ENBpin = 32; //motor2 speed

ControllerPtr myControllers[BP32_MAX_GAMEPADS];

// 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.printf("CALLBACK: Controller is connected, index=%d\n", i);
            // Additionally, you can get certain gamepad properties like:
            // Model, VID, PID, BTAddr, flags, etc.
            ControllerProperties properties = ctl->getProperties();
            Serial.printf("Controller model: %s, VID=0x%04x, PID=0x%04x\n", ctl->getModelName().c_str(), properties.vendor_id,
                           properties.product_id);
            myControllers[i] = ctl;
            foundEmptySlot = true;
            break;
        }
    }
    if (!foundEmptySlot) {
        Serial.println("CALLBACK: Controller connected, but could not found empty slot");
    }
}

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

    for (int i = 0; i < BP32_MAX_GAMEPADS; i++) {
        if (myControllers[i] == ctl) {
            Serial.printf("CALLBACK: Controller disconnected from index=%d\n", i);
            myControllers[i] = nullptr;
            foundController = true;
            break;
        }
    }

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

void dumpGamepad(ControllerPtr ctl) {
    Serial.printf(
        "idx=%d, dpad: 0x%02x, buttons: 0x%04x, axis L: %4d, %4d, axis R: %4d, %4d, brake: %4d, throttle: %4d, "
        "misc: 0x%02x, gyro x:%6d y:%6d z:%6d, accel x:%6d y:%6d z:%6d\n",
        ctl->index(),        // Controller Index
        ctl->dpad(),         // D-pad
        ctl->buttons(),      // bitmask of pressed buttons
        ctl->axisX(),        // (-511 - 512) left X Axis
        ctl->axisY(),        // (-511 - 512) left Y axis
        ctl->axisRX(),       // (-511 - 512) right X axis
        ctl->axisRY(),       // (-511 - 512) right Y axis
        ctl->brake(),        // (0 - 1023): brake button
        ctl->throttle(),     // (0 - 1023): throttle (AKA gas) button
        ctl->miscButtons(),  // bitmask of pressed "misc" buttons
        ctl->gyroX(),        // Gyro X
        ctl->gyroY(),        // Gyro Y
        ctl->gyroZ(),        // Gyro Z
        ctl->accelX(),       // Accelerometer X
        ctl->accelY(),       // Accelerometer Y
        ctl->accelZ()        // Accelerometer Z
    );
}

void dumpMouse(ControllerPtr ctl) {
    Serial.printf("idx=%d, buttons: 0x%04x, scrollWheel=0x%04x, delta X: %4d, delta Y: %4d\n",
                   ctl->index(),        // Controller Index
                   ctl->buttons(),      // bitmask of pressed buttons
                   ctl->scrollWheel(),  // Scroll Wheel
                   ctl->deltaX(),       // (-511 - 512) left X Axis
                   ctl->deltaY()        // (-511 - 512) left Y axis
    );
}

void dumpKeyboard(ControllerPtr ctl) {
    static const char* key_names[] = {
        // clang-format off
        // To avoid having too much noise in this file, only a few keys are mapped to strings.
        // Starts with "A", which is offset 4.
        "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
        "W", "X", "Y", "Z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0",
        // Special keys
        "Enter", "Escape", "Backspace", "Tab", "Spacebar", "Underscore", "Equal", "OpenBracket", "CloseBracket",
        "Backslash", "Tilde", "SemiColon", "Quote", "GraveAccent", "Comma", "Dot", "Slash", "CapsLock",
        // Function keys
        "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
        // Cursors and others
        "PrintScreen", "ScrollLock", "Pause", "Insert", "Home", "PageUp", "Delete", "End", "PageDown",
        "RightArrow", "LeftArrow", "DownArrow", "UpArrow",
        // clang-format on
    };
    static const char* modifier_names[] = {
        // clang-format off
        // From 0xe0 to 0xe7
        "Left Control", "Left Shift", "Left Alt", "Left Meta",
        "Right Control", "Right Shift", "Right Alt", "Right Meta",
        // clang-format on
    };
    Serial.printf("idx=%d, Pressed keys: ", ctl->index());
    for (int key = Keyboard_A; key <= Keyboard_UpArrow; key++) {
        if (ctl->isKeyPressed(static_cast<KeyboardKey>(key))) {
            const char* keyName = key_names[key-4];
            Serial.printf("%s,", keyName);
       }
    }
    for (int key = Keyboard_LeftControl; key <= Keyboard_RightMeta; key++) {
        if (ctl->isKeyPressed(static_cast<KeyboardKey>(key))) {
            const char* keyName = modifier_names[key-0xe0];
            Serial.printf("%s,", keyName);
        }
    }
    Console.printf("\n");
}

void dumpBalanceBoard(ControllerPtr ctl) {
    Serial.printf("idx=%d,  TL=%u, TR=%u, BL=%u, BR=%u, temperature=%d\n",
                   ctl->index(),        // Controller Index
                   ctl->topLeft(),      // top-left scale
                   ctl->topRight(),     // top-right scale
                   ctl->bottomLeft(),   // bottom-left scale
                   ctl->bottomRight(),  // bottom-right scale
                   ctl->temperature()   // temperature: used to adjust the scale value's precision
    );
}

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

// PS4 X Button
//if (ctl->buttons() == 0x0001) {
  //  digitalWrite(ledPin, HIGH);
//}
//if (ctl->buttons() != 0x0001) {
  //  digitalWrite(ledPin, LOW);
//}

// RIGHT JOYSTICK UP

if (ctl->axisRY() <= -25) {

    int motorSpeed = map(ctl->axisRY(), -25, -508, 50, 225);

    digitalWrite(IN1pin, HIGH);
    digitalWrite(IN2pin, LOW);
    analogWrite(ENApin, motorSpeed);
  
}

// RIGHT JOYSTICK DOWN
if (ctl->axisRY() >= 25) {

    int motorSpeed = map(ctl->axisRY(), 25, 512, 50, 225);

    digitalWrite(IN1pin, LOW);
    digitalWrite(IN2pin, HIGH);
    analogWrite(ENApin, motorSpeed);

}
// LEFT JOYSTICK LEFT

if (ctl->axisRX() <= -25) {

    int motorSpeed = map(ctl->axisRX(), -25, -508, 50, 225);


    digitalWrite(IN3pin, HIGH);
    digitalWrite(IN4pin, LOW);
   analogWrite(ENBpin, motorSpeed);
}

// LEFT JOYSTICK Right
if (ctl->axisRX() >= 25) {

    int motorSpeed = map(ctl->axisRX(), 25, 512, 50, 225);

    digitalWrite(IN3pin, LOW);
    digitalWrite(IN4pin, HIGH);
    analogWrite(ENBpin, motorSpeed);
}


    //LEFT JOYSTICK DEADZONE
    if (ctl->axisRY() > -25 && ctl->axisRY() < 25 && ctl->axisRX() > -25 && ctl->axisRX() < 25) {
        analogWrite(ENApin, 0);
        analogWrite(ENBpin, 0);
    }


    if (ctl->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
                ctl->setColorLED(255, 0, 0);
                break;
            case 1:
                // Green
                ctl->setColorLED(0, 255, 0);
                break;
            case 2:
                // Blue
                ctl->setColorLED(0, 0, 255);
                break;
        }
        colorIdx++;
    }

    if (ctl->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:
        ctl->setPlayerLEDs(led & 0x0f);
    }

    if (ctl->x()) {
        // Some gamepads like DS3, DS4, DualSense, Switch, Xbox One S, Stadia support rumble.
        // It is possible to set it by calling:
        // Some controllers have two motors: "strong motor", "weak motor".
        // It is possible to control them independently.
        ctl->playDualRumble(0 /* delayedStartMs */, 250 /* durationMs */, 0x80 /* weakMagnitude */,
                            0x40 /* strongMagnitude */);
    }

    // Another way to query controller data is by getting the buttons() function.
    // See how the different "dump*" functions dump the Controller info.
    dumpGamepad(ctl);
}

//void processMouse(ControllerPtr ctl) {
    // This is just an example.
  //  if (ctl->scrollWheel() > 0) {
        // Do Something
    //} else if (ctl->scrollWheel() < 0) {
        // Do something else
    //}

    // See "dumpMouse" for possible things to query.
   // dumpMouse(ctl);
//}

//void processKeyboard(ControllerPtr ctl) {
  //  if (!ctl->isAnyKeyPressed())
    //    return;

    // This is just an example.
    //if (ctl->isKeyPressed(Keyboard_A)) {
        // Do Something
      //  Serial.println("Key 'A' pressed");
    //}

    // Don't do "else" here.
    // Multiple keys can be pressed at the same time.
    //if (ctl->isKeyPressed(Keyboard_LeftShift)) {
        // Do something else
        //Serial.println("Key 'LEFT SHIFT' pressed");
    //}

    // Don't do "else" here.
    // Multiple keys can be pressed at the same time.
    //if (ctl->isKeyPressed(Keyboard_LeftArrow)) {
        // Do something else
        //Serial.println("Key 'Left Arrow' pressed");
    //}

    // See "dumpKeyboard" for possible things to query.
    //dumpKeyboard(ctl);
//}

void processBalanceBoard(ControllerPtr ctl) {
    // This is just an example.
    if (ctl->topLeft() > 10000) {
        // Do Something
    }

    // See "dumpBalanceBoard" for possible things to query.
    dumpBalanceBoard(ctl);
}

void processControllers() {
    for (auto myController : myControllers) {
        if (myController && myController->isConnected() && myController->hasData()) {
            if (myController->isGamepad()) {
                processGamepad(myController);
            }
            else {            
                Serial.println("Unsupported controller");
            }
        }
    }
}

// Arduino setup function. Runs in CPU 1
void setup() {
    pinMode(ledPin, OUTPUT);
    pinMode(IN1pin, OUTPUT);
    pinMode(IN2pin, OUTPUT);
    pinMode(ENApin, OUTPUT);
    pinMode(IN3pin, OUTPUT);
    pinMode(IN4pin, OUTPUT);
    pinMode(ENBpin, OUTPUT);




    Serial.begin(115200);
    Serial.printf("Firmware: %s\n", BP32.firmwareVersion());
    const uint8_t* addr = BP32.localBdAddress();
    Serial.printf("BD Addr: %2X:%2X:%2X:%2X:%2X:%2X\n", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);

    // Setup the Bluepad32 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();

    // Enables mouse / touchpad support for gamepads that support them.
    // When enabled, controllers like DualSense and DualShock4 generate two connected devices:
    // - First one: the gamepad
    // - Second one, which is a "virtual device", is a mouse.
    // By default, it is disabled.
    BP32.enableVirtualDevice(false);
}

// Arduino loop function. Runs in CPU 1.
void loop() {
    // This call fetches all the controllers' data.
    // Call this function in your main loop.
    bool dataUpdated = BP32.update();
    if (dataUpdated)
        processControllers();

    // The main loop must have some kind of "yield to lower priority task" event.
    // Otherwise, the watchdog will get triggered.
    // If your main loop doesn't have one, just add a simple `vTaskDelay(1)`.
    // Detailed info here:
    // https://stackoverflow.com/questions/66278271/task-watchdog-got-triggered-the-tasks-did-not-reset-the-watchdog-in-time

    //     vTaskDelay(1);
    delay(150);
}

this code can spin the motor:

#include <BTS7960.h>
//BTS7960 works between +3v and +5v so you can use a uno, mega or a nano.
#define L_EN 2
#define R_EN 4
#define L_PWM 5                             //pin 5 supports 980hz pwm frequency
#define R_PWM 6                             //pin 6 supports 980hz pwm frequency

BTS7960 motor1(L_EN, R_EN, L_PWM, R_PWM);   //This method will create a object of the class BTS7960

void setup() {
  Serial.begin(9600);                       //begin the serial monitor for output
  motor1.begin();                           //This method will set the motor driver pins as output
  motor1.enable();                          //This method will set the L_EN and R_EN to HIGH or digitalWrite them to +5v/3v depending on your mcu
}

void loop() {
  
  for(int i=0; i<=255; i=i+10)
  {
    motor1.pwm = i;                         //Set the speed, by default the speed is set to 255 you can change it 
    motor1.front();                         //front functions should turn the motor in clockwise direction
    delay(500);
  }
  motor1.stop();                            //stop function should halt the motor by applying 0 pwm to both R_PWM and L_PWM
  delay(500);
  for(int i=0; i<=255; i=i+10)
  { 
    motor1.pwm = i;                         //Set the speed
    motor1.back();                          //back functions should turn the motor in anti-clockwise direction
    delay(500);
  }
  delay(500);
  motor1.disable();                         //This method will set the L_EN and R_EN to LOW or digitalWrite them to 0v
}

how do i combine the two so i can move the BTS7960 motors with the ps4 controller?

What do you mean by "works"?

Does it control your motor? That code seems to control two motors using L298 motor drivers.

Good.

  1. How many motors do you want to control? Three? If so, which control do you want to use for the third motor? Your first code already seems to use the joysticks?
    Or do you want to replace the L298 by the VTS7960?
  2. Do you need the LED functionality? The first thing to do is to eliminate pin conflicts; the first code uses pin 2 for a LED, the second code uses that pin for the BTS7960.
    I suggest that you first make a list of all pins that you want to use and what they are used for.

I currently have two motors connected via aL298N motor driver for the "head".
Left and right. Tilt up and down. That code is working and i can controller the motors with the PS4 controller on the right stick.

I need to connect two more motors via two BTS7960 that i want to control on the left stick.

this is the code that I am busy with:

#include <Bluepad32.h>
#include <BTS7960.h>

//PIN CONNECTIONS L298N
int ledPin = 2;
int ENApin = 14; //motor1 speed
int IN1pin = 27; //motor1 dir1
int IN2pin = 26; //motor1 dir2
int IN3pin = 25; //motor2 dir1
int IN4pin = 33; //motor2 dir2
int ENBpin = 32; //motor2 speed

//BYS7960 Board
#define L_EN 19
#define R_EN 21
#define L_PWM 22                            //pin 5 supports 980hz pwm frequency
#define R_PWM 23                            //pin 5 supports 980hz pwm frequency

BTS7960 motor1(L_EN, R_EN, L_PWM, R_PWM);   //This method will create a object of the class BTS7960

ControllerPtr myControllers[BP32_MAX_GAMEPADS];

// 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.printf("CALLBACK: Controller is connected, index=%d\n", i);
            // Additionally, you can get certain gamepad properties like:
            // Model, VID, PID, BTAddr, flags, etc.
            ControllerProperties properties = ctl->getProperties();
            Serial.printf("Controller model: %s, VID=0x%04x, PID=0x%04x\n", ctl->getModelName().c_str(), properties.vendor_id,
                           properties.product_id);
            myControllers[i] = ctl;
            foundEmptySlot = true;
            break;
        }
    }
    if (!foundEmptySlot) {
        Serial.println("CALLBACK: Controller connected, but could not found empty slot");
    }
}

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

    for (int i = 0; i < BP32_MAX_GAMEPADS; i++) {
        if (myControllers[i] == ctl) {
            Serial.printf("CALLBACK: Controller disconnected from index=%d\n", i);
            myControllers[i] = nullptr;
            foundController = true;
            break;
        }
    }

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

void dumpGamepad(ControllerPtr ctl) {
    Serial.printf(
        "idx=%d, dpad: 0x%02x, buttons: 0x%04x, axis L: %4d, %4d, axis R: %4d, %4d, brake: %4d, throttle: %4d, "
        "misc: 0x%02x, gyro x:%6d y:%6d z:%6d, accel x:%6d y:%6d z:%6d\n",
        ctl->index(),        // Controller Index
        ctl->dpad(),         // D-pad
        ctl->buttons(),      // bitmask of pressed buttons
        ctl->axisX(),        // (-511 - 512) left X Axis
        ctl->axisY(),        // (-511 - 512) left Y axis
        ctl->axisRX(),       // (-511 - 512) right X axis
        ctl->axisRY(),       // (-511 - 512) right Y axis
        ctl->brake(),        // (0 - 1023): brake button
        ctl->throttle(),     // (0 - 1023): throttle (AKA gas) button
        ctl->miscButtons(),  // bitmask of pressed "misc" buttons
        ctl->gyroX(),        // Gyro X
        ctl->gyroY(),        // Gyro Y
        ctl->gyroZ(),        // Gyro Z
        ctl->accelX(),       // Accelerometer X
        ctl->accelY(),       // Accelerometer Y
        ctl->accelZ()        // Accelerometer Z
    );
}

void dumpMouse(ControllerPtr ctl) {
    Serial.printf("idx=%d, buttons: 0x%04x, scrollWheel=0x%04x, delta X: %4d, delta Y: %4d\n",
                   ctl->index(),        // Controller Index
                   ctl->buttons(),      // bitmask of pressed buttons
                   ctl->scrollWheel(),  // Scroll Wheel
                   ctl->deltaX(),       // (-511 - 512) left X Axis
                   ctl->deltaY()        // (-511 - 512) left Y axis
    );
}

void dumpKeyboard(ControllerPtr ctl) {
    static const char* key_names[] = {
        // clang-format off
        // To avoid having too much noise in this file, only a few keys are mapped to strings.
        // Starts with "A", which is offset 4.
        "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
        "W", "X", "Y", "Z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0",
        // Special keys
        "Enter", "Escape", "Backspace", "Tab", "Spacebar", "Underscore", "Equal", "OpenBracket", "CloseBracket",
        "Backslash", "Tilde", "SemiColon", "Quote", "GraveAccent", "Comma", "Dot", "Slash", "CapsLock",
        // Function keys
        "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
        // Cursors and others
        "PrintScreen", "ScrollLock", "Pause", "Insert", "Home", "PageUp", "Delete", "End", "PageDown",
        "RightArrow", "LeftArrow", "DownArrow", "UpArrow",
        // clang-format on
    };
    static const char* modifier_names[] = {
        // clang-format off
        // From 0xe0 to 0xe7
        "Left Control", "Left Shift", "Left Alt", "Left Meta",
        "Right Control", "Right Shift", "Right Alt", "Right Meta",
        // clang-format on
    };
    Serial.printf("idx=%d, Pressed keys: ", ctl->index());
    for (int key = Keyboard_A; key <= Keyboard_UpArrow; key++) {
        if (ctl->isKeyPressed(static_cast<KeyboardKey>(key))) {
            const char* keyName = key_names[key-4];
            Serial.printf("%s,", keyName);
       }
    }
    for (int key = Keyboard_LeftControl; key <= Keyboard_RightMeta; key++) {
        if (ctl->isKeyPressed(static_cast<KeyboardKey>(key))) {
            const char* keyName = modifier_names[key-0xe0];
            Serial.printf("%s,", keyName);
        }
    }
    Console.printf("\n");
}

void dumpBalanceBoard(ControllerPtr ctl) {
    Serial.printf("idx=%d,  TL=%u, TR=%u, BL=%u, BR=%u, temperature=%d\n",
                   ctl->index(),        // Controller Index
                   ctl->topLeft(),      // top-left scale
                   ctl->topRight(),     // top-right scale
                   ctl->bottomLeft(),   // bottom-left scale
                   ctl->bottomRight(),  // bottom-right scale
                   ctl->temperature()   // temperature: used to adjust the scale value's precision
    );
}

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

// PS4 X Button
//if (ctl->buttons() == 0x0001) {
  //  digitalWrite(ledPin, HIGH);
//}
//if (ctl->buttons() != 0x0001) {
  //  digitalWrite(ledPin, LOW);
//}


// LEFT JOYSTICK UP
if (ctl->axisRY() <= -25) {

int motor1 = map(ctl->axisY(), 25, 512, 50, 225);
    digitalWrite(L_EN, HIGH);
    digitalWrite(R_EN, HIGH);
    analogWrite(L_PWM, motor1);
    //int motor1.pwm = map(ctl->axisY(), -25, -508, 0, 255);
    //    motor1.pwm = i;                         //Set the speed, by default the speed is set to 255 you can change it 
     //   motor1.front();                         //front functions should turn the motor in clockwise direction
    
//}

// RIGHT JOYSTICK UP

if (ctl->axisRY() <= -25) {

    int motorSpeed = map(ctl->axisRY(), -25, -508, 50, 225);

    digitalWrite(IN1pin, HIGH);
    digitalWrite(IN2pin, LOW);
    analogWrite(ENApin, motorSpeed);
   
}

// RIGHT JOYSTICK DOWN
if (ctl->axisRY() >= 25) {

    int motorSpeed = map(ctl->axisRY(), 25, 512, 50, 225);

    digitalWrite(IN1pin, LOW);
    digitalWrite(IN2pin, HIGH);
    analogWrite(ENApin, motorSpeed);

}
// RIGHT JOYSTICK LEFT

if (ctl->axisRX() <= -25) {

    int motorSpeed = map(ctl->axisRX(), -25, -508, 50, 225);

    digitalWrite(IN3pin, HIGH);
    digitalWrite(IN4pin, LOW);
    analogWrite(ENBpin, motorSpeed);
}

// RIGHT JOYSTICK RIGHT
if (ctl->axisRX() >= 25) {

    int motorSpeed = map(ctl->axisRX(), 25, 512, 50, 225);

    digitalWrite(IN3pin, LOW);
    digitalWrite(IN4pin, HIGH);
    analogWrite(ENBpin, motorSpeed);
}


    //RIGHT JOYSTICK DEADZONE
    if (ctl->axisRY() > -25 && ctl->axisRY() < 25 && ctl->axisRX() > -25 && ctl->axisRX() < 25) {
        analogWrite(ENApin, 0);
        analogWrite(ENBpin, 0);
    }


    //LEFT JOYSTICK DEADZONE
    if (ctl->axisY() > -25 && ctl->axisY() < 25 && ctl->axisX() > -25 && ctl->axisX() < 25) {
        digitalWrite(L_EN, LOW);
        digitalWrite(R_EN, LOW);
        //analogWrite(ENApin, 0);
        //analogWrite(ENBpin, 0);
    }

    if (ctl->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
                ctl->setColorLED(255, 0, 0);
                break;
            case 1:
                // Green
                ctl->setColorLED(0, 255, 0);
                break;
            case 2:
                // Blue
                ctl->setColorLED(0, 0, 255);
                break;
        }
        colorIdx++;
    }

    if (ctl->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:
        ctl->setPlayerLEDs(led & 0x0f);
    }

    if (ctl->x()) {
        // Some gamepads like DS3, DS4, DualSense, Switch, Xbox One S, Stadia support rumble.
        // It is possible to set it by calling:
        // Some controllers have two motors: "strong motor", "weak motor".
        // It is possible to control them independently.
        ctl->playDualRumble(0 /* delayedStartMs */, 250 /* durationMs */, 0x80 /* weakMagnitude */,
                            0x40 /* strongMagnitude */);
    }

    // Another way to query controller data is by getting the buttons() function.
    // See how the different "dump*" functions dump the Controller info.
    dumpGamepad(ctl);
}

//void processMouse(ControllerPtr ctl) {
    // This is just an example.
  //  if (ctl->scrollWheel() > 0) {
        // Do Something
    //} else if (ctl->scrollWheel() < 0) {
        // Do something else
    //}

    // See "dumpMouse" for possible things to query.
   // dumpMouse(ctl);
//}

//void processKeyboard(ControllerPtr ctl) {
  //  if (!ctl->isAnyKeyPressed())
    //    return;

    // This is just an example.
    //if (ctl->isKeyPressed(Keyboard_A)) {
        // Do Something
      //  Serial.println("Key 'A' pressed");
    //}

    // Don't do "else" here.
    // Multiple keys can be pressed at the same time.
    //if (ctl->isKeyPressed(Keyboard_LeftShift)) {
        // Do something else
        //Serial.println("Key 'LEFT SHIFT' pressed");
    //}

    // Don't do "else" here.
    // Multiple keys can be pressed at the same time.
    //if (ctl->isKeyPressed(Keyboard_LeftArrow)) {
        // Do something else
        //Serial.println("Key 'Left Arrow' pressed");
    //}

    // See "dumpKeyboard" for possible things to query.
    //dumpKeyboard(ctl);
//}

//void processBalanceBoard(ControllerPtr ctl) {
    // This is just an example.
  //  if (ctl->topLeft() > 10000) {
        // Do Something
    //}

    // See "dumpBalanceBoard" for possible things to query.
    //dumpBalanceBoard(ctl);
//}

void processControllers() {
    for (auto myController : myControllers) {
        if (myController && myController->isConnected() && myController->hasData()) {
            if (myController->isGamepad()) {
                processGamepad(myController);
            }
            else {            
                Serial.println("Unsupported controller");
            }
        }
    }
}

// Arduino setup function. Runs in CPU 1
void setup() {

    //L298N OUTPUT
    pinMode(ledPin, OUTPUT);
    pinMode(IN1pin, OUTPUT);
    pinMode(IN2pin, OUTPUT);
    pinMode(ENApin, OUTPUT);
    pinMode(IN3pin, OUTPUT);
    pinMode(IN4pin, OUTPUT);
    pinMode(ENBpin, OUTPUT);

    //BTS7960 OUTPUT
    pinMode(L_EN, OUTPUT);
    pinMode(R_EN, OUTPUT);
    pinMode(L_PWM, OUTPUT);
    pinMode(R_PWM, OUTPUT);


  //motor1.begin();                           //This method will set the motor driver pins as output
 // motor1.Enable();                          //This method will set the L_EN and R_EN to HIGH or digitalWrite them to +5v/3v depending on your mcu



    Serial.begin(115200);
    Serial.printf("Firmware: %s\n", BP32.firmwareVersion());
    const uint8_t* addr = BP32.localBdAddress();
    Serial.printf("BD Addr: %2X:%2X:%2X:%2X:%2X:%2X\n", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);

    // Setup the Bluepad32 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();

    // Enables mouse / touchpad support for gamepads that support them.
    // When enabled, controllers like DualSense and DualShock4 generate two connected devices:
    // - First one: the gamepad
    // - Second one, which is a "virtual device", is a mouse.
    // By default, it is disabled.
    BP32.enableVirtualDevice(false);
}

// Arduino loop function. Runs in CPU 1.
void loop() {
    // This call fetches all the controllers' data.
    // Call this function in your main loop.
    bool dataUpdated = BP32.update();
    if (dataUpdated)
        processControllers();

    // The main loop must have some kind of "yield to lower priority task" event.
    // Otherwise, the watchdog will get triggered.
    // If your main loop doesn't have one, just add a simple `vTaskDelay(1)`.
    // Detailed info here:
    // https://stackoverflow.com/questions/66278271/task-watchdog-got-triggered-the-tasks-did-not-reset-the-watchdog-in-time

    //     vTaskDelay(1);
    delay(150);
}

I know I only have on BTS7960 connected, I am waiting for more to be delivered.

Your code does not compile because you're missing a } at the end of the processGamepad() function.

Assuming that this is supposed to control one of the motors connected to the BTS7960 here are some comments.

You have a motor object called motor1 created with above.

And you created another variable called motor1 (of type int) with above.

int motor1.pwm = map(ctl->axisY(), -25, -508, 0, 255); makes kind of sense to control the motor connected to the BTS7960. But motor1 is already (as mentioned) a BTS7960 object. So get rid of the int. You can give the below a try.

if (ctl->axisRY() <= -25) {
    // set speed based on joystick position
    motor1.pwm = map(ctl->axisY(), -25, -508, 0, 255);
    // motor clockwise
    motor1.front();
}

Hi, @nocoder88
Welcome to the forum.

The ESP32 is a 3V3 device, have you written some code to test the BTS7960, as it is a 5V input device.

Tom.... :smiley: :+1: :coffee: :australia:

Thanks sterretje, will try this code and let you know. Saw a R that needs to be removed.

if (ctl->axisY() <= -25) {
    // set speed based on joystick position
    motor1.pwm = map(ctl->axisY(), -25, -508, 0, 255);
    // motor clockwise
    motor1.front();
}

@TomGeorge

If you load the following code on the ESP32. It spins the motor from 0 to 255. then stops then back wards to full speed then stops. and this is with the with the ESP32 and BTS7960

#include <BTS7960.h>
//BTS7960 works between +3v and +5v so you can use a uno, mega or a nano.
#define L_EN 2
#define R_EN 4
#define L_PWM 5                             //pin 5 supports 980hz pwm frequency
#define R_PWM 6                             //pin 6 supports 980hz pwm frequency

BTS7960 motor1(L_EN, R_EN, L_PWM, R_PWM);   //This method will create a object of the class BTS7960

void setup() {
  Serial.begin(9600);                       //begin the serial monitor for output
  motor1.begin();                           //This method will set the motor driver pins as output
  motor1.enable();                          //This method will set the L_EN and R_EN to HIGH or digitalWrite them to +5v/3v depending on your mcu
}

void loop() {
  
  for(int i=0; i<=255; i=i+10)
  {
    motor1.pwm = i;                         //Set the speed, by default the speed is set to 255 you can change it 
    motor1.front();                         //front functions should turn the motor in clockwise direction
    delay(500);
  }
  motor1.stop();                            //stop function should halt the motor by applying 0 pwm to both R_PWM and L_PWM
  delay(500);
  for(int i=0; i<=255; i=i+10)
  { 
    motor1.pwm = i;                         //Set the speed
    motor1.back();                          //back functions should turn the motor in anti-clockwise direction
    delay(500);
  }
  delay(500);
  motor1.disable();                         //This method will set the L_EN and R_EN to LOW or digitalWrite them to 0v
}

Is there a way to check what is in this library?

If you have the library installed you can look at the library in the libraries directory under the sketchbook directory

Managed to get my project working with two L298N and four RS380 motors. Only issue is the L298N H bridge gets really hot. Will keep trying to get BTS7960 going.

I got two libraries. One is BTS7960_Motordriver

Keywords:

`````
# Methods and Functions (KEYWORD2)
BTS7960	KEYWORD2
begin	KEYWORD2
enable	KEYWORD2
disable	KEYWORD2
stop	KEYWORD2
front	KEYWORD2
back	KEYWORD2

````````````


And BTS7960.

Keywords:

```````
Enable	KEYWORD2
Stop	KEYWORD2
Disable	KEYWORD2
TurnLeft	KEYWORD2
TurnRight	KEYWORD2

````````````

You actually will have to look at the source code; usually the public methods in the .h file give you the available functions and implementation of those (and other) functions are in the .cpp files.

It depends on how much detail you need what you'll have to look at.