3D Model: Download here
Electronics parts (Buy link on my Youtube video):
- 1x ESP32C3 Super Mini
- 2x 6mm motor with 2-stage gearbox
- 1x 6mm motor with 3-stage gearbox
- 3x Driver RZ7888
- 1x 50mah Lipo battery
Others:
- 40x 1mm screw
- 2x bearings 1x3x1
Android App: https://thehlab.org/products
Arduino code:
/*
* author: The H Lab
* Board Name: ESP32 C3 SuperMini
* Board selected in Arduino IDE: ESP32C3 Dev Module
* Board Manager: esp32 by Espressif Systems
*/
#include
#include
#include
#include
char command;
String string;
int svangle = 0;
int slideBarValue = 50;
int hindex = 0;
String aCmd;
int speeds = 0;//STOP_SPEED;
int gear = 0;
int turn_blink_state = LOW;
int turn_status_cmd = 0;
long previousMillis = 0;
int cDeepSleepButton = 0;
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
#define PULSE_WIDTH 20
#define MOTOR1A 10
#define MOTOR1B 20
#define MOTOR2A 9
#define MOTOR2B 8
#define MOTOR3A 1
#define MOTOR3B 2
int pulse_count = 0;
int pulse_high1 = 0; // speed 0 to 10 (PULSE_WIDTH)
bool direction1 = false;
int pulse_high2 = 0; // speed 0 to 10 (PULSE_WIDTH)
bool direction2 = false;
int pulse_high3 = 0;
bool direction3 = false;
hw_timer_t *My_timer = NULL;
void IRAM_ATTR onTimer() {
pulse_count++;
if ( pulse_count >= PULSE_WIDTH ){
pulse_count = 0;
}
// motor1
if ( pulse_count < pulse_high1 ){
if ( direction1 ){
digitalWrite(MOTOR1A, LOW);
digitalWrite(MOTOR1B, HIGH);
} else {
digitalWrite(MOTOR1A, HIGH);
digitalWrite(MOTOR1B, LOW);
}
} else {
digitalWrite(MOTOR1A, LOW);
digitalWrite(MOTOR1B, LOW);
}
// motor2
if ( pulse_count < pulse_high2 ){
if ( direction2 ){
digitalWrite(MOTOR2A, LOW);
digitalWrite(MOTOR2B, HIGH);
} else {
digitalWrite(MOTOR2A, HIGH);
digitalWrite(MOTOR2B, LOW);
}
} else {
digitalWrite(MOTOR2A, LOW);
digitalWrite(MOTOR2B, LOW);
}
// motor3
if ( pulse_count < pulse_high3 ){
if ( direction3 ){
digitalWrite(MOTOR3A, LOW);
digitalWrite(MOTOR3B, HIGH);
} else {
digitalWrite(MOTOR3A, HIGH);
digitalWrite(MOTOR3B, LOW);
}
} else {
digitalWrite(MOTOR3A, LOW);
digitalWrite(MOTOR3B, LOW);
}
}
BLECharacteristic *pCharacteristic;
void setupBLE() {
BLEDevice::init("ESP32");
BLEServer *pServer = BLEDevice::createServer();
BLEService *pService = pServer->createService(SERVICE_UUID);
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE);
//pCharacteristic->setValue("Hello World");
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();
}
void setup() {
// esp_sleep_wakeup_cause_t wakeup_reason;
// wakeup_reason = esp_sleep_get_wakeup_cause();
//esp_sleep_enable_ext0_wakeup(WAKE_UP_PIN, 0); //1 = High, 0 = Low
//esp_deep_sleep_enable_gpio_wakeup(1 << 9, ESP_GPIO_WAKEUP_GPIO_HIGH);
// Serial.begin( 115200 );
setupBLE();
//Serial.println("OK!");
//Timer
My_timer = timerBegin(0, 80, true);
timerAttachInterrupt(My_timer, &onTimer, true);
timerAlarmWrite(My_timer, 1000, true); // 1000 call per sec
timerAlarmEnable(My_timer); //Just Enable
pinMode(MOTOR1A, OUTPUT);
pinMode(MOTOR1B, OUTPUT);
pinMode(MOTOR2A, OUTPUT);
pinMode(MOTOR2B, OUTPUT);
pinMode(MOTOR3A, OUTPUT);
pinMode(MOTOR3B, OUTPUT);
//Serial.println("Setup done!");
}
void loop() {
//delay(2000);
string = "";
if (pCharacteristic->getLength() > 0) {
std::string s = pCharacteristic->getValue();
string += s.c_str();
}
// Serial.println(string);
while (string.length() >= 3) {
aCmd = string.substring(0, 3);
string = string.substring(3);
if (aCmd.lastIndexOf("A") == 0) {
speeds = aCmd.substring(1).toInt();
if (speeds >= 0) {
//sgo1.writeMicroseconds(map(speeds, 0, 100, MAX_SPEED_BACK, MAX_SPEED_GO));
if ( speeds > 50 ) direction1 = true;
else direction1 = false;
pulse_high1 = abs(50 - speeds)/5;
delay(5);
}
} else if (aCmd.lastIndexOf("B") == 0) {
speeds = aCmd.substring(1).toInt();
if (speeds >= 0) {
//sgo2.writeMicroseconds(map(speeds, 0, 100, MAX_SPEED_BACK, MAX_SPEED_GO));
if ( speeds > 50 ) direction2 = true;
else direction2 = false;
pulse_high2 = abs(50 - speeds)/5;
delay(5);
}
} else if (aCmd.lastIndexOf("C") == 0) {
speeds = aCmd.substring(1).toInt();
if (speeds >= 0) {
//sgo1.writeMicroseconds(map(speeds, 0, 100, MAX_SPEED_BACK, MAX_SPEED_GO));
if ( speeds > 50 ) direction3 = true;
else direction3 = false;
pulse_high3 = abs(50 - speeds)/10;
delay(5);
}
}
}
}