Skip to content

Instantly share code, notes, and snippets.

@samuelcaldas
Last active April 9, 2023 03:37
Show Gist options
  • Save samuelcaldas/9abb4a6c80664cf33ac187e66f4cf547 to your computer and use it in GitHub Desktop.
Save samuelcaldas/9abb4a6c80664cf33ac187e66f4cf547 to your computer and use it in GitHub Desktop.
Este código é um exemplo de como implementar um Perceptron simples usando um Arduino e um LED endereçável.
/*
PerceptrUINO - Perceptron com Arduino
Samuel Oliveira Caldas
Como utilizar o PerceptrUINO:
- Conecte o Arduino a uma fonte de energia
- O LED piscará azul, verde e vermelho 3 vezes e ficará branco indicando está pronto para ser utilizado
- Para treinar a rede, pressione e segure um dos três botões de entrada enquanto o LED estiver piscando
- Pressione o botão "Certo" ou "Errado" para indicar se a cor do LED é a cor esperada para aquele botão
- Faça isso algumas vezes para que a rede aprenda
- Para validar a rede, pressione o botão "Validar" e, enquanto o LED estiver piscando, pressione um dos botões de entrada
- O LED acenderá de acordo com a cor que a rede aprendeu para aquele botão
*/
#include <Adafruit_NeoPixel.h>
#define PinLED 2 // Endereço do LED endereçavel
// Botões
#define botaoCerto A0 // Endereço do botão "Certo"
#define botaoErrado A1 // Endereço do botão "Errado"
#define botaoValidar A2 // Endereço do botão "Validar"
static int botaoEntrada[3] = {6, 5, 4}; // Endereços dos botões de entrada
// Cores
static int vermelho[3] = {255, 0, 0};
static int verde[3] = {0, 255, 0};
static int azul[3] = {0, 0, 255};
static int branco[3] = {255, 255, 255};
static int preto[3] = {0, 0, 0};
int valorEntrada[3] = {0, 0, 0}; // Valores de entrada
double pesoEntrada[3] = {0, 0, 0}; // Pesos de entrada
double LR = 0.1; // Taxa de aprendizado
double entropia = 1.0; // Adiciona uma pequena entropia para evitar que a rede fique presa em um mínimo local
double Saida; // Saída da rede
int intervalo = 200; // Tempo a se esperar entre as ações em milissegundos
bool debug = true; // Ativa ou desativa o modo debug
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(1, PinLED, NEO_GRB + NEO_KHZ800); // Parametros: numero de pixels na fita, numero do pino do Arduino, tipo de pixel
void setup()
{
Serial.begin(9600); // Inicializa a comunicação serial
pixels.begin(); // Inicializa a biblioteca NeoPixel.
}
void loop()
{
blink(3);
readInputs();
delay(3 * intervalo);
Saida = getAction(1);
if (Saida > 0)
{
defineCor(azul);
}
else if (Saida < 0)
{
defineCor(verde);
}
else
{
defineCor(vermelho);
}
// Aguarda algum botão ser pressionado
while (digitalRead(botaoCerto) == LOW && digitalRead(botaoErrado) == LOW && digitalRead(botaoValidar) == LOW)
;
// Treina a rede
if (digitalRead(botaoCerto) == HIGH)
{
train(0.1);
defineCor(branco);
delay(intervalo);
}
else if (digitalRead(botaoErrado) == HIGH)
{
train(-0.1);
defineCor(branco);
delay(intervalo);
}
}
// Lê os valores dos botões de entrada
void readInputs()
{
for (size_t i = 0; i < 3; i++)
{
valorEntrada[i] = inverterValor(digitalRead(botaoEntrada[i]));
if (debug)
{
Serial.print("Valor entrada ");
Serial.print(i + 1);
Serial.print(": ");
Serial.println(valorEntrada[i]);
}
}
}
// Treina a rede
void train(double erro)
{
for (size_t i = 0; i < 3; i++)
{
pesoEntrada[i] += LR * erro * valorEntrada[i];
}
}
// obtem uma acao
double getAction(int activationFunction)
{
double action = 0;
for (size_t i = 0; i < 3; i++)
{
action += pesoEntrada[i] * valorEntrada[i];
}
if (activationFunction == 0)
{
action = sigmoide(action);
}
else if (activationFunction == 1)
{
action = tanh(action);
}
if (debug)
{
Serial.print("Acao: ");
Serial.println(action);
}
return action;
}
// defineCor() envia a cor desejada ao LED
void defineCor(int Cor[3])
{
pixels.setPixelColor(0, pixels.Color(Cor[0], Cor[1], Cor[2])); // pixels.Color aceita valores RGB, de 0,0,0 a 255.255.255
pixels.show(); // Isso envia a cor atualizada do pixel para o hardware.
}
// Pisca os leds x vezes
void blink(int x)
{
for (size_t i = 0; i < x; i++)
{
defineCor(azul);
delay(intervalo);
defineCor(verde);
delay(intervalo);
defineCor(vermelho);
delay(intervalo);
defineCor(branco);
}
}
// Função de ativação sigmoide
// retorna um valor entre 0 e 1
double sigmoide(double x)
{
return 1.0 / (1.0 + exp(-x));
}
// Função de ativação tangente hiperbólica
// retorna um valor entre -1 e 1
double tanh(double x)
{
return 2.0 / (1.0 + exp(-2.0 * x)) - 1.0;
}
// inverte o valor de x
double inverterValor(int x)
{
return (x == 1) ? 1 : -1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment