Production line product counter using Arduino

arduino-product-counter

Few weeks ago,I was asked by a friend of mine if I could help him build a product counter that will count finished products after a worker has processed them. The current situation was that a worker manning a processing station had to take each product and process it, then count them and sort them into batches. And eventually he also places them in a shipping box/crate where they would be sent off to another factory. All this was done by manually noting down the amount of processed products after each process and then note down the amount of finished batches using only pen and paper.

Considering that each day several thousands of these products need to be processed by a single worker ,a product counter will save a lot of time and eliminate any counting mistakes that will require a recount of an entire batch.We are dealing with irregular sized products which come in different sizes (but all circular) and travel on different sized guide rails. So he asked if I can produce a simple counter that can be configured on site according to the size of the products and also that it can be easily moved from one station to the other without too much hassle.

PARTS REQUIRED:

  1. 1x Arduino Uno board
  2. 1x Olimex LCD + 4 buttons shield
  3. 1x Sharp 4-30 cm IR sensor
  4. 1x 3 wire cable with JST connector

WORKING OF PRODUCT COUNTER:

The code was written so that it will continuously monitor the analog input signal coming from the sensor. Once the signal value has reached a certain threshold it will trigger a count and then wait for the signal to drop a certain amount below the threshold for the count function to reset and prepare for the next count.

This allows the product counter to be used on various sized objects (assuming that they are all round and they all travel in line one after another). Since the accuracy of the counter greatly depends on the way that the sensor is mounted and positioned it is important to remember that the smaller the counted products are the more precision, calibration and testing that needs to be applied before using this counter in a production environment.

product-counter-setup

Note that I chose to setup the sensor above the products and facing down towards the guide rail. You can position the sensor in any other way only take into consideration interference from the work environment that might trigger false counts such as people walking close by or other objects. If you choose to position the sensor on the side or the bottom you should consider adding some sort of enclosed housing or a back plate that will provide a constant distance value for when there are no products passing the sensor. If you are dealing with smaller sized products than the ones demonstrated in the video you might also need to consider adding housing to the IR LED on the sensor which will direct the light beam onto a defined area instead of just allowing it to spread in the default manner that the sensor was designed for.

assembly-line-product-counter-setup

Below you will find a diagram explaining about the calibration and the minimum and maximum values used in the source code; also you will find the source code itself which mainly focuses on making the device more user-friendly and can be customized on site alongside with some photos from the testing phase.

calibration-product-counter

HOW TO SET UP PRODUCT COUNTER USING ARDUINO – VIDEO:

You can find better explanation for this product counter in the below video.

CODE:

#include <LCD16x2.h> // OLIMEX LIBRARY
#include <Wire.h> // OLIMEX LIBRARY

LCD16x2 lcd; // LCD OBJECT

int buttons; // HOLDS THE 4 BUTTONS VALUE FROM THE OLIMEX LCD SHIELD

int iCounter=0; // holds the number of products counted
int iSenseMin=420; // sensor minimum value for count function reset (calibrate in a testing enviroment then set as default values)
int iSenseMax=450; // sensor maximum value to indicate a valid count (calibrate in a testing enviroment then set as default values)
bool bCountFlag=0; // a flag indicating the specific count current state
bool bActiveFlag=0; // a flag indicating if the device is in counting mode or menu mode
bool bMenuFlag=0; // a flag indicating if the menu is active

void setup(){
  //Serial.begin(9600); // serial for debugging
  Wire.begin(); // communication with the 4 built in buttons on the shield
  lcd.lcdClear(); // clears the lcd
  BootDelay(); // an initial delay for settling and logo
}

void loop()
{
  ButtonRead(); // reads the state of the buttons (button 1 specifically to break the counting function)
  if(bActiveFlag) // active counter function loop
  {
    if (SensorRead()>iSenseMax) 
    {
      if(!bCountFlag) // if the count state flag is not set a new count will be carried out
      {
        iCounter++;    // add count
        Counting(); // display new count value
        //Serial.println(iCounter); // debugging
        bCountFlag=1; // sets the count flag to true indicating that no further counts can be made until flag is set to false
        while(bCountFlag) // a hold to wait for the sensor to go below the minimum value
        {
          if(SensorRead()<iSenseMin) bCountFlag=0; // break the loop
        }
      }
    }  
    delay(10); // function settle
  }
  else // active menu loop
  {
    bMenuFlag=1; // menu display flag set to true
    MenuScreen(); // display menu
    while(bMenuFlag) // menu display loop
    {
      ButtonRead(); // read buttons
    }
  }
}

int SensorRead() // READ AND RETURN IR SENSOR OUTPUT VALUE
{
  int sensorValue = analogRead(A0); // sensor voltage output connected to Arduino analog pin A0
  return sensorValue;
}

void BootDelay() // BOOT SETTLE AND LOGO
{
  lcd.lcdGoToXY(1,1);
  lcd.lcdWrite("Booting up...");
  delay(3000);
}

void ButtonRead() // BUTTON HANDLER 
{
  buttons = lcd.readButtons(); // reads the state of the buttons from the lcd object (example taken from the OLIMEX code samples)
  if(!(buttons & 0x01))  // menu break button
  {
    bActiveFlag=0;
    MenuScreen();
  }
  
  if(!bActiveFlag) // only if the menu is in active state
  {
    if(!(buttons & 0x02)) // raise min value
    {
      iSenseMin++;
      MenuUpdate();
      return;
    }
    
    if(!(buttons & 0x04)) // raise max value
     {
      iSenseMax++;
      MenuUpdate();
      return;
    }
   
    if(buttons & 0x08)  
    {
      MenuUpdate();
    }
    else // break the menu loop and switch to counting loop
    {
      bMenuFlag=0;
      bActiveFlag=1;
      CountScreen();
      return;
    }
  }
}

void MenuScreen() // DISPLAY MENU STATICS
{
  lcd.lcdClear();
  
  lcd.lcdGoToXY(1,1);
  lcd.lcdWrite("SMN:");
  
  lcd.lcdGoToXY(10,1);
  lcd.lcdWrite("SMX:");
  
  lcd.lcdGoToXY(1,2);
  lcd.lcdWrite("SVO:");

  lcd.lcdGoToXY(10,2);
  lcd.lcdWrite("TOT:");

  MenuUpdate();
}

void MenuUpdate() // DISPLAY MENU VARS
{
  lcd.lcdGoToXY(5,1);
  lcd.lcdWrite(iSenseMin);
  
  lcd.lcdGoToXY(14,1);
  lcd.lcdWrite(iSenseMax);
  
  lcd.lcdGoToXY(5,2);
  lcd.lcdWrite(SensorRead());
  
  lcd.lcdGoToXY(14,2);
  lcd.lcdWrite(iCounter);
}

void CountScreen() // DISPLAY COUNT SCREEN STATICS
{
  lcd.lcdClear();
  
  lcd.lcdGoToXY(1,1);
  lcd.lcdWrite("TOT:");

  Counting();
}

void Counting() // DISPLAY COUNT SCREEN VARS
{
  lcd.lcdGoToXY(5,1);
  lcd.lcdWrite(iCounter);
}

Leave a Comment

Your email address will not be published. Required fields are marked *