========================= Getting Started ========================= Overview ======== This section provides a step-by-step guide to setting up the **Arduino IDE** and preparing your **ESP32 D1 Mini (WROOM-32)** for uploading the evolutronix state machine firmware. All software tools used here are free and can be installed on Windows, macOS, or Linux. Arduino IDE Installation ======================== To upload firmware to the ESP32 board, we use the **Arduino IDE**. Download the installer from the official Arduino website: πŸ”— https://www.arduino.cc/en/software After downloading, follow the installation wizard for your operating system. Once installed, open the Arduino IDE to verify that it runs correctly. .. figure:: ../images/gettingstarted/arduino.png :alt: Arduino IDE download page :align: center :width: 70% *Figure 1 – Download page of the Arduino IDE.* Setting up the ESP32 Board ========================== After the Arduino IDE is installed, you need to install the **ESP32 board definitions** to enable support for your hardware. 1. Open the Arduino IDE. 2. Navigate to **File β†’ Preferences**. 3. Copy and paste the following URL into the β€œAdditional Boards Manager URLs” field: .. code-block:: text https://dl.espressif.com/dl/package_esp32_index.json or .. code-block:: text https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json 4. Click **OK**, then open **Tools β†’ Board β†’ Boards Manager**. 5. Search for **ESP32 by Espressif Systems** and install the latest version (for example: version 3.x). .. figure:: ../images/gettingstarted/arduino_ide.png :alt: ESP32 board installation :align: center :width: 70% *Figure 2 – Installing the ESP32 board in the Arduino IDE.* Installing USB-to-UART Drivers ============================== Your computer requires the correct USB driver to communicate with the ESP32. For the **ESP32-WROOM-32**, download and install the **CP210x USB to UART Bridge VCP Driver** from Silicon Labs: πŸ”— https://www.silabs.com/developers/usb-to-uart-bridge-vcp-drivers?tab=downloads Select the appropriate driver version for your operating system. .. note:: Some ESP32 variants may use **CH340** drivers instead of CP210x. If your device is not detected after installation, install the **CH340 driver** and reconnect your board. Testing the ESP32 Installation ============================== Now that all software and drivers are installed, you can verify the setup by uploading a simple LED blink example. **Step 1:** Open the Arduino IDE and go to **File β†’ New**. Copy the following code into the editor: .. code-block:: cpp :linenos: #include #define LED 2 void setup() { Serial.begin(115200); pinMode(LED, OUTPUT); } void loop() { digitalWrite(LED, HIGH); Serial.println("LED is on"); delay(1000); digitalWrite(LED, LOW); Serial.println("LED is off"); delay(1000); } **Step 2:** Select your board and port: - Navigate to **Tools β†’ Board β†’ Select other board and port...** - Choose your ESP32 model (for example: *DOIT ESP32 DEVKIT V1*). - Select the correct **COM port**, then click **OK**. **Step 3:** Click the **Upload** button. If prompted, hold the **BOOT** button on your ESP32 board while the code is uploading. .. figure:: ../images/arduino_upload.png :alt: Uploading code to the ESP32 :align: center :width: 70% *Figure 4 – Uploading the blink example.* Once the upload completes successfully, the on-board LED (GPIO 2) should blink every second, confirming that your ESP32 and Arduino IDE are working correctly. Summary ======== You have now: - Installed the Arduino IDE - Configured the ESP32 board manager - Installed the required USB-to-UART drivers - Uploaded and verified your first program esp32 state machine =================== copy de tekst and past in arduino and save upload to esp32 .. code-block:: cpp :linenos: #include "FS.h" #include "SPIFFS.h" #include "esp_heap_caps.h" #include #include #include "esp_timer.h" Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(); esp_timer_handle_t timer; volatile bool updateFlag = false; //int currentSequenceIndex = 0; bool sequenceActive = false; #define SERVO_MIN 150 #define SERVO_MAX 600 #define MAX_SEQUENCES 10 #define NUM_SERVOS 13 #define PWM_FREQ 50 struct Sequence { int angle[NUM_SERVOS]; int speed[NUM_SERVOS]; }; struct Group { String name; Sequence sequences[MAX_SEQUENCES]; int numSequences; }; struct ServoControl { uint8_t channel; int currentAngle = 90; int targetAngle = 90; int speedDelay = 20; unsigned long lastUpdate = 0; ServoControl(uint8_t ch) : channel(ch) {} }; ServoControl servos[NUM_SERVOS] = { {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, {11}, {12} }; bool reachedTarget[NUM_SERVOS] = {false}; // Forward declarations void saveSequenceToFile(String input); void MoveServo(String input); void loadSequenceGroupFromFile(const String& fileName); void loadSequenceGroupFromSerial(const String& serialData); void parseSequenceGroupData(const String& groupName, const String& rawData); int angleToPWM(int angle); void printFreeHeap(); void printMemoryInfo(); void IRAM_ATTR onTimer(void* arg); void moveServoTo(int index, int angle); Group currentGroup; String input; bool isPlaying = false; bool loopSequences = false; float globalSpeedFactor = 1.0f; int currentSequenceIndex = 0; class CommandHandler { public: void processCommand(String input) { if (input.length() < 3) return; input = input.substring(1, input.length() - 1); int firstComma = input.indexOf(','); String mainCommand = (firstComma != -1) ? input.substring(0, firstComma) : input; String parameters = (firstComma != -1) ? input.substring(firstComma + 1) : ""; if (mainCommand == "PLAY") { loadSequenceGroupFromFile(parameters); currentSequenceIndex = 0; isPlaying = true; } else if (mainCommand == "SAVE") { saveSequenceToFile(parameters); } else if (mainCommand == "RUN") { loadSequenceGroupFromSerial(parameters); currentSequenceIndex = 0; isPlaying = true; } else if (mainCommand == "MOVE") { MoveServo(parameters); } else if (mainCommand == "STOP") { isPlaying = false; } else if (mainCommand == "START") { isPlaying = true; } else if (mainCommand == "LOOP") { loopSequences = (parameters.toInt() == 1); } else if (mainCommand == "SPEED") { globalSpeedFactor = parameters.toFloat(); if (globalSpeedFactor <= 0.0f) globalSpeedFactor = 1.0f; } else { Serial.println("Onbekend commando!"); } } }; void IRAM_ATTR onTimer(void* arg) { updateFlag = true; } // Globalen CommandHandler handler; void setup() { Serial.begin(115200); pwm.begin(); pwm.setPWMFreq(PWM_FREQ); if (!SPIFFS.begin(true)) { Serial.println("SPIFFS mount failed"); return; } const esp_timer_create_args_t timer_args = { .callback = &onTimer, .arg = nullptr, .dispatch_method = ESP_TIMER_TASK, .name = "servo_update_timer" }; esp_timer_create(&timer_args, &timer); esp_timer_start_periodic(timer, 1000); // elke 1 ms } void loop() { while (Serial.available()) { char received = Serial.read(); if (received == '>') { input += received; handler.processCommand(input); input = ""; } else if (received == '<') { input = "<"; } else { input += received; } } if (updateFlag) { updateFlag = false; if (!isPlaying || currentGroup.numSequences == 0) return; Sequence& seq = currentGroup.sequences[currentSequenceIndex]; bool allReached = true; for (int i = 0; i < NUM_SERVOS; i++) { int delta = seq.angle[i] - servos[i].currentAngle; if (abs(delta) > 0) { int dir = (delta > 0) ? 1 : -1; int stepSize = max(1, (int)(seq.speed[i] * globalSpeedFactor)); servos[i].currentAngle += dir * min(abs(delta), stepSize); moveServoTo(i, servos[i].currentAngle); allReached = false; } } if (allReached) { currentSequenceIndex++; if (currentSequenceIndex >= currentGroup.numSequences) { if (loopSequences) currentSequenceIndex = 0; else isPlaying = false; } } } } int angleToPWM(int angle) { return map(angle, 0, 180, 102, 512); } void moveServoTo(int index, int angle) { int pulse = angleToPWM(angle); pwm.setPWM(servos[index].channel, 0, pulse); } void MoveServo(String parameters) { int commaIndex = parameters.indexOf(','); if (commaIndex == -1) return; int servoId = parameters.substring(0, commaIndex).toInt(); int position = parameters.substring(commaIndex + 1).toInt(); if (servoId >= 0 && servoId < NUM_SERVOS) { moveServoTo(servoId, position); servos[servoId].currentAngle = position; } } void saveSequenceToFile(String input) { int firstComma = input.indexOf(','); if (firstComma == -1) return; String fileName = input.substring(0, firstComma); String data = input.substring(firstComma + 1); File file = SPIFFS.open("/" + fileName + ".txt", FILE_WRITE); if (!file) return; file.println(data); file.close(); } void loadSequenceGroupFromFile(const String& fileName) { File file = SPIFFS.open("/" + fileName + ".txt", FILE_READ); if (!file) return; String content = file.readString(); file.close(); parseSequenceGroupData(fileName, content); } void loadSequenceGroupFromSerial(const String& serialData) { int firstComma = serialData.indexOf(','); if (firstComma == -1) return; String groupName = serialData.substring(0, firstComma); String dataPart = serialData.substring(firstComma + 1); parseSequenceGroupData(groupName, dataPart); } void parseSequenceGroupData(const String& groupName, const String& rawData) { currentGroup.name = groupName; currentGroup.numSequences = 0; String content = rawData; content.trim(); int pos = 0; while ((pos = content.indexOf("sequence", pos)) != -1 && currentGroup.numSequences < MAX_SEQUENCES) { int next = content.indexOf("sequence", pos + 1); String seqData = (next != -1) ? content.substring(pos, next) : content.substring(pos); Sequence& seq = currentGroup.sequences[currentGroup.numSequences]; memset(&seq, 0, sizeof(Sequence)); int dataStart = seqData.indexOf(',') + 1; seqData = seqData.substring(dataStart); for (int i = 0; i < NUM_SERVOS && seqData.length() > 0; i++) { int comma1 = seqData.indexOf(','); if (comma1 == -1) break; seq.angle[i] = seqData.substring(0, comma1).toInt(); seqData = seqData.substring(comma1 + 1); int comma2 = seqData.indexOf(','); seq.speed[i] = (comma2 == -1) ? seqData.toInt() : seqData.substring(0, comma2).toInt(); seqData = (comma2 == -1) ? "" : seqData.substring(comma2 + 1); } currentGroup.numSequences++; pos = next; } } Evolutronix GUI =============== Nu hebben we nog de evolutronix GUI nodig download de evolutronix GUI vanaf hun website www.evolutronix-robotics.com .. figure:: ../images/EvolutronixGUI.png :alt: Uploading code to the ESP32 :align: center :width: 70% *Figure 4 – Evolutronix GUI.* In the next section, we will move on to configuring the **electronics setup** and connecting the servo controller.