diff --git a/README.md b/README.md index 725e5dd..2659d5a 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,28 @@ -# arduino-gamepad -super simple gamepad project where Pro Mini is in a gamepad and sends keys over USART +# Spatial RGB -LED connected to D9 (on-board one at D13). +## What + +- Arduino +- 3 sonars +- 3 colors in the spectrum +- RGB led strip +- Magic! + +## Building + +To run this project, you need Arduino Pro Mini, or Nano (those $2 eBay clones will work perfectly). +You can also try to use a genuine Arduino, even larger (UNO), though I haven't tried that. + +To flash the firmware, run `make flash`. Adjustment the Makefile as needed. Naturally, you'll need +`avr-gcc` and `avrdude` installed (and Linux or OSX). + +Make sure the correct Serial device is defined in the Makefile (`/dev/ttyUSB0` or other - it tends +to be something really strange on OSX). + +## Hardware + +- RGB LED strip with WS2812 or WS2812B. It's set up for a 30-led strip, adjust as needed. -Buttons connected from pins to ground with internal pull-up. -Keys are sent as A - pressed, a - released (different letters), over UART at 115200 baud. -Key press is indicated by LED at D9. diff --git a/main.c b/main.c index a9b76fd..30aef30 100644 --- a/main.c +++ b/main.c @@ -23,6 +23,53 @@ #define ECHO2_PIN 8 #define ECHO3_PIN 10 +#define LED_COUNT 30 + +/** Phase of the measurement (state-machine state) */ +typedef enum { + MEAS_WAIT_1, + MEAS_WAIT_0, + MEAS_DONE +} MeasPhase; + + +// averaging buffer length (number of samples) +#define MBUF_LEN 16 + +/** Averaging buffer instance */ +typedef struct { + float data[MBUF_LEN]; +} MBuf; + +static MBuf mb_offs1; +static MBuf mb_offs2; +static MBuf mb_offs3; + +/** RGB color structure */ +typedef struct __attribute__((packed)) { + uint8_t r; + uint8_t g; + uint8_t b; +} RGB; + +/** LED strip colors */ +static RGB history[LED_COUNT]; + +/** Add a value to the averaging buffer. Returns currrent mean value */ +static float mbuf_add(MBuf *buf, float value) +{ + float aggr = value; + for (int i = MBUF_LEN - 1; i > 0; i--) { + float m = buf->data[i - 1]; + aggr += m; + buf->data[i] = m; + } + + buf->data[0] = value; + + return aggr / (float)MBUF_LEN; +} + /** Wait long enough for the colors to show */ static inline __attribute__((always_inline)) @@ -35,6 +82,9 @@ void ws_show(void) static inline __attribute__((always_inline)) void ws_send_byte(uint8_t bb) { + // If your LEDs don't work right, you may need to adjust the number of NOPs here + // It's a good idea to debug this with oscilloscope or a logic analyzer + for (int8_t i = 8; i > 0; i--) { pin_up(WS_PIN); if (bb & 0x80) { @@ -59,7 +109,7 @@ void ws_send_byte(uint8_t bb) } } - +/** Send a RGB color to the strip */ static void ws_send_rgb(uint8_t r, uint8_t g, uint8_t b) { ws_send_byte(g); @@ -67,7 +117,7 @@ static void ws_send_rgb(uint8_t r, uint8_t g, uint8_t b) ws_send_byte(b); } - +/** Init hardware resources */ static void hw_init(void) { usart_init(BAUD_115200); @@ -85,51 +135,18 @@ static void hw_init(void) as_output(13); } -typedef enum { - MEAS_WAIT_1, - MEAS_WAIT_0, - MEAS_DONE -} MeasPhase; - - -#define MBUF_LEN 16 -typedef struct { - float data[MBUF_LEN]; -} MBuf; - -static float mbuf_add(MBuf *buf, float value) -{ - float aggr = value; - for (int i = MBUF_LEN - 1; i > 0; i--) { - float m = buf->data[i - 1]; - aggr += m; - buf->data[i] = m; - } - - buf->data[0] = value; - - return aggr / (float)MBUF_LEN; -} - -static MBuf mb_offs1; -static MBuf mb_offs2; -static MBuf mb_offs3; - -typedef struct { - uint8_t r; - uint8_t g; - uint8_t b; -} RGB; - -static RGB history[30]; - - -static uint16_t meas(MBuf *mbuf, uint8_t TRIG, uint8_t ECHO) +/** + * Measure one ultrasonic sensor distance + * + * We could run all 3 at once, but then the sound waves tend to reflect + * into different receives and you get false readings. + */ +static uint8_t meas(MBuf *mbuf, uint8_t trig_pin, uint8_t echo_pin) { _delay_ms(6); - pin_up_n(TRIG); + pin_up_n(trig_pin); _delay_ms(1); - pin_down_n(TRIG); + pin_down_n(trig_pin); MeasPhase meas_phase = MEAS_WAIT_1; @@ -140,12 +157,12 @@ static uint16_t meas(MBuf *mbuf, uint8_t TRIG, uint8_t ECHO) while (true) { if (meas_phase == MEAS_WAIT_1) { - if (pin_is_high_n(ECHO)) { + if (pin_is_high_n(echo_pin)) { echo = TCNT1; meas_phase = MEAS_WAIT_0; } } else if (meas_phase == MEAS_WAIT_0) { - if (pin_is_low_n(ECHO)) { + if (pin_is_low_n(echo_pin)) { echo = TCNT1 - echo; break; } @@ -160,11 +177,13 @@ static uint16_t meas(MBuf *mbuf, uint8_t TRIG, uint8_t ECHO) TCCR1B = 0; // stop - // Both pulses measured with 0.5us accuracy + // Pulse measured with 0.5us accuracy + // To convert to mm -> multiply by 0.8 - // Convert to mm + // --- convert to R/G/B value 0-255 --- - float offset = 255 - echo / (1.25f * 25.0f); //25 + // The number '25.0f' here determines the sensitivity + float offset = 255 - echo / (1.25f * 25.0f); if (offset > 255) { offset = 255; @@ -172,31 +191,31 @@ static uint16_t meas(MBuf *mbuf, uint8_t TRIG, uint8_t ECHO) offset = 0; } + // averaging offset = mbuf_add(mbuf, offset); - return (uint16_t) roundf(offset); // converted to RGB-level + // to int + return (uint8_t) roundf(offset); } - - - +/** Measure all 3 sensors and update the colors */ static void sonar_measure(void) { - uint16_t c1 = meas(&mb_offs1, TRIG1_PIN, ECHO1_PIN); - uint16_t c2 = meas(&mb_offs2, TRIG2_PIN, ECHO2_PIN); - uint16_t c3 = meas(&mb_offs3, TRIG3_PIN, ECHO3_PIN); + uint8_t c1 = meas(&mb_offs1, TRIG1_PIN, ECHO1_PIN); + uint8_t c2 = meas(&mb_offs2, TRIG2_PIN, ECHO2_PIN); + uint8_t c3 = meas(&mb_offs3, TRIG3_PIN, ECHO3_PIN); - for (int i = 30 - 1; i > 0; i--) { + for (int i = LED_COUNT - 1; i > 0; i--) { history[i].r = history[i - 1].r; history[i].g = history[i - 1].g; history[i].b = history[i - 1].b; } - history[0].r = (uint8_t)c1; - history[0].g = (uint8_t)c2; - history[0].b = (uint8_t)c3; + history[0].r = c1; + history[0].g = c2; + history[0].b = c3; - for (int i = 0; i < 30; i++) { + for (int i = 0; i < LED_COUNT; i++) { ws_send_rgb(history[i].r, history[i].g, history[i].b); } @@ -210,8 +229,8 @@ int main(void) usart_puts_P(PSTR("===========================\r\n")); usart_puts_P(PSTR("\r\n")); - usart_puts_P(PSTR("RGB SONAR DEMO\r\n")); - usart_puts_P(PSTR("FEL CVUT K338\r\n")); + usart_puts_P(PSTR("SPATIAL RGB - SONAR DEMO\r\n")); + usart_puts_P(PSTR("FEE CTU Prague, K338\r\n")); usart_puts_P(PSTR("\r\n")); usart_puts_P(PSTR("(c) Ondrej Hruska 2016\r\n")); usart_puts_P(PSTR("\r\n")); @@ -230,7 +249,7 @@ int main(void) if (++cnt == 20) { cnt = 0; - pin_toggle(13); + pin_toggle(13); // blink the indicator to show that we're OK } } }