├── .gitignore ├── smart-car ├── README.md ├── smart-car.jpg └── smart-car.ino ├── basurito ├── front.jpg ├── rear.jpg ├── internal.jpg ├── README.md ├── basurito.ino └── LowPower.h ├── bluetooth-car ├── bluetooth-car-1.jpg ├── bluetooth-car-2.jpg ├── README.md └── bluetooth-car.ino ├── rocking-servo └── rocking-servo.ino ├── hexalamp └── hexalamp.ino ├── xmas-tree ├── pitches.h ├── xmas-tree.ino └── arduino_christmas_songs.ino └── traffic-lights └── traffic-lights.ino /.gitignore: -------------------------------------------------------------------------------- 1 | local.h 2 | -------------------------------------------------------------------------------- /smart-car/README.md: -------------------------------------------------------------------------------- 1 | # Self-orienting "smart" car 2 | 3 | ![](smart-car.jpg) 4 | -------------------------------------------------------------------------------- /basurito/front.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanilves/arduino-sketches/HEAD/basurito/front.jpg -------------------------------------------------------------------------------- /basurito/rear.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanilves/arduino-sketches/HEAD/basurito/rear.jpg -------------------------------------------------------------------------------- /basurito/internal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanilves/arduino-sketches/HEAD/basurito/internal.jpg -------------------------------------------------------------------------------- /smart-car/smart-car.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanilves/arduino-sketches/HEAD/smart-car/smart-car.jpg -------------------------------------------------------------------------------- /bluetooth-car/bluetooth-car-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanilves/arduino-sketches/HEAD/bluetooth-car/bluetooth-car-1.jpg -------------------------------------------------------------------------------- /bluetooth-car/bluetooth-car-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanilves/arduino-sketches/HEAD/bluetooth-car/bluetooth-car-2.jpg -------------------------------------------------------------------------------- /bluetooth-car/README.md: -------------------------------------------------------------------------------- 1 | # Bluetooth controlled car 2 | 3 | ![](bluetooth-car-1.jpg) 4 | 5 | ### My first Arduino project, just to test if I need all this Arduino madness in my life :laughing: 6 | 7 | *Aside from Arduino coding includes a lot of soldering, woodworking and painting. Was a pain in the ass to build!* 8 | 9 | ![](bluetooth-car-2.jpg) 10 | -------------------------------------------------------------------------------- /basurito/README.md: -------------------------------------------------------------------------------- 1 | # Self-opening trash can 2 | 3 | Started as a woodworking project, a trash can and a lid made from two pine boards and a sheet of plywood. Made almost entirely using a jigsaw and then painted with acrylic spray... then ...to make it less boring, I've soldered some electronic circuits and wrote an Arduino sketch to control the automation :robot: 4 | *Oh shi- now I feed it with the garbage all day long and you know, it does feel so relaxing* :joy: 5 | 6 | ![](front.jpg) 7 | 8 | ## Video demo? 9 | https://www.dropbox.com/s/rejr2ne6q7ah067/basurito.mp4?dl=0 :movie_camera: 10 | 11 | ![gif](https://i.imgur.com/fKpMDtb.gif) 12 | 13 | ## Features 14 | 15 | * Opens when detects any presense above the lid; 16 | * Closes automatically in a few seconds if open automatically; 17 | * Can be open and closed manually with a button (to change bags or keep open for a longer time); 18 | * Has a led signaling opening/closing/booting states; 19 | 20 | ![](rear.jpg) 21 | 22 | ## Components 23 | 24 | * Arduino Nano (not genuine, some inexpensive clone, I'm a bum); 25 | * Ultrasonic proximity sensor; 26 | * 25kg-cm servo (some noname from AliExpress, works awesome); 27 | * 12V battery power + DC/DC step down adaptor (12V=>5V); 28 | 29 | ![](internal.jpg) 30 | -------------------------------------------------------------------------------- /rocking-servo/rocking-servo.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define START_ANGLE 90 4 | #define STOP_ANGLE 120 5 | #define LOOP_DELAY 250 6 | #define SRV_PIN 9 7 | #define SPD_PIN A0 8 | 9 | const int startAngle = START_ANGLE; 10 | const int stopAngle = STOP_ANGLE; 11 | const int loopDelay = LOOP_DELAY; 12 | 13 | const int srvPin = SRV_PIN; 14 | const int spdPin = SPD_PIN; 15 | 16 | const int stepAngle = 1; 17 | 18 | Servo srv; 19 | 20 | void setup() { 21 | Serial.begin(9600); 22 | 23 | srv.attach(srvPin); 24 | srv.write(startAngle); 25 | } 26 | 27 | int getSpd() { 28 | int a = analogRead(spdPin); 29 | 30 | if (a < 24) { 31 | return 0; 32 | } 33 | 34 | return ((a - 24) / 100); 35 | } 36 | 37 | int getStepDelay(int spd) { 38 | return (10 - spd) * 2; 39 | } 40 | 41 | int pos = startAngle; 42 | int spd = 0; 43 | bool fw = true; 44 | 45 | void loop() { 46 | spd = getSpd(); 47 | 48 | if (spd == 0) { 49 | srv.write(startAngle); 50 | delay(loopDelay); 51 | return; 52 | } 53 | 54 | if (fw) { 55 | pos += stepAngle; 56 | } else { 57 | pos -= stepAngle; 58 | } 59 | 60 | srv.write(pos); 61 | 62 | if (pos >= stopAngle) { 63 | delay(loopDelay); 64 | fw = false; 65 | } else { 66 | if (pos <= startAngle) { 67 | delay(loopDelay); 68 | fw = true; 69 | } 70 | } 71 | 72 | delay(getStepDelay(spd)); 73 | } 74 | -------------------------------------------------------------------------------- /hexalamp/hexalamp.ino: -------------------------------------------------------------------------------- 1 | //#define DEBUG 2 | #define ON_PIN 3 3 | #define BT_PIN 5 4 | #define IR_PIN A6 5 | #define PR_PIN A4 6 | #define IR_TRH 900 7 | #define PR_TRH 50 8 | 9 | const int graceMillis = 100; 10 | const int lightMillis = 30000; 11 | 12 | void setup() { 13 | pinMode(ON_PIN, OUTPUT); 14 | pinMode(IR_PIN, INPUT); 15 | pinMode(PR_PIN, INPUT); 16 | pinMode(BT_PIN, INPUT_PULLUP); 17 | 18 | #ifdef DEBUG 19 | Serial.begin(9600); 20 | #endif 21 | } 22 | 23 | bool trig = false; 24 | bool on = false; 25 | bool bt = false; 26 | int ir, pr; 27 | unsigned long t = 0; 28 | char _src = '?'; 29 | 30 | bool irTrig(int ir, int pr, bool on) { 31 | if (_src == 'b') { 32 | return false; 33 | } 34 | 35 | if ((!on and ir < IR_TRH and pr < PR_TRH) or (on and ir < IR_TRH)) { 36 | if (on) { 37 | _src = '?'; 38 | } else { 39 | _src = 'i'; 40 | } 41 | 42 | return true; 43 | } 44 | 45 | return false; 46 | } 47 | 48 | bool btPush(bool bt, bool on) { 49 | if (bt) { 50 | if (on) { 51 | _src = '?'; 52 | } else { 53 | _src = 'b'; 54 | } 55 | 56 | return true; 57 | } 58 | 59 | return false; 60 | } 61 | 62 | void loop() { 63 | ir = analogRead(IR_PIN); 64 | pr = analogRead(PR_PIN); 65 | bt = digitalRead(BT_PIN) == LOW; 66 | 67 | trig = (irTrig(ir, pr, on) or btPush(bt, on)); 68 | 69 | #ifdef DEBUG 70 | Serial.print("IR: "); 71 | Serial.print(ir); 72 | Serial.print(" / PR: "); 73 | Serial.print(pr); 74 | Serial.print(" / BT: "); 75 | Serial.print(bt); 76 | Serial.print(" / SRC: "); 77 | Serial.println(_src); 78 | #endif 79 | 80 | if (trig) { 81 | on = !on; 82 | 83 | digitalWrite(ON_PIN, on); 84 | delay(5 * graceMillis); 85 | 86 | if (on) { 87 | t = millis(); 88 | } 89 | } 90 | 91 | if (_src == 'i') { 92 | if (on) { 93 | if (millis() - t > lightMillis) { 94 | digitalWrite(ON_PIN, !on); 95 | t = millis(); 96 | _src = '?'; 97 | } 98 | } 99 | } 100 | 101 | delay(graceMillis); 102 | } 103 | -------------------------------------------------------------------------------- /xmas-tree/pitches.h: -------------------------------------------------------------------------------- 1 | /************************************************* 2 | 3 | * Public Constants 4 | 5 | *************************************************/ 6 | 7 | #define NOTE_B0 31 8 | #define NOTE_C1 33 9 | #define NOTE_CS1 35 10 | #define NOTE_D1 37 11 | #define NOTE_DS1 39 12 | #define NOTE_E1 41 13 | #define NOTE_F1 44 14 | #define NOTE_FS1 46 15 | #define NOTE_G1 49 16 | #define NOTE_GS1 52 17 | #define NOTE_A1 55 18 | #define NOTE_AS1 58 19 | #define NOTE_B1 62 20 | #define NOTE_C2 65 21 | #define NOTE_CS2 69 22 | #define NOTE_D2 73 23 | #define NOTE_DS2 78 24 | #define NOTE_E2 82 25 | #define NOTE_F2 87 26 | #define NOTE_FS2 93 27 | #define NOTE_G2 98 28 | #define NOTE_GS2 104 29 | #define NOTE_A2 110 30 | #define NOTE_AS2 117 31 | #define NOTE_B2 123 32 | #define NOTE_C3 131 33 | #define NOTE_CS3 139 34 | #define NOTE_D3 147 35 | #define NOTE_DS3 156 36 | #define NOTE_E3 165 37 | #define NOTE_F3 175 38 | #define NOTE_FS3 185 39 | #define NOTE_G3 196 40 | #define NOTE_GS3 208 41 | #define NOTE_A3 220 42 | #define NOTE_AS3 233 43 | #define NOTE_B3 247 44 | #define NOTE_C4 262 45 | #define NOTE_CS4 277 46 | #define NOTE_D4 294 47 | #define NOTE_DS4 311 48 | #define NOTE_E4 330 49 | #define NOTE_F4 349 50 | #define NOTE_FS4 370 51 | #define NOTE_G4 392 52 | #define NOTE_GS4 415 53 | #define NOTE_A4 440 54 | #define NOTE_AS4 466 55 | #define NOTE_B4 494 56 | #define NOTE_C5 523 57 | #define NOTE_CS5 554 58 | #define NOTE_D5 587 59 | #define NOTE_DS5 622 60 | #define NOTE_E5 659 61 | #define NOTE_F5 698 62 | #define NOTE_FS5 740 63 | #define NOTE_G5 784 64 | #define NOTE_GS5 831 65 | #define NOTE_A5 880 66 | #define NOTE_AS5 932 67 | #define NOTE_B5 988 68 | #define NOTE_C6 1047 69 | #define NOTE_CS6 1109 70 | #define NOTE_D6 1175 71 | #define NOTE_DS6 1245 72 | #define NOTE_E6 1319 73 | #define NOTE_F6 1397 74 | #define NOTE_FS6 1480 75 | #define NOTE_G6 1568 76 | #define NOTE_GS6 1661 77 | #define NOTE_A6 1760 78 | #define NOTE_AS6 1865 79 | #define NOTE_B6 1976 80 | #define NOTE_C7 2093 81 | #define NOTE_CS7 2217 82 | #define NOTE_D7 2349 83 | #define NOTE_DS7 2489 84 | #define NOTE_E7 2637 85 | #define NOTE_F7 2794 86 | #define NOTE_FS7 2960 87 | #define NOTE_G7 3136 88 | #define NOTE_GS7 3322 89 | #define NOTE_A7 3520 90 | #define NOTE_AS7 3729 91 | #define NOTE_B7 3951 92 | #define NOTE_C8 4186 93 | #define NOTE_CS8 4435 94 | #define NOTE_D8 4699 95 | #define NOTE_DS8 4978 96 | -------------------------------------------------------------------------------- /basurito/basurito.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define OPENING_DELAY 10 5 | #define CLOSING_DELAY 10 6 | 7 | #define BTN_PIN 2 8 | #define LED_PIN 13 9 | 10 | #define SRV_PIN 9 11 | #define SRV_CLOSED 45 12 | #define SRV_OPEN 135 13 | 14 | Servo srv; 15 | 16 | int srvPos = SRV_CLOSED; 17 | 18 | #define TRIG_PIN 3 19 | #define ECHO_PIN 4 20 | 21 | #define MAX_DIST 50 22 | #define MIN_DIST 20 23 | 24 | int distance; 25 | 26 | bool isOpen = false; 27 | bool isManual = false; 28 | bool isOpening = false; 29 | bool isClosing = false; 30 | 31 | bool isMoving() { 32 | return isOpening || isClosing; 33 | } 34 | 35 | bool isClosed() { 36 | return !isOpen && !isMoving(); 37 | } 38 | 39 | bool isManuallyOpen() { 40 | return isOpen && isManual; 41 | } 42 | 43 | bool isAutoOpen() { 44 | return isOpen && !isManual; 45 | } 46 | 47 | void setup() { 48 | pinMode(BTN_PIN, INPUT_PULLUP); 49 | pinMode(LED_PIN, OUTPUT); 50 | pinMode(SRV_PIN, OUTPUT); 51 | pinMode(TRIG_PIN, OUTPUT); 52 | pinMode(ECHO_PIN, INPUT); 53 | 54 | srv.attach(SRV_PIN); 55 | srv.write(SRV_CLOSED); 56 | } 57 | 58 | void ledOn() { 59 | digitalWrite(LED_PIN, HIGH); 60 | } 61 | 62 | void ledOff() { 63 | digitalWrite(LED_PIN, LOW); 64 | } 65 | 66 | bool buttonPressed() { 67 | return digitalRead(BTN_PIN) == HIGH; 68 | } 69 | 70 | int calculateDistance() { 71 | digitalWrite(TRIG_PIN, HIGH); 72 | delayMicroseconds(10); 73 | digitalWrite(TRIG_PIN, LOW); 74 | delayMicroseconds(2); 75 | 76 | int duration = pulseIn(ECHO_PIN, HIGH); 77 | 78 | return duration * 0.034 / 2; 79 | } 80 | 81 | void loop() { 82 | // With lid closed we check for the ultrasound signal to see if we need to open lid 83 | if (isClosed()) { 84 | distance = calculateDistance(); 85 | 86 | // If distance to obstacle (trash bag or hand) is within the range, signal opening 87 | if (distance >= MIN_DIST and distance <= MAX_DIST) { 88 | isOpening = true; 89 | isManual = false; 90 | } else { 91 | // ... if not, just sleep waiting for the better times ... 92 | LowPower.powerDown(SLEEP_500MS, ADC_OFF, BOD_OFF); 93 | } 94 | } 95 | 96 | // While lid not moving we also accept the button-triggered manual open/close directives 97 | if (!isMoving()) { 98 | if (buttonPressed()) { 99 | if (isOpen) { 100 | isOpen = false; 101 | isManual = true; 102 | isOpening = false; 103 | isClosing = true; 104 | } else { 105 | isManual = true; 106 | isOpening = true; 107 | isClosing = false; 108 | } 109 | } 110 | } 111 | 112 | // Keep opening the lid until we open it 113 | if (isOpening) { 114 | if (srvPos < SRV_OPEN) { 115 | srvPos++; 116 | srv.write(srvPos); 117 | } else { 118 | isOpen = true; 119 | isOpening = false; 120 | isClosing = false; 121 | srvPos = SRV_OPEN; 122 | srv.write(srvPos); 123 | } 124 | delay(OPENING_DELAY); 125 | } 126 | 127 | // Keep closing the lid until we close it 128 | if (isClosing) { 129 | if (srvPos > SRV_CLOSED) { 130 | srvPos--; 131 | srv.write(srvPos); 132 | } else { 133 | isOpen = false; 134 | isManual = false; 135 | isOpening = false; 136 | isClosing = false; 137 | srvPos = SRV_CLOSED; 138 | srv.write(srvPos); 139 | delay(CLOSING_DELAY); 140 | LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF); 141 | } 142 | delay(CLOSING_DELAY); 143 | } 144 | 145 | // After being open automatically (by sensor trigger), sleep and signal opening again ;) 146 | if (isAutoOpen()) { 147 | LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF); 148 | isOpen = false; 149 | isClosing = true; 150 | } 151 | 152 | // If we are moving the lid, light the led on 153 | // ... if we are not, put the led light off ... 154 | if (isMoving()) { 155 | ledOn(); 156 | } else { 157 | ledOff(); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /basurito/LowPower.h: -------------------------------------------------------------------------------- 1 | #ifndef LowPower_h 2 | #define LowPower_h 3 | 4 | #include "Arduino.h" 5 | 6 | enum period_t 7 | { 8 | SLEEP_15MS, 9 | SLEEP_30MS, 10 | SLEEP_60MS, 11 | SLEEP_120MS, 12 | SLEEP_250MS, 13 | SLEEP_500MS, 14 | SLEEP_1S, 15 | SLEEP_2S, 16 | SLEEP_4S, 17 | SLEEP_8S, 18 | SLEEP_FOREVER 19 | }; 20 | 21 | enum bod_t 22 | { 23 | BOD_OFF, 24 | BOD_ON 25 | }; 26 | 27 | enum adc_t 28 | { 29 | ADC_OFF, 30 | ADC_ON 31 | }; 32 | 33 | enum timer5_t 34 | { 35 | TIMER5_OFF, 36 | TIMER5_ON 37 | }; 38 | 39 | enum timer4_t 40 | { 41 | TIMER4_OFF, 42 | TIMER4_ON 43 | }; 44 | 45 | enum timer3_t 46 | { 47 | TIMER3_OFF, 48 | TIMER3_ON 49 | }; 50 | 51 | enum timer2_t 52 | { 53 | TIMER2_OFF, 54 | TIMER2_ON 55 | }; 56 | 57 | enum timer1_t 58 | { 59 | TIMER1_OFF, 60 | TIMER1_ON 61 | }; 62 | 63 | enum timer0_t 64 | { 65 | TIMER0_OFF, 66 | TIMER0_ON 67 | }; 68 | 69 | enum spi_t 70 | { 71 | SPI_OFF, 72 | SPI_ON 73 | }; 74 | 75 | enum usart0_t 76 | { 77 | USART0_OFF, 78 | USART0_ON 79 | }; 80 | 81 | enum usart1_t 82 | { 83 | USART1_OFF, 84 | USART1_ON 85 | }; 86 | 87 | enum usart2_t 88 | { 89 | USART2_OFF, 90 | USART2_ON 91 | }; 92 | 93 | enum usart3_t 94 | { 95 | USART3_OFF, 96 | USART3_ON 97 | }; 98 | 99 | enum twi_t 100 | { 101 | TWI_OFF, 102 | TWI_ON 103 | }; 104 | 105 | enum usb_t 106 | { 107 | USB_OFF, 108 | USB_ON 109 | }; 110 | 111 | enum idle_t 112 | { 113 | IDLE_0, 114 | IDLE_1, 115 | IDLE_2 116 | }; 117 | 118 | class LowPowerClass 119 | { 120 | public: 121 | #if defined (__AVR__) 122 | 123 | #if defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168__) || defined (__AVR_ATmega168P__) || defined (__AVR_ATmega88__) 124 | void idle(period_t period, adc_t adc, timer2_t timer2, 125 | timer1_t timer1, timer0_t timer0, spi_t spi, 126 | usart0_t usart0, twi_t twi); 127 | #elif defined __AVR_ATmega644P__ || defined (__AVR_ATmega1284P__) 128 | void idle(period_t period, adc_t adc, timer2_t timer2, 129 | timer1_t timer1, timer0_t timer0, spi_t spi, 130 | usart1_t usart1, usart0_t usart0, twi_t twi); 131 | #elif defined __AVR_ATmega2560__ 132 | void idle(period_t period, adc_t adc, timer5_t timer5, 133 | timer4_t timer4, timer3_t timer3, timer2_t timer2, 134 | timer1_t timer1, timer0_t timer0, spi_t spi, 135 | usart3_t usart3, usart2_t usart2, usart1_t usart1, 136 | usart0_t usart0, twi_t twi); 137 | #elif defined __AVR_ATmega256RFR2__ 138 | void idle(period_t period, adc_t adc, timer5_t timer5, 139 | timer4_t timer4, timer3_t timer3, timer2_t timer2, 140 | timer1_t timer1, timer0_t timer0, spi_t spi, 141 | usart1_t usart1, 142 | usart0_t usart0, twi_t twi); 143 | #elif defined __AVR_ATmega32U4__ 144 | void idle(period_t period, adc_t adc, timer4_t timer4, 145 | timer3_t timer3, timer1_t timer1, timer0_t timer0, 146 | spi_t spi, usart1_t usart1, twi_t twi, usb_t usb); 147 | #else 148 | #error "Please ensure chosen MCU is either 88, 168, 168P, 328P, 32U4, 2560 or 256RFR2." 149 | #endif 150 | void adcNoiseReduction(period_t period, adc_t adc, timer2_t timer2) __attribute__((optimize("-O1"))); 151 | void powerDown(period_t period, adc_t adc, bod_t bod) __attribute__((optimize("-O1"))); 152 | void powerSave(period_t period, adc_t adc, bod_t bod, timer2_t timer2) __attribute__((optimize("-O1"))); 153 | void powerStandby(period_t period, adc_t adc, bod_t bod) __attribute__((optimize("-O1"))); 154 | void powerExtStandby(period_t period, adc_t adc, bod_t bod, timer2_t timer2) __attribute__((optimize("-O1"))); 155 | 156 | #elif defined (__arm__) 157 | 158 | #if defined (__SAMD21G18A__) 159 | void idle(idle_t idleMode); 160 | void standby(); 161 | #else 162 | #error "Please ensure chosen MCU is ATSAMD21G18A." 163 | #endif 164 | 165 | #else 166 | 167 | #error "Processor architecture is not supported." 168 | 169 | #endif 170 | }; 171 | 172 | extern LowPowerClass LowPower; 173 | #endif 174 | -------------------------------------------------------------------------------- /traffic-lights/traffic-lights.ino: -------------------------------------------------------------------------------- 1 | #define PIN_RED 2 2 | #define PIN_YELLOW 3 3 | #define PIN_GREEN 4 4 | #define PIN_MODE_MANUAL 11 5 | #define PIN_MODE_YELLOW 12 6 | 7 | #define COLOR_RED 0 8 | #define COLOR_YELLOW 1 9 | #define COLOR_GREEN 2 10 | 11 | #define DELAY_RED 5000 12 | #define DELAY_YELLOW 1500 13 | #define DELAY_GREEN 5000 14 | #define DELAY_BLINK 250 15 | #define DELAY_BUTTON_PRESS 500 16 | 17 | #define MODE_AUTO 0 18 | #define MODE_YELLOW 1 19 | #define MODE_MANUAL 2 20 | 21 | unsigned long lastColorChangeTime = millis(); 22 | unsigned long lastButtonPressTime = millis(); 23 | 24 | unsigned int mode = MODE_AUTO; 25 | unsigned int color = COLOR_RED; 26 | unsigned int prevColor; 27 | bool on = true; 28 | 29 | void setup() { 30 | pinMode(PIN_RED, OUTPUT); 31 | pinMode(PIN_YELLOW, OUTPUT); 32 | pinMode(PIN_GREEN, OUTPUT); 33 | pinMode(PIN_MODE_YELLOW, INPUT_PULLUP); 34 | pinMode(PIN_MODE_MANUAL, INPUT_PULLUP); 35 | } 36 | 37 | void setRedLight(bool on) { 38 | digitalWrite(PIN_YELLOW, LOW); 39 | digitalWrite(PIN_GREEN, LOW); 40 | 41 | if (on) { 42 | digitalWrite(PIN_RED, HIGH); 43 | } else { 44 | digitalWrite(PIN_RED, LOW); 45 | } 46 | } 47 | 48 | void setYellowLight(bool on) { 49 | digitalWrite(PIN_RED, LOW); 50 | digitalWrite(PIN_GREEN, LOW); 51 | 52 | if (on) { 53 | digitalWrite(PIN_YELLOW, HIGH); 54 | } else { 55 | digitalWrite(PIN_YELLOW, LOW); 56 | } 57 | } 58 | 59 | void setGreenLight(bool on) { 60 | digitalWrite(PIN_RED, LOW); 61 | digitalWrite(PIN_YELLOW, LOW); 62 | 63 | if (on) { 64 | digitalWrite(PIN_GREEN, HIGH); 65 | } else { 66 | digitalWrite(PIN_GREEN, LOW); 67 | } 68 | } 69 | 70 | void setAllLightsOn() { 71 | digitalWrite(PIN_RED, HIGH); 72 | digitalWrite(PIN_YELLOW, HIGH); 73 | digitalWrite(PIN_GREEN, HIGH); 74 | } 75 | 76 | void setLight(int color, bool on) { 77 | switch (color) { 78 | case COLOR_RED: 79 | setRedLight(on); 80 | break; 81 | case COLOR_YELLOW: 82 | setYellowLight(on); 83 | break; 84 | case COLOR_GREEN: 85 | setGreenLight(on); 86 | break; 87 | default: 88 | setAllLightsOn(); 89 | break; 90 | } 91 | } 92 | 93 | bool yellowButtonPressed() { 94 | return digitalRead(PIN_MODE_YELLOW) == LOW; 95 | } 96 | 97 | bool blueButtonPressed() { 98 | return digitalRead(PIN_MODE_MANUAL) == LOW; 99 | } 100 | 101 | void loop() { 102 | if (millis() - lastButtonPressTime > DELAY_BUTTON_PRESS) { 103 | if (yellowButtonPressed()) { 104 | if (mode != MODE_YELLOW) { 105 | mode = MODE_YELLOW; 106 | color = COLOR_YELLOW; 107 | } else { 108 | mode = MODE_AUTO; 109 | color = COLOR_RED; 110 | } 111 | on = true; 112 | lastColorChangeTime = millis(); 113 | lastButtonPressTime = millis(); 114 | } 115 | if (blueButtonPressed()) { 116 | if (mode != MODE_MANUAL) { 117 | mode = MODE_MANUAL; 118 | color = COLOR_RED; 119 | } else { 120 | if (color == COLOR_RED) { 121 | color = COLOR_GREEN; 122 | } else { 123 | color = COLOR_RED; 124 | } 125 | } 126 | on = true; 127 | lastColorChangeTime = millis(); 128 | lastButtonPressTime = millis(); 129 | } 130 | } 131 | 132 | switch (mode) { 133 | case MODE_AUTO: 134 | switch (color) { 135 | case COLOR_RED: 136 | if (millis() - lastColorChangeTime > DELAY_RED) { 137 | lastColorChangeTime = millis(); 138 | color = COLOR_YELLOW; 139 | prevColor = COLOR_RED; 140 | } 141 | break; 142 | case COLOR_YELLOW: 143 | if (millis() - lastColorChangeTime > DELAY_YELLOW) { 144 | lastColorChangeTime = millis(); 145 | if (prevColor == COLOR_GREEN) { 146 | color = COLOR_RED; 147 | } else { 148 | color = COLOR_GREEN; 149 | } 150 | prevColor = COLOR_YELLOW; 151 | } 152 | break; 153 | case COLOR_GREEN: 154 | if (millis() - lastColorChangeTime > DELAY_GREEN) { 155 | lastColorChangeTime = millis(); 156 | color = COLOR_YELLOW; 157 | prevColor = COLOR_GREEN; 158 | } 159 | break; 160 | default: 161 | setAllLightsOn(); 162 | break; 163 | } 164 | break; 165 | case MODE_YELLOW: 166 | if (millis() - lastColorChangeTime > DELAY_BLINK) { 167 | lastColorChangeTime = millis(); 168 | if (on) { 169 | on = false; 170 | } else { 171 | on = true; 172 | } 173 | } 174 | break; 175 | case MODE_MANUAL: 176 | break; 177 | } 178 | 179 | setLight(color, on); 180 | 181 | delay(10); 182 | } 183 | -------------------------------------------------------------------------------- /xmas-tree/xmas-tree.ino: -------------------------------------------------------------------------------- 1 | #define LED0_PIN 3 2 | #define LED1_PIN 4 3 | #define LED2_PIN 7 4 | #define LED3_PIN 8 5 | #define LED4_PIN 11 6 | #define LED5_PIN 10 7 | #define LED6_PIN 9 8 | #define LED7_PIN 6 9 | #define LED8_PIN 5 10 | 11 | #define BUZZ_PIN 2 12 | #define ECHO_PIN A0 13 | #define TRIG_PIN A1 14 | 15 | #define PLAY_DISTANCE 30 16 | #define MODE_LOOPS 3 17 | #define LOOP_DELAY 50 18 | #define PLAY_CONFIRMATIONS 5 19 | #define PLAY_COOLDOWN_DELAY 10000 20 | 21 | //#define DEBUG 22 | 23 | /* 24 | You should be able to fine-tune this sketch only by changing the "define"s above. 25 | Go below this comment if you want to make deeper changes (you are welcome anyway) 26 | */ 27 | 28 | const int LED_PINS[] = { LED0_PIN, LED1_PIN, LED2_PIN, LED3_PIN, LED4_PIN, LED5_PIN, LED6_PIN, LED7_PIN, LED8_PIN }; 29 | const int LED_PAIRS[][2] = { 30 | { LED0_PIN, LED0_PIN }, 31 | { LED1_PIN, LED8_PIN }, 32 | { LED2_PIN, LED7_PIN }, 33 | { LED3_PIN, LED6_PIN }, 34 | { LED4_PIN, LED5_PIN }, 35 | { LED3_PIN, LED6_PIN }, 36 | { LED2_PIN, LED7_PIN }, 37 | { LED1_PIN, LED8_PIN }, 38 | { LED0_PIN, LED0_PIN }, 39 | }; 40 | const int LED_PIN_NUM = sizeof(LED_PINS) / sizeof(LED_PINS[0]); 41 | const int LED_PAIR_NUM = sizeof(LED_PAIRS) / sizeof(LED_PAIRS[0]); 42 | 43 | const int SINGLE = 0; 44 | const int PAIRED = 1; 45 | const int X_PLAY = 2; 46 | 47 | // Mutable global state variables (handle with care) 48 | int mode = SINGLE; 49 | int _modeLoop = 0; 50 | bool _loopFinished = false; 51 | int _activeLed = -1; 52 | int _activeLedPair = -1; 53 | int _playConfirmation = 0; 54 | 55 | void setup() { 56 | for (int l = 0; l < LED_PIN_NUM; l++) { 57 | pinMode(LED_PINS[l], OUTPUT); 58 | } 59 | 60 | pinMode(BUZZ_PIN, OUTPUT); 61 | pinMode(ECHO_PIN, INPUT); 62 | pinMode(TRIG_PIN, OUTPUT); 63 | 64 | allLedsOn(); delay(500); allLedsOff(); 65 | 66 | #ifdef DEBUG 67 | Serial.begin(9600); 68 | #endif 69 | } 70 | 71 | int calculateDistance() { 72 | digitalWrite(TRIG_PIN, LOW); 73 | delayMicroseconds(2); 74 | digitalWrite(TRIG_PIN, HIGH); 75 | delayMicroseconds(10); 76 | digitalWrite(TRIG_PIN, LOW); 77 | 78 | int duration = pulseIn(ECHO_PIN, HIGH); 79 | int distance = duration * 0.034 / 2; 80 | 81 | #ifdef DEBUG 82 | Serial.print(distance); Serial.print(" ("); Serial.print(_playConfirmation); Serial.println(");"); 83 | #endif 84 | 85 | return distance; 86 | } 87 | 88 | bool distanceInRange() { 89 | int distance = calculateDistance(); 90 | 91 | return distance < PLAY_DISTANCE and distance > 2; 92 | } 93 | 94 | void holdWhileOnDistance() { 95 | int confirmations = 0; 96 | 97 | while (true) { 98 | if (distanceInRange()) { 99 | confirmations = 0; 100 | } else { 101 | confirmations++; 102 | } 103 | 104 | if (confirmations >= PLAY_CONFIRMATIONS) { 105 | return; 106 | } 107 | 108 | delay(LOOP_DELAY); 109 | } 110 | } 111 | 112 | void allLedsOn() { 113 | for (int l = 0; l < LED_PIN_NUM; l++) { 114 | digitalWrite(LED_PINS[l], HIGH); 115 | } 116 | } 117 | 118 | void allLedsOff() { 119 | for (int l = 0; l < LED_PIN_NUM; l++) { 120 | digitalWrite(LED_PINS[l], LOW); 121 | } 122 | } 123 | 124 | void singleLedOn(int led) { 125 | for (int l = 0; l < LED_PIN_NUM; l++) { 126 | if (l == led) { 127 | digitalWrite(LED_PINS[l], HIGH); 128 | } 129 | else { 130 | digitalWrite(LED_PINS[l], LOW); 131 | } 132 | } 133 | } 134 | 135 | int nextLed() { 136 | if (_activeLed < LED_PIN_NUM - 1) { 137 | _activeLed++; 138 | } else { 139 | _loopFinished = true; 140 | _activeLed = 0; 141 | } 142 | 143 | return _activeLed; 144 | } 145 | 146 | void ledPairOn(int pair) { 147 | digitalWrite(LED_PAIRS[pair][0], HIGH); 148 | digitalWrite(LED_PAIRS[pair][1], HIGH); 149 | } 150 | 151 | void activeLedPairOff() { 152 | digitalWrite(LED_PAIRS[_activeLedPair][0], LOW); 153 | digitalWrite(LED_PAIRS[_activeLedPair][1], LOW); 154 | } 155 | 156 | int nextLedPair() { 157 | if (_activeLedPair < LED_PAIR_NUM - 1) { 158 | _activeLedPair++; 159 | } else { 160 | _loopFinished = true; 161 | _activeLedPair = 0; 162 | } 163 | 164 | return _activeLedPair; 165 | } 166 | 167 | int nextMode() { 168 | if (!_loopFinished) { 169 | return mode; 170 | } 171 | 172 | _loopFinished = false; 173 | 174 | if (_modeLoop < MODE_LOOPS) { 175 | _modeLoop++; 176 | 177 | return mode; 178 | } 179 | 180 | _modeLoop = 0; 181 | 182 | if (mode == SINGLE) { 183 | return PAIRED; 184 | } 185 | 186 | return SINGLE; 187 | } 188 | 189 | bool validatePlayConfirmation() { 190 | if (_playConfirmation < PLAY_CONFIRMATIONS) { 191 | _playConfirmation++; 192 | return false; 193 | } 194 | 195 | _playConfirmation = 0; 196 | return true; 197 | } 198 | 199 | void discardPlayConfirmation() { 200 | _playConfirmation = 0; 201 | } 202 | 203 | void loop() { 204 | if (distanceInRange()) { 205 | if (validatePlayConfirmation()) { 206 | mode = X_PLAY; 207 | } else { 208 | mode = nextMode(); 209 | } 210 | } else { 211 | mode = nextMode(); 212 | discardPlayConfirmation(); 213 | } 214 | 215 | switch (mode) { 216 | case SINGLE: 217 | singleLedOn(nextLed()); 218 | break; 219 | case PAIRED: 220 | activeLedPairOff(); 221 | ledPairOn(nextLedPair()); 222 | break; 223 | case X_PLAY: 224 | allLedsOn(); 225 | randomSeed(millis()); 226 | sing(random(1, 4)); 227 | holdWhileOnDistance(); 228 | delay(PLAY_COOLDOWN_DELAY); 229 | mode = SINGLE; 230 | break; 231 | default: 232 | // blink leds to signal error 233 | allLedsOn(); 234 | tone(BUZZ_PIN, 250); 235 | delay(250); 236 | allLedsOff(); 237 | noTone(BUZZ_PIN); 238 | break; 239 | } 240 | 241 | delay(LOOP_DELAY); 242 | } 243 | -------------------------------------------------------------------------------- /xmas-tree/arduino_christmas_songs.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Arduino Christmas Songs 3 | 4 | Based on a project and code by Dipto Pratyaksa, updated on 31/3/13 5 | 6 | Modified for Christmas by Joshi, on Dec 17th, 2017. 7 | 8 | ... then copy/pasted and modified by Ivan Ilves on Dec 23th, 2020. :) 9 | 10 | P.S.: Thank you Dipto and Joshi! <3 11 | */ 12 | 13 | #include "pitches.h" 14 | 15 | // Jingle Bells 16 | 17 | int melody[] = { 18 | NOTE_E5, NOTE_E5, NOTE_E5, 19 | NOTE_E5, NOTE_E5, NOTE_E5, 20 | NOTE_E5, NOTE_G5, NOTE_C5, NOTE_D5, 21 | NOTE_E5, 22 | NOTE_F5, NOTE_F5, NOTE_F5, NOTE_F5, 23 | NOTE_F5, NOTE_E5, NOTE_E5, NOTE_E5, NOTE_E5, 24 | NOTE_E5, NOTE_D5, NOTE_D5, NOTE_E5, 25 | NOTE_D5, NOTE_G5 26 | }; 27 | 28 | int tempo[] = { 29 | 8, 8, 4, 30 | 8, 8, 4, 31 | 8, 8, 8, 8, 32 | 2, 33 | 8, 8, 8, 8, 34 | 8, 8, 8, 16, 16, 35 | 8, 8, 8, 8, 36 | 4, 4 37 | }; 38 | 39 | // We wish you a merry Christmas 40 | 41 | int wish_melody[] = { 42 | NOTE_B3, 43 | NOTE_F4, NOTE_F4, NOTE_G4, NOTE_F4, NOTE_E4, 44 | NOTE_D4, NOTE_D4, NOTE_D4, 45 | NOTE_G4, NOTE_G4, NOTE_A4, NOTE_G4, NOTE_F4, 46 | NOTE_E4, NOTE_E4, NOTE_E4, 47 | NOTE_A4, NOTE_A4, NOTE_B4, NOTE_A4, NOTE_G4, 48 | NOTE_F4, NOTE_D4, NOTE_B3, NOTE_B3, 49 | NOTE_D4, NOTE_G4, NOTE_E4, 50 | NOTE_F4 51 | }; 52 | 53 | int wish_tempo[] = { 54 | 4, 55 | 4, 8, 8, 8, 8, 56 | 4, 4, 4, 57 | 4, 8, 8, 8, 8, 58 | 4, 4, 4, 59 | 4, 8, 8, 8, 8, 60 | 4, 4, 8, 8, 61 | 4, 4, 4, 62 | 2 63 | }; 64 | 65 | // Santa Claus is coming to town 66 | 67 | int santa_melody[] = { 68 | NOTE_G4, 69 | NOTE_E4, NOTE_F4, NOTE_G4, NOTE_G4, NOTE_G4, 70 | NOTE_A4, NOTE_B4, NOTE_C5, NOTE_C5, NOTE_C5, 71 | NOTE_E4, NOTE_F4, NOTE_G4, NOTE_G4, NOTE_G4, 72 | NOTE_A4, NOTE_G4, NOTE_F4, NOTE_F4, 73 | NOTE_E4, NOTE_G4, NOTE_C4, NOTE_E4, 74 | NOTE_D4, NOTE_F4, NOTE_B3, 75 | NOTE_C4 76 | }; 77 | 78 | int santa_tempo[] = { 79 | 8, 80 | 8, 8, 4, 4, 4, 81 | 8, 8, 4, 4, 4, 82 | 8, 8, 4, 4, 4, 83 | 8, 8, 4, 2, 84 | 4, 4, 4, 4, 85 | 4, 2, 4, 86 | 1 87 | }; 88 | 89 | int switchOne = 0; 90 | int switchTwo = 0; 91 | int switchThree = 0; 92 | 93 | int song = 0; 94 | 95 | void sing(int s) { 96 | // iterate over the notes of the melody: 97 | song = s; 98 | if (song == 3) { 99 | #ifdef DEBUG 100 | Serial.println(" 'We wish you a Merry Christmas'"); 101 | #endif 102 | int size = sizeof(wish_melody) / sizeof(int); 103 | for (int thisNote = 0; thisNote < size; thisNote++) { 104 | 105 | // to calculate the note duration, take one second 106 | // divided by the note type. 107 | //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc. 108 | int noteDuration = 1000 / wish_tempo[thisNote]; 109 | 110 | buzz(BUZZ_PIN, wish_melody[thisNote], noteDuration); 111 | 112 | // to distinguish the notes, set a minimum time between them. 113 | // the note's duration + 30% seems to work well: 114 | int pauseBetweenNotes = noteDuration * 1.30; 115 | delay(pauseBetweenNotes); 116 | 117 | // stop the tone playing: 118 | buzz(BUZZ_PIN, 0, noteDuration); 119 | 120 | } 121 | } else if (song == 2) { 122 | #ifdef DEBUG 123 | Serial.println(" 'Santa Claus is coming to town'"); 124 | #endif 125 | int size = sizeof(santa_melody) / sizeof(int); 126 | for (int thisNote = 0; thisNote < size; thisNote++) { 127 | 128 | // to calculate the note duration, take one second 129 | // divided by the note type. 130 | //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc. 131 | int noteDuration = 900 / santa_tempo[thisNote]; 132 | 133 | buzz(BUZZ_PIN, santa_melody[thisNote], noteDuration); 134 | 135 | // to distinguish the notes, set a minimum time between them. 136 | // the note's duration + 30% seems to work well: 137 | int pauseBetweenNotes = noteDuration * 1.30; 138 | delay(pauseBetweenNotes); 139 | 140 | // stop the tone playing: 141 | buzz(BUZZ_PIN, 0, noteDuration); 142 | 143 | } 144 | } else { 145 | #ifdef DEBUG 146 | Serial.println(" 'Jingle Bells'"); 147 | #endif 148 | int size = sizeof(melody) / sizeof(int); 149 | for (int thisNote = 0; thisNote < size; thisNote++) { 150 | 151 | // to calculate the note duration, take one second 152 | // divided by the note type. 153 | //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc. 154 | int noteDuration = 1000 / tempo[thisNote]; 155 | 156 | buzz(BUZZ_PIN, melody[thisNote], noteDuration); 157 | 158 | // to distinguish the notes, set a minimum time between them. 159 | // the note's duration + 30% seems to work well: 160 | int pauseBetweenNotes = noteDuration * 1.30; 161 | delay(pauseBetweenNotes); 162 | 163 | // stop the tone playing: 164 | buzz(BUZZ_PIN, 0, noteDuration); 165 | 166 | } 167 | } 168 | } 169 | 170 | void buzz(int targetPin, long frequency, long length) { 171 | digitalWrite(13, HIGH); 172 | long delayValue = 1000000 / frequency / 2; // calculate the delay value between transitions 173 | //// 1 second's worth of microseconds, divided by the frequency, then split in half since 174 | //// there are two phases to each cycle 175 | long numCycles = frequency * length / 1000; // calculate the number of cycles for proper timing 176 | //// multiply frequency, which is really cycles per second, by the number of seconds to 177 | //// get the total number of cycles to produce 178 | for (long i = 0; i < numCycles; i++) { // for the calculated length of time... 179 | digitalWrite(targetPin, HIGH); // write the buzzer pin high to push out the diaphram 180 | delayMicroseconds(delayValue); // wait for the calculated delay value 181 | digitalWrite(targetPin, LOW); // write the buzzer pin low to pull back the diaphram 182 | delayMicroseconds(delayValue); // wait again or the calculated delay value 183 | } 184 | digitalWrite(13, LOW); 185 | } 186 | -------------------------------------------------------------------------------- /bluetooth-car/bluetooth-car.ino: -------------------------------------------------------------------------------- 1 | #define ENA_PIN 10 2 | #define ENB_PIN 11 3 | #define IN1_PIN 3 4 | #define IN2_PIN 2 5 | #define IN3_PIN 5 6 | #define IN4_PIN 4 7 | #define F_LIGHT_PIN 7 8 | #define R_LIGHT_PIN 6 9 | #define BT_RX_PIN 9 10 | #define BT_TX_PIN 8 11 | #define BUZZ_PIN 13 12 | 13 | #define CRS_PIN A0 14 | #define CRS_BASE 512 15 | #define CRS_PCT 25 16 | 17 | #define MIN_SPEED 96 18 | #define MAX_SPEED 255 19 | 20 | #include 21 | SoftwareSerial bt(BT_RX_PIN, BT_TX_PIN); 22 | 23 | void setup() { 24 | pinMode(ENA_PIN, OUTPUT); 25 | pinMode(ENB_PIN, OUTPUT); 26 | pinMode(IN1_PIN, OUTPUT); 27 | pinMode(IN2_PIN, OUTPUT); 28 | pinMode(IN3_PIN, OUTPUT); 29 | pinMode(IN4_PIN, OUTPUT); 30 | pinMode(F_LIGHT_PIN, OUTPUT); 31 | pinMode(R_LIGHT_PIN, OUTPUT); 32 | pinMode(BT_RX_PIN, INPUT); 33 | pinMode(BT_TX_PIN, OUTPUT); 34 | 35 | Serial.begin(9600); 36 | bt.begin(9600); 37 | 38 | info("Initialization complete ;)"); 39 | } 40 | 41 | byte _spd = MAX_SPEED; 42 | byte _spdc = 10; 43 | 44 | char btcmd; 45 | 46 | const unsigned int buzzint = 500; 47 | const unsigned int buzzfreq = 1000; 48 | bool buzzer = false; 49 | 50 | bool f_light = false; 51 | bool r_light = false; 52 | 53 | const unsigned int xint = 200; 54 | bool xtra = false; 55 | bool xtac = true; 56 | unsigned long xtime = millis(); 57 | 58 | void loop() { 59 | if (bt.available()) { 60 | btcmd = (char)bt.read(); 61 | 62 | _spd = calculateSpeed(_spdc); 63 | 64 | switch (btcmd) { 65 | case 'D': 66 | fullStop(); 67 | break; 68 | case 'S': 69 | stopMovement(); 70 | break; 71 | case 'F': 72 | goForward(_spd); 73 | break; 74 | case 'I': 75 | goForwardLeft(_spd); 76 | break; 77 | case 'G': 78 | goForwardRight(_spd); 79 | break; 80 | case 'B': 81 | goBackward(_spd); 82 | break; 83 | case 'J': 84 | goBackwardLeft(_spd); 85 | break; 86 | case 'H': 87 | goBackwardRight(_spd); 88 | break; 89 | case 'R': 90 | turnRight(_spd); 91 | break; 92 | case 'L': 93 | turnLeft(_spd); 94 | break; 95 | case '0': 96 | _spdc = 0; 97 | break; 98 | case '1': 99 | _spdc = 1; 100 | break; 101 | case '2': 102 | _spdc = 2; 103 | break; 104 | case '3': 105 | _spdc = 3; 106 | break; 107 | case '4': 108 | _spdc = 4; 109 | break; 110 | case '5': 111 | _spdc = 5; 112 | break; 113 | case '6': 114 | _spdc = 6; 115 | break; 116 | case '7': 117 | _spdc = 7; 118 | break; 119 | case '8': 120 | _spdc = 8; 121 | break; 122 | case '9': 123 | _spdc = 9; 124 | break; 125 | case 'q': 126 | _spdc = 10; 127 | break; 128 | case 'V': 129 | buzzer = true; 130 | break; 131 | case 'v': 132 | buzzer = false; 133 | break; 134 | case 'W': 135 | digitalWrite(F_LIGHT_PIN, HIGH); 136 | f_light = true; 137 | break; 138 | case 'w': 139 | digitalWrite(F_LIGHT_PIN, LOW); 140 | f_light = false; 141 | break; 142 | case 'U': 143 | digitalWrite(R_LIGHT_PIN, HIGH); 144 | r_light = true; 145 | break; 146 | case 'u': 147 | digitalWrite(R_LIGHT_PIN, LOW); 148 | r_light = false; 149 | break; 150 | case 'X': 151 | xtra = true; 152 | break; 153 | case 'x': 154 | xtra = false; 155 | break; 156 | default: 157 | Serial.print("Unhandled command: "); Serial.println(btcmd); 158 | break; 159 | } 160 | } 161 | 162 | if (buzzer) { 163 | tone(BUZZ_PIN, buzzfreq); 164 | delay(buzzint); 165 | noTone(BUZZ_PIN); 166 | 167 | buzzer = false; 168 | } 169 | 170 | if (xtra) { 171 | if (millis() - xtime > xint) { 172 | xtime = millis(); 173 | xtac = !xtac; 174 | } 175 | 176 | if (xtac) { 177 | if (f_light) { 178 | digitalWrite(F_LIGHT_PIN, HIGH); 179 | } 180 | if (r_light) { 181 | digitalWrite(R_LIGHT_PIN, LOW); 182 | } 183 | } else { 184 | if (f_light) { 185 | digitalWrite(F_LIGHT_PIN, LOW); 186 | } 187 | if (r_light) { 188 | digitalWrite(R_LIGHT_PIN, HIGH); 189 | } 190 | } 191 | } else { 192 | if (f_light) { 193 | digitalWrite(F_LIGHT_PIN, HIGH); 194 | } else { 195 | digitalWrite(F_LIGHT_PIN, LOW); 196 | } 197 | if (r_light) { 198 | digitalWrite(R_LIGHT_PIN, HIGH); 199 | } else { 200 | digitalWrite(R_LIGHT_PIN, LOW); 201 | } 202 | } 203 | 204 | delay(10); 205 | } 206 | 207 | void info(String txt) { 208 | Serial.print("INFO: "); Serial.println(txt); 209 | } 210 | 211 | void goForward(byte mspd) { 212 | int crs = analogRead(CRS_PIN); 213 | 214 | byte rspd = crs2cR(crs) * mspd / 100; 215 | byte lspd = crs2cL(crs) * mspd / 100; 216 | 217 | digitalWrite(IN1_PIN, LOW); 218 | digitalWrite(IN2_PIN, HIGH); 219 | digitalWrite(IN3_PIN, LOW); 220 | digitalWrite(IN4_PIN, HIGH); 221 | analogWrite(ENA_PIN, rspd); 222 | analogWrite(ENB_PIN, lspd); 223 | } 224 | 225 | void goForwardRight(byte mspd) { 226 | digitalWrite(IN1_PIN, LOW); 227 | digitalWrite(IN2_PIN, HIGH); 228 | digitalWrite(IN3_PIN, LOW); 229 | digitalWrite(IN4_PIN, HIGH); 230 | analogWrite(ENA_PIN, mspd); 231 | analogWrite(ENB_PIN, 0); 232 | } 233 | 234 | void goForwardLeft(byte mspd) { 235 | digitalWrite(IN1_PIN, LOW); 236 | digitalWrite(IN2_PIN, HIGH); 237 | digitalWrite(IN3_PIN, LOW); 238 | digitalWrite(IN4_PIN, HIGH); 239 | analogWrite(ENA_PIN, 0); 240 | analogWrite(ENB_PIN, mspd); 241 | } 242 | 243 | void goBackward(byte mspd) { 244 | digitalWrite(IN1_PIN, HIGH); 245 | digitalWrite(IN2_PIN, LOW); 246 | digitalWrite(IN3_PIN, HIGH); 247 | digitalWrite(IN4_PIN, LOW); 248 | analogWrite(ENA_PIN, mspd); 249 | analogWrite(ENB_PIN, mspd); 250 | } 251 | 252 | void goBackwardRight(byte mspd) { 253 | digitalWrite(IN1_PIN, HIGH); 254 | digitalWrite(IN2_PIN, LOW); 255 | digitalWrite(IN3_PIN, HIGH); 256 | digitalWrite(IN4_PIN, LOW); 257 | analogWrite(ENA_PIN, mspd); 258 | analogWrite(ENB_PIN, 0); 259 | } 260 | 261 | void goBackwardLeft(byte mspd) { 262 | digitalWrite(IN1_PIN, HIGH); 263 | digitalWrite(IN2_PIN, LOW); 264 | digitalWrite(IN3_PIN, HIGH); 265 | digitalWrite(IN4_PIN, LOW); 266 | analogWrite(ENA_PIN, 0); 267 | analogWrite(ENB_PIN, mspd); 268 | } 269 | 270 | void turnRight(byte mspd) { 271 | digitalWrite(IN1_PIN, LOW); 272 | digitalWrite(IN2_PIN, HIGH); 273 | digitalWrite(IN3_PIN, HIGH); 274 | digitalWrite(IN4_PIN, LOW); 275 | analogWrite(ENA_PIN, mspd); 276 | analogWrite(ENB_PIN, mspd); 277 | } 278 | 279 | void turnLeft(byte mspd) { 280 | digitalWrite(IN1_PIN, HIGH); 281 | digitalWrite(IN2_PIN, LOW); 282 | digitalWrite(IN3_PIN, LOW); 283 | digitalWrite(IN4_PIN, HIGH); 284 | analogWrite(ENA_PIN, mspd); 285 | analogWrite(ENB_PIN, mspd); 286 | } 287 | 288 | void stopMovement() { 289 | digitalWrite(IN1_PIN, LOW); 290 | digitalWrite(IN2_PIN, LOW); 291 | digitalWrite(IN3_PIN, LOW); 292 | digitalWrite(IN4_PIN, LOW); 293 | analogWrite(ENA_PIN, 0); 294 | analogWrite(ENB_PIN, 0); 295 | } 296 | 297 | void fullStop() { 298 | stopMovement(); 299 | 300 | buzzer = false; 301 | 302 | f_light = false; 303 | r_light = false; 304 | 305 | xtra = false; 306 | } 307 | 308 | byte calculateSpeed(byte spdc) { 309 | if (spdc == 10) { 310 | return MAX_SPEED; 311 | } 312 | 313 | byte cspd = MIN_SPEED + (MAX_SPEED - MIN_SPEED) / 10 * spdc; 314 | 315 | return cspd; 316 | } 317 | 318 | byte crs2cR(int crs) { 319 | if (crs == 0) { 320 | return 100; 321 | } 322 | 323 | if (crs >= 500) { 324 | crs = CRS_BASE; 325 | } 326 | 327 | float q = CRS_BASE - crs; 328 | float p = q / CRS_BASE * CRS_PCT; 329 | 330 | return 100 - p; 331 | } 332 | 333 | byte crs2cL(int crs) { 334 | if (crs == 0) { 335 | return 100; 336 | } 337 | 338 | if (crs < 524) { 339 | crs = CRS_BASE; 340 | } 341 | 342 | float q = crs - CRS_BASE; 343 | float p = q / CRS_BASE * CRS_PCT; 344 | 345 | return 100 - p; 346 | } 347 | -------------------------------------------------------------------------------- /smart-car/smart-car.ino: -------------------------------------------------------------------------------- 1 | #define DEBUG 2 | 3 | #define SENSOR_DELAY 10 4 | 5 | #define MAX_QUIRKS 3 6 | #define MAX_TURNS 10 7 | 8 | #define ENA_PIN 10 9 | #define ENB_PIN 11 10 | #define IN1_PIN 2 11 | #define IN2_PIN 3 12 | #define IN3_PIN 5 13 | #define IN4_PIN 4 14 | 15 | #define LEDR_PIN 6 16 | #define LEDL_PIN 7 17 | 18 | #define ECHOR_PIN A0 19 | #define TRIGR_PIN A1 20 | #define ECHOC_PIN A2 21 | #define TRIGC_PIN A3 22 | #define ECHOL_PIN A4 23 | #define TRIGL_PIN A5 24 | 25 | #include "local.h" 26 | 27 | #ifdef RPCT_OVERRIDE 28 | const int rPct = RPCT_OVERRIDE; 29 | #else 30 | const int rPct = 100; 31 | #endif 32 | 33 | #ifdef LPCT_OVERRIDE 34 | const int lPct = LPCT_OVERRIDE; 35 | #else 36 | const int lPct = 100; 37 | #endif 38 | 39 | const byte initSpd = 128; // speed to start on the first loop to gain acceleration 40 | const byte moveSpd = 72; // speed to continue after first loop passed and we gained initial acceleration 41 | 42 | const int turnDist = 40; // distance in cm on which normal turn will be triggered to avoid collision 43 | const int spinDist = 15; // distance in cm on which obstacle is considered too close and radical spin or pulling back will be triggered 44 | 45 | const char _FWD = 'f'; 46 | const char _RHT = 'r'; 47 | const char _LFT = 'l'; 48 | const char _SPR = 'R'; 49 | const char _SPL = 'L'; 50 | const char _BCK = 'b'; 51 | 52 | // sensor distances and movement direction saved from the previous loop 53 | int pcd; 54 | int prd; 55 | int pld; 56 | char pdir; 57 | 58 | // quirk counter - triggers "circuir breaker" on reaching MAX_QUIRKS 59 | int qc = 0; 60 | 61 | // turns counter - triggers "direction adjustment" on reaching MAX_TURNS 62 | int tc = 0; 63 | 64 | void setup() { 65 | #ifdef DEBUG 66 | Serial.begin(9600); 67 | Serial.println("---"); 68 | Serial.print("> rPct: "); Serial.print(rPct); Serial.print(" lPct: "); Serial.println(lPct); 69 | Serial.println("---"); 70 | #endif 71 | 72 | pinMode(ENA_PIN, OUTPUT); 73 | pinMode(ENB_PIN, OUTPUT); 74 | pinMode(IN1_PIN, OUTPUT); 75 | pinMode(IN2_PIN, OUTPUT); 76 | pinMode(IN3_PIN, OUTPUT); 77 | pinMode(IN4_PIN, OUTPUT); 78 | 79 | pinMode(LEDR_PIN, OUTPUT); 80 | pinMode(LEDL_PIN, OUTPUT); 81 | 82 | pinMode(ECHOR_PIN, INPUT); 83 | pinMode(TRIGR_PIN, OUTPUT); 84 | pinMode(ECHOC_PIN, INPUT); 85 | pinMode(TRIGC_PIN, OUTPUT); 86 | pinMode(ECHOL_PIN, INPUT); 87 | pinMode(TRIGL_PIN, OUTPUT); 88 | } 89 | 90 | void debug(char dir, byte spd, int cdist, int rdist, int ldist) { 91 | Serial.print("> "); Serial.print(dir); 92 | Serial.print(" @ "); Serial.print(spd); 93 | Serial.print(" | C: "); Serial.print(cdist); 94 | Serial.print(" | R: "); Serial.print(rdist); 95 | Serial.print(" | L: "); Serial.print(ldist); 96 | Serial.print(" | TC: "); Serial.print(tc); 97 | Serial.println(""); 98 | } 99 | 100 | int calculateDistance(int trig, int echo) { 101 | digitalWrite(trig, LOW); 102 | delayMicroseconds(2); 103 | digitalWrite(trig, HIGH); 104 | delayMicroseconds(10); 105 | digitalWrite(trig, LOW); 106 | 107 | int duration = pulseIn(echo, HIGH); 108 | 109 | return duration * 0.034 / 2; 110 | } 111 | 112 | int cDist() { 113 | return calculateDistance(TRIGC_PIN, ECHOC_PIN); 114 | } 115 | 116 | int rDist() { 117 | return calculateDistance(TRIGR_PIN, ECHOR_PIN); 118 | } 119 | 120 | int lDist() { 121 | return calculateDistance(TRIGL_PIN, ECHOL_PIN); 122 | } 123 | 124 | char chooseDirection(int cdist, int rdist, int ldist) { 125 | // below or equal "0" is a sensor quirk ... 126 | if ((cdist <= 0) or (rdist <= 0) or (ldist <= 0)) { 127 | // ... continue with previously chosen direction before reaching MAX_QUIRKS 128 | if (qc < MAX_QUIRKS) { 129 | qc++; 130 | return pdir; 131 | } 132 | // ... pull back after reaching MAX_QUIRKS 133 | qc = 0; 134 | return _BCK; 135 | } else { 136 | // reset quirk counter if sensor quirk is not the case 137 | qc = 0; 138 | } 139 | 140 | // we got stuck: spin left or right ... 141 | if ((cdist == pcd) and (rdist == prd) and (ldist == pld)) { 142 | // ... or just pull back if we already were spinning 143 | if ((pdir == _SPR) or (pdir == _SPL)) { 144 | return _BCK; 145 | } 146 | if (rdist < ldist) { 147 | return _SPL; 148 | } 149 | return _SPR; 150 | } 151 | 152 | // obstacle too close to center sensor: pull back to avoid collision ... 153 | if (cdist < spinDist) { 154 | return _BCK; 155 | } 156 | // ... or spin left or right in case of proximity with lateral sensors ... 157 | if (rdist < spinDist) { 158 | // ... or just pull back if we were already spinning left 159 | if (pdir == _SPL) { 160 | return _BCK; 161 | } 162 | return _SPL; 163 | } 164 | if (ldist < spinDist) { 165 | // ... or just pull back if we were already spinning right 166 | if (pdir == _SPR) { 167 | return _BCK; 168 | } 169 | return _SPR; 170 | } 171 | 172 | // don't keep turning right or left more than one loop step 173 | if ((pdir == _RHT) or (pdir == _LFT)) { 174 | return _FWD; 175 | } 176 | 177 | // when obstacle detected: decide to turn left or right 178 | if (cdist < turnDist) { 179 | if (rdist < ldist) { 180 | return _LFT; 181 | } 182 | return _RHT; 183 | } 184 | if (rdist < turnDist) { 185 | return _LFT; 186 | } 187 | if (ldist < turnDist) { 188 | return _RHT; 189 | } 190 | 191 | // no obstacles: move forward by default 192 | return _FWD; 193 | } 194 | 195 | char adjustDirection(char dir) { 196 | // not moving forward, neither turning currently 197 | if (dir != _FWD and dir != _RHT and dir != _LFT) { 198 | tc = 0; 199 | return dir; 200 | } 201 | 202 | // moving forward currently after anything BUT turning 203 | if (dir == _FWD and (pdir != _RHT and pdir != _LFT)) { 204 | tc = 0; 205 | return dir; 206 | } 207 | 208 | // turning currently after anything BUT moving forward or turning 209 | if ((dir == _RHT or dir == _LFT) and (pdir != _FWD and pdir != _RHT and pdir != _LFT)) { 210 | tc = 0; 211 | return dir; 212 | } 213 | 214 | tc++; 215 | 216 | // too many turn/forward sequences: pull back! 217 | if (tc >= MAX_TURNS) { 218 | tc = 0; 219 | return _BCK; 220 | } 221 | 222 | // by default: preserve direction 223 | return dir; 224 | } 225 | 226 | int getSpeed(char dir) { 227 | if (dir == pdir) { 228 | return moveSpd; 229 | } 230 | 231 | if (dir == _RHT) { 232 | return moveSpd; 233 | } 234 | 235 | if (dir == _LFT) { 236 | return moveSpd; 237 | } 238 | 239 | return initSpd; 240 | } 241 | 242 | void goForward(int spd) { 243 | digitalWrite(IN1_PIN, LOW); 244 | digitalWrite(IN2_PIN, HIGH); 245 | digitalWrite(IN3_PIN, LOW); 246 | digitalWrite(IN4_PIN, HIGH); 247 | analogWrite(ENA_PIN, spd * lPct / 100); 248 | analogWrite(ENB_PIN, spd * rPct / 100); 249 | 250 | digitalWrite(LEDR_PIN, LOW); 251 | digitalWrite(LEDL_PIN, LOW); 252 | } 253 | 254 | void goRight(int spd) { 255 | digitalWrite(IN1_PIN, LOW); 256 | digitalWrite(IN2_PIN, HIGH); 257 | digitalWrite(IN3_PIN, LOW); 258 | digitalWrite(IN4_PIN, HIGH); 259 | analogWrite(ENA_PIN, spd); 260 | analogWrite(ENB_PIN, 0); 261 | 262 | digitalWrite(LEDR_PIN, HIGH); 263 | digitalWrite(LEDL_PIN, LOW); 264 | } 265 | 266 | void goLeft(int spd) { 267 | digitalWrite(IN1_PIN, LOW); 268 | digitalWrite(IN2_PIN, HIGH); 269 | digitalWrite(IN3_PIN, LOW); 270 | digitalWrite(IN4_PIN, HIGH); 271 | analogWrite(ENA_PIN, 0); 272 | analogWrite(ENB_PIN, spd); 273 | 274 | digitalWrite(LEDR_PIN, LOW); 275 | digitalWrite(LEDL_PIN, HIGH); 276 | } 277 | 278 | void spinRight(int spd) { 279 | digitalWrite(IN1_PIN, LOW); 280 | digitalWrite(IN2_PIN, HIGH); 281 | digitalWrite(IN3_PIN, HIGH); 282 | digitalWrite(IN4_PIN, LOW); 283 | analogWrite(ENA_PIN, spd); 284 | analogWrite(ENB_PIN, spd); 285 | 286 | digitalWrite(LEDR_PIN, HIGH); 287 | digitalWrite(LEDL_PIN, LOW); 288 | } 289 | 290 | void spinLeft(int spd) { 291 | digitalWrite(IN1_PIN, HIGH); 292 | digitalWrite(IN2_PIN, LOW); 293 | digitalWrite(IN3_PIN, LOW); 294 | digitalWrite(IN4_PIN, HIGH); 295 | analogWrite(ENA_PIN, spd); 296 | analogWrite(ENB_PIN, spd); 297 | 298 | digitalWrite(LEDR_PIN, LOW); 299 | digitalWrite(LEDL_PIN, HIGH); 300 | } 301 | 302 | void goBackward(int spd) { 303 | digitalWrite(IN1_PIN, HIGH); 304 | digitalWrite(IN2_PIN, LOW); 305 | digitalWrite(IN3_PIN, HIGH); 306 | digitalWrite(IN4_PIN, LOW); 307 | analogWrite(ENA_PIN, spd); 308 | analogWrite(ENB_PIN, spd); 309 | 310 | digitalWrite(LEDR_PIN, HIGH); 311 | digitalWrite(LEDL_PIN, HIGH); 312 | } 313 | 314 | void stopMovement(int spd) { 315 | digitalWrite(IN1_PIN, LOW); 316 | digitalWrite(IN2_PIN, LOW); 317 | digitalWrite(IN3_PIN, LOW); 318 | digitalWrite(IN4_PIN, LOW); 319 | analogWrite(ENA_PIN, 0); 320 | analogWrite(ENB_PIN, 0); 321 | } 322 | 323 | void loop() { 324 | int cd = cDist(); 325 | delay(SENSOR_DELAY); 326 | int rd = rDist(); 327 | delay(SENSOR_DELAY); 328 | int ld = lDist(); 329 | delay(SENSOR_DELAY); 330 | 331 | char dir = chooseDirection(cd, rd, ld); 332 | 333 | dir = adjustDirection(dir); 334 | 335 | byte spd = getSpeed(dir); 336 | 337 | #ifdef DEBUG 338 | debug(dir, spd, cd, rd, ld); 339 | #endif 340 | 341 | switch (dir) { 342 | case _FWD: 343 | goForward(spd); 344 | break; 345 | case _RHT: 346 | goRight(spd); 347 | break; 348 | case _LFT: 349 | goLeft(spd); 350 | break; 351 | case _SPR: 352 | spinRight(spd); 353 | break; 354 | case _SPL: 355 | spinLeft(spd); 356 | break; 357 | case _BCK: 358 | goBackward(spd); 359 | break; 360 | default: 361 | stopMovement(spd); 362 | break; 363 | } 364 | 365 | if (dir == _BCK) { 366 | delay(50); 367 | } 368 | 369 | prd = rd; 370 | pcd = cd; 371 | pld = ld; 372 | pdir = dir; 373 | } 374 | --------------------------------------------------------------------------------