Elektrický ping-pong

Cílem projektu bylo vytvořit jednoduchou digitální verzi klasické hry ping-pong pomocí mikrokontroleru Arduino a základních elektronických komponent. Slouží k interaktivní výuce programování a rozvíjí logické myšlení a umožňuje hráčům ovládat pálky a sledovat pohyb míčku na displeji. Hra demonstruje propojení hardwaru a softwaru, což z ní činí zábavný a vzdělávací projekt.

Zapojení:

Funkce komponenty Pin na Arduinu
Tlačítko – pohyb nahoru  2
Tlačítko – pohyb dolů  3
OLED displej – DC  8
OLED displej – CS  10
OLED displej – RESET  9
OLED displej – SCL 13

Kód pro Arduino:

#include <Arduino.h>

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define UP_BUTTON 2
#define DOWN_BUTTON 3

const unsigned long PADDLE_RATE = 33;
const unsigned long BALL_RATE = 16;
const uint8_t PADDLE_HEIGHT = 24;

// On MEGA, MOSI is 51, CLK is 52
#define OLED_DC    11
#define OLED_CS    12
#define OLED_RESET 13
// MOSI is Data pin on display breakout

Adafruit_SSD1306 display(OLED_DC, OLED_RESET, OLED_CS);

void drawCourt();

uint8_t ball_x = 64, ball_y = 32;
uint8_t ball_dir_x = 1, ball_dir_y = 1;
unsigned long ball_update;

unsigned long paddle_update;
const uint8_t CPU_X = 12;
uint8_t cpu_y = 16;

const uint8_t PLAYER_X = 115;
uint8_t player_y = 16;

void setup() {
    display.begin(SSD1306_SWITCHCAPVCC);

    // Display the splash screen (we're legally required to do so)
    display.display();
    unsigned long start = millis();

    pinMode(UP_BUTTON, INPUT);
    pinMode(DOWN_BUTTON, INPUT);

    display.clearDisplay();
    drawCourt();

    while(millis() - start < 2000);

    display.display();

    ball_update = millis();
    paddle_update = ball_update;
}

void loop() {
    bool update = false;
    unsigned long time = millis();

    static bool up_state = false;
    static bool down_state = false;
    
    up_state |= (digitalRead(UP_BUTTON) == LOW);
    down_state |= (digitalRead(DOWN_BUTTON) == LOW);

    if(time > ball_update) {
        uint8_t new_x = ball_x + ball_dir_x;
        uint8_t new_y = ball_y + ball_dir_y;

        // Check if we hit the vertical walls
        if(new_x == 0 || new_x == 127) {
            ball_dir_x = -ball_dir_x;
            new_x += ball_dir_x + ball_dir_x;
        }

        // Check if we hit the horizontal walls.
        if(new_y == 0 || new_y == 63) {
            ball_dir_y = -ball_dir_y;
            new_y += ball_dir_y + ball_dir_y;
        }

        // Check if we hit the CPU paddle
        if(new_x == CPU_X & new_y >= cpu_y && new_y <= cpu_y + PADDLE_HEIGHT) {
            ball_dir_x = -ball_dir_x;
            new_x += ball_dir_x + ball_dir_x;
        }

        // Check if we hit the player paddle
        if(new_x == PLAYER_X
           & new_y >= player_y
           && new_y <= player_y + PADDLE_HEIGHT)
        {
            ball_dir_x = -ball_dir_x;
            new_x += ball_dir_x + ball_dir_x;
        }

        display.drawPixel(ball_x, ball_y, BLACK);
        display.drawPixel(new_x, new_y, WHITE);
        ball_x = new_x;
        ball_y = new_y;

        ball_update += BALL_RATE;

        update = true;
    }

    if(time > paddle_update) {
        paddle_update += PADDLE_RATE;

        // CPU paddle
        display.drawFastVLine(CPU_X, cpu_y, PADDLE_HEIGHT, BLACK);
        const uint8_t half_paddle = PADDLE_HEIGHT >> 1;
        if(cpu_y + half_paddle > ball_y) {
            cpu_y -= 1;
        }
        if(cpu_y + half_paddle < ball_y) {
            cpu_y += 1;
        }
        if(cpu_y < 1) cpu_y = 1;
        if(cpu_y + PADDLE_HEIGHT > 63) cpu_y = 63 - PADDLE_HEIGHT;
        display.drawFastVLine(CPU_X, cpu_y, PADDLE_HEIGHT, WHITE);

        // Player paddle
        display.drawFastVLine(PLAYER_X, player_y, PADDLE_HEIGHT, BLACK);
        if(up_state) {
            player_y -= 1;
        }
        if(down_state) {
            player_y += 1;
        }
        up_state = down_state = false;
        if(player_y < 1) player_y = 1;
        if(player_y + PADDLE_HEIGHT > 63) player_y = 63 - PADDLE_HEIGHT;
        display.drawFastVLine(PLAYER_X, player_y, PADDLE_HEIGHT, WHITE);

        update = true;
    }

    if(update)
        display.display();
}


void drawCourt() {
    display.drawRect(0, 0, 128, 64, WHITE);
}

Další podobné články

ROBOTICKÉ RAMENO

Stavebnice obsahuje všechny potřebné díly na sestavení robotnického ramene včetně spojovacího materiálu, pouze je nutné dokoupit čtyři kusy MIKRO SERV SG90. Dále je nutné dokoupit řídící jednotku já jsem použil domácí zásoby ARDUINO NANO a pro něho pak modul ARDUINO NANO IO SHIELD pro jednoduchost zapojení. Díly pro sestavení ramene jdou dobře tzv. vylamovat „vypadávají skoro sami. K servům pokud použijete nové tak doporučuji je před montáží odzkoušet zda jsou funkční v plném rozsahu tj. od 0° do 180°, po namontování a zjištění že servo nefunguje to pak opravdu dost zahýbá s nervy. 

Electronic TiltMaze

Cílem tohoto projektu je vytvoření jednoduchého ovládacího systému, který umožňuje naklápění dvou servomotorů pomocí analogového joysticku. Platforma řízená servomotory může simulovat pohyb například v ose X a Y — tedy naklánění doleva/doprava a dopředu/dozadu. Tento systém může sloužit jako základ pro různé aplikace:

- Manuální ovládání kamery nebo senzoru (např. na pohyblivé konstrukci nebo robotovi)
- Interaktivní ovládací panel pro školní projekty nebo herní ovladač