roboattic Lab
Published © CC BY-NC-SA

I Controlled Chrome Dino With Rock-Paper-Scissors

A camera looks at my hand, the AI recognizes the gesture, and then the controller sends the corresponding keyboard command to the laptop.

BeginnerFull instructions provided51

Things used in this project

Story

Read more

Code

XIAO ESP32S3 Code

C/C++
#include <Wire.h>
#include <Seeed_Arduino_SSCMA.h>
#include "USB.h"
#include "USBHIDKeyboard.h"

#define GESTURE_PAPER    0
#define GESTURE_ROCK     1
#define GESTURE_SCISSORS 2

#define MIN_CONFIDENCE           40
#define SCISSORS_CONFIDENCE      60
#define COOLDOWN_MS              60
#define NO_DETECT_FRAMES_RESET   1
#define STATE_NONE              -1

SSCMA AI;
USBHIDKeyboard Keyboard;

int8_t currentGesture = STATE_NONE;
unsigned long lastCommandTime = 0;
uint8_t noDetectCount = 0;
bool isDucking = false;

const char* gestureName(int8_t target)
{
    switch (target)
    {
        case GESTURE_ROCK:     return "ROCK";
        case GESTURE_PAPER:    return "PAPER";
        case GESTURE_SCISSORS: return "SCISSORS";
        default:               return "UNKNOWN";
    }
}

inline void releaseDuck()
{
    if (isDucking)
    {
        Keyboard.release(KEY_DOWN_ARROW);
        isDucking = false;
        Serial.println("[DUCK] Released Down Arrow");
    }
}

inline int8_t findBestDetection(uint8_t &outScore)
{
    int8_t bestTarget = STATE_NONE;
    uint8_t bestScore = 0;

    int totalBoxes = AI.boxes().size();
    for (int i = 0; i < totalBoxes; i++)
    {
        uint8_t target = AI.boxes()[i].target;
        uint8_t score  = AI.boxes()[i].score;
        uint8_t threshold = (target == GESTURE_SCISSORS) ? SCISSORS_CONFIDENCE : MIN_CONFIDENCE;

        if (score >= threshold && score > bestScore)
        {
            bestTarget = (int8_t)target;
            bestScore  = score;
        }
    }

    outScore = bestScore;
    return bestTarget;
}

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

    Keyboard.begin();
    USB.begin();

    Wire.begin();
    Wire.setClock(400000);

    if (AI.begin(&Wire, -1, 0x62, 0, 400000))
    {
        Serial.println("[OK] Grove Vision AI V2 initialized");
    }
    else
    {
        Serial.println("[FAIL] Grove Vision AI V2 initialization failed!");
    }

    Serial.println("[OK] USB HID Keyboard ready");
}

void loop()
{
    if (AI.invoke() != 0)
    {
        return;
    }

    uint8_t bestScore = 0;
    int8_t detectedGesture = findBestDetection(bestScore);
    unsigned long now = millis();

    if (detectedGesture == STATE_NONE)
    {
        noDetectCount++;
        if (noDetectCount >= NO_DETECT_FRAMES_RESET && currentGesture != STATE_NONE)
        {
            releaseDuck();
            currentGesture = STATE_NONE;
        }
    }
    else
    {
        noDetectCount = 0;

        if (detectedGesture != currentGesture)
        {
            if (now - lastCommandTime < COOLDOWN_MS)
            {
                return;
            }

            releaseDuck();
            currentGesture = detectedGesture;
            lastCommandTime = now;

            if (detectedGesture == GESTURE_ROCK)
            {
                Keyboard.write(' ');
                Serial.printf("[JUMP] Rock (%d%%)\n", bestScore);
            }
            else if (detectedGesture == GESTURE_PAPER)
            {
                Keyboard.press(KEY_DOWN_ARROW);
                isDucking = true;
                Serial.printf("[DUCK] Paper (%d%%)\n", bestScore);
            }
            else if (detectedGesture == GESTURE_SCISSORS)
            {
                Keyboard.write(KEY_RETURN);
                Serial.printf("[RESTART] Scissors (%d%%)\n", bestScore);
            }
        }
        else
        {
            if (detectedGesture == GESTURE_PAPER && !isDucking)
            {
                Keyboard.press(KEY_DOWN_ARROW);
                isDucking = true;
            }
        }
    }
}

Credits

roboattic Lab
28 projects • 21 followers
YouTube Content CreatorRobotics Enthusiast

Comments