Low Bluetooth Classical Bitrate using ESP32

I'm trying to use classic bluetooth to stream images from ESP32, already did this with the HC12 using RF and got an FPS of around 1.53 which makes sense considering the maximum 115200 baud rate from the ESP32 to the HC12.

The ESP32 I'm using is a ESP32-WROVER-E with camera (OV2640).

Using classic bluetooth I expected to get a considerably higher FPS, was hoping for at least 3-4 FPS hopefully considerably more (1-3Mbps), however I am getting even less than with RF, an an FPS of around 0.97-1.3 FPS. The arduino code is as follows, I'm leaving in the code for RF since I hope to be able to switch between RF streaming and Bluetooth streaming, in case there is some funky interaction I'm not aware of which may be causing this problem:

#include <HardwareSerial.h>
#include "esp_camera.h"
#include "esp_bt_main.h"
#include "esp_bt_device.h"
#include "BluetoothSerial.h"

BluetoothSerial SerialBT;
// BT Address : A0:B7:65:FE:74:62

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

// HC12 is on 115,200bps Baud Rate, 236,000 over the air baud rate, channel 010 (437.4MHz), maximum power settings (+20dBM, 100mW) and FU3 transmission mode
// Commands for setup are:
// AT+B115200
// AT+C010
// After setting SET to HIGH for 80ms, then LOW and waiting 40ms
#define RXD2 33	//(RX2)
#define TXD2 32	//(TX2)
#define SET 13 // (SET)
HardwareSerial HC12(2);  //Hardware serial 2 on the ESP32

// OV2640 camera module pins
#define PWDN_GPIO_NUM  -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM  21
#define SIOD_GPIO_NUM  26
#define SIOC_GPIO_NUM  27
#define Y9_GPIO_NUM    35
#define Y8_GPIO_NUM    34
#define Y7_GPIO_NUM    39
#define Y6_GPIO_NUM    36
#define Y5_GPIO_NUM    19
#define Y4_GPIO_NUM    18
#define Y3_GPIO_NUM    5
#define Y2_GPIO_NUM    4
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM  23
#define PCLK_GPIO_NUM  22

//Bluetooth Flag
int btFlag = 1;

int takeImg = 0;
int first = 0;

long timer;


void takeImage(){
  camera_fb_t * fb = NULL;  
  fb = esp_camera_fb_get();
  //Sometimes Bugs
  if(first == 0){
    esp_camera_fb_return(fb);
    fb = NULL;
    fb = esp_camera_fb_get();
    first++;
  }
  if (!fb) {
    Serial.println("Camera capture failed");
    return;
  }
  if(btFlag==0){  //Check if bluetooth flag is active
  //HC12.println(fb->len);
    for(int iter = 0; iter < fb->len; iter++){
      HC12.write(fb->buf[iter]); // Send byte by byte over HC12 (Radio)
    }
  } else { // If bluetooth flag is active

    for(int iter = 0; iter < fb->len; iter++){
      SerialBT.write(fb->buf[iter]); // Send byte by byte over Bluetooth 
    }
  }
  Serial.println(fb->len);
  esp_camera_fb_return(fb);
  fb = NULL;
}

// Function to enter setup for HC12 so that settings can be changed, to be called in setup()
void HC12Setup(){
  pinMode(SET, OUTPUT);
  digitalWrite(SET,  HIGH);
  delay(80);
  digitalWrite(SET, LOW);
  delay(40);
}

void setup() 
{
  Serial.begin(115200);           // Serial port to computer
  HC12.begin(115200, SERIAL_8N1, RXD2, TXD2);      // Serial port to HC12

  // OV2640 camera module
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  //config.frame_size = FRAMESIZE_VGA; //640x480
  config.frame_size = FRAMESIZE_HVGA; //480x320
  //config.frame_size = FRAMESIZE_SVGA; //800x600
  config.pixel_format = PIXFORMAT_JPEG;
  config.jpeg_quality = 10;
  config.fb_count = 2;
  config.grab_mode = CAMERA_GRAB_LATEST;
  config.fb_location = CAMERA_FB_IN_PSRAM;

// Init camera
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
  }

// Change camera settings for better visibility KEEP COMMENTED OR THE FUCKING IMAGE QUALITY GETS SHOT IN THE HEAD LIKE I WISH I WAS FOR ADDING THESE LINES
  sensor_t * s = esp_camera_sensor_get();
  /*
  s->set_brightness(s, 0);     // -2 to 2
  s->set_contrast(s, 0);       // -2 to 2
  s->set_saturation(s, 0);     // -2 to 2
  s->set_special_effect(s, 0); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia)
  s->set_whitebal(s, 1);       // 0 = disable , 1 = enable
  s->set_awb_gain(s, 1);       // 0 = disable , 1 = enable
  s->set_wb_mode(s, 0);        // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home)
  s->set_exposure_ctrl(s, 1);  // 0 = disable , 1 = enable
  s->set_aec2(s, 0);           // 0 = disable , 1 = enable
  s->set_ae_level(s, 0);       // -2 to 2
  s->set_aec_value(s, 300);    // 0 to 1200
  s->set_gain_ctrl(s, 1);      // 0 = disable , 1 = enable
  s->set_agc_gain(s, 0);       // 0 to 30
  s->set_gainceiling(s, (gainceiling_t)0);  // 0 to 6 (6 from "timelapse" example sjr, OK)
  s->set_bpc(s, 0);            // 0 = disable , 1 = enable
  s->set_wpc(s, 1);            // 0 = disable , 1 = enable
  s->set_raw_gma(s, 1);        // 0 = disable , 1 = enable
  s->set_lenc(s, 1);           // 0 = disable , 1 = enable
  s->set_hmirror(s, 0);        // 0 = disable , 1 = enable
  s->set_vflip(s, 0);          // 0 = disable , 1 = enable
  s->set_dcw(s, 1);            // 0 = disable , 1 = enable
  s->set_colorbar(s, 0);       // 0 = disable , 1 = enable
*/

// Start BT
  SerialBT.begin("Cubesat");

  delay(1000);


}

void loop() 
{
  delay(50);
  takeImage();
  // We use the following section only really for debugging and changing HC12 settings
/*
  while (HC12.available()) 
  {        
    // If HC-12 has data
    Serial.write(HC12.read());      // Send the data to Serial monitor
  }
  while (Serial.available()) 
  {      
    // If we have data from Serial monitor
    HC12.write(Serial.read());      // Send that data to HC-12
  }
  */
}

In the case of RF, another ESP32 is connected to another HC12 module and feeding the data from the HC12 directly to my computer through UART. The code is extremely simple and should not have any influence on the bluetooth comms.
In the case of bluetooth my computer connects to it through python using the socket library. I could attach the python code as well but I'd like to make sure I didn't make a stupid mistake on the ESP32 side since I'm a newbie in all things arduino related and have a bit more experience in python, although not much.

Any help is appreciated since this problem has been stumping me for a while now.

Thanks!!

Worth mentioning most frames are around 6-8KB

Esp32 or Arduino Nano Esp32?
Esp32 connected to HC12? Post a simple scheme of your setup.
Also, bluetooth serial port protocol has baud rate max 128k, anything above is question of luck.

ESP32-WROVER-E, the connection to HC12 and everything through RF is going just fine, the only problem is the bluetooth giving me an extremely low bitrate.

I thought classical bluetooth could get 1-3Mbps, am I completely wrong in this or am I approaching the bluetooth connection wrong?

You have your post in wrong category.
Look for information about Bluetooth SPP baud rate.

I moved your topic to a more appropriate forum category @pabstersac.

The Nano ESP32 category you chose is only used for discussions directly related to the Arduino Nano ESP32 board.

In the future, please take the time to pick the forum category that best suits the subject of your question. There is an "About the _____ category" topic at the top of each category that explains its purpose.

Thanks in advance for your cooperation.

Thanks!! Sorry I looked for ESP32 and clicked on the first one I saw, which was the only one, I'll pay more attention in the future.

1 Like

Sorry about the wrong category.

Looking at the documentation (Classic Bluetooth - - — ESP-FAQ latest documentation) it says I should be able to reach at maximum 1400Kbps, which is considerably less than what I am getting of around 80Kbps.

Between two Esp32 boards?

It doesn't specify, but I would assume that to be the case since it references bi-directional communication.

Be clear. Your communication is between two Esp32 boards or between Esp32 and something else?

Its between an ESP32 and a python script running on my computer, I couldn't get the ESP32 to ESP32 to work because they couldn't 'find' each other, but I see where you're going could the python script using the sockets library be limiting the bit rate?

I don't know ,but the bluetooth module on your computer definitely could (limit).

This question might be kinda dumb, but how do I find out if this is the case? I'm searching online and not really finding much regarding the bitrate of your computer's SPP everything is about audio codecs

You didn't post your setup. What part has HC12 here??

I know, Just try... Standard gives 128k.

Regarding the bluetooth nothing, I'm only using it for RF which works as intended with the expected baud rate. Using the ESP32s inbuilt bluetooth, I think what I'm gonna end up doing is sending the images via Bluetooth from one ESP32 to another and then through UART to my computer, same as with RF.
Thanks a lot for the help!

Good luck :+1: