← Back to list

🤖 A Newbie’s Journey to Building His Dream Robot

This is the true story of how I, a complete beginner in C programming and microcontrollers, tried to build a cheap version of the…

Jahrulnr · 2025-08-27 20:01 · 12 claps · 10.8 min read
#esp32 #robotics #arduino #esp-idf
Open on Medium ↗
Wiki topics: 💻 · Programming 📟 · Gadgets & IoT

🤖 A Newbie’s Journey to Building His Dream Robot

This is the true story of how I, a complete beginner in C programming and microcontrollers, tried to build a cheap version of the ridiculously expensive Cozmo robot…

The Beginning: When Dreams Meet Reality

December 2024, Electronics Store

I stood in front of the store display, staring at the cute Cozmo robot with starry eyes. The price? $1,000!

“Damn, that’s expensive,” I muttered while counting my savings, which were nowhere near enough.

But in my heart, I had already decided something. “I’m going to build this robot myself. I can do it!”

The problem? I had never coded in C before. All I knew was PHP and JavaScript web development. Microcontroller? ESP32? SPI? I2C? It all sounded like alien language.

Day One: When Newbie Meets Hardware

3:47 AM, Messy Dorm Room

The laptop screen glowed bright in the darkness. I stared at the ESP32-S3 I had just bought with a week’s worth of food money. Scattered around it were breadboards, jumper cables, and resistors whose functions I had no clue about.

“Okay, YouTube tutorials say just upload the code… how do I do that?” I muttered while opening ESP32 documentation that made my head spin.

The first time I powered up the ESP32, all I got were compilation errors:

error: 'Serial' was not declared in this scope
error: expected ';' before 'setup'
fatal error: WiFi.h: No such file or directory

“Good God, why is C syntax so weird?”

Coming from simple PHP, I was shocked by semicolons, pointers, and complicated memory management. But my determination was set — Cozmo must be built!

The Learning Curve from Hell

Weeks 1–2: Learning C basics and Arduino IDE

  • The syntax is so complicated! Why do I need * and & for everything?
  • setup() and loop() concepts are completely different from web development
  • Memory leaks keep making the ESP32 restart

Weeks 3–4: Trying basic projects like:

  • Turn on LED: Success after 2 hours of figuring out pin mapping 😅
  • Read sensors: ADC, I2C, still completely confused
  • Camera module: This is what drove me totally crazy!
// First code that "worked"
void setup() {
    Serial.begin(115200);
    Serial.println("Hello World!"); // I was so excited when this worked
}

Month Two: Protocol Learning Marathon

After basic Arduino was working, I started researching the protocols I needed:

📹 Camera Protocol — ESP32-CAM

// Trial and error about 100+ times
#include "esp_camera.h"

camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
// ... 20 lines of pin configuration that confused me

Common errors:

  • Camera init failed → Wrong pins
  • Brownout detector → Insufficient power supply
  • Guru meditation error → Bad code 😭

💾 SPIFFS vs SD Card — Storage Learning

At first I tried SD Card, but it kept getting corrupted. So I learned SPIFFS:

// First time successfully saving a file
if(SPIFFS.begin(true)) {
    File file = SPIFFS.open("/test.txt", "w");
    file.print("I did it!");
    file.close();
    Serial.println("YES! SPIFFS is working!");
}

It felt like winning a Nobel Prize! 🏆

🔌 SPI Master-Slave Communication

This was the most confusing part. Master-Slave concept, MOSI, MISO, clock… everything was alien!

// After 3 weeks of trial and error
SPIClass hspi(HSPI);
hspi.begin(14, 12, 13, 15); // SCK, MISO, MOSI, SS
// Send data to slave device
hspi.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));

Month Three: The Servo Learning Curve

RC Car Experiment: First Real Project

Before diving into the complex Cozmo robot, I started with a simple experiment — RC car control using a phone! 🚗📱

“What if I could control an RC car using WebSocket, that would be cool,” I thought naively.

RC Car

RC Car

First Hardware Learning: RC Car Project

I bought components for RC car control:

  • SG90 Servo for camera pan/tilt
  • DC motors for car wheels
  • L298N mini motor driver for controlling DC motors
  • ESP32 as the brain

First setup for servo (this was correct):

#include <ESP32Servo.h>

Servo cameraServo;

void setup() {
    cameraServo.attach(13);  // Servo directly to ESP32 pin
}

void loop() {
    cameraServo.write(90);   // Center
    delay(1000);
    cameraServo.write(180);  // Full right  
    delay(1000);
    cameraServo.write(0);    // Full left
    delay(1000);
}

This servo setup was actually correct! The SG90 servo connects directly to the ESP32 pin.

The Motor Driver Confusion 🤔

The real problem was with the RC car wheels! I bought a motor driver that only controlled speed, but what I needed was a driver that could reverse DC current for forward/backward and left/right movement!

The motor driver I bought (the wrong one):

// Simple speed controller - only one direction!
int motorPin = 27;
int enablePin = 14;

void setup() {
    pinMode(motorPin, OUTPUT);
    pinMode(enablePin, OUTPUT);
}

void setSpeed(int speed) {
    analogWrite(enablePin, speed); // Only controls speed
    digitalWrite(motorPin, HIGH);  // But direction stays the same!
}

Problem: This motor driver could only control speed (0–255), but couldn’t reverse direction! An RC car needs to:

  • Forward/backward = reverse current to front motor
  • Left/right = reverse current to left/right motors differently

Research Phase: Learning DC Motor Direction Control

After getting frustrated that my RC car could only go forward (couldn’t go backward or turn), I did serious research:

What I needed for an RC car:

  • H-Bridge Motor Driver = can reverse DC current polarity
  • Dual motor control = control left/right motors independently
  • PWM speed control = variable speed for smooth movement

The RIGHT motor drivers for RC cars:

  • L298N / L298N mini: H-bridge, can reverse current, good for medium motors
  • DRV8833: Smaller H-bridge, efficient for small motors
  • TB6612FNG: Advanced H-bridge with better performance
  • L9110S: Cheap H-bridge option for simple projects
// L298N mini that's PROPER - with H-bridge functionality
// Motor A (Left)
int motor1Pin1 = 27; // Direction pin 1
int motor1Pin2 = 26; // Direction pin 2  

// Motor B (Right)
int motor2Pin1 = 25; // Direction pin 1
int motor2Pin2 = 24; // Direction pin 2

void moveForward() {
    // Left motor forward
    digitalWrite(motor1Pin1, HIGH);
    digitalWrite(motor1Pin2, LOW);

    // Right motor forward  
    digitalWrite(motor2Pin1, HIGH);
    digitalWrite(motor2Pin2, LOW);
}

void moveBackward() {
    // REVERSE polarity = backward!
    digitalWrite(motor1Pin1, LOW);
    digitalWrite(motor1Pin2, HIGH);

    digitalWrite(motor2Pin1, LOW);
    digitalWrite(motor2Pin2, HIGH);
}

void turnLeft() {
    // Left motor backward, right motor forward = turn left
    digitalWrite(motor1Pin1, LOW);
    digitalWrite(motor1Pin2, HIGH);
    digitalWrite(motor2Pin1, HIGH);
    digitalWrite(motor2Pin2, LOW);
}

Lesson learned: RC cars need H-bridge drivers that can reverse current direction, not just speed controllers!

Buying the RIGHT Motor Driver

Finally I bought the L298N mini module that was correct — which could: ✅ Reverse current for forward/backward ✅ Independent control of left/right motors ✅ Handle 2 DC motors simultaneously

First test with the correct L298N mini:

Forward: ✅ Moves forward
Backward: ✅ Can go backward! 
Turn Left: ✅ Smooth left turn
Turn Right: ✅ Perfect right turn
Stop: ✅ Proper braking

SUCCESS! The RC car could finally move in all directions! 🚗✨

The Broken Servo Incident 💔

The servo itself wasn’t the problem, but I broke it because of stuck movement:

// Code that broke the servo - TOO FAST!
void setup() {
    cameraServo.attach(13);

    // Movement too fast without delay!
    for(int i = 0; i <= 180; i++) {
        cameraServo.write(i);
        // No delay = servo stress!
    }
}

CRACK! The servo gear broke because it got stuck while moving down. RIP first SG90 😢

Learning Smooth Movement

After buying a replacement servo, I researched the proper way:

// Smooth servo movement - finally!
void smoothMove(int currentPos, int targetPos, int stepDelay) {
    if (currentPos < targetPos) {
        for (int pos = currentPos; pos <= targetPos; pos++) {
            myServo.write(pos);
            delay(stepDelay);  // Crucial for servo health!
        }
    } else {
        for (int pos = currentPos; pos >= targetPos; pos--) {
            myServo.write(pos);  
            delay(stepDelay);
        }
    }
}

Game changer! The servo became smooth and durable.

Camera Streaming Success: RC Car

After solving the servo issue, I combined it with ESP32-CAM:

Hardware Setup:

  • ESP32-CAM for camera streaming
  • ESP32 DevKit for servo control
  • SG90 servo for camera pan/tilt
  • Power from USB (lesson learned: stable power is important!)

Software Architecture:

// WebSocket server for real-time control
void handleWebSocketMessage(String message) {
    JsonDocument doc;
    deserializeJson(doc, message);

    String command = doc["command"];

    if (command == "servo") {
        int angle = doc["angle"];
        smoothMove(currentAngle, angle, 15);
        currentAngle = angle;
    }

    if (command == "camera") {
        String action = doc["action"];
        if (action == "capture") {
            captureAndSend();
        }
    }
}

Web Interface:

<!-- Simple joystick control -->
<div id="joystick"></div>
<video id="camera-stream" autoplay></video>

<script>
// WebSocket for real-time control
const ws = new WebSocket('ws://192.168.1.100/ws');

// Joystick event
joystick.on('move', (event) => {
    const angle = mapJoystickToServo(event.x, event.y);
    ws.send(JSON.stringify({
        command: 'servo',
        angle: angle
    }));
});
</script>

The “Eureka!” Moment: From Learning Platform to Real Robot

The RC car experiment was incredibly successful! I could: ✅ Control servo via smartphone ✅ Stream camera in real-time ✅ Responsive WebSocket communication ✅ Stable servo movements

But this was just the beginning! The RC car was just a learning platform for me to understand basic components:

  • Servo control ✅ Learned!
  • Motor drivers ✅ Mastered!
  • Camera streaming ✅ Implemented!
  • Battery management ✅ Understood!

But now it’s time for the REAL project: “I want to build a real Cozmo pet robot!”

The Hidden Struggle: From Spaghetti Code to Clean Architecture

Before getting into Arduino framework challenges, there’s an interesting story about why I developed the ESP32-MVC-Framework.

Background: I’m a web developer who fell in love with Laravel PHP framework. Clean architecture, elegant syntax, beautiful MVC pattern — everything just makes sense!

When coding ESP32 for Cozmo, I felt incredibly frustrated with traditional Arduino code structure:

// Traditional Arduino style - MESSY!
void loop() {
    if (WiFi.status() == WL_CONNECTED) {
        if (webServer.hasArg("action")) {
            String action = webServer.arg("action");
            if (action == "move_forward") {
                // Movement logic mixed with web handling
                motorControl.moveForward();
                webServer.send(200, "text/plain", "OK");
            } else if (action == "camera_start") {
                // Camera logic mixed with HTTP responses
                camera.startStreaming();
                webServer.send(200, "application/json", "{\"status\":\"started\"}");
            }
            // ... and so on for 500+ lines of spaghetti!
        }
    }
}

“How come there’s no beautiful code like Laravel ported to ESP32?” That’s when the idea struck me!

Birth of ESP32-MVC-Framework

I created a separate project dedicated to bringing Laravel-style MVC architecture to ESP32:

// ESP32-MVC-Framework - Laravel-inspired elegance!
class MotorController : public Controller {
public:
    Response moveForward(Request& request) {
        // Clean separation of concerns
        if (!Motors::getInstance()->moveForward()) {
            return error(request, "Motor movement failed", 500);
        }
        return success(request, "Robot moved forward successfully");
    }

    Response getStatus(Request& request) {
        JsonDocument status;
        status["position"] = Motors::getInstance()->getCurrentPosition();
        status["battery"] = Battery::getInstance()->getLevel();
        return json(request, status);
    }
};

// Routes definition - familiar Laravel syntax!
void registerRoutes() {
    Route::post("/motor/forward", MotorController::moveForward);
    Route::get("/motor/status", MotorController::getStatus);
    Route::resource("/camera", CameraController::class); // Full REST resource
}

Mind = Blown! Suddenly ESP32 code became as beautiful as Laravel!

The Arduino Framework Challenge

One of the biggest challenges I often face is finding deprecated code and ESP-IDF specific libraries that have to be ported to the Arduino framework.

Why Arduino Framework?

  • Easier for beginners like me
  • Better community support
  • Familiar C++ syntax
  • Extensive library ecosystem

But the reality…

Almost every time I find a cool library or example code on GitHub:

// Typical ESP-IDF code I find
#include "esp_log.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"

static const char* TAG = "AUDIO";
esp_err_t ret = i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
ESP_LOGI(TAG, "I2S driver installed");

Problem: This code is ESP-IDF specific! Arduino framework has a different structure.

Real Examples of Porting Challenges:

1. ESP-SR Speech Recognition Porting

// Original ESP-IDF code (deprecated methods)
#include "esp_sr_api.h"
#include "esp_mn_speech_commands.h"

// Had to port to Arduino-compatible version
#include "esp32-sr-arduino.h" // Custom wrapper I made

2. PicoTTS Library Adaptation

// DiUS Computing original (ESP-IDF style)
esp_err_t picotts_init(uint8_t volume, picotts_cb_t cb, uint8_t lang);

// My Arduino framework port
bool picoTTS_begin(int volume, AudioCallback callback, LanguageType lang);

3. Camera Module Integration

// ESP-IDF camera driver
#include "esp_camera.h"
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;

// Arduino framework version
#include "Arduino.h"
#include "esp32-camera-arduino.h" // Porting effort

The Porting Process: Trial and Error Marathon

Step 1: Find Cool Library 🎯 Step 2: Realize it’s ESP-IDF only 😫 Step 3: Study the source code 📚 Step 4: Create Arduino wrapper ⚙️ Step 5: Debug compatibility issues 🐛 Step 6: Test and refine

Repeat this process ~15 times for various libraries!

[embed]Develoment progress

The Great Refactoring: From Chaos to Harmony

Act 1: Architectural Revolution

I decided to do a massive refactoring. Out with all the messy legacy code, in with new, more robust architecture:

// OLD: Monolithic chaos
void handleWebSocketEvent(...) {
    // 500+ lines of spaghetti code
    if (type == "system_status") {
        // Inline processing
    } else if (type == "camera_command") {
        // More inline processing  
    }
    // ... nightmare continues
}

// NEW: Clean MVC architecture
class SystemWebSocketController : public WebSocketController {
public:
    static WebSocketResponse getSystemStatus(WebSocketRequest& request);
    static WebSocketResponse handleCameraCommand(WebSocketRequest& request);
    // Clean, testable, maintainable
};

Act 2: The Great Library Purge

The commit that changed everything:

- lib/Pico/src/pico/picotok.c (1577 lines deleted)
- lib/Pico/src/pico/picotrns.c (745 lines deleted)  
- lib/Pico/src/pico/picowa.c (582 lines deleted)
+ https://github.com/jahrulnr/esp32-picoTTS.git

2,904 lines of legacy code — GONE! Replaced with external libraries that were already tested and optimized.

“Sometimes, deleting code is the best thing you can do,” I muttered while pressing the delete button.

The Hidden Lessons: Wisdom from Debugging Hell

After the presentation, a junior student asked, “Sir, what’s the secret to this project’s success?”

I smiled, remembering the long debugging nights. “The secret is understanding that failure is not the opposite of success — it’s part of it.”

Technical Lessons Learned:

  1. Race Conditions are Real: In embedded systems, synchronization isn’t optional
  2. Memory is Sacred: 8MB PSRAM feels like a lot, but can run out quickly
  3. Task Priorities Matter: FreeRTOS priority system must be understood well
  4. Library Selection is Critical: Using mature libraries is better than reinventing the wheel
  5. Architecture Evolution: Sometimes total refactoring is better than layered patches

Life Lessons:

  1. Persistence Beats Talent: 72 hours of debugging taught me more than 1 semester of classes
  2. Community Matters: Open source libraries like esp32-picoTTS are the result of collaboration
  3. Documentation is Love: Well-documented code is a gift for future self
  4. Failure is Data: Every crash is information for improvement
  5. Simplicity Wins: Clean architecture beats clever tricks

Cozmo Robot

Cozmo Robot

From Expensive Dreams to Affordable Reality

Remember my initial motivation? Wanting Cozmo but it cost $1,000? Now I have a robot that:

  • Total cost: ~$250 (10x cheaper!)
  • Capabilities: Almost on par with the original Cozmo
  • Customization: Unlimited! Can be modified as desired
  • Learning value: PRICELESS! Knowledge gained can’t be bought

Community Impact: Sharing the Knowledge

I decided to open-source all these projects. Why? Because:

  • Democratize Robotics: Robotics doesn’t have to be expensive
  • Educational Value: Perfect project for learning embedded systems
  • Community Building: Together we can build better robots
  • Documentation: This story becomes a tutorial for others

Repository: cozmo-system (this repository you're exploring!) License: MIT (free for everyone) Documentation: Comprehensive (including this story)

The Journey Continues — Still in Development Phase

Present Day — August 2025

The Cozmo project is still in active development phase. I continue to improve and add new techniques for new features. This project isn’t fully ready for release yet, but all core components are there and the foundation is very solid.

Current Status:

  • 🚧 In Development: Still improving and adding new features
  • Core Systems: All basic functionality working
  • 🔄 Ongoing Improvements: Continuous enhancement of existing features
  • 🎯 Future Potential: Great foundation for amazing things to come

🤝 Join the Journey — Contributors Welcome!

I really welcome anyone who wants to contribute to this project! Whether you’re:

  • 🔧 Hardware enthusiast who wants to improve mechanical design
  • 💻 Software developer who’s interested in ESP32 programming
  • 🎨 UI/UX designer who can make the interface cooler
  • 📚 Documentation writer who can help explain things better
  • 🐛 Bug hunter who’s careful at spotting issues
  • 💡 Feature suggester with creative ideas

Every contribution matters! From fixing typos to major feature additions, all forms of help are greatly appreciated.

Ready to contribute? Check out our repository at: https://github.com/jahrulnr/esp32-cozmo-system/

Don’t hesitate to:

  • 🌟 Star the repo if you find it interesting
  • 🍴 Fork it and experiment with your own ideas
  • 🐛 Report bugs through GitHub Issues
  • 💬 Join discussions in the Issues section
  • 📝 Submit Pull Requests with improvements

Written based on the true story of a developer who learned that debugging hell is actually a gateway to mastery. Every error message is a teacher, every crash is a lesson, and every successful compilation is a small victory worth celebrating. 🎉

THE END (or maybe… THE BEGINNING? 😊)


메타데이터
post_id
ff8ecf2fff68
slug
a-newbies-journey-to-building-his-dream-robot-ff8ecf2fff68
url
https://medium.com/@jahrulnr/a-newbies-journey-to-building-his-dream-robot-ff8ecf2fff68
canonical_url
https://medium.com/@jahrulnr/a-newbies-journey-to-building-his-dream-robot-ff8ecf2fff68
author_url
https://medium.com/@jahrulnr
status
ok
fetched_at
2026-06-27 23:56:40