Week 10: Output Devices
Planted March 31, 2026

This week was a week that I didn’t get to experiment much due to it coinciding with our schools exam week below. Below is some coding I did with output devices readily avaliable.
WS2812B
I started out with the RGB LED WS2812B just getting a R,G,B loop on it
#include <Adafruit_NeoPixel.h>
#define PIN 3
#define NUM_LEDS 1
Adafruit_NeoPixel strip(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);
void setup() {
strip.begin();
strip.show();
}
void loop() {
strip.setPixelColor(0, strip.Color(255, 0, 0));
strip.show();
delay(1000);
// GREEN
strip.setPixelColor(0, strip.Color(0, 255, 0));
strip.show();
delay(1000);
strip.setPixelColor(0, strip.Color(0, 0, 255));
strip.show();
delay(1000);
}
WS2812B
Next it was onto programming the most commonplace output device for me, the servo. below is “hello world” spin code I ran on it
video
code
#include <Adafruit_NeoPixel.h>
#include <ESP32Servo.h>
#define LED_PIN 9
#define NUMPIXELS 1
#define SERVO_PIN 3
Servo myServo;
int angle = 0;
int direction = 1;
int colorState = 0;
unsigned long lastMove = 0;
void setup() {
pixel.begin();
pixel.setBrightness(50);
myServo.attach(SERVO_PIN);
}
void loop() {
if (now - lastMove > 15) {
angle += direction;
if (angle >= 180 || angle <= 0) direction *= -1;
myServo.write(angle);
lastMove = now;
}
}
OLED
next it was onto the most fun part of them all i2c and oled.
I decided to re-create a couple of this I worked with back when I was learning / using OpenProcessing
First I created Conway’s game of life
video
code
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SDA_PIN 6
#define SCL_PIN 7
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
#define W 128
#define H 64
uint8_t grid[W][H];
uint8_t newGrid[W][H];
void setup() {
Wire.begin(SDA_PIN, SCL_PIN);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
while (1);
}
display.clearDisplay();
randomSeed(analogRead(0));
for (int x = 0; x < W; x++) {
for (int y = 0; y < H; y++) {
grid[x][y] = random(2); // 0 or 1
}
}
}
int countNeighbors(int x, int y) {
int count = 0;
for (int dx = -1; dx <= 1; dx++) {
for (int dy = -1; dy <= 1; dy++) {
if (dx == 0 && dy == 0) continue;
int nx = (x + dx + W) % W;
int ny = (y + dy + H) % H;
count += grid[nx][ny];
}
}
return count;
}
void loop() {
for (int x = 0; x < W; x++) {
for (int y = 0; y < H; y++) {
int neighbors = countNeighbors(x, y);
if (grid[x][y] == 1) {
if (neighbors < 2 || neighbors > 3)
newGrid[x][y] = 0;
else
newGrid[x][y] = 1;
} else {
if (neighbors == 3)
newGrid[x][y] = 1;
else
newGrid[x][y] = 0;
}
}
}
for (int x = 0; x < W; x++) {
for (int y = 0; y < H; y++) {
grid[x][y] = newGrid[x][y];
}
}
display.clearDisplay();
for (int x = 0; x < W; x++) {
for (int y = 0; y < H; y++) {
if (grid[x][y]) {
display.drawPixel(x, y, SSD1306_WHITE);
}
}
}
display.display();
delay(50);
}
Then I created a simple flocking simulation
video
code
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SDA_PIN 6
#define SCL_PIN 7
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
#define NUM_BOIDS 25
struct Boid {
float x, y;
float vx, vy;
};
Boid boids[NUM_BOIDS];
float maxSpeed = 1.5;
float neighborDist = 12;
float separationDist = 6;
void setup() {
Wire.begin(SDA_PIN, SCL_PIN);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
while (1);
}
display.clearDisplay();
randomSeed(analogRead(0));
for (int i = 0; i < NUM_BOIDS; i++) {
boids[i].x = random(SCREEN_WIDTH);
boids[i].y = random(SCREEN_HEIGHT);
boids[i].vx = random(-10, 10) / 10.0;
boids[i].vy = random(-10, 10) / 10.0;
}
}
void limitSpeed(Boid &b) {
float speed = sqrt(b.vx * b.vx + b.vy * b.vy);
if (speed > maxSpeed) {
b.vx = (b.vx / speed) * maxSpeed;
b.vy = (b.vy / speed) * maxSpeed;
}
}
void loop() {
for (int i = 0; i < NUM_BOIDS; i++) {
float sepX = 0, sepY = 0;
float alignX = 0, alignY = 0;
float cohX = 0, cohY = 0;
int count = 0;
for (int j = 0; j < NUM_BOIDS; j++) {
if (i == j) continue;
float dx = boids[j].x - boids[i].x;
float dy = boids[j].y - boids[i].y;
float dist = sqrt(dx * dx + dy * dy);
if (dist < neighborDist) {
alignX += boids[j].vx;
alignY += boids[j].vy;
cohX += boids[j].x;
cohY += boids[j].y;
count++;
if (dist < separationDist) {
sepX -= dx;
sepY -= dy;
}
}
}
if (count > 0) {
alignX /= count;
alignY /= count;
cohX = (cohX / count) - boids[i].x;
cohY = (cohY / count) - boids[i].y;
}
boids[i].vx += sepX * 0.05 + alignX * 0.05 + cohX * 0.01;
boids[i].vy += sepY * 0.05 + alignY * 0.05 + cohY * 0.01;
limitSpeed(boids[i]);
}
for (int i = 0; i < NUM_BOIDS; i++) {
boids[i].x += boids[i].vx;
boids[i].y += boids[i].vy;
if (boids[i].x < 0) boids[i].x = SCREEN_WIDTH;
if (boids[i].x >= SCREEN_WIDTH) boids[i].x = 0;
if (boids[i].y < 0) boids[i].y = SCREEN_HEIGHT;
if (boids[i].y >= SCREEN_HEIGHT) boids[i].y = 0;
}
display.clearDisplay();
for (int i = 0; i < NUM_BOIDS; i++) {
display.drawPixel((int)boids[i].x, (int)boids[i].y, SSD1306_WHITE);
}
display.display();
delay(30);
}
then I moved onto a classic graphics challenge. 3D wireframe cube
video
code
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SDA_PIN 6
#define SCL_PIN 7
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
float angleX = 0;
float angleY = 0;
struct Point3D { float x, y, z; };
Point3D cube[8] = {
{-1, -1, -1}, { 1, -1, -1}, { 1, 1, -1}, {-1, 1, -1},
{-1, -1, 1}, { 1, -1, 1}, { 1, 1, 1}, {-1, 1, 1}
};
int edges[12][2] = {
{0,1},{1,2},{2,3},{3,0},
{4,5},{5,6},{6,7},{7,4},
{0,4},{1,5},{2,6},{3,7}
};
void project(Point3D p, int &x2d, int &y2d) {
float scale = 50;
float z = p.z + 4;
x2d = (int)(p.x * scale / z) + 64;
y2d = (int)(p.y * scale / z) + 32;
}
void setup() {
Wire.begin(SDA_PIN, SCL_PIN);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
}
void loop() {
display.clearDisplay();
Point3D r[8];
for (int i = 0; i < 8; i++) {
float x = cube[i].x;
float y = cube[i].y;
float z = cube[i].z;
float cosX = cos(angleX);
float sinX = sin(angleX);
float y1 = y * cosX - z * sinX;
float z1 = y * sinX + z * cosX;
float cosY = cos(angleY);
float sinY = sin(angleY);
float x2 = x * cosY + z1 * sinY;
float z2 = -x * sinY + z1 * cosY;
r[i] = {x2, y1, z2};
}
for (int i = 0; i < 12; i++) {
int x0, y0, x1, y1;
project(r[edges[i][0]], x0, y0);
project(r[edges[i][1]], x1, y1);
display.drawLine(x0, y0, x1, y1, SSD1306_WHITE);
}
display.display();
angleX += 0.05;
angleY += 0.04;
delay(15);
}
Overall I was sad that I couldn’t get as much done or get to experiment with many things as I did in previous weeks, but I was able to atleast get the core stuff for this week done. It was an okay week.