Jonathan Himawan
Published

Chicago Crime Interpretation in the form of Sisyphus

This project takes crime data from the Chicago Data Portal and the figure (Sisyphus) will travel up the mountain a certain distance.

IntermediateFull instructions provided5 hours22
Chicago Crime Interpretation in the form of Sisyphus

Things used in this project

Hardware components

Photon 2
Particle Photon 2
×1
DC Motor, 12 V
DC Motor, 12 V
×1
Dual H-Bridge motor drivers L298
SparkFun Dual H-Bridge motor drivers L298
×1
Adafruit NeoPixel Digital RGB LED Strip 144 LED, 1m White
Adafruit NeoPixel Digital RGB LED Strip 144 LED, 1m White
×1
Magnets
×2

Software apps and online services

Google Sheets
Google Sheets

Hand tools and fabrication machines

Multitool, Screwdriver
Multitool, Screwdriver

Story

Read more

Schematics

Video Of Project Working

Lego Technic Figure Behind The Mountain

Code

Code for Crime Data Interpretation

C/C++
#include <neopixel.h>

#define PIXEL_COUNT 4
#define PIXEL_PIN1 SPI1
#define PIXEL_TYPE WS2812B

#if (PLATFORM_ID == 32)
#define PIXEL_PIN2 SPI
#else
#define PIXEL_PIN2 MOSI
#endif

int count;
boolean cbnoValid;
int cbnoTemp = 0;
int cbno = 30452375;
String chargesArr[7];
int val = 0;
int fine = 0;
int runTime = 0;

int button = 0;

int enA = 14;
int motorA1 = 8;
int motorA2 = 9;

Adafruit_NeoPixel strip1 = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN1, PIXEL_TYPE);
Adafruit_NeoPixel strip2 = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN2, PIXEL_TYPE);

Adafruit_NeoPixel* neoPixelArr[] = {&strip1, &strip2};
//red (least "strong") --> purple (most "strong")

/*
Feloney = purple
Misdemeanor = blue
L = orange
P = orange
U = yellow
Z = red

Class = white
*/

uint32_t red = 0xFF0000;
uint32_t yellow = 0xFFFF00;
uint32_t orange = 0xFFA500;
uint32_t white = 0xFFFFFF;
uint32_t blue = 0x0000FF;
uint32_t purple = 0xFF00FF;
uint32_t off = 0x000000;

void setup() {
    Serial.begin(9600);
    
    pinMode(button, INPUT_PULLUP);
    
    pinMode(enA, OUTPUT);
    pinMode(motorA1, OUTPUT);
    pinMode(motorA2, OUTPUT);
    
    neoPixelArr[0]->begin();
    neoPixelArr[0]->show();
    neoPixelArr[0]->setBrightness(255);
    
    neoPixelArr[1]->begin();
    neoPixelArr[1]->show();
    neoPixelArr[1]->setBrightness(255);
    
    clearLEDValues();
    
    Serial.println("Setup Checker");
    
    Serial.println(cbnoTemp);
    
    Particle.publish("ctPull");
    
    Particle.subscribe("hook-response/ctPull/0", counterPuller, MY_DEVICES);
    
    Particle.subscribe("hook-response/AC/0", arrestChargesPuller, MY_DEVICES);
}


void loop() {
    
    int btn =  digitalRead(button);
    
    if (btn == LOW) {
        Serial.println("click");
        
        Particle.publish("ctPull");
        
        delay(500);
    }
}

void clearLEDValues() {
    for (int i = 0; i < sizeof(neoPixelArr) / sizeof(neoPixelArr[0]); i++) {
        for (int j = 0; j < PIXEL_COUNT; j++) {
            neoPixelArr[i]->setPixelColor(j, 0, 0, 0);
        }
        neoPixelArr[i]->show();
    }
}

void setAllPixels(Adafruit_NeoPixel* neoPixel, uint32_t color) {
    for (int i = 0; i < neoPixel->numPixels(); i++) {
        neoPixel->setPixelColor(i, color);
    }
    neoPixel->show();
}

void activateLightning() {
    for (int i = 1; i < 6; i++) {
        simulateLightning(i, i + 1);
        i++;
    }
    
    Serial.println("End Lightning Simulation");
}

void simulateLightning(int x, int y) {
    Serial.println("Reached Lightning Simulation");
    Serial.println(x);
    Serial.println(y);
    int chargeType;
    int chargeClass = 0;
    int count = 0;
    boolean felony = false;
    boolean misdemeanor = false;
    boolean l = false;
    boolean p = false;
    boolean u =  false;
    boolean z = false;

    if (chargesArr[x].equals("F")) {
        Serial.println("F Type Lightning");
        felony = true;
        count = 4;
        
        chargeType = 1;
        chargeClass = chargesArr[y].toInt();
    } else if (chargesArr[x].equals("M")) {
        Serial.println("M Type Lightning");
        misdemeanor = true;
        count = 3;
        
        chargeType = 2;
        if (chargesArr[y].equals("C")) {
            Serial.println("C Class Lightning");
            chargeClass = 3;
        } else if (chargesArr[y].equals("B")) {
            Serial.println("B Class Lightning");
            chargeClass = 2;
        } else if (chargesArr[y].equals("A")) {
            Serial.println("A Class Lightning");
            chargeClass = 1;
        }
    } else if (chargesArr[x].equals("L")) {
        l = true;
    } else if (chargesArr[x].equals("P")) {
        p = true;
    } else if (chargesArr[x].equals("U")) {
        u = true;
    } else if (chargesArr[x].equals("Z")) {
        z = true;
    }

    while (count + 1 > 0) {
        Serial.print("Actual Count: ");
        Serial.println(count);
        Serial.print("Lightning Count: ");
        Serial.println(count + 1);
        int randomLightning = random(0, sizeof(neoPixelArr) / sizeof(neoPixelArr[0]));

        if (felony) {
            setAllPixels(neoPixelArr[randomLightning], purple);
            
            delay(random(20, 100));
            
            setAllPixels(neoPixelArr[randomLightning], off);
            felony = false;
            
            delay(1000);
        } 
        else if (misdemeanor) {
            setAllPixels(neoPixelArr[randomLightning], blue);
            
            delay(random(20, 100));
            
            setAllPixels(neoPixelArr[randomLightning], off);
            misdemeanor = false;
            
            delay(1000);
        } else if (l) {
            setAllPixels(neoPixelArr[randomLightning], orange);
            
            delay(random(20, 100));
            
            setAllPixels(neoPixelArr[randomLightning], off);
            
            delay(1000);
        } else if (p) {
            setAllPixels(neoPixelArr[randomLightning], orange);
            
            delay(random(20, 100));
            
            setAllPixels(neoPixelArr[randomLightning], off);
            
            delay(1000);
        } else if (u) {
            setAllPixels(neoPixelArr[randomLightning], yellow);
            
            delay(random(20, 100));
            
            setAllPixels(neoPixelArr[randomLightning], off);
            
            delay(1000);
        } else if (z) {
            setAllPixels(neoPixelArr[randomLightning], red);
            
            delay(random(20, 100));
            
            setAllPixels(neoPixelArr[randomLightning], off);
            
            delay(1000);
        } else {
            setAllPixels(neoPixelArr[randomLightning], white);
                        
            delay(random(20, 100));
                        
            setAllPixels(neoPixelArr[randomLightning], off);
            
            delay(1000);
        }
        
        count--;
    }
}


void activateSisyphus() {
    for (int i = 1; i < 6; i++) {
        checkCharge(i, i + 1);
        i++;
    }
    
    activateLightning();
    
    switch(val) {
        case 0 ... 6:
            runTime += 500;
            Serial.println("movement");
            break;
        case 7 ... 12:
            runTime += 1000;
            Serial.println("movement");
            break;
        case 13 ... 18:
            runTime += 1500;
            Serial.println("movement");
            break;
    }
    
    switch(fine) {
        case 0 ... 1000:
            runTime += 100;
            Serial.println("movement");
            break;
        case 1001 ... 2000:
            runTime += 200;
            Serial.println("movement");
            break;
        case 2001 ... 3000:
            runTime += 300;
            Serial.println("movement");
            break;
    }
    
    forward(runTime);
    
    delay(5000);
    
    backward();
}

void checkCharge(int x, int y) {
    int chargeType = 0;
    int chargeClass = 0;
    
    if (chargesArr[x].equals("F")) {
        chargeType = 1;

        chargeClass = chargesArr[y].toInt();
        
    } else if (chargesArr[x].equals("M")) {
        chargeType = 2;
        
        if (chargesArr[y].equals("C")) {
            chargeClass = 3;
        } else if (chargesArr[y].equals("B")) {
            chargeClass = 2;
        } else if (chargesArr[y].equals("A")) {
            chargeClass = 1;
        }
        
    } else if (chargesArr[x].equals("L")) {
        fine += 250;
    } else if (chargesArr[x].equals("P")) {
        fine += 25;
    } else if (chargesArr[x].equals("U")) {
        fine += 1000;
    } else if (chargesArr[x].equals("Z")) {
        fine += 150;
    }
    
    switch(chargeType) {
        case 1:
            switch(chargeClass) {
                case 4:
                    val += 1;
                    break;
                case 3:
                    val += 2;
                    break;
                case 2:
                    val += 3;
                    break;
                case 1:
                    val += 4;
                    break;
                case 0:
                    val += 6;
                    break;
            }
        case 2:
            switch(chargeClass) {
                case 3:
                    val += 0.1;
                    break;
                case 2:
                    val += 0.3;
                    break;
                case 1:
                    val += 0.5;
                    break;
            }
        default:
            break;
    }
}

void counterPuller(const char *event, const char *data) {
    count = atoi(data);
    
    Serial.print("Count: ");
    Serial.println(count);
    
    cbnoTemp = cbno + count;
    
    Serial.print("cbnoTemp: ");
    Serial.println(cbnoTemp);
    
    Particle.publish("AC", String(cbnoTemp));
}

void arrestChargesPuller(const char *event, const char *data) {
    
    Serial.println("AC Activated");
    Serial.println(data);
    
    String charges = String(data);
    int ct = 0;
    
    if (charges.charAt(0) == ',') {
        Serial.print("Count Number: ");
        Serial.print(count);
        Serial.print(" is bad. Trying next number. ");
        
        count++;
        cbnoTemp = cbno + count;
        
        Particle.publish("AC", String(cbnoTemp));
    }
    else {
        Serial.print("Count Number: ");
        Serial.print(count);
        Serial.println(" is valid.");
        while (charges.length() > 0 && ct < 7) {
            int commaIndex = charges.indexOf(",");
        
            String temp = charges.substring(0, commaIndex);
        
            if(temp.equals(",")) {
                chargesArr[ct] = "";
            
                int secondComma = charges.indexOf(",", commaIndex + 1);
            
                charges = charges.substring(secondComma + 1);
            }
            else {
                chargesArr[ct] = charges.substring(0, commaIndex).trim();
            
                charges = charges.substring(commaIndex + 1);
            }
        
            ct++;
        }
        
        for (int i = 0; i < sizeof(chargesArr) / sizeof(chargesArr[0]); i++) {
            Serial.println(chargesArr[i]);
        }
        
        Particle.publish("ctPush", String(count + 1));
        
        delay(500);
        
        activateSisyphus();
    }
    
    delay(200);
}

void forward(int x) {
    digitalWrite(motorA1, HIGH);
    digitalWrite(motorA2, LOW);
    
    analogWrite(enA, 255);
    
    delay(x);
    
    analogWrite(enA, 0);
}

void backward() {
    digitalWrite(motorA1, LOW);
    digitalWrite(motorA2, HIGH);
    
    analogWrite(enA, 255);
    
    delay(runTime);
    
    analogWrite(enA, 0);
}

Credits

Jonathan Himawan
2 projects • 0 followers

Comments