ESP32 PS3 Controller: controlling a relay

In this tutorial we will learn how to connect a PS3 controller to an ESP32 and control a relay by pressing the controller buttons. The tests from this tutorial were done using a DFRobot’s ESP32 module integrated in a ESP32 development board and this relay board.

Introduction

In this tutorial we will learn how to connect a PS3 controller to an ESP32 and control a relay by pressing the controller buttons. The tests from this tutorial were done using this relay board from DFRobot.

We will be using the Arduino core and this library. For an introductory guide on using the library, please check this previous tutorial.

The connection diagram between the ESP32 and the relay board is shown on figure 1.

Electric diagram with the connection between the ESP32 and the relay board.
Figure 1 – Connection diagram between the ESP32 and the relay board.

Important: The tutorial will focus only on controlling the relay. Taking that into consideration, we will only work with low voltages and currents. Nonetheless, a relay can be used to control circuits operating with the mains, which is dangerous if you don’t know what you are doing. Please stay safe and don’t work with the mains if you don’t have experience with it.

For a similar tutorial using a PS4 controller, please check here.

The tests from this tutorial were done using a DFRobot’s ESP32 module integrated in a ESP32 development board.

The code

As usual, we start by including the Ps3Controller.h library, so we have access to the Ps3 extern variable.

#include <Ps3Controller.h>

After this, we will define a variable that will hold the number of the ESP32 pin connected to the relay board. I will be using pin 13, but you can use a different one if you prefer.

int relayPin = 13;

We will then move to the Arduino setup function. The first thing we will do is opening a serial connection, so we can output some messages from our program.

Serial.begin(115200);

After opening the serial connection, we will set the operating mode of the pin connected to the relay as output. This is done with a call to the pinMode function.

As first input, this function receives the number of the pin we are configuring. Naturally, we will pass the global variable we defined earlier. As second input we need to pass the operating mode. In our case, we should pass the constant OUTPUT.

pinMode(relayPin, OUTPUT);

Then we will take care of initializing the Bluetooth layer of the ESP32, to be ready to receive a controller connection. As covered in many previous tutorials, we simply need to call the begin method on the Ps3 extern variable, passing as input a string containing the Bluetooth Address stored in the controller.

The easiest way to obtain this address is by using a computer software covered on this tutorial. Note that the mentioned tutorial covers the procedure for a PS4 controller but it is exactly the same for a PS3 controller.

if (!Ps3.begin("01:01:01:01:01:01")) {
    Serial.println("Initialization failed.");
    return;
}

Serial.println("Initialization finished.");

To finalize the Arduino setup, we will register two callback functions: one to handle the controller connection event and the other to handle controller buttons clicked events. We will cover the implementation of both functions later

Ps3.attach(onEvent);
Ps3.attachOnConnect(onConnection);

The full Arduino setup function implementation is shown below.

void setup() {

  Serial.begin(115200);

  pinMode(relayPin, OUTPUT);

  if (!Ps3.begin("01:01:01:01:01:01")) {
    Serial.println("Initialization failed.");
    return;
  }

  Serial.println("Initialization finished.");

  Ps3.attach(onEvent);
  Ps3.attachOnConnect(onConnection);

}

Since our implementation will be event based, we won’t need to use the Arduino main loop. Thus we will delete the corresponding FreeRTOS task.

void loop() {
  vTaskDelete(NULL);
}

Next we will check the implementation of the onConnection callback function, which will handle the controller connection event. We will simply print a message indicating that the controller was connected.

Note that we are doing an additional check by calling the isConnected method on the Ps3 extern variable but it should be redundant since this callback is only invoked when the controller connects.

void onConnection() {
  
  if (Ps3.isConnected()) {
    Serial.println("Controller connected.");
  }
}

To finalize, we will check the implementation of the onEvent callback. Here we will detect if either the cross or the square button were clicked and turn on or off the relay, respectively.

void onEvent(){
  // Function implementation 
}

So, to check if the cross button was pressed, we start by accessing the event attribute of the Ps3 extern variable. This attribute is a struct of type ps3_event_t.

Then, on this struct, we will access the button_down attribute, which is another struct, of type ps3_button_t. To finalize, we access the cross field of this struct, which indicates if the button was pressed or not.

Putting these accesses together and using an if condition, we get the following:

if(Ps3.event.button_down.cross){
    // Turn on the relay
}  

To turn on the relay, inside the conditional block, we need to set the ESP32 pin connected to it to a digital high state. This is done with a call to the digitalWrite function.

As first input this function receives the number of the pin and as second it receives a constant representing the digital state we want to set. In our case, we should pass the value HIGH as second input.

if(Ps3.event.button_down.cross){
    digitalWrite(relayPin, HIGH);
}

To turn the relay off when the user presses the square button, the code will be similar. In this case we will access square field of the ps3_button_t struct and we pass the constant LOW to the digitalWrite function instead.

if(Ps3.event.button_down.square){
    digitalWrite(relayPin, LOW);
}

The complete callback function can be seen below.

void onEvent(){
  
  if(Ps3.event.button_down.cross){
    digitalWrite(relayPin, HIGH);
  }
  
  if(Ps3.event.button_down.square){
    digitalWrite(relayPin, LOW);
  }
}

The final code can be seen below.

#include <Ps3Controller.h>

int relayPin = 13;

void onEvent(){
  
  if(Ps3.event.button_down.cross){
    digitalWrite(relayPin, HIGH);
  }
  
  if(Ps3.event.button_down.square){
    digitalWrite(relayPin, LOW);
  }
}

void onConnection() {
  
  if (Ps3.isConnected()) {
    Serial.println("Controller connected.");
  }
}

void setup() {

  Serial.begin(115200);

  pinMode(relayPin, OUTPUT);

  if (!Ps3.begin("01:01:01:01:01:01")) {
    Serial.println("Initialization failed.");
    return;
  }

  Serial.println("Initialization finished.");

  Ps3.attach(onEvent);
  Ps3.attachOnConnect(onConnection);

}

void loop() {
  vTaskDelete(NULL);
}

Testing the code

After connecting the ESP32 and the relay accordingly to the schematic from figure 1, compile and upload the code using the Arduino IDE.

Once the procedure concludes, open the IDE serial monitor and wait for the “Initialization finished” message to be displayed.

After that, connect the PS3 controller by pressing the PS button. A new message should be printed to the serial monitor indicating the controller was connected.

Then, test the system by pressing the cross and square buttons, which should turn the relay on and off, respectively. This is demonstrated on the video below.

Leave a Reply