Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
hwhardsoft
Published © GPL3+

Crazy Arduino Hose Display

How to make a unique display from a transparent hose and an Arduino UNO.

AdvancedShowcase (no instructions)22,653
Crazy Arduino Hose Display

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×1
Saint Smart Motorshield
×1
ArduiBox Enclosure
×1
DC Power Supply
×1
transparent hose, 4mm diameter, 5m long
×1

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Schematics

Schematic Overview

Block diagram

Code

Firmware

C/C++
for Arduino Uno
/*
 *  hose display for Maker Faire Hannover 2016 
 *  Version 1.0
 *  Copyright (C) 2016  Hartmut Wendt  www.hwhardsoft.de
 *  
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <AFMotor.h>
#include <font5x7.h>

#define DEBOUNCE 10  // button debouncer, how many ms to debounce, 5+ ms is usually plenty

// here is where we define the buttons that we'll use. button "1" is the first, button "6" is the 6th, etc
byte buttons[] = {14, 15, 17, 18, 19}; // the analog 0-5 pins are also known as 14-19
// This handy macro lets us determine how big the array up above is, by checking the size
#define NUMBUTTONS sizeof(buttons)
// we will track if a button is just pressed, just released, or 'currently pressed'
byte pressed[NUMBUTTONS], justpressed[NUMBUTTONS], justreleased[NUMBUTTONS];
byte previous_keystate[NUMBUTTONS], current_keystate[NUMBUTTONS];

unsigned char  pump_air_cnt;
unsigned char  pump_liquid_cnt;
unsigned char  last_pixel;
unsigned char  display_row[8];

const unsigned char test_pattern[] = {
  0xC0, 0xC0, 0x00, 
  0x40, 0x3C, 0x02, 
  0x40, 0x3C, 0x02, 
  0x40, 0x3C, 0x02,
  0x40, 0x3C, 0x02, 
  0x40, 0x3C, 0x02, 
  0x40, 0x3C, 0x02, 
};



const unsigned char Maker_pattern[] = {
  0xC0, 0xC0, 0xC0,  
  0x89, 0x92, 0xEE, 
  0xDA, 0x54, 0x89, 
  0xAB, 0xD8, 0xCE, 
  0x8A, 0x54, 0x89, 
  0x8A, 0x52, 0xE9, 
};


const unsigned char Faire_pattern[] = {
  0xC0, 0xC0, 0xC0,  
  0x73, 0x3B, 0x9C, 
  0x44, 0x92, 0x50, 
  0x77, 0x93, 0x9C, 
  0x44, 0x92, 0x50, 
  0x44, 0xBA, 0x5C, 
};


// program modes
enum {
  PM_stop,      // program mode stop
  PM_pump_air,  // program mode pump air runs endless
  PM_pump_liquid, // program mode pump liquid runs endless
  PM_demo,      // program mode full automatic demo
  PM_demo2,      // program mode full automatic demo
  PM_test,      // shows test pattern
  PM_wait,      // wait 1 min in demo
  PM_wait2,      // wait 1 min in demo

};

// set pin numbers:
#define buttonStop 0
#define buttonDemo 1
#define buttonPumpAir 4
#define buttonPumpLiquid 3
#define buttonTest 2

#define pixel_liquid 0
#define pixel_air 1

#define RIGHT 0
#define LEFT 1
#define space_picture_start 10
//#define space_picture_loop 30
//#define space_picture_end 62
#define space_picture_loop 7
#define space_picture_end 13

#define pump_speed 80    //80
#define pump_steps 200
#define pump_delay 100     //100



AF_Stepper pump_liquid(pump_steps, 2);
AF_Stepper pump_air(pump_steps, 1);

unsigned char PMode = PM_stop;
unsigned int wait_cnt;
/*
  void draw_pixel_air() {
  if (pump_air_cnt < 2) {
    pump_air.step(66,  BACKWARD, SINGLE);
    pump_air_cnt++;
  } else {
    pump_air.step(68,  BACKWARD,SINGLE);
    pump_air_cnt = 0;
  }
  pump_air.release();
  delay(5);
  }

  void draw_pixel_liquid() {
  if (pump_liquid_cnt < 2) {
    pump_liquid.step(66,  BACKWARD, SINGLE);
    pump_liquid_cnt++;
  } else {
    pump_liquid.step(68,  BACKWARD, SINGLE);
    pump_liquid_cnt = 0;
  }
  pump_liquid.release();
  delay(5);
  }
*/

void draw_pixel_air() {
  pump_air.step(200,  FORWARD, DOUBLE);
  pump_air.release();
  //delay(5);
}

void draw_pixel_liquid() {
  pump_liquid.step(200,  FORWARD, DOUBLE);
  pump_liquid.release();
  //delay(5);
}



void copy_line(unsigned char ucline, const unsigned char *pattern) {
  unsigned char uc1;
  for (uc1 = 0; uc1 < 3; uc1++) {
    display_row[uc1] = pattern[(ucline * 3) + uc1];
  }

}

void draw_line(unsigned ucdirection) {
  unsigned char uc1, uc2;
  if (ucdirection == LEFT) {
    for (uc1 = 0; uc1 < 3; uc1++)
      for (uc2 = 0; uc2 < 8; uc2++) {
        if ((display_row[uc1] << uc2) & 0x80) {
          if (last_pixel != pixel_liquid) delay(pump_delay);
          draw_pixel_liquid();
          last_pixel = pixel_liquid;
        } else {
          if (last_pixel != pixel_air) delay(pump_delay);  
          draw_pixel_air();
          last_pixel = pixel_air;
        }
      }

  } else {
    for (uc1 = 3; uc1 > 0; uc1--)
      for (uc2 = 0; uc2 < 8; uc2++) {
        if ((display_row[uc1 - 1] >> uc2) & 0x01) {
          if (last_pixel != pixel_liquid) delay(pump_delay);
          draw_pixel_liquid();
          last_pixel = pixel_liquid;
        } else {
          if (last_pixel != pixel_air) delay(pump_delay);  
          draw_pixel_air();
          last_pixel = pixel_air;
        }
      }
  }


}

void draw_empty_space(unsigned char ucSpace) {
  unsigned char uc1;
  for (uc1 = 0; uc1 < ucSpace; uc1++) draw_pixel_air();
}


void draw_picture(const unsigned char *pattern) {
  //draw_empty_space(space_picture_start);
  copy_line(0, pattern);
  draw_line(RIGHT);
  draw_empty_space(space_picture_loop);
  copy_line(1, pattern);
  draw_line(LEFT);
  draw_empty_space(space_picture_loop);
  copy_line(2, pattern);
  draw_line(RIGHT);
  draw_empty_space(space_picture_loop);
  copy_line(3, pattern);
  draw_line(LEFT);
  draw_empty_space(space_picture_loop);
  copy_line(4, pattern);
  draw_line(RIGHT);
  draw_empty_space(space_picture_loop);
  copy_line(5, pattern);
  draw_line(LEFT);
  draw_empty_space(space_picture_end);
}


void check_switches()
{
  static byte previousstate[NUMBUTTONS];
  static byte currentstate[NUMBUTTONS];
  static long lasttime;
  byte index;
  if (millis() < lasttime) {
    lasttime = millis(); // we wrapped around, lets just try again
  }

  if ((lasttime + DEBOUNCE) > millis()) {
    return; // not enough time has passed to debounce
  }
  // ok we have waited DEBOUNCE milliseconds, lets reset the timer
  lasttime = millis();

  for (index = 0; index < NUMBUTTONS; index++) {
    justpressed[index] = 0;       // when we start, we clear out the "just" indicators
    justreleased[index] = 0;

    currentstate[index] = digitalRead(buttons[index]);   // read the button
    if (currentstate[index] == previousstate[index]) {
      if ((pressed[index] == HIGH) && (currentstate[index] == HIGH)) {
        // just pressed
        justpressed[index] = 1;
      }
      else if ((pressed[index] == LOW) && (currentstate[index] == LOW)) {
        // just released
        justreleased[index] = 1;
      }
      pressed[index] = !currentstate[index];  // remember, digital HIGH means NOT pressed
    }
    //Serial.println(pressed[index], DEC);
    previousstate[index] = currentstate[index];   // keep a running tally of the buttons
  }
}

byte thisSwitch_justPressed() {
  byte thisSwitch = 255;
  check_switches();  //check the switches &amp; get the current state
  for (byte i = 0; i < NUMBUTTONS; i++) {
    current_keystate[i] = justpressed[i];
    if (current_keystate[i] != previous_keystate[i]) {
      if (current_keystate[i]) thisSwitch = i;
    }
    previous_keystate[i] = current_keystate[i];
  }
  return thisSwitch;
}


void setup() {
  byte i;
  Serial.begin(9600); // set up Serial library at 9600 bps
  Serial.println("bit.flow!");
  // set input pins for keys

  pump_liquid.setSpeed(pump_speed); // 100 rpm
  pump_air.setSpeed(pump_speed); // 100 rpm
  pump_liquid.release();
  pump_air.release();

  pump_air_cnt = 0;
  pump_liquid_cnt = 0;

  // Make input on switch pins
  for (i = 0; i < NUMBUTTONS; i++) {
    pinMode(buttons[i], INPUT);
  }


}

void loop() {
  byte thisSwitch = thisSwitch_justPressed();
  switch (thisSwitch)
  {
    case buttonStop:
      Serial.println("switch Stop just pressed");
      PMode = PM_stop;
      break;

    case buttonDemo:
      Serial.println("switch demo just pressed");
      PMode = PM_demo;
      break;

    case buttonTest:
      Serial.println("switch test pattern just pressed");
      PMode = PM_test;
      break;

    case buttonPumpLiquid:
      Serial.println("switch pump liquid just pressed");
      PMode = PM_pump_liquid;
      break;

    case buttonPumpAir:
      Serial.println("switch pump air just pressed");
      PMode = PM_pump_air;
      break;


  }


  switch (PMode) {
    case PM_stop:
      pump_air.release();
      pump_liquid.release();
      break;

    case PM_pump_air:
      draw_pixel_air();
      break;

    case PM_pump_liquid:
      draw_pixel_liquid();
      break;

    case PM_test:
      draw_picture(test_pattern);
      PMode = PM_stop;
      break;


    case PM_demo:
      draw_picture(Maker_pattern);
      wait_cnt = 0;
      PMode = PM_wait;
      break;
 
    case PM_demo2:
      draw_picture(Faire_pattern);
      wait_cnt = 0;
      PMode = PM_wait2;
      break;

    case PM_wait:
      delay(10);
      wait_cnt++;      
      if (wait_cnt > 6000) PMode = PM_demo2;
      break;
  
    case PM_wait2:
      delay(10);
      wait_cnt++;      
      if (wait_cnt > 6000) PMode = PM_demo;
      break;
  
  }



}

Credits

hwhardsoft

hwhardsoft

17 projects • 76 followers

Comments