본문 바로가기

NodeMCU

Wireless 바코드 스캔 피드백

Wireless 바코드 스캔 피드백


왕허접하지만 실제 업무용.


2016-04-10


개요 : 창고의 물건을 특정 지역에 넣을때 Wireless Scanner는 전 창고를 커버하지만 문제는 스캔한 데이타가 중앙 자료 데이다베이스에 잘 들어 갔는지, 무슨 문제가 없는지를 알 방법이 없기에 이 피드백장비를 만들게 되었음.  자체 데이타 관리 프로그램에서 신호를 보내서 현재 상황을 알려줌.


문제 : 왜 간단하게 안드로이드로 셀폰용 앱을 만들어 처리하지, 귀찮게 저런걸 만들어야 하나?  답은 직원들이 일하다 고가의 셀폰을 떨어뜨려 망가지면 최소 칠십만원짜리 셀폰을 사주기는 무리.    창고에서 일하는 남미계열 직원들은 어려서 그런지 셀폰은 최고제품들을 사용함.  막 쓰는 용이 필요함. 


해법 : 아주 싸게 LCD (2줄/16자) 와, NodeMCU V.1.0과 싸구려 셀폰 배터리 파워 뱅크만을 사용해서 전체 가격은 $18 (2만원) 이내로 만들었음.  (비고 : 사실상 가격은 대량생산용이 아니라 중요한 요소가 아니었지만 그냥 재미삼아 가장 간단하게 만들었음.)

 

기술 : 컴과 장비(NodeMCU)는 무선 UDP 통신으로 함.

      NodeMCU는 I2C로 LCD에 메세지를 보냄.


참고 : 우리나라에서 이런 장비를 만들어 팔려면 통신관련인증이나 허가를 받아야 하는데 비용이 기본이 수천만원이니깐 일반 상업용 제품을 만드는 시도도 하지 마실길(지랄맞은 망국규제).  나는 미국에서 내가 소프트웨어 일봐주는 회사의 창고용으로 만든것임.  우리나라의  innovation은 거의 중견기업 내지는 대기업 전용인것 같슴.   안타깝게도 대한민국은 IoT의 후진국이 될 수 밖에 없는 운명..    판매용을 만들때는 문제지만 본인 소유의 농장이나 공장을 자동화하는 용도로는 문제가 없을듯.   아님 회사내 사용을 목적으로 만든다면, 그래도 법에 걸릴라나?  그건 잘 모름.


회로 : 

LCD는 5V 전압을 사용함.




사진 :

(장비의 최종 조립 전)



(밧데리 붙이기 전 - 초 강력 양면 테입 사용)


(조립후 뒷 모습 : 세워놓을수 있음)


(조립후 윗 모습)


완성된 앞모습.


동영상 :




코드 : (NodeMCU의 코드만) - 공개용.  라이브러리는 각자 알아서 설치할것.

/*  THIS IS WRITTEN FOR NodeMCU ESP-12E Development Board V.1.0  */

/*  Author: Hyun Ja. License for this code is set to public domain(free) */

/*  License of each library is as specified by each library authors. */

#include <ESP8266WiFi.h> 

#include <WiFiUdp.h>

#include <Wire.h> 

#include <LiquidCrystal_I2C.h>


WiFiUDP port;

LiquidCrystal_I2C lcd(0x3F,16,2);  // set the LCD address to 0x3F for a 16 chars and 2 line display


char packetBuffer[30];

unsigned int localPort = 6767;

const int ThisMachine = 2;


/* Set these to your desired credentials. */

const char* ssid = "****";  // 당신의 와이파이 명칭 

const char* password = "**********";   // 당신의 와이파이 패스워드 

char botresp[30] = "002-WB: Scan Box First!";  

int P2B_NEWLINE  = 11; // < -- Beginning of Command to BOT (ESP-BOT)

int P2B_COM_TYPE = 12; // 0..int  p2b_pin = 0;9 -- First 2 letters after "<"

                       // Total Command Types : 10 x 10 = 100

int P2B_DATA     = 12; // Data section

int P2B_ENDING   = 13; // > -- End of Message Signal


int P2B_STAT_NONE = 1; // Do nothing until '<' has received

int P2B_STAT_CMD  = 2; // Accepting Command

int P2B_STAT_DATA = 3; // Accepting Command data

int P2B_STAT_END  = 4; // '>' has receieve, it is the end of   command;


char p2b_mach[4];    // always needed + 1

char p2b_command[3]; // always needed + 1

char p2b_data[17];   // always needed + 1

int  p2b_machno = 0;

int  p2b_status = 0;


int  iD0 = 16;  // GPIO 16;  

int  iD1 = 5;   // GPIO 5;   

int  iD2 = 4;   // GPIO 4;   

int  iD3 = 0;   // GPIO 0;    

int  iD4 = 2;   // GPIO 2;   

int  iD5 = 14;  // GPIO 14;  

int  iD6 = 12;  // GPIO 12;  

int  iD7 = 13;  // GPIO 13;  

int  iD8 = 15;  // GPIO 15;  

int  iD9 = 3;   // GPIO 3;   

int iD10 = 1;   // GPIO 1;   

int iD11 = 9;   // GPIO 9;   

int iD12 = 10;  // GPIO 10; 


// Head Light using relay

int HeadLight = iD0; // using GPIO = 16 to turn on/off relay


int i = 0;  // dumb int

int j = 0;  // dumb int

int k = 0;  // dumb int

int n = 0;

int lp =0;  // dumb last position ofinput command string

char    inputString[30];       // a string to hold incoming data

boolean stringComplete = false; // whether the string is complete

char    inChar;

String  tempStr;

String  BoxLine;

String  ItemLine;

char    buffer[12];  // buffer used for itoa  (int to string conversion)

int     inlen = 0;  // Length of inputString


void ClearP2BCommand()

{

   p2b_mach[0] = 0;  // null

   p2b_mach[1] = 0;  // null

   p2b_mach[2] = 0;  // null

   p2b_mach[3] = 0;  // null

   

   p2b_command[0] = 0;  // null

   p2b_command[1] = 0;  // null

   p2b_command[2] = 0;  // null

   for (int i=0; i <= 16; i++){

      p2b_data[i] = 0;  // null

   }

   p2b_machno = 0;


   BoxLine = " ";

   ItemLine = " ";

}


void setup(){

   lcd.init();    // initialize the lcd 

   lcd.backlight();

   // clear the screen

   lcd.clear();

   lcd.print("Scan Box First!");


   pinMode(HeadLight, OUTPUT);   // iD0

   

   WiFi.begin("****", "********");  // 각자의 와이파이 연결 코드


   port.begin(localPort);

  

   BoxLine = "Configuring AP..";

   WriteBox();

   

   // Wait for connection

   while (WiFi.status() != WL_CONNECTED) {

      delay(500);

   };

   ItemLine = "SSID : ";

   ItemLine +=  ssid;

   WriteItem();

   digitalWrite(HeadLight, HIGH);

   delay(1000);

   BoxLine = "Scan Box First!";

   WriteBox();

   delay(1000);

   ItemLine = "  ";

   WriteItem();

   

   digitalWrite(HeadLight, LOW); // Off for Begining (HIGH = off, LOW = on

}


void uPrint(char* msg){   

   port.beginPacket(port.remoteIP(),port.remotePort());

   port.write(p2b_mach);

   port.write("-");

   port.write(msg);  // Getting Command Works

   port.write(": ");

   port.write(p2b_data); 

   port.endPacket(); 

}


void WriteBox(){

   lcd.clear();

   lcd.setCursor(0,0);

   lcd.print(BoxLine);

}


void WriteItem(){

   lcd.setCursor(0,1);

   lcd.print("                ");

   lcd.setCursor(0,1);

   lcd.print(ItemLine);

}


// Test Sample send-out from PC

// #002-IT:Item: 125412-25>

// #002-WB:BOX : 1A-293>


void ExecuteLogicalCommand()

   // Write to the top row

   if (((char)p2b_command[0] == 'W') and ((char)p2b_command[1] == 'B')) { 

      BoxLine = p2b_data;

      WriteBox();

   };  


   // Write to the second row

   if (((char)p2b_command[0] == 'I') and ((char)p2b_command[1] == 'T')) {

      ItemLine = p2b_data;

      WriteItem();

   }; 


   uPrint(p2b_command);  // print to UDP Port

}  


void ClearParamsAndInputstring(){

   // clear the string:

   for (i=0;i<=29;i++) {

      inputString[i] = 0;

   };

   i = 0;

   j = 0;

     

   stringComplete = false;

}


void loop(){

   int packetSize = port.parsePacket();

   if (packetSize) {

      int len = port.read(packetBuffer, 30); // here, len = packetSize

      if (len > 0) {

         packetBuffer[len] = 0;

         if (len < 26) {

            for (i=1;i<26;i++)

               botresp[i+3] = packetBuffer[i];            

         }

      };      

      

      i = 0;

    

      while ((packetSize) >= i){

         inChar = packetBuffer[i];  // get the new byte:

         inputString[i] = inChar;

         i++;

         

         // if the incoming character is a newline, set a flag

         if ((inChar == '#') or (inChar == '<')) {

            p2b_status = P2B_STAT_CMD;

            ClearP2BCommand();

            j = i-1;         

         } else if (inChar == '>') {

            p2b_machno  = 0;

            if (inputString[j+1] != '0') {

               p2b_machno = (int(inputString[j+1])-48) * 100;

            }

            if (inputString[j+2] != '0') {

               p2b_machno = p2b_machno + (int(inputString[j+2])-48) * 10;

            }

            if (inputString[j+3] != '0') {

               p2b_machno = p2b_machno + (int(inputString[j+3])-48);

            }


            // If this command is for ME (This machine)

            if (ThisMachine == p2b_machno){

              

               p2b_mach[0] = inputString[j+1];

               p2b_mach[1] = inputString[j+2];

               p2b_mach[2] = inputString[j+3];


               p2b_command[0] = inputString[j+5];

               p2b_command[1] = inputString[j+6];

            

               j = j + 8;   

               

               k = 0;

               for (n=j;n<=packetSize;n++){

                  // end of param 

                  if (inputString[n] == '>'){  


                  } else {

                     p2b_data[k] += inputString[n];

                     k++; 

                  }

               }

            

               ExecuteLogicalCommand();

            } 

            

            stringComplete = true;

            p2b_status = P2B_STAT_NONE;

            

         } else {

            lp = i-1;  // set last position on each entry;

         }

      }

   }

  

   if (stringComplete) {

      ClearParamsAndInputstring(); 

   };        

}