HELP!

Hi guys,

I am new the the Arduino environment and need a little bit of help with a problem I have.

I am building an automatic drink dispenser which consists of three tap solenoids (3 different taps), 5 LDR's (Home position, tap 1 position, tap 2 position, tap 3 position and the End position) + a few other little things to make it all work.

Below I am stuck on a problem: When I push a Tap button it calls the function mainSchedule (referring to the main schedule of events) .... it all works fine, but it goes to change the direction to false during the main schedule but for some reason it jumps back to //Home to Tap Approach and goes through the process on repeat.

I need it to go through once, come back to the start and stop. and then be able to work again for the other switches.

sketch_oct11a_motorDriveV7.zip (4.2 KB)

and need a little bit of help with a problem I have.

Defining a decent thread title? Everybody here wants help.

If your "dispenser" is to deliver product at three or more different rates.. Why would you reverse the motor?
I think you have not spent the time to consider your Code, Hardware and it's Real purpose...
There is an old engineering method that is 100% workable...
First, Plan Your Work... Carefully...
Then, Work your Plan.
Most first attempts fail due to inadequate knowledge of both the hardware and the software programming environment.
Foolish but fixable... Remember that pain is the ultimate teacher... Always.

Doc

it all works fine, but it goes to change the direction to false during the main schedule but for some reason it jumps back to //Home to Tap Approach and goes through the process on repeat.

Perhaps you could refer to non-comment lines in your code. You can't "jump to" a comment.

I've downloaded your zip but can only see half of your files in the IDE (too many tabs and my screen is not that wide) Unfortunately I can't even find the "mainschedule" function.

I know some like to promote the notion of splitting the code up into multiple files but if I add up all the lines of code that I can actually see in the IDE it comes to a grand total of less than 200 lines of code before my old laptop runs out of space to display the tabs.

Ah found it!

/*

 Main Schedule of the process from start to finish of the automatic Beer Dispenser - this schedule goes through and calls functions of code
 in seperated tabs
 
 */

int mainSchedule (int TapNumber, int TapSolenoid, int FillingTime){
  
  delay (1500);

  Direction = true;

  //Home to Tap Approach
  MotorDrive(Direction, SequenceSpeed);
  delay(TapApproach);
  MotorDrive(Direction, ApproachSpeed);

  //Tap Position LDR
  LDRDetect = LDRScan(TapNumber, 500);
  if (LDRDetect == 1)
  {
    MotorStop();
    delay(1000);
  }
  else
  {
    EmergencyStop();
  }
  
  delay(2000);

  //Filling Glass
  GlassFill(TapSolenoid, FillingTime); 
   
  delay(2000); 
   
  //Tap to End Approach
  MotorDrive(Direction, SequenceSpeed);
  delay(EndApproach);
  MotorDrive(Direction, ApproachSpeed);

  //End Position LDR
  LDRDetect = LDRScan(EndLDR, 500);
  if (LDRDetect == 1)
  {
    MotorStop();
  }
  else
  {
    EmergencyStop();
  }

  delay (10000);
  
  //End to Home Approach
  Direction = false;                  // <<<<<<<<<<<  Look this is where you are telling it Direction = false  
                                                    //                              NO IF'S OR BUTS, JUST DO IT.
    
  MotorDrive(Direction, SequenceSpeed);
  delay(HomeApproach);
  MotorDrive(Direction, ApproachSpeed);  

}

A possible solution is a pump with a sensor to dispense accurately counted/measured amounts of beverage rather than counting on a delay to do it..
This, because you have no real control on the beverage storage container internal pressure.
And that you have no means of adding the pressure compensation into your calculations.
I have found several pumps capable of one or more liters per minute with hall sensor counters.
I bought two for an enclosed controlled growing area where accurate dispensing is more important than the time it takes to deliver the liquid medium... They're available on FleBay.. several example products are easily found with a simple search.
The two I bought cost me ~$10.00 US...

Doc

I don't think you are doing yourself any favours by having so many different .ino file. All that code would easily and unambiguoulsy fit in on file. There might be a case for splitting it into two - especially if you envisage re-using part of it for another project.

I KNOW you are creating a massive problem for yourself by scattering delay()s everywhere you can possibly fit one in. The Arduino is unable to do anything while it is waiting for a delay() period to expire.

If you want the concept of emergency stop you MUST get rid of all the delay()s and use non-blocking code to manage the timing. See the Blink Without Delay example sketch and the demo several things at a time.

I think it would also make the logic a lot easier if you put all the detection (buttons and LDRs) in one place and the Action code in a separate place so you have something like this

void loop() {
    readButtons();
    readLDRs();
    checkEmergency();
    operateDispenser();
}

...R

This is a university project.

I have 7 weeks to build and complete it...

Yes, it could be engineered and designed to run and operate a lot more efficient and effectively than its been designed to.

But

  1. I don't have the ability to run a volume sensor to measure the volume at the moment, so I am using a timer so it can easily be changed.

  2. There are a few functions I still have to write, including, flashing a Green LED to indicate to place a glass on the trolley before the system initialises (When glass is placed on trolley, it turns on a LED, which triggers an LDR), and to remove glass at the EndLDR. It will then return back to the start once glass has been removed.

  3. My lecturer likes functions and code to be spaced and separated out in different tabs, don't ask me why, but he just prefers it and its him i have to please :slight_smile:

I just need help to figure out why it keeps looping rather than coming back to the start.

Any help to do with this would be much appreciated!

Here is a new zip file,

I've taken out all of the extra .ino files and put it into the main sketch apart from one tab which is the operateDispenser tab function.

sketch_oct11a_motorDriveV8.zip (2.45 KB)

  1. My lecturer likes functions and code to be spaced and separated out in different tabs, don't ask me why, but he just prefers it and its him i have to please

When do you need to please him? When the program is working correctly, and is ready to be submitted? That is the ONLY time his peccadilloes matters. Until then, screw him. Organize the code in a way that makes sense to YOU.

The emergency stop function stops the trolley if in case the LDR did not pick up a signal from the trolley. It will send the system into an error state and flash the LED (Will have to reset the system to get out of it).

Could someone show me how they would re-write this code and/or set up the emergencyStop function using the 'unsigned long' data type (Blinking Without Delay)

Really stuck on this project

Firesurf:
Could someone show me how they would re-write this code and/or set up the emergencyStop function using the 'unsigned long' data type (Blinking Without Delay)

I should have linked to this demo in my previous post - but, hopefully, you have already read it as it is one of the stickies.

You can't set up the emergency stop on its own using millis(). All of the delay()s will have to go so that the code can respond to the emergency stop without delay :slight_smile:

I suggested an outline for your reorganized code in my earlier post. This Thread Planning and Implementing a Program expands on the idea.

...R

The program is now skipping the emergency stop function completely...

Not sure what i've done to have the happen, i think it might be something to do with the LDRScan 'timer'.

sketch_oct11a_motorDriveV8.zip (2.73 KB)

The program is now skipping the emergency stop function completely...

How do you know this? Why are there NO Serial.print() statements ANYWHERE in that code?

I don't know how this emergency stop will work with the code filled with delays. Maybe it will stop after 5 seconds if you are lucky.

How about a rewrite?

A state machine might help too:

Firesurf:
The program is now skipping the emergency stop function completely...

Not sure what i've done to have the happen, i think it might be something to do with the LDRScan 'timer'.

It would help if you explain what parts of the advice you have already been given have been incorporated into your code and what parts have not been incorporated and why.

My guess is that you haven't bothered with any of the advice - so I am not inclined to offer any more help.

If you have not understood any of the advice please say so and we can try to help.

...R

No, No, No... I really appreciate the help.

I have done my best to take on advice and change the code to make it more simplified to try solve these errors... but I am a total newby to the Arduino coding environment and I may need a little more help to write it out properly. This is not an issue in terms of university marking, I just have to reference the help given to me.

Here is a the order of sequence from start to finish I am trying to code:

MicroSwitch --> Home Position Switch
HomeLDR --> Home Position LDR / Far left of contraption
EndLDR --> End Position LDR / Far Right of contraption

  1. Power On Machine

  2. Checks if trolley is at the start position, if not then (Home Approach Speed) slow anti-clockwise speed until trolley triggers micro switch then stops.

  3. Scan's for button selection (Tap Number)

  4. When 1 of the 3 buttons are pushed, e.g. Tap Number 1. green LED blinks to signal to place a glass on the trolley. (Trolley has an LED attached to it and is turned on when a glass is placed on it.

  5. When HomeLDR senses there is a glass on the trolley, then trolley moves forward at 'Sequence Speed' then drops to 'Approach Speed' once the glass is close to the chosen tap number.

  6. Program takes ambient light readings of the chosen tap LDR and as the trolley approaches, the LED triggers the LDR to stop the motor. If there is a fault, e.g. Battery runs out on trolley and LDR doesn't pick up the LED after a chosen time period, system will enter 'Emergency Stop' mode and a RED LED will blink until system is reset.

  7. When LDR is trigger, there is a two second delay before the solenoid is set off to let liquid into the glass to fill the glass.

  8. After a chosen time period the solenoid will close, and there will be a two second delay to let the liquid settle.

  9. Trolley then moves forward again at Sequence Speed then drops to Approach speed as it searches for the ENDLDR. Again If there is a fault, e.g. Battery runs out on trolley and LDR doesn't pick up the LED after a chosen time period, system will enter 'Emergency Stop' mode and a RED LED will blink until system is reset.

  10. Once ENDLDR has been triggered, a green LED will blink to indicate to take the glass off the trolley.

  11. When the LDR senses that the LED has been switched off (Glass removed) then it will return home (Left) at 'Home Approach' speed until it triggers the microswitch (HomePosSwitch).

  12. End Of Sequence ... Returns back to Button Selection scanning


@Robin2 I have tried to put that BlinkWithoutDelay code that you showed in a separate forum but I haven't had any luck... It's just my lack of coding knowledge.

Please attach your latest code - preferably not zipped.

//PIN Setup
//====================================================

//Dispenser Motor initalisation
const int MotorSpeed = 6;
const int MotorSeq = 4;
const int MotorRet = 7;

//Tap Solenoid Pins
const int TapSol1 = 8;
const int TapSol2 = 9;
const int TapSol3 = 10;

//Tap LDR Pins
const int HomeLDR = 0;
const int Tap1LDR = 1;
const int Tap2LDR = 2;
const int Tap3LDR = 3;
const int EndLDR = 4;

//Signal LED pins
unsigned long currentMillis = 0; //stores the value of millis() in each iteration of loop()

const int RedLed = 13; //Red LED is on PIN number 13
byte RedLedState = LOW; //used to record whether the LED is on or off (LOW = Off)
const int RedLedInterval = 1000; // Number of milliseconds between blinks
const int RedLedDuration = 500; //Number of milliseconds that the LED is on for
unsigned long previousRedLedMillis = 0; //will store last time LED was updated

const int GreenLed = 1; //Green LED is on PIN number 12
byte GreenLedState = LOW; //used to record whether the LED is on or off (LOW = Off)
const int GreenLedInterval = 1000; // Number of milliseconds between blinks
const int GreenLedDuration = 500; //Number of milliseconds that the LED is on for
unsigned long previousGreenLedMillis = 0; //will store last time LED was updated

//Tap Selection Button Pins
const int TapBut1 = 11;
const int TapBut2 = 12;
const int TapBut3 = 13;

//Home Position Micro-Switch
const int HomePosSwitch = 0;

//==========================================================

//Motor Speed
const int SequenceSpeed = 100;
const int ApproachSpeed = 80;
const int HomeCheckSpeed = 80;

//Glass Filling Timers(ms)
const int Tap1 = 10000;
const int Tap2 = 10000;
const int Tap3 = 10000;

//Motor Sequence Timers
const int TapApproach = 5000;
const int EndApproach = 5000;
const int HomeApproach = 5000;

//general vars
boolean Direction = true;

int TapNumber = 0;
int TapSolenoid = 0;
int FillingTime = 0;

int LDRDetect = 0;

//Pre-initalisation sequence
void setup()
{
  pinMode(MotorSpeed, OUTPUT ); 
  pinMode(MotorSeq, OUTPUT ); 
  pinMode(MotorRet, OUTPUT ); 

  pinMode(TapSol1, OUTPUT);
  pinMode(TapSol2, OUTPUT);
  pinMode(TapSol3, OUTPUT);

  pinMode(HomeLDR, INPUT);
  pinMode(Tap1LDR, INPUT);
  pinMode(Tap2LDR, INPUT);
  pinMode(Tap3LDR, INPUT);
  pinMode(EndLDR, INPUT);

  pinMode(TapBut1, INPUT);
  pinMode(TapBut2, INPUT);
  pinMode(TapBut3, INPUT);

  pinMode(RedLed, OUTPUT);
  pinMode(GreenLed, OUTPUT);

  pinMode(HomePosSwitch, INPUT);
}

//====================================================

// Main program sequence
void loop(){
  
  updateRedLedState();
  
   if (digitalRead (TapBut1) == HIGH){
    TapNumber = Tap1LDR;
    TapSolenoid = TapSol1;
    FillingTime = Tap1;
  }
  else if (digitalRead (TapBut2) == HIGH){
    TapNumber = Tap2LDR;
    TapSolenoid = TapSol2;
    FillingTime = Tap2;
  }
  else if (digitalRead (TapBut3) == HIGH){
    TapNumber = Tap3LDR;
    TapSolenoid = TapSol3;
    FillingTime = Tap3;
  }
  
  
  if ((TapNumber > 0) && (TapSolenoid > 0) && (FillingTime > 0)){    
    operateDispenser(TapNumber, TapSolenoid, FillingTime);
  }

}

//========================================================================

//FUNCTION DEFINITIONS

//Puts the beer dispenser into a error state - Stops Motor/Flashes Red LED
void updateRedLedState(){
  
  if (RedLedState == LOW) {
    if (currentMillis - previousRedLedMillis >= RedLedInterval){
      RedLedState = HIGH;
      previousRedLedMillis += RedLedInterval;
    }
  }
  else {
    if (currentMillis - previousRedLedMillis >= RedLedDuration){
      RedLedState = LOW;
      previousRedLedMillis += RedLedDuration;
    }
  }
}


void EmergencyStop(){
  
  digitalWrite( 4, LOW );
  digitalWrite( 7, LOW );
  digitalWrite( 6, LOW );
  digitalWrite(RedLed, RedLedState);
  
}



//Function to trigger the solenoid and fill the glass
int GlassFill(int TapSole, int FillTime){

  switch (TapSole) {

  case 8:
    digitalWrite(TapSol1, HIGH);
    delay(FillTime);
    digitalWrite(TapSol1, LOW);
    break;

  case 9:
    digitalWrite(TapSol2, HIGH);
    delay(FillTime);
    digitalWrite(TapSol2, LOW);
    break;

  case 10:
    digitalWrite(TapSol3, HIGH);
    delay(FillTime);
    digitalWrite(TapSol3, LOW);
    break;

  default:
    return -1;

  }

}


/*
LDR Scanner scans the chosen LDR (Beer Tap) every 10ms for the trolley when it is in approach to chosen position. 
This also takes an ambient light reading when triggered. There is also a built in timer on this function which allows the system
to enter an error state in case an LDR fails to sense the LED mounted on the trolley. The system will enter 'EmergencyStop'
*/

int LDRScan (int LDR, int Time){

int Ambient = 0;
int Reading = 0;
int TimerCount = 0;

Ambient = analogRead(LDR);
Reading = Ambient;

  while ((Reading >= (Ambient - 100))&&(TimerCount < Time)){ //for false triggers increase ambient off set, for detection failures or lack of sensitivity decrease off set.
    Reading = analogRead(LDR);
    delay(10);
    TimerCount ++;
    }
    
    
if (TimerCount == Time)
  {
  return -1;
  }
  else
  {
  return 1;
  }
}

//Function to control the motor direction and speed
void MotorDrive(boolean Direction, int Speed){
     
      analogWrite( MotorSpeed, Speed);
      if (Direction)
        {
        digitalWrite( MotorSeq, HIGH);
        digitalWrite( MotorRet, LOW);
        }
      else 
        {
        digitalWrite( MotorSeq, LOW);
        digitalWrite( MotorRet, HIGH);
        }       
    
}

//Function to call the motor on ChannelB H-Bridge to stop
void MotorStop()
{
  digitalWrite( 4, LOW );
  digitalWrite( 7, LOW );
  digitalWrite( 6, LOW );
}

//======================================================================


/*

 Main Schedule of the process from start to finish of the automatic Beer Dispenser - this schedule goes through and calls functions of code
 in seperated tabs
 
 */

int operateDispenser (int TapNumber, int TapSolenoid, int FillingTime){
  
  delay (1500);

  Direction = true;

  //Home to Tap Approach
  MotorDrive(Direction, SequenceSpeed);
  delay(TapApproach);
  MotorDrive(Direction, ApproachSpeed);

  //Tap Position LDR
  LDRDetect = LDRScan(TapNumber, 500);
  if (LDRDetect == 1)
  {
    MotorStop();
    delay(1000);
  }
  else
  {
    EmergencyStop();
  }
  
  delay(1500);

  //Filling Glass
  GlassFill(TapSolenoid, FillingTime); 
   
  delay(1500); 
   
  //Tap to End Approach
  MotorDrive(Direction, SequenceSpeed);
  delay(EndApproach);
  MotorDrive(Direction, ApproachSpeed);

  //End Position LDR
  LDRDetect = LDRScan(EndLDR, 500);
  if (LDRDetect == 1)
  {
    MotorStop();
  }
  else
  {
    EmergencyStop();
  }

  delay (10000);
  
  //End to Home Approach
  Direction = false;
    
  MotorDrive(Direction, SequenceSpeed);
  delay(HomeApproach);
  MotorDrive(Direction, ApproachSpeed); 
 
  MotorStop();

}


___


**** The end ten second delay is temporary, it will be replaced with the green LED Blinking function to indicate remove glass***
**** The Home Position Micro switch hasn't been programmed in yet, so the end of the sequence doesn't have it****
**** Green LED and RED Led functions need to be programmed still