ESP32로 장난감을 만든 다음 붙여있는 센서들의 input을 기초로 모델을 만들어 저장하려고 했는데, 가지고 있는 ESP32 보드들이 4MB PSRAM이 없는 WROOM 칩들을 사용하는 옛날 보드들이었습니다.

WROVER 버전들만 (4M / 8M / 16M)짜리 PSRAM이 있더군요.

가지고 있는 WROOM에도 SPIFFS 기능을 사용해서 화일을 쓰고 읽고 삭제할 수 있지만 크기가 많이 줄어듭니다.

실험용으로는 별 문제는 없겠지만 그래도 무척 아쉽군요.

온라인에 ESP32로 AI를 사용하는 대부분의 경우는 Training을 PC에서 텐서플로같은 툴들을 사용해서 한 후 결과값만 코드로 옮겨서 사용하더군요. 단순한 센서의 값을 이용하는 경우의 대부분이 단순한 linear regression 문제라서 ESP32 자체적으로 금방 훈련도 될 것 같은데 원시적인 코딩이 불편한가 봅니다.

저도 원시적인 코딩이 귀찮아서 라이브러리들을 설치하게 되더군요.

 

SPIFFS 화일 작업 실험.

 

 

새로 설치한 ESP32에서 쓸 수 있는 인공지능용 라이브러리들.  (key term : Neural, Tensor)

신경망 라이브러리 설치.

 

 

Tensor Flow 관련 라이브러리 설치 

 

NeuralNetwork 라이브러리의 샘플을 실행해 본 사진.

 

 

 

'인공지능 ESP32' 카테고리의 다른 글

Demo32_Simple_ML  (0) 2021.10.09
ESP32로 고전 인공지능 OR 문제 1개의 퍼셉트론으로 풀기.  (0) 2021.10.08
Code Block 실험.  (0) 2019.07.27
/*
 *   https://www.iotsharing.com/2017/09/simple-machine-learning-neural-network-demo-using-arduino-esp32.html
 * 
 */
#include <math.h>

#define B1  12
#define B2  13
#define LED 14

int X[1][2]    =   {{1,0}};
/*these matrices was calculated by python */
float W1[2][3] =   {{0.74000854,  4.47769531, -0.98692059}, 
                    {0.83034991,  4.48772758, -0.55733578}};
float W2[3][1] =   {{-6.17234487}, 
                    {4.8835918}, 
                    {1.28875386}};
float Wo1[1][3];
float sum = 0;
float Y = 0;

/*sigmoid function*/
float sigmoid (float x)
{
    return 1/(1 + exp(-x));
}


void setup()
{
  Serial.begin(115200);
  pinMode(B1, INPUT_PULLUP); 
  pinMode(B2, INPUT_PULLUP); 
  pinMode(LED, OUTPUT); 
  digitalWrite(LED, LOW);
}

void loop()
{
  X[0][0] = digitalRead(B1);
  X[0][1] = digitalRead(B2);
  printf("B1 = %d, B2 = %d\n", X[0][0], X[0][1]);
  
  /* calculate forward part based on weights */
  //hidden layer
  for(int i=0; i<1; i++)
  {
      for(int j=0;j <3; j++)
      {
          for(int k=0; k<2; k++)
          {
              sum += X[i][k]*W1[k][j];
          }
          Wo1[i][j] = sigmoid(sum);
          sum = 0;  
      }
  }
  //output layer
  for(int i=0; i<1; i++)
  {
      for(int j=0;j <1; j++)
      {
          for(int k=0; k<3; k++)
          {
              Y += Wo1[i][k]*W2[k][j];
          } 
      }
  }
  printf("Y = %f\n", (Y));
  Y = round(Y);
  digitalWrite(LED, int(Y));
  Y = 0;
  delay(1000);
}

특별한 인공지능용 라이브러리 전혀 안쓰고 시도해 봤습니다.

옛날 1960년대 전산자원이 지극히 열악한 환경에서 시도한 방식이라 XOR을 시도하면 옛날처럼 틀린 값이 나옵니다.

 

결과 :

 

코드 :

/* "OR" problem with 1 neuron in ESP32
  ----------------------------------
   input1   |  input2   |  output
  ----------+-----------+-----------
   1(True)  |  1(True)  |  1(True)
   1(True)  |  0(False) |  1(True)
   0(False) |  1(True)  |  1(True)
   0(False) |  0(False) |  0(False)
  ----------------------------------*/
#include <math.h>

const int PatternCount = 4;  // 4 cases, 총 가능한 경우의 수
const int InputCol = 2;      // 2 key values (input1, input2)
const float learning_rate = 0.1;  // 학습률
const float x[PatternCount][InputCol] = {  // Inputs of OR - All cases
   {1, 1},  // 1(True)  |  1(True)
   {1, 0},  // 1(True)  |  0(False)
   {0, 1},  // 0(False) |  1(True)
   {0, 0}   // 0(False) |  0(False)
};

// known results (원하는 결과값)
const float y[PatternCount] = { 
   1, 
   1, 
   1, 
   0 
};

float w[InputCol]; // 가중치 (입력항 갯수만큼), 난수(Random)로 초기화할 것.
float b;           // 편향치 (항상 1개만 사용) - bias, 난수(Random)로 초기화할 것.
float b_x = 1.0;
int j;
float output;
float error;
float error_sum;
float tempval;
String s;

// 활성화 함수 (Activation Function)
float sigmoid (float n) {
    return 1/(1 + exp(-n));
}

void setup() {
   Serial.begin(19200);
   Serial.println(" ");
   Serial.println("OR problem solving using ESP32 with only 1 neuron.");
   
   // Initialize, 난수(Random)로 초기화할 것.  이번에는 대충 초기화했슴.
   w[0] = 0.7245;  // Any number (0 < n < 1) to initialize
   w[1] = 0.4356;  // Any number (0 < n < 1) to initialize
   b = 0.76254;    // Any number (0 < n < 1) to initialize

  // 첫번째 루프 : 2000번의 학습을 진행시킬 예정.
   for (int i = 1; i <= 2000; i++) {  
      error_sum = 0;  // 한번의 학습 결과를 저장 (기본 값은 0)

      // 두번째 루프  : 4번의 인스턴스 (ROW)를 사용함.
      j = 0;
      do {
         output = sigmoid((x[j][0] * w[0]) + (x[j][1] * w[1]) + b_x * b);   
         error = y[j] - output;
         w[0] = w[0] + (x[j][0]) * learning_rate * error;
         w[1] = w[1] + (x[j][1]) * learning_rate * error;
         b = b + b_x * learning_rate * error;
         error_sum += error;    
         j++;
      } while (j < 4);   
      
      if ((i % 200)==0) {  // 결과 표시 매 200번마다
         s = "";  s = s + i;  s = s +" - Output :";   s = s + output;
         s = s + "   Error_Sum :";  s = s + error_sum;
         Serial.println(s);
      }     
   }
   // 최종 확인
   Serial.println("-------- Final -----------");
   for (int i = 0; i < 4; i++) {
      s = i;  s = s + " - Output :";
      tempval = sigmoid((x[i][0] * w[0]) + (x[i][1] * w[1]) + b);
      s = s + tempval;  s = s + "   Round : ";   s = s + round(tempval);
      s = s + "  Exp.Y : ";  s = s + y[i];
      Serial.println(s);
   }
}

void loop() {
  
}

'인공지능 ESP32' 카테고리의 다른 글

ESP32에서 다층 신경망을 돌리고 결과를 저장하기 - (구상)  (0) 2021.10.09
Demo32_Simple_ML  (0) 2021.10.09
Code Block 실험.  (0) 2019.07.27

와!!  코드가  포멧에 맞춰서 들어간다~~~

 

 

#include "SSD1306Wire.h" // legacy include: `#include "SSD1306.h"`

#define _CIRCLE_RAD 10

// (PIN NO) - 4 PhotoResistors (Front, Back, Left, Right)
const int prFrontPin = 36; // default A/D
const int prBackPin  = 39; // default A/D
const int prLeftPin  = 2;  // (*) this analog port dies if Wifi is enabled
const int prRightPin = 14; // (*) this analog port dies if Wifi is enabled
    // Also need to call on setup() to enable as A/D. "adcAttachPin(prLeftPin)";
    // Also need to call on setup() to enable as A/D. "adcAttachPin(prRightPin)";
/* PROBLEM WITH ESP32 A/D : GPIO25, GPIO26, GPIO4, GPIO0 did not work as A/D */  

// For Two Buttons
const int btnRUN      = 13; // Run
const int btnTraining = 15; // Training Neural Network

bool IsRunning = false;
bool IsTraining = false;

// For TB6612FNG Motor Driver

// Currently problem with short number of pins, I will use GPIO16 for all following 
// three pins on motor controller to put it HIGH,
// Will not use PWM, since this board sucks, and PWM has too much trouble.
// The OLED board that I used for this project is by far worst in all the ESP32 boards that I have used so far.
const int md_STBY_pin  = 16;  // Enables whole motor drive.
const int md_A_PWM_pin = 16; // Speed of Motor A 
const int md_B_PWM_pin = 16; // Speed of Motor B 

// I can disable motor A by in1 & in2 both LOW
const int md_AIN1_pin  = 26; // Direction of Motor A
const int md_AIN2_pin  = 0;  // Direction of Motor A

// I can disable motor B by in1 & in2 both LOW
const int md_BIN1_pin  = 12; // Direction of Motor B
const int md_BIN2_pin  = 25; // Direction of Motor B


// (VALUES) 4 PhotoResistors (Front, Back, Left, Right) 
int prFrontValue = 0;
int prBackValue  = 0;
int prLeftValue  = 0;
int prRightValue = 0;

SSD1306Wire  display(0x3c, 5, 4);

int MotorTestL = 0;  // 0 : stop, 1 : Forward, 2 : Backward
int MotorTestR = 0;  // 0 : stop, 1 : Forward, 2 : Backward

const int WheelLeft  = 32; // motor L on my design sheet
const int WheelRight = 27; // motor R on my design sheet

int r = 0; // Simple Counter to replace delay() in the main loop

String s; // Temporary string for general purpose

String sendbuff;
String commandstring;
String cs = ""; // Command String
String rs = ""; // Respond String = 'R' + Command String

char ReplyBuffer[] = "acknowledged"; // a string to send back
unsigned long preMillis = 0;
unsigned long curMillis = 0;

void drawTop(void) {
   display.drawCircle(10, display.getHeight()/2, _CIRCLE_RAD);
   display.display();
}

void drawBottom(void) {
   display.drawCircle(50, display.getHeight()/2, _CIRCLE_RAD);
   display.display();
}

void drawLeft(void) {
   display.drawCircle(30, display.getHeight()-12, _CIRCLE_RAD);
   display.display();
}

void drawRight(void) {
   display.drawCircle(30, 10, _CIRCLE_RAD);
   display.display();
}

void drawTest() {
   display.init();
   display.setContrast(255);
   display.clear();
   display.display();
   
   delay(1000);
   drawTop();
   delay(500);
   drawBottom();
   delay(500);
   drawLeft();
   delay(500);
   drawRight();
   delay(500);  
}

void IRAM_ATTR onRunPressed() {
   if (IsRunning == false) {
      Serial.println("RUN"); 
      IsRunning = true;     
   } else {
      Serial.println("OFF RUN");   
   } 
   MotorTestL += 1;
   if (MotorTestL > 2) { MotorTestL = 0; }
   
}

void IRAM_ATTR onTrainingPressed() {
   if (IsTraining == false) {
      Serial.println("TRAINING");   
      IsTraining = true;  
   } else {
      Serial.println("OFF TRAINING");   
   }  
   MotorTestR += 1;
   if (MotorTestR > 2) { MotorTestR = 0; }

   
}

void turn_right() {  // Turn Right
   digitalWrite(md_AIN1_pin, HIGH);
   digitalWrite(md_AIN2_pin, LOW);
   digitalWrite(md_BIN1_pin, LOW);
   digitalWrite(md_BIN2_pin, HIGH);
}

void turn_left() {  // Turn Left
   digitalWrite(md_AIN1_pin, LOW);
   digitalWrite(md_AIN2_pin, HIGH);
   digitalWrite(md_BIN1_pin, HIGH);
   digitalWrite(md_BIN2_pin, LOW);
}

void move_forward() {  // 
   digitalWrite(md_AIN1_pin, HIGH);
   digitalWrite(md_AIN2_pin, LOW);
   digitalWrite(md_BIN1_pin, HIGH);
   digitalWrite(md_BIN2_pin, LOW);
}

void move_backward() {  // 
   digitalWrite(md_AIN1_pin, LOW);
   digitalWrite(md_AIN2_pin, HIGH);
   digitalWrite(md_BIN1_pin, LOW);
   digitalWrite(md_BIN2_pin, HIGH);
}

void wheel_stop() {
   digitalWrite(md_AIN1_pin, LOW);
   digitalWrite(md_AIN2_pin, LOW);
   digitalWrite(md_BIN1_pin, LOW);
   digitalWrite(md_BIN2_pin, LOW); 
}
void setup() { 
   r = 0;
   
   pinMode(btnRUN,   INPUT);     // BUTTON B1
   pinMode(btnTraining, INPUT);  // BUTTON B2

   attachInterrupt(btnRUN, onRunPressed, RISING);
   attachInterrupt(btnTraining, onTrainingPressed, RISING);

   pinMode(md_STBY_pin, OUTPUT); // 16; // (6 will CRASH) Enables whole motor drive.

   pinMode(md_AIN1_pin, OUTPUT); // 26;// Direction of Motor A
   pinMode(md_AIN2_pin, OUTPUT); // 0; // Direction of Motor A
//   pinMode(md_A_PWM_pin, OUTPUT);// 16; // Speed of Motor A 

   pinMode(md_BIN1_pin, OUTPUT); // 12;// Direction of Motor A
   pinMode(md_BIN2_pin, OUTPUT); // 25; // Direction of Motor A
//   pinMode(md_B_PWM_pin, OUTPUT);// 16; // Speed of Motor A 
   
   Serial.begin(112500);

   drawTest();

   adcAttachPin(prLeftPin);
   adcAttachPin(prRightPin);

   digitalWrite(md_STBY_pin, HIGH);  // it will make ON for both PWMA, PWMB also
//   digitalWrite(md_A_PWM_pin, HIGH);
//   digitalWrite(md_B_PWM_pin, HIGH);

   move_forward();  delay(1000);

   wheel_stop();    delay(1000);

   move_backward(); delay(1000);
   
   wheel_stop();    delay(1000);

   turn_right(); delay(1000);
   
   wheel_stop();    delay(1000);

   turn_left(); delay(1000);
   
   wheel_stop();    delay(1000);
}

void loop() {
   r++;
   if (r > 650000){ // THIS IS DESCENT DELAY  // about 1 sec
      prFrontValue = analogRead(prFrontPin);   // delay in between reads for stability
      prBackValue = analogRead(prBackPin);    // delay in between reads for stability
      prLeftValue = analogRead(prLeftPin);   // delay in between reads for stability
      prRightValue = analogRead(prRightPin);  // delay in between reads for stability 
     // delay(50);  // delay in between reads for stability 

      s = " ";
      s += prFrontValue;
      s += ", ";
      s += prBackValue;
      s += ", ";
      s += prLeftValue;
      s += ", ";
      s += prRightValue;
      Serial.println(s);
      
      r = 0;
   }  
}

+ Recent posts