Last active
April 9, 2023 03:37
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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