Elemental AI – Automatic Fruit-Sorting Machine

by Cesosas in Circuits > Arduino

4505 Views, 69 Favorites, 0 Comments

Elemental AI – Automatic Fruit-Sorting Machine

Cover.png

Nowadays it is common to hear about Artificial Intelligence (AI), Machine Learning, and similar related concepts daily. It usually appears on the news with some incredible applications, or we can even interact with some of this stuff at home with devices such as Amazon’s Alexa and similar gadgets.

However, with all this information, it is common for us to think that AI is something so advanced and complex that we might even think of it as some sort of wizardry. But, when interested in this subject, one can find that even the simplest system can be called “Artificially intelligent.”

On this Instructable we will learn how to create a simple Sorting system that will make use of a basic, but powerful, form of Artificial Neural Network known as Perceptron. 

Supplies

Drill.jpg
Jigsaw.jpg
dREMEL.jpg
irwin.jpg
silicon.jpg
escuadra.jpg
glue.jpg
wood glue.jpg

To develop this entire project, it was necessary to use both power tools, like a drill and a jigsaw, and some other more delicate like a soldering iron for the electronics. Here is a list of every tool I used:

Some Basic Tools

  • Drill and drill bits
  • Jigsaw
  •  Dremel with routing bits
  • Clamps
  • Soldering Iron
  •  Needle
  • Hot glue Gun
  • Electrical pliers
  • Crimping pliers
  • Philipps and Standard Screwdrivers
  • Aluminium Square

In the following steps, I present you a list of materials and electronics components for making this project.

Materials

Here is a list of the materials used to build the entire system:

  • 3/8” thick MDF – I had some of it laying around.
  • Leftover fabric – I used cotton, but anything else might work.
  • Nylon thread – I used it to sew the belt to the required “length.”
  • Hot Glue bars – for holding LEGO pieces in place.
  • Super glue – This is going to end up being your best friend.
  • Duct-tape – Because one never knows.
  • One 5/16” threaded rod – this works as an axis for each roller of the system
  • 10 5/16” washers and nuts (each).
  • ¾” PVC pipe – This is used for the rollers.
  • Zip ties – Just in case
  • 220 grit Sandpaper – To incresae the grip of the rollers.

Electronic Components

Elecyronis.jpeg
Servo.jpeg
515b4656ce395f8a38000000.png
Dupont.jpeg
Wire.jpeg
WhatsApp Image 2023-01-13 at 11.34.48.jpeg

Sensors and Stuff

As for the electronics, here is everything that was considered:

  • 1 RGB Sensor – To detect the colour of the fruit. It is particularly important.
  • 1 SD Card reader Module – To store the data from every colour measurement.
  • SD Card and SD Card Reader– Make sure it has the adequate format, FAT32, otherwise the Arduino Module will not recognize it.
  • 3 IR sensors – Used to automate the entire process.
  • Micro Servomotor – To sort the fruits.
  • Arduino Uno Board – This will be the brain of the whole operation.
  • Protoboard – To make sure everything is connected.
  • ATX Power Supply – I commonly use this to power my projects as it provides enough current for my needs, but you can use anything else that serves the same purpose.
  • 12V Electric motor – it was salvaged from a chord-less drill (Not a great idea, but more on that later).

Motor Driver

As for the speed controller for the DC Motor, I used the following components:

  • 1 – NE555 IC
  • 1 – 4N28 Optocoupler
  • 1 – TIP120 Darlington Transistor with heatsink
  • 3 – 1kΩ resistors
  • 2 – 100nF ceramic capacitors
  • 1 – 1uF electrolytic capacitor
  • 1 – 10kΩ potentiometer with knob
  • 2 – 1N4004 rectifier diode
  • 1 – 1N4148 Diode 

The corresponding diagrams are shown below on a later step.

Finally, as I decided to try something new for the electrical connections, I tried crimping my own connectors to make sure that everything was custom made. With that in mind, the following materials were required:

  • 22-AWG wire – I bought a few meters from distinct colours so I could establish some sort of colour-coding.
  • Crimping pliers – These come handy when making new wires.
  • Dupont Connectors – The most important part for crimping your own wires.

Let's Dive Into AI

Neural Network.png
Perceptron.png

We may commence by introducing some key concepts so that we can all understand what we are going to do along the process. We must first define what composes an artificial Neural network. In general, it can be divided into three parts:

Input layer – It is the one that receives information from the external environment.

Intermediate layer – Here is where the neurons are present. They are responsible for the processing within the network

Output layer – there are also neurons in this type of layer. They are responsible for presenting the results from previous layers.

 In this case, we will use one of the simplest Neural Networks available, the perceptron. The following concepts are especially important in the coding section:

Perceptron – According to [1], a perceptron consists of one input layer and a single neural layer which also acts as the output layer (thus no intermediate layers here). It is important to mention that the number or inputs/outputs is not dependent on the number of layers.

This type of network is especially used in pattern classification, which is what we want to achieve at a later step. The use of the Perceptron requires two main steps: Training and implementation. These two topics will be discussed later. 


Mechanical System – the Conveyor Belt

Conveyor Belt - Plano_page-0001.jpg
Conveyor Belt - Plano_page-0002.jpg
Conveyor Belt - Plano_page-0003.jpg
Assemly.jpeg
Assembly.jpeg
Motor Coupling.jpeg
sewing results.jpeg

I must admit that the final project that I am presenting to you in this Instructable is the result of multiple iterations. This since I was not sure about the overall measurements for the entire system. First, with the help from a few CAD tools I designed some of the parts considering the materials that were available

the fabric band isn't shown on the CAD Drawings as it was built after assembling the conveyor's main body.

A few notes...

  • The sand paper was used to increase the traction of the external rollers. I wrapped the PVC pipe with this paper and glued it with super glue.
  • For the band, the fabric was folded to into three to get a robust band. The sides were secured with glue and then sewed using the nylon thread. It can be useful to mark the points where the needle should pass in order to be consistent with the stitches.

Wiring All the Electronics

Speed Controller.jpeg
Diagram.PNG
Speed Controller.PNG
Data collection.jpeg
Speed Test.jpeg
Wiring Done.jpeg

As there are different bits of electronics within this project, I started testing everything separately just to verify that everything would work when I decided to put everything together.

Arduino and sensors

I started testing the RGB sensor and the SD card module to gather data samples from the fruits I wanted to sort. For this purpose, I used a little push button to tell the Arduino when to read data from the sensor and store it in a file with a specific format.

At a later stage, I decided test the functioning of the IR sensors, as they would be used as an object detection barrier all along the conveyor belt. This was kind of simple, as each sensor comes with only three connection pins: +5V, GND and data, which switches from 0 to 5V as required.

I also tested the servo motor and tried to specify a position where it could modify the fruit’s trajectory when needed. For this, I simply used a pot to change the position of the servo as needed and printing the corresponding values in the serial monitor of Arduino’s IDE.

DC Motor Speed Controller

As for the motor’s speed controller, even though it could have been easier to control it via a PWM pin from the Arduino, I thought it would be easier if I just did it the “old-school” way with a 555 timer-base circuit to alter the speed of the motor. The resulting circuit is show in the image above.


For the final circuit, it is important to replace the jumper at pin 4 of the 555 IC with a wire to Digital Pin 4 on the Arduino board. This allows us to control the activation of the speed controller with a single pin instead of altering the speed.

Gathering Relevant Data

lemons.jpeg
potatos.jpeg

Before our AI can be used to sort different fruits, it must undergo a process called training. And for this, we must first collect some data from the specific fruits we want to sort. In this case, as it was what I had in hand, I decided to sort lemons from potatoes. I know this might sound a little strange, but for demonstration purposes it serves our need

When training any AI, the more data the better. However, we must consider that we are dealing with a small system built-in within an Arduino board, so we don’t need to acquire millions of points; with approximately fifty data points from each type of fruit, we must have enough to train our AI.

At this point it is important to mention that when giving data to an AI, one must not use the same data used from training to verify its functioning. Put in other words, we must use different fruits from those we use now when testing our system.

With that being said, the gathering process is simple: you take a lemon/potato and place it near the RGB sensor. When it is within range, a few millimiters are fine, you press the push button on the protoboard and verify that the data has been stored correctly on th SD Card.

It is also important that you take note as to which measurement corresponds to which sample, because we must label it correspondingly before training our AI with the help of some spreadsheet editor like MS Excel.

The code below was developed for this purpose:

/*The main purpose of the following code is to handle both an RGB sensor and
  an SD Card module in order to take samples of different fruits  and register
  them in a file for a later analysis.
  WIRING :
  A4 - SDA
  A5 - SCL
  04 - CS
  11 - MOSI
  12 - MISO
  13 - SCK
*/
#include <Wire.h>
#include "Adafruit_TCS34725.h"  //Library for th RGB Sensor

#include <SPI.h>
#include <SD.h>                 //Library for the SD Card Module
//PIN ASSIGNMENT
const int chipSelect = 10;       //Control Pin for the SD Card Module
int trigger = 2;
//VARIABLES DEFINITION
String fileName = "rgbData";
String extension = ".csv";
String file = fileName + extension;
int samples = 0;
Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_24MS, TCS34725_GAIN_16X);

void setup() {
  Serial.begin(9600); //Start Serial Communication
  pinMode(trigger, INPUT_PULLUP);
  Serial.println("Perceptron Test");
  loadRGB();   //RGB Sensor Loading sequence
  loadSD();  //SD Card Module Loading sequence
  addHeaders();
}

void loop() {
  String dataString = ""; //Variable para escribir los datos en el archivo
  float red, green, blue; //Variables con el valor de cada color
  if (!digitalRead(trigger)) {
    samples += 1;
    //Lectura de color del sensor
    tcs.setInterrupt(false);    //Enciende el LED
    delay(60);                  //Le lleva 50ms leer
    tcs.setInterrupt(true);    //Apaga el LED
    tcs.getRGB(&red, &green, &blue);
    Serial.print("S:\t");      Serial.print(samples);
    Serial.print("\tR:\t");    Serial.print(red);
    Serial.print("\tG:\t");    Serial.print(green);
    Serial.print("\tB:\t");    Serial.println(blue);

    //Concatenación de los valores como cadenas de texto
    dataString = String(samples) + "," + String(red) + "," + String(green) + ","  + String(blue);
    File dataFile = SD.open(String(file), FILE_WRITE);
    // if the file is available, write to it:
    if (dataFile) {
      dataFile.println(dataString);
      dataFile.close();
      // print to the serial port too:
      Serial.println(dataString);
    }
    // if the file isn't open, pop up an error:
    else {
      Serial.println("error opening File");
    }
  }
}
void loadRGB() {
  Serial.println("Looking for a sensor");
  delay(100);
  Serial.println("Looking for a sensor.");
  delay(100);
  Serial.println("Looking for a sensor..");
  delay(100);
  Serial.println("Looking for a sensor...");
  delay(100);
    if (tcs.begin()) {
    Serial.println("Sensor Detected");
  } else {
    Serial.println("No sensor Available :(");
    while (1);
  }
}
void loadSD() {
  Serial.println("Initializing SD Module");
  delay(100);
  Serial.println("Initializing SD Module.");
  delay(100);
  Serial.println("Initializing SD Module..");
  delay(100);
  Serial.println("Initializing SD Module...");
  delay(100);
   // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("SD Card failed, or not present");
    // don't do anything more:
    while (1);
  }
  Serial.println("SD Card initialized");
}
void addHeaders() {
  File dataFile = SD.open(String(file), FILE_WRITE);
  String encabezados = "Sample,R,G,B";
  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(encabezados);
    dataFile.close();
    // print to the serial port too:
    Serial.println("los encabezados: " + encabezados + " fueron agregados");
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening File");
  }
}


With this Arduino script, I could store data within a .csv file in which i get the sample number and the value of each of the three varaibles: red, green and blue. At the end, I added a new column to each data set with the same particular value: 1 for lemons and -1 for potatoes. This will make sense later.

Time for Some Training

Gr&aacute;fica.png
Training.png
Resultados Entrenamiento.JPG

To implement the Perceptron, it is first required to train it. And for this purpose, we must first visualize our data sets to determine whether these are separated enough for us to use them to train our AI.

To do this, I created a Script in Matlab to import the desired data sets from different files and visualize them in both 3D and 2D dispersion graphs. This task can be done in Excel, using only 2d graphs, which should be more than enough to view our data.

close all, clear all, clc
%Load data to train the Perceptron
limon = readtable('Add here the location of the file','Sheet','DataLemon');
papa = readtable('Add here the location of the file','Sheet','DataPotato');
Data = [limon;papa];
figure(1)
subplot(2,2,1) %Create a plot using our 3 variables
scatter3(Data,"R","G","B","filled","ColorVariable","Clase")
colorbar
subplot(2,2,2)
scatter(Data,"R","G","filled","ColorVariable","Clase")
colorbar
xlabel("R"), ylabel("G")
subplot(2,2,3)
scatter(Data,"R","B","filled","ColorVariable","Clase")
colorbar
xlabel("R"), ylabel("B")
subplot(2,2,4)
scatter(Data,"G","B","filled","ColorVariable","Clase")
colorbar
xlabel("G"), ylabel("B")


The result is shown in the image above. In this, we see that both data sets are well separated, so we can continue with our process.

Then we can create a script to get the desired values for our neural network. But you may wonder, how on earth are we supposed to train the perceptron. Well, the answer is simple; we will give a few data points and tell it the desired result. From there, it must adjust its values accordingly to make “no mistakes” when in operation.

For this purpose, I used the data gathered in an earlier stage for the training process developed by following the algorithm depicted on the picture above. This process is programming-based, and the completion time depends on different parameters, but usually doesn’t take more than a few minutes. 

But which programming language? You may wonder. I did all this in Matlab as I have access to it at school, but you can try to do it with Visual Studio Code using C or even with another tool, like Matlab but Open Source (Free) called Scilab. However, I recommend you search for the easiest option as you may need to import data from external files.

Here is the resulting Matlab Code:

close all, clear all, clc
%carga de datos para entrenar el perceptrón
limon = readtable('Add here the location of the file','Sheet','DataLemon');
papa = readtable('Add here the location of the file','Sheet','DataPotato');
%Create a new input vector and add a column with "-1's"
samples = [limon;papa];
inputs = table2array(samples(:,1:end-1));
inputs = [-ones(max(size(inputs)),1),inputs];
%Se crea un vector para las salidas deseadas
results = table2array(samples(:,end));
%Se define el número de entradas del perceptrón
entradas = 3;
%Generate random values for the initial values
w = rand(entradas,1);
w_0=1; %Activation threshold
disp("Valores iniciales para w (Al azar, considerando el umbral):")
w = [w_0;w] %Rezise the synaptic weights vector
learningRate = 0.25; %Specify a learning rate. Results depend on this value
epoch = 0; %Start the EPOCH counter
error = 1; %We begin by considering there will be an error within the first iteration
tic %Let's meausre the elapsed time
while error ~=0
error = 0;
for i = 1:1:length (results)
u = w'*inputs(i,:)';
y = signal(u);
if y ~=results(i)
w = w + learningRate*(results(i)-y)*inputs(i,:)';
error = 1;
end
end
epoch = epoch + 1;
end
toc
disp("número de épocas: " + epoch);
disp("Vector w resultante:");
disp(w)
save("informacion.mat","epoch","w")
function y = signal(u)
if u < 0
y = -1;
else
y = 1;
end
end


The execution of the script above took me around three minutes. At the end, I got a message with the results. This same message can be seen above. It took around a million and a half iterations to get a “clean result”. This can be changed by modifying the learning rate value and is dependent on the random numbers that the algorithm starts with.

a few notes...

  • the signal(u) part on the algorithm refers to the activation function of the neuron. This is done with a function within the script.

Implementing the Perceptron

F3RO7DLLCUJ5PKV.jpg

The implementation of our AI is done within the Arduino script. For this task, we must follow a similar algorithm using the results from the training session done earlier. This is even simpler that the one shown on step 6. As a reference, you can look at the algorithm depicted in the image above.

Here is the resulting Arduino Code (omitting some parts that appear earlier):

/*  Wiring:
  A4 - SDA
  A5 - SCL
  10 - CS
  11 - MOSI
  12 - MISO
  13 - SCK
*/
#include <Wire.h>
#include "Adafruit_TCS34725.h"  //Library for th RGB Sensor

#include <SPI.h>
#include <SD.h>                 //Library for the SD Card Module
//PIN ASSIGNMENT
const int chipSelect = 10;       //Control Pin for the SD Card Module
int trigger = 2;

Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X);
//VARIABLES DEFINITION
String fileName = "perceptron";
String extension = ".csv";
String file = fileName + extension;
int samples = 0;
int resultado = 0;
//PERCEPTRON PARAMETERS
float w[4] = { 103469, -1136.342623965437, 1770.317859324734, 274.6130405099033};
// these were calculated with Matlab and copied into a vector
void setup() {
  Serial.begin(9600); //inicia la comunicación Serial
  pinMode(trigger, INPUT_PULLUP);
  Serial.println("Perceptron Test");
  loadRGB();  //RGB Sensor Start Sequence
  loadSD(); //SD Card module start sequence
}

void loop() {
  String dataString = ""; //Variable for writing data into the file
  float red, green, blue; //One variable for each colour
  if (!digitalRead(trigger)) {
    resultado=0;
    samples += 1;
    //We use the RGB Sensor
    tcs.setInterrupt(false);    //Turn the LED on
    delay(60);                  //It takes 50ms to read
    tcs.setInterrupt(true);    //Turn the LED off
    tcs.getRGB(&red, &green, &blue);
    Serial.print("S:\t");      Serial.print(samples);
    Serial.print("\tR:\t");    Serial.print(red);
    Serial.print("\tG:\t");    Serial.print(green);
    Serial.print("\tB:\t");    Serial.println(blue);
    //Once the values are obtained, we use our trained perceptron
    Serial.print("Result: ");
    resultado = perceptron(red, green, blue);
    if (resultado == -1) {
      Serial.println("Potato");
    }
    else if (resultado == 1) {
      Serial.println("Lemon");
    }
  }
}

int perceptron(float r, float g, float b) {
  float u = 0;
  int y = 0;
  float inputs[3] = {r, g, b};
  for (int i = 0; i < 4; i++) {
    for (int j = 0; i < 3; i++) {
      u = w[i] * inputs[j];
      y = biStepSignal(u);
      return y;
    }
  }
}
int biStepSignal( float u) {
  if (u < 0) {
    return -1;
  }
  else if(u>=0){
    return 1;
  }
}


This Arduino sketch will take a measurement using the RGB sensor, use the values to feed our AI and calculate wether the fruit is a Lemon or a potato. Then, it will show the results on the serial monitor and store them in a file within the SD Card.

Getting Everything Together – State Machines

State Machine.PNG

We already have our AI implementation within the Arduino script, however, this AI is only a small part of the project, as our intention is to create a sorting machine using the conveyor belt from earlier steps. So, to achieve this, we must think of a way for our system to work as a whole.

For this purpose, we will use a design technique called “State Machine”. It is a powerful tool when creating sequential systems just like this that have a well-established and recurrent behaviour. We then consider the flow diagram shown above. It describes everything that must be done while our system is operating.

Process Description

The behaviour we are looking for with this project is simple but can be challenging to achieve. Here is a quick description of what was done:

  • First, when the system is booted, it executes its setup: it loads its modules, turns the motor off and adjusts the servo’s position. This occurs only the first time and it is automatic. The entire system will stay on hold until the user decides to press the start button.
  • Then, the system will display a message asking the user for input. The user can then put some fruit on the conveyor belt at the starting position. The conveyor belt will start moving when the first IR sensor detects that the fruit is in position.
  • While moving, the fruit will only stop when it reaches the second IR sensor. Then the system will read the colour from the fruit and use the Neural network. After all this is done, the sequence continues, and the fruit keeps moving.
  • When the fruit reaches the selection point, the conveyor will stop using the signal from the third IR sensor, and based on the result from our AI, it will adjust the servo accordingly. Then the process repeats itself.

Here is the resulting Arduino Code:

#include <Wire.h>
#include "Adafruit_TCS34725.h"  //Libraries for the RGB Sensor
Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X);
#include <SPI.h>
#include <SD.h>                 //Libraries for the SD Module
File dataFile;
#include <Servo.h>
Servo servo;  // create servo object to control a servo

// INPUT PINS ASSIGNMENT:
#define BTN1 2  //botón de Inicio
#define SIR1 7  //Sensor infrarrojo 1
#define SIR2 6  //Sensor Infrarrojo 2
#define SIR3 5  //Sensor Infrarrojo 3
const int chipSelect = 10; //Control del módulo SD

//OUTPUT PINS ASSIGNMENT:
#define MTR 4
#define SRVO 3

//VARIABLE DEFINITION
unsigned char file = "Sort.csv";
int samples = 0;
int resultado = 0;
float red = 0, green = 0, blue = 0; //Variables con el valor de cada color

//PARAMETERS AND CONTROL VARIABLES
enum {Arranque, Hold, Movimiento1, Lectura, Movimiento2}; //We use this to handle the states of the system
unsigned char estadoActual;
#define ANGLE_MAX 135
#define ANGLE_MIN 70
int switchValue[4] = {0, 0, 0, 0};
bool switchClosed[4] = {0, 0, 0, 0};
bool switchClosedSetup[4] = {1, 1, 1, 1};
bool systemOk = false;  //Variable de Arranque
bool messageDisplayed = false;  //Variable de Hold
// PERCEPTRON PARAMETERS
float w[4] = { 103469, -1136.342623965437, 1770.317859324734, 274.6130405099033};

void setup() {
  Serial.begin(9600); //inicio de Comunicación mediante puerto serial
  servo.attach(SRVO); //Definición del pin del servomotor
  //Definición de entradas
  pinMode(BTN1, INPUT_PULLUP);
  pinMode(SIR1, INPUT);
  pinMode(SIR2, INPUT);
  pinMode(SIR3, INPUT);
  //Definción de salidas
  pinMode(MTR, OUTPUT);
  //Acciones iniciales de arranque:
  digitalWrite(MTR, LOW);
  servo.write(0);  //revisar este valor de inicio (apuntando hacia fuera)
  Serial.println("Sorting Machine");  //Mensaje Inicial en la consola
  loadRGB();  //Arranque del Sensor RGB
  loadSD(); //Arranque del del Módulo con la SD
}
void loop() {
  switchCheck();
  switch (estadoActual) {
    case Arranque:
      if (!systemOk) {
        Serial.println("STATUS: On Hold");
        systemOk = true;
      }//Revisar si se puede omitir el else
      if (switchClosed[0]) { //Se presiona el botón de Inicio
        estadoActual = Hold;
        break;
      }
      else { //el botón no se presiona
        break;
      }
    case Hold:
      resultado = 0;
      if (!messageDisplayed) {
        Serial.println("Waiting for Fruit...");
        messageDisplayed = true;
      }
      if (switchClosed[1]) { //Se detecta Fruta en la banda (SIR1)
        //Se procede al siguiente estado
        messageDisplayed = false;
        estadoActual = Movimiento1;
        break;
      }
      else { //No se detecta nada en la banda
        break;
      }
    case Movimiento1:
      digitalWrite(MTR, HIGH);
      if (switchClosed[2]) { //Se detecta Fruta en la región del sensor RGB (SIR2)
        //Se procede al siguiente estado
        estadoActual = Lectura;
        break;
      }
      else { //No se detecta nada en la región del sensor RGB
        break;
      }
    case Lectura:
      if (resultado == 0) {
        digitalWrite(MTR, LOW);
        Serial.println("Fruit in Position");
        lecturaRGB();
        resultado = perceptron(red, green, blue);
        storeData();
        delay(1000);
        Serial.println("Moving...");
      }
      else {
        digitalWrite(MTR, HIGH);
      }
      if (switchClosed[3]) { //Se detecta fruta en la región de clasificación
        estadoActual = Movimiento2;
        break;
      }
      else { //No se detecta nada en la región del sensor RGB
        break;
      }
    case Movimiento2:
      digitalWrite(MTR, LOW);
      sortFruit();
      delay(1000);
      digitalWrite(MTR, HIGH);
      delay(1000);
      digitalWrite(MTR, LOW);
      estadoActual = Hold;
      break;
  }
}
//DEFINICION DE FUNCIONES ADICIONALES
void loadRGB() {  //Mensaje de carga para el sensor RGB
  Serial.println("Searching sensor...");
  delay(100);
  if (tcs.begin()) {
    Serial.println("Sensor Detecter");
  } else {
    Serial.println("No sensor available :(");
    while (1);
  }
}
void loadSD() { //Mensaje de Carga para el módulo SD
  Serial.println("Initializing SD Card Module...");
  delay(100);
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("SD Card failed, or not present :(");
    // don't do anything more:
    while (1);
  }
  Serial.println("SD Card initialized :)");
}
void switchCheck() { //Verifica la transición de los sensores infrarrojos
  int sensors[4] = {2, 7, 6, 5};
  for (int i = 0; i < 4; i++) {
    switchValue[i] = digitalRead(sensors[i]);
    switchClosed[i] = (!switchValue[i] and switchClosedSetup[i]);
    switchClosedSetup[i] = switchValue[i];
  }
}
void lecturaRGB() { //Se realiza la medición con el sensor RGB
  samples += 1;
  //Lectura de color del sensor
  tcs.setInterrupt(false);   //Enciende el LED
  delay(1000);               //Le lleva 50ms leer
  tcs.setInterrupt(true);    //Apaga el LED
  tcs.getRGB(&red, &green, &blue);
  Serial.print("S:\t");      Serial.print(samples);
  Serial.print("\tR:\t");    Serial.print(red);
  Serial.print("\tG:\t");    Serial.print(green);
  Serial.print("\tB:\t");    Serial.println(blue);
}
void storeData() { //Se concatenan los valores y se almacenan en la SD.
  dataFile = SD.open(file, FILE_WRITE);
  // if the file is available, write to it:
  if (dataFile) {
    dataFile.print(samples); //write sample number
    dataFile.print(",");
    dataFile.print(red); //write Red Value
    dataFile.print(",");
    dataFile.print(green); //write Green Value
    dataFile.print(",");
    dataFile.print(blue); //write Blue Value
    dataFile.print(",");
    dataFile.println(resultado); //Write result
    dataFile.close(); //Close the File
    Serial.println("Data is written");
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening File");
  }
}
void sortFruit() {
  Serial.print("Result: ");
  if (resultado == -1) {
    Serial.println("Potato");  //El servo se mueve a una posición paralela a la banda
    servo.write(ANGLE_MIN);
  }
  else if (resultado == 1) {
    Serial.println("Lemon"); //El servo se cruza para sacar el objeto por un costado
    servo.write(ANGLE_MAX);//
  }
}
int perceptron(float r, float g, float b) { //Implementación del perceptrón
  float u = 0;
  int y = 0;
  float inputs[4] = { -1.0, r, g, b};
  for (int i = 0; i < 4; i++) { //Al tamaño del vector w que coincide con el de entradas
    u = u + w[i] * inputs[i];
  }
  y = biStepSignal(u);  
  return y;
}
int biStepSignal( float u) {  //Señal de activación
  if (u < 0) {
    return -1;
  }
  else if (u >= 0) {
    return 1;
  }
}


Let’s Try It

looks.jpeg
view.jpeg
pos1.jpeg
pos2.jpeg
pos3.jpeg
results.PNG

At this point, we must have finished assembling the conveyor belt, tested our sensors and trained our AI accordingly. The only thing left for us to do is to mount the electronics and place the sensors/actuators as needed for the system to work. As I mentioned earlier, I decided to create my own wires to facilitate wiring at a later stage.


Step 9: a Few Considerations…

As you may have read on the earlier step, there was some trouble with the result, so you may be thinking it was all a waste of both resources and precious time. However, let me tell you that it ended up being quite the opposite.

As Niki Lauda used to say:

“From success, you learn absolutely nothing. From failure and setbacks conclusions can be drawn.”

With everything that gone wrong with this project I learned something that could help in the future to avoid making the same mistakes or taking some things into consideration from the very beginning that I didn’t have in mind when I started. 

Some Ideas for the Future

On the other hand, I can recognize that some errors were made along the way, and I’m not afraid of recognizing it.

Take the conveyor’s motor for example. I used a direct drive mechanism, which only contributed to chaos when moving the fruit along the belt. Precision was sacrificed in the search of keeping within a budget, so if you ask me, I’d prefer to add some reduction mechanism like a pulley to improve the system.

Other thing worth noting is that the belt wasn’t sturdy at all, which contributed to the fruit getting stuck sometimes. This led to the possibility of a sensor triggering incorrectly or the system getting stuck in an apparent infinite loop. To correct this, I considered the idea of adding some plates below the belt to help stabilize the movement, especially of lemons that tend to be more spherical.

At last, but not least, I must warn you that the use of the RGB sensor and the later results from the perceptron are strongly ambient-light dependant. This was one of my biggest problems on a later stage of the development of this project, so it could be a good idea to try to control the ambient light when taking samples for training and then when using the fully automated sorting machine. 


References

[1] I. Nunes da Silva, Artificial Neural Networks, Springer, 2017