Showing posts with label ESP32-DevKitC V4. Show all posts
Showing posts with label ESP32-DevKitC V4. Show all posts

Monday, January 25, 2021

ESP32 drive NeoPixel using Adafruit_NeoPixel library

ESP32 (ESP32-DevKitC V4) code in Arduino Framework to drive a 8X NeoPixel Ring using Adafruit_NeoPixel library simple example.

In Arduino IDE library manager, install Adafruit_NeoPixel library.


Open Example > Adafruit_NeoPixel > simple


Edit PIN on the Arduino is connected to the NeoPixels, and number of NeoPixels are attached.


 Connect NexPixel to ESP32 accordingly, verify and upload your code to run:



Note that if you assign PIN to a wrong pin, such as input only. Error message will be output to Serial:




~ more examples of ESP32-DevKitC V4

Sunday, January 24, 2021

BLE Notification example: ESP32 BLE server read analog input and notify connected device

Code run on ESP32-DevKitC V4 (Arduino framework), to act as BLE server. Once connected, it read Analog Input and notify connected device.

It's modified from last post of ESP32 BLE_notify example.

The client side is programmed using Python run on Raspberry Pi, handle the notification and plot the value graphically.


BLE_notify_AIN.ino
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

#define PinAnalogIn 36

BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;
bool deviceConnected = false;
bool oldDeviceConnected = false;
uint32_t value = 0;

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

bool rqsNotify;
unsigned long prvMillis;
#define INTERVAL_READ 1000
int valNotify;
#define MAX_VALNOTIFY 255

int ain = 0;

class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;

      rqsNotify = false;
      prvMillis = millis();
      Serial.println("Device connected");
    };

    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
      rqsNotify = false;
      Serial.println("Device disconnected");
    }
};

void prcRead(){
  if(deviceConnected){
    unsigned long curMillis = millis();
    if((curMillis-prvMillis) >= INTERVAL_READ){
      int valAIO = analogRead(PinAnalogIn);
      valNotify = map(valAIO, 0, 4096, 0, 255);
      Serial.println(valNotify);
      
      rqsNotify = true;
      prvMillis = curMillis;
    }
  }
  
}


void setup() {
  Serial.begin(115200);

  // Create the BLE Device
  BLEDevice::init("ESP32");

  // Create the BLE Server
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID,
                      BLECharacteristic::PROPERTY_READ   |
                      BLECharacteristic::PROPERTY_WRITE  |
                      BLECharacteristic::PROPERTY_NOTIFY |
                      BLECharacteristic::PROPERTY_INDICATE
                    );

  // Create a BLE Descriptor
  pCharacteristic->addDescriptor(new BLE2902());

  // Start the service
  pService->start();

  // Start advertising
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(false);
  pAdvertising->setMinPreferred(0x0);  // set value to 0x00 to not advertise this parameter
  BLEDevice::startAdvertising();
  Serial.println("Waiting a client connection to notify...");

  
}

void loop() {
    // notify changed value
    if (deviceConnected) {
        if(rqsNotify){
          rqsNotify = false;
          //pCharacteristic->setValue((uint8_t*)valNotify, 1);
          //pCharacteristic->notify();

          value = valNotify;

          pCharacteristic->setValue((uint8_t*)&value, 4);
          pCharacteristic->notify();
          //value++;
          
        }
    }
    // disconnecting
    if (!deviceConnected && oldDeviceConnected) {
        delay(500); // give the bluetooth stack the chance to get things ready
        pServer->startAdvertising(); // restart advertising
        Serial.println("start advertising");
        oldDeviceConnected = deviceConnected;
    }
    // connecting
    if (deviceConnected && !oldDeviceConnected) {
        // do stuff here on connecting
        oldDeviceConnected = deviceConnected;
    }

    prcRead();
}


Wednesday, January 20, 2021

ESP32 BLE_notify example, handle Notification with Python/Raspberry Pi.

ESP32 BLE_notify example create a BLE server that, once we receive a connection, will send periodic notifications.

In ESP32 side, load
Examples > ESP32 BLE Arduino > BLE_notify

Tested on ESP32-DevKitC V4 in my case.

I implemented a simple Python code run on Raspberry Pi, connect to ESP32 and handle notification.

BLE_notify.ino
/*
    Video: https://www.youtube.com/watch?v=oCMOYS71NIU
    Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
    Ported to Arduino ESP32 by Evandro Copercini
    updated by chegewara

   Create a BLE server that, once we receive a connection, will send periodic notifications.
   The service advertises itself as: 4fafc201-1fb5-459e-8fcc-c5c9c331914b
   And has a characteristic of: beb5483e-36e1-4688-b7f5-ea07361b26a8

   The design of creating the BLE server is:
   1. Create a BLE Server
   2. Create a BLE Service
   3. Create a BLE Characteristic on the Service
   4. Create a BLE Descriptor on the characteristic
   5. Start the service.
   6. Start advertising.

   A connect hander associated with the server starts a background task that performs notification
   every couple of seconds.
*/
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;
bool deviceConnected = false;
bool oldDeviceConnected = false;
uint32_t value = 0;

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"


class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };

    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};



void setup() {
  Serial.begin(115200);

  // Create the BLE Device
  BLEDevice::init("ESP32");

  // Create the BLE Server
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID,
                      BLECharacteristic::PROPERTY_READ   |
                      BLECharacteristic::PROPERTY_WRITE  |
                      BLECharacteristic::PROPERTY_NOTIFY |
                      BLECharacteristic::PROPERTY_INDICATE
                    );

  // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
  // Create a BLE Descriptor
  pCharacteristic->addDescriptor(new BLE2902());

  // Start the service
  pService->start();

  // Start advertising
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(false);
  pAdvertising->setMinPreferred(0x0);  // set value to 0x00 to not advertise this parameter
  BLEDevice::startAdvertising();
  Serial.println("Waiting a client connection to notify...");
}

void loop() {
    // notify changed value
    if (deviceConnected) {
        pCharacteristic->setValue((uint8_t*)&value, 4);
        pCharacteristic->notify();
        value++;
        delay(3); // bluetooth stack will go into congestion, if too many packets are sent, in 6 hours test i was able to go as low as 3ms
    }
    // disconnecting
    if (!deviceConnected && oldDeviceConnected) {
        delay(500); // give the bluetooth stack the chance to get things ready
        pServer->startAdvertising(); // restart advertising
        Serial.println("start advertising");
        oldDeviceConnected = deviceConnected;
    }
    // connecting
    if (deviceConnected && !oldDeviceConnected) {
        // do stuff here on connecting
        oldDeviceConnected = deviceConnected;
    }
}


Next:

Sunday, January 17, 2021

BLE_server example run on ESP32 (Arduino framework), accessed by Python on Raspberry Pi/ESP32 BLE_client

BLE_server:

In Arduino Ide, Examples > ESP32 BLE Arduino > BLE_server is a simple BLE server for ESP32. This video show it run on ESP32-DevKitC V4, read the Characteristic "Hello World says Neil" using Python on Raspberry Pi.

BLE_server.ino

/*
    Based on Neil Kolban example for IDF: 
    https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp
    Ported to Arduino ESP32 by Evandro Copercini
    updates by chegewara
*/

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

void setup() {
  Serial.begin(115200);
  Serial.println("Starting BLE work!");

  BLEDevice::init("Long name works now");
  BLEServer *pServer = BLEDevice::createServer();
  BLEService *pService = pServer->createService(SERVICE_UUID);
  BLECharacteristic *pCharacteristic = pService->createCharacteristic(
                                         CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE
                                       );

  pCharacteristic->setValue("Hello World says Neil");
  pService->start();
  // BLEAdvertising *pAdvertising = pServer->getAdvertising();  
  // this still is working for backward compatibility
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();
  Serial.println("Characteristic defined! Now you can read it in your phone!");
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(2000);
}


BLE_client: 

You can also program Examples > ESP32 BLE Arduino > BLE_client on another ESP32 to access the BLE_server.

After powered up, BLE_client to read and change the characteristic value.



BLE_client.ino
/**
 * A BLE client example that is rich in capabilities.
 * There is a lot new capabilities implemented.
 * author unknown
 * updated by chegewara
 */

#include "BLEDevice.h"
//#include "BLEScan.h"

// The remote service we wish to connect to.
static BLEUUID serviceUUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b");
// The characteristic of the remote service we are interested in.
static BLEUUID    charUUID("beb5483e-36e1-4688-b7f5-ea07361b26a8");

static boolean doConnect = false;
static boolean connected = false;
static boolean doScan = false;
static BLERemoteCharacteristic* pRemoteCharacteristic;
static BLEAdvertisedDevice* myDevice;

static void notifyCallback(
  BLERemoteCharacteristic* pBLERemoteCharacteristic,
  uint8_t* pData,
  size_t length,
  bool isNotify) {
    Serial.print("Notify callback for characteristic ");
    Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str());
    Serial.print(" of data length ");
    Serial.println(length);
    Serial.print("data: ");
    Serial.println((char*)pData);
}

class MyClientCallback : public BLEClientCallbacks {
  void onConnect(BLEClient* pclient) {
  }

  void onDisconnect(BLEClient* pclient) {
    connected = false;
    Serial.println("onDisconnect");
  }
};

bool connectToServer() {
    Serial.print("Forming a connection to ");
    Serial.println(myDevice->getAddress().toString().c_str());
    
    BLEClient*  pClient  = BLEDevice::createClient();
    Serial.println(" - Created client");

    pClient->setClientCallbacks(new MyClientCallback());

    // Connect to the remove BLE Server.
    pClient->connect(myDevice);  
    // if you pass BLEAdvertisedDevice instead of address, 
    // it will be recognized type of peer device address (public or private)
    Serial.println(" - Connected to server");

    // Obtain a reference to the service we are after in the remote BLE server.
    BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
    if (pRemoteService == nullptr) {
      Serial.print("Failed to find our service UUID: ");
      Serial.println(serviceUUID.toString().c_str());
      pClient->disconnect();
      return false;
    }
    Serial.println(" - Found our service");


    // Obtain a reference to the characteristic in the service of the remote BLE server.
    pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
    if (pRemoteCharacteristic == nullptr) {
      Serial.print("Failed to find our characteristic UUID: ");
      Serial.println(charUUID.toString().c_str());
      pClient->disconnect();
      return false;
    }
    Serial.println(" - Found our characteristic");

    // Read the value of the characteristic.
    if(pRemoteCharacteristic->canRead()) {
      std::string value = pRemoteCharacteristic->readValue();
      Serial.print("The characteristic value was: ");
      Serial.println(value.c_str());
    }

    if(pRemoteCharacteristic->canNotify())
      pRemoteCharacteristic->registerForNotify(notifyCallback);

    connected = true;
    return true;
}
/**
 * Scan for BLE servers and find the first one that advertises 
 * the service we are looking for.
 */
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
 /**
   * Called for each advertising BLE server.
   */
  void onResult(BLEAdvertisedDevice advertisedDevice) {
    Serial.print("BLE Advertised Device found: ");
    Serial.println(advertisedDevice.toString().c_str());

    // We have found a device,
    // let us now see if it contains the service we are looking for.
    if (advertisedDevice.haveServiceUUID() && 
			advertisedDevice.isAdvertisingService(serviceUUID)) {

      BLEDevice::getScan()->stop();
      myDevice = new BLEAdvertisedDevice(advertisedDevice);
      doConnect = true;
      doScan = true;

    } // Found our server
  } // onResult
}; // MyAdvertisedDeviceCallbacks


void setup() {
  Serial.begin(115200);
  Serial.println("Starting Arduino BLE Client application...");
  BLEDevice::init("");

  // Retrieve a Scanner and set the callback we want to use to be informed when we
  // have detected a new device.  Specify that we want active scanning and start the
  // scan to run for 5 seconds.
  BLEScan* pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setInterval(1349);
  pBLEScan->setWindow(449);
  pBLEScan->setActiveScan(true);
  pBLEScan->start(5, false);
} // End of setup.


// This is the Arduino main loop function.
void loop() {

  // If the flag "doConnect" is true then we have scanned for and found the desired
  // BLE Server with which we wish to connect.  Now we connect to it.  Once we are 
  // connected we set the connected flag to be true.
  if (doConnect == true) {
    if (connectToServer()) {
      Serial.println("We are now connected to the BLE Server.");
    } else {
      Serial.println("We have failed to connect to the server; there is nothin more we will do.");
    }
    doConnect = false;
  }

  // If we are connected to a peer BLE Server,
  // update the characteristic each time we are reached
  // with the current time since boot.
  if (connected) {
    String newValue = "Time since boot: " + String(millis()/1000);
    Serial.println("Setting new characteristic value to \"" + newValue + "\"");
    
    // Set the characteristic's value to be the array of bytes that is actually a string.
    pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length());
  }else if(doScan){
    BLEDevice::getScan()->start(0);  
    // this is just eample to start scan after disconnect, 
    // most likely there is better way to do it in arduino
  }
  
  delay(1000); // Delay a second between loops.
} // End of loop

Thursday, December 31, 2020

Bi-direction Bluetooth Classic comm. between ESP32 (Arduino framework)

Last post show my exercise of "ESP-32S as Bluetooth classic Server, bi-direction communication with Raspberry Pi/Python". Here is the ESP32 implementation for the Client side, to connect to the ESP32 server in last post.

NodeMCU ESP-32S act as a server (in last post):
It echo what received from bluetooth back to sender, and display on SPI ST7735 display.

ESP32-DevKitC-V4 as client (this post):
Connect to server, forward data from serial,  to Bluetooth. Display data from Bluetooth on I2C SSD1306 OLED display.

The code start from ESP32 example of SerialToSerialBTM. But I found that the code SerialBT.connect() always return "true", and prompt "Connected Succesfully!", no matter the device name and MAC address, even no server exist. 

To solve it, I implement my bluetooth callback function to double check if ESP_SPP_OPEN_EVT raised. I don't know is it a long time solution, anyway it work in this exercise.

SPPClient_ESP32_ssd1306_20201231b.ino
/*
 * SPP Client on ESP32
 * Display on  SSD1306
 */

#include "ssd1306.h"
#include "ssd1306_console.h"
#include "BluetoothSerial.h"

Ssd1306Console  console;

BluetoothSerial SerialBT;

String ServerMACadd = "3C:71:BF:0D:DD:6A";
uint8_t ServerMAC[6]  = {0x3C, 0x71, 0xBF, 0x0D, 0xDD, 0x6A};
String ServerName = "ESP32_SPP";
char *pin = "1234"; //<- standard pin would be provided by default
bool connected;
bool isSppOpened = false;

/*
.arduino15/packages/esp32/hardware/esp32/1.0.4/libraries/
BluetoothSerial/src/BluetoothSerial.cpp

 */

void btCallback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param){
  
  switch (event)
    {
    case ESP_SPP_INIT_EVT:
        Serial.println("ESP_SPP_INIT_EVT");
        break;

    case ESP_SPP_SRV_OPEN_EVT://Server connection open
        Serial.println("ESP_SPP_SRV_OPEN_EVT");
        break;

    case ESP_SPP_CLOSE_EVT://Client connection closed
        Serial.println("ESP_SPP_CLOSE_EVT");
        isSppOpened = false;
        break;

    case ESP_SPP_CONG_EVT://connection congestion status changed
        Serial.println("ESP_SPP_CONG_EVT");
        break;

    case ESP_SPP_WRITE_EVT://write operation completed
        Serial.println("ESP_SPP_WRITE_EVT");
        break;

    case ESP_SPP_DATA_IND_EVT://connection received data
        Serial.println("ESP_SPP_DATA_IND_EVT");
        break;

    case ESP_SPP_DISCOVERY_COMP_EVT://discovery complete
        Serial.println("ESP_SPP_DISCOVERY_COMP_EVT");
        break;

    case ESP_SPP_OPEN_EVT://Client connection open
        Serial.println("ESP_SPP_OPEN_EVT");
        isSppOpened = true;
        break;

    case ESP_SPP_START_EVT://server started
        Serial.println("ESP_SPP_START_EVT");
        break;

    case ESP_SPP_CL_INIT_EVT://client initiated a connection
        Serial.println("ESP_SPP_CL_INIT_EVT");
        break;

    default:
        Serial.println("unknown event!");
        break;
    }
}

static void startupScreen()
{
    ssd1306_setFixedFont(ssd1306xled_font6x8);
    ssd1306_clearScreen();
    ssd1306_printFixed(0, 0, "arduiino-er.blogspot.com", STYLE_BOLD);
    ssd1306_printFixed(0, 24, "ESP32 SPP Client", STYLE_NORMAL);
}

void setup()
{
    Serial.begin(115200);
    Serial.println("\n------ begin ----------------\n");
    
    ssd1306_128x64_i2c_init();
    ssd1306_clearScreen();
    startupScreen();
    delay(500);

    Serial.println("- to connect -");
    ssd1306_printFixed(0, 32, "...to connect", STYLE_NORMAL);
    
    SerialBT.begin("ESP32_Client", true);
    SerialBT.register_callback(btCallback);
    //connected = SerialBT.connect(ServerName);
    connected = SerialBT.connect(ServerMAC);

    /*
     * In my trial, 
     * SerialBT.connect() always return  true, even no server exist.
     * To solve it, I implemented bluetooth event callback function,
     * double varify if ESP_SPP_OPEN_EVT raised.
     */
    
    if(connected) {
      Serial.println("SerialBT.connect() == true");
    } else {
      Serial.println("Failed to connect! Reset to re-try");
      Serial.println("SerialBT.connect() == false");
      ssd1306_printFixed(0, 32, 
          "Failed to connect! Reset to re-try", STYLE_NORMAL);
      while(true){
      }
    }

    //may be there are some delay to call callback function,
    //delay before check
    delay(500);
    if(isSppOpened == false){
      Serial.println("isSppOpened == false");
      Serial.println("Reset to re-try");
      ssd1306_printFixed(0, 32, 
          "SPP_OPEN not raised! Reset to re-try", STYLE_NORMAL);
      while(true){
      }
    }
    
    Serial.println("isSppOpened == true");
    Serial.println("CONNECTED");

    ssd1306_clearScreen();
    ssd1306_setFixedFont(ssd1306xled_font6x8);
    console.println("CONNECTED:");
}

void loop()
{
    if(!isSppOpened){
      Serial.println("isSppOpened == false : DISCONNECTED");
      Serial.println("Reset to re-connect");
      console.println("DISCONNECTED");
      console.println("Reset to re-connect");
      while(true){
      }
    }
    if (Serial.available()) {
      SerialBT.write(Serial.read());
    }
    if (SerialBT.available()) {
      char c = SerialBT.read();
      //Serial.write(c);
      console.print(c);
    }
    delay(20);
}

For the setup of SPI ST7735 IPS used on server side, refer to the post "ESP32 display with 0.96" 80x160 SPI ST7735 IPS Display, using TFT_eSPI lib".

For the setup of I2C SSD1306 OLED used on client side, refer to the post "I2C SSD1306 OLED@ESP32 (ESP32-DevKitC-V4), using SSD1306 lib".

Friday, December 25, 2020

ESP32 receive Bluetooth Classic command from Raspberry Pi/Python, to control Servos.

In my previous posts, I show simple examples of ESP32 Bluetooth Classic serial exampleServo Motor Control and I2C SSD1306 OLED. In this exercise, group three altogether run on ESP32-DevKitC-V4, receive single character command from Raspberry Pi/Python via Bluetooth Classic, control Servo Motors, and display position on 0.96" 128x64 I2C SSD1306 OLED.

Connection:

BTServoServer_20201226.ino

// BTServoServer

#include "BluetoothSerial.h"
#include "esp_bt_device.h"
#include "ssd1306.h"
#include <ESP32Servo.h>

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

BluetoothSerial SerialBT;
Servo myservoX;  // create servo objects to control a servo
Servo myservoY;
int servoPinX = 18;
int servoPinY = 19;

#define CMD_ORG 'O'
#define CMD_XDEC 'A'
#define CMD_XDEC10 'B'
#define CMD_XINC 'C'
#define CMD_XINC10 'D'
#define CMD_YDEC 'E'
#define CMD_YDEC10 'F'
#define CMD_YINC 'G'
#define CMD_YINC10 'H'

int x = 0;
int y = 0;

void printDeviceAddress() {
 
  const uint8_t* point = esp_bt_dev_get_address();
 
  for (int i = 0; i < 6; i++) {
 
    char str[3];
 
    sprintf(str, "%02X", (int)point[i]);
    Serial.print(str);
 
    if (i < 5){
      Serial.print(":");
    }
 
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println("\n---Start---");
  SerialBT.begin("ESP32test"); //Bluetooth device name
  
  Serial.println("The device started, now you can pair it with bluetooth!");
  Serial.println("Device Name: ESP32test");
  Serial.print("BT MAC: ");
  printDeviceAddress();
  Serial.println();

  ssd1306_setFixedFont(ssd1306xled_font6x8);
  ssd1306_128x64_i2c_init();
  ssd1306_clearScreen();
  ssd1306_printFixed(0,  8, "BTServoServer", STYLE_BOLD);
  ssd1306_printFixed(0,  40, "arduino-er.blogspot.com", STYLE_BOLD);

  // Allow allocation of all timers
  ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);
  myservoX.setPeriodHertz(50);    // standard 50 hz servo
  myservoX.attach(servoPinX, 500, 2500); // attaches the servo on pin 18 to the servo object
  myservoY.setPeriodHertz(50);    // standard 50 hz servo
  myservoY.attach(servoPinY, 500, 2500);

  myservoX.write(90);
  myservoY.write(90);
}

void loop() {
  if (SerialBT.available()) {
    char cmd = SerialBT.read();
    switch(cmd) {
      case CMD_ORG:
            x = 0;
            y = 0; 
            break;
      case CMD_XDEC:
            x--;
            break;
      case CMD_XDEC10:
            x = x-10;
            break;
      case CMD_XINC:
            x++;
            break;
      case CMD_XINC10:
            x = x+10;
            break;
      case CMD_YDEC:
            y--;
            break;
      case CMD_YDEC10:
            y = y-10;
            break;
      case CMD_YINC:
            y++;
            break;
      case CMD_YINC10:
            y = y+10;
            break;
      default:
            Serial.println("unknown command!");
            break;
    }

    if(x < -90)
      x = -90;
    if(x > 90)
      x = 90;
    if(y < -90)
      y = -90;
    if(y > 90)
      y = 90;

    String s = String(x, DEC) + " : " + String(y, DEC) + "    ";
    const char* c;
    c = s.c_str();
    Serial.println(s);
    ssd1306_printFixed(0, 25, c, STYLE_NORMAL);

    myservoX.write(x + 90);
    myservoY.write(y + 90);
    delay(200);             // wait for the servo to get there
  }
  delay(20);
}


Python code in Raspberry Pi side, refer to my another blog's post: Hello Raspberry Pi - Raspberry Pi/Python remote control ESP32/Servos via Bluetooth Classic

Next:

Thursday, December 24, 2020

I2C SSD1306 OLED@ESP32 (ESP32-DevKitC-V4), using SSD1306 lib.

ESP32 (ESP32-DevKitC-V4) run in Arduino framework, to display on 0.96" 128x64/0.91"128x32 OLED with I2C SSD1306 driver, using SSD1306 library.

Install Library:

Search and install ssd1306 library (by Alexey Dynda) via Arduino IDE library manager.

Connection:

ESP32			I2C SSD1306 OLED
(ESP32-DevKitC-V4)
====================================
3V3			VCC
GND			GND
IO22			SCL
IO21			SDA

Example:

Open File > Examples > ssd1306 > demos > ssd1306_demo

Save, verify and upload.


Related:


Wednesday, December 23, 2020

ESP32 i2c_scanner

i2c_scanner in Arduino Playground is a very simple sketch scans the I2C-bus for devices. If a device is found, it is reported to the Arduino serial monitor. It can be run on ESP32 to scan your connected I2C device and print its I2C address.

i2c_scanner

 // --------------------------------------
// i2c_scanner
//
// Version 1
//    This program (or code that looks like it)
//    can be found in many places.
//    For example on the Arduino.cc forum.
//    The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
//     Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26  2013
//    V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
//    by Arduino.cc user Krodal.
//    Changes by louarnold removed.
//    Scanning addresses changed from 0...127 to 1...119,
//    according to the i2c scanner by Nick Gammon
//    https://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
//    As version 4, but address scans now to 127.
//    A sensor seems to use address 120.
// Version 6, November 27, 2015.
//    Added waiting for the Leonardo serial communication.
// 
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//

#include <Wire.h>


void setup()
{
  Wire.begin();

  Serial.begin(9600);
  while (!Serial);             // Leonardo: wait for serial monitor
  Serial.println("\nI2C Scanner");
}


void loop()
{
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");

  nDevices = 0;
  for(address = 1; address < 127; address++ ) 
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error==4) 
    {
      Serial.print("Unknown error at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");

  delay(5000);           // wait 5 seconds for next scan
}



Next: 

Tuesday, December 22, 2020

ESP32 (ESP32-DevKitC-V4) to drive Servo Motors using ESP32Servo lib

This example show how to program ESP32 (ESP32-DevKitC-V4) to drive Servo Motors (one SG90/two DS3120) using ESP32Servo lib, using ESP32Servo library.

Drive one SG90 Servo Motor:

Connection:

Install ESP32Servo in Arduino IDE's Library manager.

Open example of ESP32Server > Sweep.

As shown in the video, change min/max to 500/2500.

Sweep_esp32_sg90.ino
/* Sweep
Original from ESP32Servo examples Sweep
https://github.com/madhephaestus/ESP32Servo

 */

#include <ESP32Servo.h>

Servo myservo;  // create servo object to control a servo
// 16 servo objects can be created on the ESP32

int pos = 0;    // variable to store the servo position
// Recommended PWM GPIO pins on the ESP32 include 2,4,12-19,21-23,25-27,32-33 
int servoPin = 18;

void setup() {
	// Allow allocation of all timers
	ESP32PWM::allocateTimer(0);
	ESP32PWM::allocateTimer(1);
	ESP32PWM::allocateTimer(2);
	ESP32PWM::allocateTimer(3);
	myservo.setPeriodHertz(50);    // standard 50 hz servo
	myservo.attach(servoPin, 500, 2500); // attaches the servo on pin 18 to the servo object
	// using default min/max of 1000us and 2000us
	// different servos may require different min/max settings
	// for an accurate 0 to 180 sweep
}

void loop() {

	for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
		// in steps of 1 degree
		myservo.write(pos);    // tell servo to go to position in variable 'pos'
		delay(15);             // waits 15ms for the servo to reach the position
	}
	for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
		myservo.write(pos);    // tell servo to go to position in variable 'pos'
		delay(15);             // waits 15ms for the servo to reach the position
	}
}

Drive two DS3120 Servo Motor:

Connection:

modify the code to add one more Servo:

Sweep_esp32_two_ds3120.ino

/* Sweep
Original from ESP32Servo examples Sweep
https://github.com/madhephaestus/ESP32Servo

 */

#include <ESP32Servo.h>

Servo myservo;  // create servo object to control a servo
Servo myservo2;
// 16 servo objects can be created on the ESP32

int pos = 0;    // variable to store the servo position
// Recommended PWM GPIO pins on the ESP32 include 2,4,12-19,21-23,25-27,32-33 
int servoPin = 18;
int servoPin2 = 19;

void setup() {
	// Allow allocation of all timers
	ESP32PWM::allocateTimer(0);
	ESP32PWM::allocateTimer(1);
	ESP32PWM::allocateTimer(2);
	ESP32PWM::allocateTimer(3);
	myservo.setPeriodHertz(50);    // standard 50 hz servo
	myservo.attach(servoPin, 500, 2500); // attaches the servo on pin 18 to the servo object
	myservo2.setPeriodHertz(50);    // standard 50 hz servo
	myservo2.attach(servoPin2, 500, 2500);
	// using default min/max of 1000us and 2000us
	// different servos may require different min/max settings
	// for an accurate 0 to 180 sweep
}

void loop() {

	for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
		// in steps of 1 degree
		myservo.write(pos);    // tell servo to go to position in variable 'pos'
		myservo2.write(pos);
		delay(15);             // waits 15ms for the servo to reach the position
	}
	for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
		myservo.write(pos);    // tell servo to go to position in variable 'pos'
		myservo2.write(pos);
		delay(15);             // waits 15ms for the servo to reach the position
	}
}



Next:

Sunday, December 20, 2020

ESP32: Get chip info

ESP_info.ino, to get chip info of ESP32.
#include <Esp.h>

void setup() {
  Serial.begin(115200);
  Serial.printf("\n\n---Start---\n");
  Serial.print("Chip Revision: ");
  Serial.print(ESP.getChipRevision());
  Serial.printf("\nCpuFreqMHz(): %lu", (unsigned long)ESP.getCpuFreqMHz());
  Serial.printf("\nSdkVersion: %s", ESP.getSdkVersion());
  Serial.printf("\nFlashChipSize: %lu", (unsigned long)ESP.getFlashChipSize());
}

void loop() {
  
}

Run on ESP32-DevKitC V4 with ESP32-WROVER-E module:


Saturday, December 19, 2020

ESP32 Bluetooth serial example

It's a simple example of ESP32 Bluetooth serial communication, run on ESP32-DevKitC V4.

The video show how it run, to communicate with Python/Raspberry Pi. The Python code is in my another blog: HelloRaspberryPi - Python (on Raspberry Pi) Bluetooth communicate with ESP32 SerialToSerialBT, using pybluez.

To make the ESP32 examples appear in examples list, you have to choose board of ESP32 first. It's ESP32 Wrover Module in may case.

The example available in Arduino IDE MENU > File > Examples > Bluetooth Serial (under Examples for Wrover Module) > SerialToSerialBT.


I make a little bit modification to display its Bluetooth MAC address.
// ref: Examples > BluetoothSerial > SerialToSerialBT

#include "BluetoothSerial.h"
#include "esp_bt_device.h"

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

BluetoothSerial SerialBT;

void printDeviceAddress() {
 
  const uint8_t* point = esp_bt_dev_get_address();
 
  for (int i = 0; i < 6; i++) {
 
    char str[3];
 
    sprintf(str, "%02X", (int)point[i]);
    Serial.print(str);
 
    if (i < 5){
      Serial.print(":");
    }
 
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println("\n---Start---");
  SerialBT.begin("ESP32test"); //Bluetooth device name
  
  Serial.println("The device started, now you can pair it with bluetooth!");
  Serial.println("Device Name: ESP32test");
  Serial.print("BT MAC: ");
  printDeviceAddress();
  Serial.println();
}

void loop() {
  if (Serial.available()) {
    SerialBT.write(Serial.read());
  }
  if (SerialBT.available()) {
    Serial.write(SerialBT.read());
  }
  delay(20);
}

The function printDeviceAddress() is copy from dfrobot ESP32 Arduino: Getting the Bluetooth Device Address.

Next:


Friday, December 18, 2020

ESP32-DevKitC V4 - ESP32-WROVER-E module, with ESP32-D0WD-V3 embedded

ESP32-DevKitC V4 is a small-sized ESP32-based development board produced by Espressif. Most of the I/O pins are broken out to the pin headers on both sides for easy interfacing. Developers can either connect peripherals with jumper wires or mount ESP32-DevKitC V4 on a breadboard.



To cover a wide range of user requirements, the following versions of ESP32-DevKitC V4 are available with different ESP32 modules:
  • ESP32-WROOM-32E
  • ESP32-WROOM-32UE
  • ESP32-WROOM-32D
  • ESP32-WROOM-32U
  • ESP32-SOLO-1
  • ESP32-WROVER-E
  • ESP32-WROVER-IE
My board is installed with ESP32-WROVER-E module.

ESP32-WROVER-E and ESP32-WROVER-IE are two powerful, generic WiFi-BT-BLE MCU modules. ESP32-WROVER-E comes with a PCB antenna, and ESP32-WROVER-IE with an IPEX antenna. They both feature a 4 MB external SPI flash and an additional 8 MB SPI Pseudo static RAM (PSRAM). 

At the core of the module is the ESP32-D0WD-V3 chip, For details on the part numbers of the ESP32 family of chips, please refer to the document ESP32 Datasheet.

Espressif has released one wafer-level change on ESP32 Series of products (ECO V3). ESP32 ECO V3 User Guide is one of the must see document describes differences between V3 and previous ESP32 silicon wafer revisions.



To install ESP32 on Arduino IDE Boards Manager:

Arduino IDE Menu > File> Preferences
Enter the url in the "Additional Board Manager URLs":

To enter more than one URL, separate it with a comma.

Then:
Menu > Tools > Board > Boards Manager…
Search and install ESP32

related:

Examples (in Arduino framework):

Usefull links: