Máquina Avançada de Classificação de Cores com Arduino e Sensor RGB
Componentes e Materiais
| Componente | Quantidade |
|---|---|
| Arduino Nano R3 | 1 |
| Sensor RGB TCS34725 | 1 |
| Conversor Buck LM2596 | 1 |
| Servos MG-90S | 2 |
| Rolamento MR105ZZ (5 x 10 x 4 mm) | 3 |
| Rolamento 608RS ou 608ZZ (8 x 22 x 7 mm) | 1 |
| Rolamento 6003RS (17 x 35 x 10 mm) | 1 |
| Parafuso sextavado M3 x 15 mm | 1 |
| Parafusos auto-roscantes M2 x 10 mm | 20 |
| LED RGB (ânodo comum) | 1 |
| Resistores de 220 ohms | 3 |
| Fios | 1 |
| Plugue jack 2.1 x 5.5 mm | 1 |
| Tubo termorretrátil | 1 |
| Conectores DuPont | 1 |
| Fonte de alimentação 9V ou 12V (mínimo 1 A) | 1 |
| Tubos de ensaio 5x 22 mm (OD) x 100 mm (Danmu Art) | 1 |
| Skittles!!!!!!!!!! | 1 |
Ferramentas e Máquinas Necessárias
- Impressora 3D
- Chave de fenda
- Alicate de corte/desencapador
- Alicates
- Ferro de solda
- Multímetro
- Ferramenta de crimpagem
Sobre este Projeto
Introdução
A história engraçada é que este projeto nunca foi planejado. Há cerca de 3,5 anos, comecei a projetar uma máquina de classificação de cores muito mais complexa e, como muitos dos meus projetos, ela ficou pela metade, acumulando poeira no parapeito da janela (tenho certeza de que ninguém mais se identifica com isso, haha).
Resumindo: há alguns meses, decidi retomar esse projeto antigo. A primeira coisa que precisei resolver foi como coletar Skittles de um reservatório e verificar sua cor de forma confiável, mantendo o sistema o mais compacto possível (o que falhei na primeira vez). Conversei comigo mesmo para projetar uma máquina de classificação de cores mais simples apenas para acertar o design do sistema de coleta. Achei ingenuamente que seria um trabalho de dois fins de semana, algo rápido e fácil... Como eu estava errado!
Foram necessários dois designs completamente diferentes e muitos protótipos ajustados para obter algo que funcionasse de maneira aceitável (ainda estou enfrentando alguns problemas de coleta de vez em quando).
Mesmo não sendo perfeito, estou bastante satisfeito com o resultado.
Como Funciona
A máquina pode ser dividida em dois estágios principais.
No topo, encontra-se o reservatório para Skittles não classificados. Na parte inferior deste reservatório, está o mecanismo de alimentação responsável por coletar os Skittles e posicioná-los em frente ao sensor de cor, onde sua cor será verificada.
O mecanismo de alimentação inclui um braço que agita o conteúdo do reservatório para garantir que os Skittles fluam suavemente através do orifício do mecanismo sem travar dentro do reservatório (infelizmente, isso ainda acontece às vezes).
Uma vez que a cor do Skittle foi identificada, o segundo estágio da máquina entra em ação. O suporte dos tubos de ensaio alinha o tubo correto em frente ao mecanismo de alimentação para que o Skittle caia dentro dele.
O ciclo pode então ser repetido até que o reservatório esteja vazio.
Quer Construir a Sua Própria?
Visite: https://www.littlefrenchkev.com/colour-sorting-machine
Montagem
Depois de baixar e imprimir as peças, você deve obter algo como isto:
Observe que a carcaça frontal vem em duas versões. Não há diferença real, apenas a aparência.
O restante das peças necessárias.
Aqui está um vídeo do processo de montagem. Até tentei ser artista fazendo uma introdução com câmera lenta da impressora 3D!
Configuração Inicial
A primeira coisa que a máquina faz ao ligar é mover ambos os servos para suas posições iniciais. Ao iniciar a máquina pela primeira vez, você precisa garantir que o eixo/engate que coleta os Skittles esteja em sua posição superior e que o suporte dos tubos esteja alinhado com o mecanismo de alimentação.
Solução de Problemas
Se você decidir construir esta máquina de classificação, pode encontrar alguns problemas comuns. Aqui está como resolvê-los.
LED piscando vermelho - sem sequência de inicialização:
Após mover para sua posição inicial, a máquina deve executar sua sequência de inicialização. Se não o fizer e, em vez disso, o LED piscar vermelho, significa que há problemas com o sensor RGB não sendo detectado. Há um problema na fiação ou o sensor está com defeito.
Os tubos não alinham corretamente:
Causa 1: Durante a sequência de inicialização, o suporte dos tubos mover-se-á 5 vezes, uma para cada cor. Você pode notar que os tubos não alinham bem com o mecanismo de alimentação. Isso pode ser devido aos servos não serem super precisos ou a variações nas dimensões da impressão.
Isso pode ser corrigido via software modificando o array colour_angle. Cada valor neste array representa a posição do servo para cada cor; alterando esses valores, você pode ajustar finamente onde o tubo vai parar para cada cor.
Causa 2: Devido a tolerâncias de impressão, você também pode obter alguma folga nas engrenagens do suporte dos tubos. Dependendo da direção em que os tubos giram, sua inércia pode fazer com que ultrapassem a posição de parada. Isso também pode ser corrigido via software modificando as variáveis forward_anti_backlash e backward_anti_backlash. Esses valores serão adicionados ou subtraídos dos valores de ângulo de cor, dependendo da direção em que o suporte gira, para compensar essa folga.
Mistura de cores:
Se você tiver alguma mistura de cores, terá que modificar os arrays colour_limit_values. Cada valor nesses arrays representa os valores mínimo e máximo para Vermelho, Verde e Azul. Para ter uma ideia melhor do que os valores devem ser, carregue a máquina com apenas uma cor, conecte-a ao computador e abra o monitor serial. Cada vez que um Skittle for verificado, você obterá seus valores RGB lidos e qual cor o programa acha que é. Isso deve dar uma ideia melhor de quais valores devem ser associados a cada cor.
Alguns Recursos Legais
(Bem, eu acho que são!)
O LED RGB:
Há um LED RGB na base da máquina. Durante o processo de classificação, ele muda de cor para combinar com a cor do Skittle que está sendo solto. Ele percorre todas as cores dos Skittles continuamente quando o reservatório está vazio.
Ele também pisca vermelho na inicialização se um problema for detectado com o sensor.
Compensação de anti-folga:
O suporte dos tubos é girado usando um par de engrenagens cilíndricas. Devido à tolerância de impressão, é muito difícil eliminar completamente qualquer folga nas engrenagens. Isso significa que o suporte tende a ultrapassar sua posição ideal. O código permite compensar isso parando o suporte um pouco antes, em uma certa quantidade, dependendo da direção em que o suporte está girando.
Atraso com extra:
O código inclui uma função set_led(ms, color). Ela age exatamente como a função delay(ms), mas permite que o LED mude suavemente para sua nova cor enquanto o atraso ocorre. Funciona muito bem para mudar as cores do LED enquanto o suporte dos tubos gira para sua posição!
Notas Extras
- Imprimi minha máquina em preto, isso afetará os valores de cor que o sensor lerá, especialmente quando nenhum Skittle for coletado pelo mecanismo de alimentação.
- Após passar pelo processo de classificação várias vezes, as cores dos Skittles parecem tornar-se mais difíceis de ler de forma confiável. Assumo que isso se deve a eles perderem o brilho após esfregar dentro do reservatório muitas vezes ou ficarem um pouco pegajosos quando manuseados à mão (soa nojento!). Ao calibrar os valores de cor, tente usar Skittles 'novos'.
- Por favor, certifique-se de tomar todas as precauções necessárias ao manusear alimentos. Isso inclui garantir que você use filamento de impressão seguro para alimentos.
- Tento postar alguns trabalhos em andamento e quais projetos estou desenvolvendo no Instagram. Se for do seu interesse, pode dar uma olhada aqui: https://www.instagram.com/little_french_kev/
Código
LFK_sorting_machine (C/C++)
Código Arduino para a máquina de classificação.
#include <Wire.h> #include "Adafruit_TCS34725.h" #include<Servo.h>
/* Based on example code for the Adafruit TCS34725 breakout library */
//=======================Variáveis relacionadas ao sensor RGB=========================
Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_24MS, TCS34725_GAIN_1X);
int colour = 0; //0-preto, 1-amarelo, 2-verde, 3-laranja, 4-vermelho, 5-roxo
int previous_colour = colour;
int black_count = 0;
int start_measurment_angle = 88;
int measurment_sweep = 2;
int measurment_angle_increment = 4;
//limit values[] = {min_red, max_red, min_green, max_green, min_blue, max_blue}
uint16_t black_limit_values[] = {0, 200, 0, 200, 0, 200};
uint16_t yellow_limit_values[] = {850, 2200, 800, 2200, 400, 1100};
uint16_t green_limit_values[] = {400, 800, 700, 1400, 300, 700};
uint16_t orange_limit_values[] = {650, 1800, 300, 850, 210, 600};
uint16_t red_limit_values[] = {400, 950, 150, 450, 150, 400};
uint16_t purple_limit_values[] = {150, 400, 150, 450, 150, 500};
//=======================Variáveis relacionadas ao LED RGB=========================
byte R_pin = 5; byte G_pin = 6; byte B_pin = 11;
int current_red_value = 255; int current_green_value = 255; int current_blue_value = 255;
const int orange[] = {0, 230, 255};
const int red[] = {0, 255, 255};
const int green[] = {255, 0, 255};
const int yellow[] = {0, 170, 255};
const int purple[] = {0, 255, 40};
//======================= Variáveis relacionadas aos servos de alimentação =========================
int release_delay = 220;
const int colour_angles[] = {10, 46, 82, 118, 154};
const int backward_anti_backlash = 2;
const int forward_anti_backlash = 2;
Servo feeder_servo;
Servo holder_servo;
//=================================== SETUP =========================================
void setup(void) {
Serial.begin(9600);
pinMode(R_pin, OUTPUT); pinMode(G_pin, OUTPUT); pinMode(B_pin, OUTPUT);
analogWrite(R_pin, 255); analogWrite(G_pin, 255); analogWrite(B_pin, 255);
feeder_servo.attach(3); holder_servo.attach(2);
feeder_servo.write(0); holder_servo.write(colour_angles[0]);
int white[] = {0, 0, 0}; int black[] = {255, 255, 255};
set_led(1000, white);
if (tcs.begin()) {
Serial.println("Found sensor"); starting_sequence();
} else {
Serial.println("No TCS34725 found ... check your connections");
while (1) { set_led(300, red); set_led(300, black); }
}
}
//=================================== LOOP =========================================
void loop(void) {
if (black_count < 10) {
feeder_servo.write(0); delay(450);
previous_colour = colour; get_colour();
if (colour == 0) { black_count++; shake(); }
else if (colour == 6) { black_count++; }
else { move_holder(); release_skittle(); black_count = 0; }
} else { end_loop(1000); }
}
//=================================== GET COLOUR =========================================
void get_colour() {
uint16_t r, g, b, c; uint16_t total_r = 0, total_g = 0, total_b = 0;
feeder_servo.write(start_measurment_angle); delay(200);
Serial.println("----------------");
for (int i = 0; i <= measurment_sweep; i++) {
tcs.getRawData(&r, &g, &b, &c);
feeder_servo.write(start_measurment_angle + i * measurment_angle_increment);
total_r += r; total_g += g; total_b += b; delay(15);
}
total_r /= measurment_sweep; total_g /= measurment_sweep; total_b /= measurment_sweep;
Serial.print(total_r); Serial.print(" "); Serial.print(total_g); Serial.print(" "); Serial.print(total_b); Serial.println(" ");
//comparar valores para determinar a cor
if ((total_r < black_limit_values[1]) && (total_g < black_limit_values[3]) && (total_b < black_limit_values[5])) {
Serial.println("black"); colour = 0;
} else if ((total_r >= yellow_limit_values[0]) && (total_r < yellow_limit_values[1]) &&
(total_g >= yellow_limit_values[2]) && (total_g < yellow_limit_values[3]) &&
(total_b >= yellow_limit_values[4]) && (total_b < yellow_limit_values[5])) {
Serial.println("yellow"); colour = 1;
} else if ((total_r >= green_limit_values[0]) && (total_r < green_limit_values[1]) &&
(total_g >= green_limit_values[2]) && (total_g < green_limit_values[3]) &&
(total_b >= green_limit_values[4]) && (total_b < green_limit_values[5])) {
Serial.println("green"); colour = 2;
} else if ((total_r >= orange_limit_values[0]) && (total_r < orange_limit_values[1]) &&
(total_g >= orange_limit_values[2]) && (total_g < orange_limit_values[3]) &&
(total_b >= orange_limit_values[4]) && (total_b < orange_limit_values[5])) {
Serial.println("orange"); colour = 3;
} else if ((total_r >= red_limit_values[0]) && (total_r < red_limit_values[1]) &&
(total_g >= red_limit_values[2]) && (total_g < red_limit_values[3]) &&
(total_b >= red_limit_values[4]) && (total_b < red_limit_values[5])) {
Serial.println("red"); colour = 4;
} else if ((total_r >= purple_limit_values[0]) && (total_r < purple_limit_values[1]) &&
(total_g >= purple_limit_values[2]) && (total_g < purple_limit_values[3]) &&
(total_b >= purple_limit_values[4]) && (total_b < purple_limit_values[5])) {
Serial.println("purple"); colour = 5;
} else { Serial.println("unknown"); colour = 6; }
}
//============================== MOVE HOLDER =============================
void move_holder() {
int new_holder_position = colour_angles[colour - 1];
int holder_delay = (abs(previous_colour - colour) * 70);
if (holder_delay < 0) holder_delay = 0;
if (previous_colour > colour) {
int anti_backlash_angle = new_holder_position - backward_anti_backlash;
holder_servo.write(anti_backlash_angle);
} else {
int anti_backlash_angle = new_holder_position + forward_anti_backlash;
holder_servo.write(new_holder_position);
}
if (colour == 1) set_led(holder_delay, yellow);
else if (colour == 2) set_led(holder_delay, green);
else if (colour == 3) set_led(holder_delay, orange);
else if (colour == 4) set_led(holder_delay, red);
else if (colour == 5) set_led(holder_delay, purple);
}
//============================= RELEASE SKITTLE ===========================
void release_skittle() { feeder_servo.write(180); delay(release_delay); }
//================================= SHAKE =================================
void shake() {
int shake_delay = 80; int shake_amount = 5; int shake_min_value = 90; int shake_max_value = 180;
feeder_servo.write(180); delay(release_delay);
feeder_servo.write(120); delay(80);
for (int i = 0; i <= shake_amount; i++) {
feeder_servo.write(shake_min_value); delay(shake_delay);
feeder_servo.write(shake_max_value); delay(shake_delay);
}
}
//============================ STARTING SEQUENCE ============================
void starting_sequence() {
colour = 1; move_holder(); set_led(300, yellow); delay(400);
colour = 2; move_holder(); set_led(300, green); delay(400);
colour = 3; move_holder(); set_led(300, orange); delay(400);
colour = 4; move_holder(); set_led(300, red); delay(400);
colour = 5; move_holder(); set_led(300, purple); delay(400);
previous_colour = colour; colour = 3; move_holder(); end_loop(200);
}
//================================ END LOOP =================================
void end_loop(int duration) {
set_led(duration, orange); set_led(duration, red); set_led(duration, green);
set_led(duration, yellow); set_led(duration, purple);
}
//============================ SET RGB LED COLOUR =======================
void set_led(int duration, int color[3]) {
int start_time = millis(); int current_time = start_time; int current_duration = 0;
while (current_duration < duration) {
analogWrite(R_pin, map(current_duration, 0, duration, current_red_value, color[0]));
analogWrite(G_pin, map(current_duration, 0, duration, current_green_value, color[1]));
analogWrite(B_pin, map(current_duration, 0, duration, current_blue_value, color[2]));
current_time = millis(); current_duration = current_time - start_time;
}
current_red_value = color[0]; current_green_value = color[1]; current_blue_value = color[2];
}
Esquemáticos
A fiação é bastante direta. Apenas certifique-se de que a saída do conversor buck seja 5V antes de conectar qualquer coisa a ele !!!!!
Processo de manufatura
- Aparelhos de EEG: Design, Fabricação e Aplicações Emergentes
- Máquinas de Venda Automática: Uma Indústria de US$ 36,6 Bilhões nos EUA
- A Evolução e Fabricação de Máquinas de Costura: Da Inovação do Século XIX à Automação Moderna
- Televisão: Das Origens Mecânicas ao Futuro Inteligente
- Mancais de Fuso: Precisão e Garantia de Qualidade
- Partes Essenciais do Torno: Funções e Visão Geral
- Entendendo Tornos: História, Tipos e Aplicações
- Componentes Principais de uma Fresadora Explicados
- O que é uma Máquina? Um Guia Completo
- JW Machine: Serviços de Fabricação por Contrato CNC de Precisão