Go Down

Topic: Need help with NEOPIXEL ring on project, can pay (Read 4644 times) previous topic - next topic

staticsea90

Jan 30, 2017, 10:14 pm Last Edit: Jan 31, 2017, 12:24 am by staticsea90
I am new to the arduino world, but I have decided for my first project to build a simple drink dispensing  machine using an arduino, LCD shield, NEOPIXEL 24 RGB ring, and a few peristaltic pumps. I have managed to come up with a working code to control everything except the NEOPIXEL ring. I have tried borrowing bits of code from the examples in the library, but I have not been able to figure out how to make them work in my project. I was hoping someone here would be able to help me with writing a bit of code.

Can pay a reasonable amount for help.


Here is my code with comments explaining what I am trying to do...

#include <Wire.h>
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();


int whiskeyVolume = 0;
int vodkaVolume = 0;
float pump1Run = 0;
float pump2Run = 0;
int pump1Analog = A0;
int pump1Digital = 9;
int pump2Analog = A1;
int pump2Digital = 10;



void setup() {
  Serial.begin(9600);
  lcd.begin(16, 2);
  lcd.print("Drink Machine");
  delay(1000);
  lcd.setCursor(0,1);
  lcd.print("Version 1.0");
  delay(4000);
 
  lcd.clear();                 
  lcd.print("Hit Left Button");
  lcd.setCursor(0,1);
  lcd.print("To Purge Pump");
 

uint8_t i=0;

}
void loop() {
 

    uint8_t buttons = lcd.readButtons();

    pump1Run = (vodkaVolume* 44.4)*1200;
    pump2Run = (whiskeyVolume* 44.4)*1200;
   

    if (buttons) {
     lcd.clear();
     lcd.setCursor(0,0);

    if (buttons & BUTTON_LEFT){   
     
     
      lcd.print("Purging Pump For");
      lcd.setCursor(0,1);
      lcd.print("10 Seconds...");

      analogWrite(pump1Analog,255);
      digitalWrite(pump1Digital,HIGH);
     
      delay(10000);

      analogWrite(pump1Analog,0);
      digitalWrite(pump1Digital,LOW);

      analogWrite(pump2Analog,255);
      digitalWrite(pump2Digital,HIGH);
     
      delay(10000);

      analogWrite(pump2Analog,0);
      digitalWrite(pump2Digital,LOW);
     
      lcd.clear();
      lcd.print("Purge Finished");
      delay(3000);
      lcd.clear();
      lcd.print("Hit Up Vodka");    // START NEOPIXEL TRACING/CRAWLING LIGHTS, CONTINUE
                                               //UNTIL PUMPING
      lcd.setCursor(0,1);
      lcd.print("Down For Whiskey");
      }
     
   

      if (buttons & BUTTON_UP) {
      vodkaVolume = (vodkaVolume+1);
      lcd.print("Vodka");
      lcd.setCursor(8,1);
      lcd.print(vodkaVolume);
      lcd.setCursor(10,1);
      lcd.print("Shot");
      }
     


      if(buttons & BUTTON_DOWN){
      whiskeyVolume = (whiskeyVolume+1);
      lcd.print("Whiskey");
      lcd.setCursor(8,1);
      lcd.print(whiskeyVolume);
      lcd.setCursor(10,1);
      lcd.print("Shot");
      }

       if(buttons & BUTTON_RIGHT){
      lcd.print("Vodka 0 ");
      lcd.setCursor(0,1);
      lcd.print("Whiskey 0 ");
      whiskeyVolume = (whiskeyVolume=0);
      vodkaVolume = (vodkaVolume=0);
      }
     
      if(buttons & BUTTON_SELECT){  //START DIFFERENT NEOPIXL SEQUENCE WHILE PUMPING   
                                                     //(SOMETHING FAST AND BRIGHT)
       
      lcd.print("Dispensing");
      lcd.setCursor(0,1);
      lcd.print("Beverage...");

      analogWrite(pump1Analog,255);
      digitalWrite(pump1Digital,HIGH);
     
      delay(pump1Run);

      analogWrite(pump1Analog,0);
      digitalWrite(pump1Digital,LOW);


      analogWrite(pump2Analog,255);
      digitalWrite(pump2Digital,HIGH);
     
      delay(pump2Run);
     
      analogWrite(pump2Analog,0);
      digitalWrite(pump2Digital,LOW);
     
     

   
      lcd.clear();
      lcd.print("Enjoy!");
      delay(5000);
      lcd.clear();
      whiskeyVolume = (whiskeyVolume=0);
      vodkaVolume = (vodkaVolume=0)    ;
      lcd.print("Hit Up Vodka");       // RETURN TO NEOPIXEL TRACING/CRAWLING LIGHTS
      lcd.setCursor(0,1);
      lcd.print("Down For Whiskey");
      }
     
      lcd.readButtons();
      delay(350);
     
     
     
    }

  }

PaulS

The code you improperly posted does something. Care to clue us in on what it actually does? On what it does that you don't want? On what it doesn't do that you do want?
The art of getting good answers lies in asking good questions.

staticsea90

Sorry about posting the code incorrectly, new to the forum. I am using a LCD shield to control 2 pumps. The code works for that. Now I am trying to add code to control a NEOPIXEL ring. I would like the lights on the ring to come on in a tracing/crawling pattern after the pumps are purged, where I added the comment in the code. I want the lights to continue that pattern until the pumps come on to dispense the liquid. I added a comment in the code for that also. At that point I would like the lights to flash in a different pattern, doesn't matter what pattern as long as it is different, until the pumps turn off. Then have the lights return to the tracing/crawling pattern.

Hope that explains what I am hoping to accomplish a little better.

Is that something you would be able to help me with?

PaulS

Code: [Select]
      whiskeyVolume = (whiskeyVolume=0);
      vodkaVolume = (vodkaVolume=0)    ;

Please explain this code.

You need to scrap that code, and start over. When your fingers stray near the 'd', 'e', 'l', 'a', and/or 'y' keys, STOP and think.

You absolutely can not use delay() and make the NeoPixel ring do dynamic things at the same time.

Google state machine. That is what you need. Make a list of the states that you think you will encounter. Purging, Dispensing, etc.

Create a variable to hold the current state.

On any given pass through loop(), see if it is time to change state (Purging has run long enough) or if some external event has occurred that necessitates a change in state (customer wants a drink).

If it is necessary to change state, record when that happens, and make the necessary things happen (preferably by calling a function - StartPurging(), StopPurging(), StartDispensing(), StopDispensing(), etc.).

When you start thinking in terms of "What do I do now?", instead of "I need to wait...", you will never need to use delay() again. And, you will never run into the problem you are having now.
The art of getting good answers lies in asking good questions.

staticsea90

Thank you for your advice. Like I said, the code I have is already working. I'm not looking to change it. I would like to find a way to add code for NeoPixel to my existing code.

Does anyone else have any ideas?

alto777

Nice work. I can appreciate your reluctance to "scrap that code". Of course PaulS has given a correct response. This would be an ideal program to scrap and redo with state machines.

But. There are other ways forward.

The last Arduino I bought wasn't an Arduino, but a knock-off or counterfeit, I think I got 5 for $12, just had to wait for them to get here on the slow boat from wherever. My point is that

If you have some code (written or found) that does what you like with a neopixel ring I suggest you simply add another Arduino whose sole task is to run the lights. If it checked somewhat frequently for the availability of a character on the serial input, it could take such as a command from the pumping Arduino, a command that could signify which, if any, clever display pattern the ring should perform.

Then in your existing code you place sending a character over to the display Arduino at each juncture where the display pattern is to change or shut off.

This can be thoroughly and completely tested as two separate projects using the serial comms from the host PC during development. See that the Drink Machine spits out command characters at the right points. Watch the Display respond to chars you send it from the host PC. With the DrinkMachine hooked to the host PC, you could run the serial out line in parallel to the Display Arduino and still see characters in the comms window. When all looks good, let 'em talk to each other freed of the host PC. Gee, I'm getting thirsty here.

I would have found this idea offensive at one time. I certainly wouldn't build 10000 copies of the Drink Machines using 2 Arduinos - arguably the task calls for at most 1/10 of a single Arduino single handedly marching itself through multiple state machines and still finding plenty of time to do nothing but wait.

I'm older now. Not so much wiser, but days closer to death.

It is just a matter of where to spend the time. Your time is worth more than a second Arduino even if you went genuine. If you aren't looking to do much more than get the machine going and start the party, consider my idea. Even if it is just a prototype to convince your investors. You can be quite sure that one very cheap microcontroller would suffice and figure it out later, or, as you are able to pay, get the whole thing done. I think anyone taking money with a straight face to do this work for you would prolly be scrapping your code except insofar as it serves as a living specification of desired behaviour.

On the other hand, state machines are way cool and it is gratifying to see the result of figuring up a piece of code like the integrated Drink Machine would be, running on an Arduino Pro Mini. I think almost anyone should at least know how to spin them up. You can see browsing here that moving beyond delay() for blinking LEDs is an early and important step.

alto777


PaulMurrayCbr

In order for crawling lights to happen, something needs to "take care" of the lights by being called repeatedly.

Code: [Select]

void take_care_of_the_lights() {
  look at the time using millis();
  if(the lights need to be updated) {
    update the lights
  }
}


To do this in your code, write a function myDelay

Code: [Select]

void myDelay(uint32_t d) {
  uint32_t ms = millis();
  while(millis()-ms < d) {
    take_care_of_the_lights();
  }
}


and use that instead of delay().
http://paulmurraycbr.github.io/ArduinoTheOOWay.html

PaulS

Quote
and use that instead of delay().
Or, use a newer version of the IDE, where delay() calls yield(), and implement the yield() function to take_care_of_the_lights().
The art of getting good answers lies in asking good questions.


PaulS

What the?  :)

What is this "yield()" black magic you speak of sir!!??


(off to google!)
Newer versions of the IDE have added a call to a function, yield(), so you can do stuff while a delay is happening. Seems stupid, and prone to abuse to me, but I wasn't asked.

The attributes on the function declaration mean that it can be overridden by a user-defined function of the same name, without conflict (I don't remember, off the top of my head, what that declaration looks like).
The art of getting good answers lies in asking good questions.

PaulMurrayCbr

Newer versions of the IDE have added a call to a function, yield(), so you can do stuff while a delay is happening. Seems stupid, and prone to abuse to me, but I wasn't asked.
Le sigh. We are going to get loads of people calling delay() inside yield(), and wondering why their sketch doesn't work.
http://paulmurraycbr.github.io/ArduinoTheOOWay.html

PaulS

Le sigh. We are going to get loads of people calling delay() inside yield(), and wondering why their sketch doesn't work.
We'll send them to stackoverflow, and see if they get the joke.
The art of getting good answers lies in asking good questions.

Go Up