Cafe Cappuccino

かふぇ・かぷちの/新幻想的独り言4 ねふぁの気まぐれな独り言

先日作った身長測定器だが、3人まとめて測定後サーバーへ転送し、電源オフでデータ消えてしまうため測定時3人が揃っている必要があった。

それは面倒なので、測定データはESP8266のSPIFFSに一旦保存しサーバー転送後にデータをクリアする方式に変更した。

以下、ソースコード。

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <WebSocketsServer.h>
#include <Hash.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <FS.h>
#include <Adafruit_NeoPixel.h>

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <ESP_Adafruit_SSD1306.h>

#define PIN_D1 5
#define PIN_D2 4
#define PIN_D3 0
#define PIN_D4 2 
#define PIN_D5 14
#define PIN_D6 12
#define PIN_D7 13
#define PIN_D8 15
#define BUILTIN_LED 2
const unsigned char pic_cloud[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0xfe, 0x03, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x18, 0x7e, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xf0, 0x01, 0xf0, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xf8, 0x03, 0xe0, 0x01, 0x00, 0x00, 0xf8, 0x00, 0xfc, 0x07, 0xc0, 0x01, 0x00, 0x00, 0x7e, 0x00, 0xfe, 0x0f, 0xc0, 0x03, 0x00, 0x00, 0x3f, 0x00, 0xef, 0x1e, 0x80, 0x03, 0x00, 0x00, 0x0f, 0x80, 0xe7, 0x3c, 0x80, 0x07, 0x00, 0x80, 0x07, 0xc0, 0xe3, 0x78, 0x80, 0x1f, 0x00, 0x80, 0x03, 0xc0, 0xe1, 0x70, 0x00, 0x3f, 0x00, 0xc0, 0x01, 0xc0, 0xe0, 0x60, 0x00, 0x78, 0x00, 0xc0, 0x01, 0x00, 0xe0, 0x00, 0x00, 0xf0, 0x00, 0xc0, 0x01, 0x00, 0xe0, 0x00, 0x00, 0xe0, 0x00, 0xc0, 0x01, 0x00, 0xe0, 0x00, 0x00, 0xe0, 0x01, 0xc0, 0x01, 0x00, 0xe0, 0x00, 0x00, 0xe0, 0x01, 0xc0, 0x01, 0x00, 0xe0, 0x00, 0x00, 0xe0, 0x01, 0xc0, 0x03, 0x00, 0xe0, 0x00, 0x00, 0xe0, 0x00, 0x80, 0x07, 0x00, 0x40, 0x00, 0x00, 0xf0, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x0f, 
};

#include <VL53L0X.h>
VL53L0X sensor;

#include "I2Cdev.h"
#include "MPU6050.h"
MPU6050 accelgyro;
int16_t ax, ay, az;

char buff[32];

#define BTN_MODE PIN_D4 //connect switch, and to gnd
#define BTN_SEL PIN_D3 //connect switch, and to gnd

static const uint8_t ALT_SDA = PIN_D2;
static const uint8_t ALT_SCL = PIN_D1;
Adafruit_SSD1306 display(-1);
char oledstrbuff[64];

#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

ESP8266WiFiMulti WiFiMulti;
const char* ssid = "ssid";
const char* password = "password";
const char* host = "ESP8266";
int lastwifi;
unsigned long lastupdateMillis = 0;
bool freezedisplay = false;

int linefeeder = 0;
void oled_drawstr(int line,char *text){
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0,line*10);
    display.print(text);
    display.display();
}
void oled_drawstr(char *text){
    oled_drawstr(linefeeder++,text);
}
void oled_overwritestr(int line, char *text){
    display.fillRect(0, line*10, 100, 10, BLACK);
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0,line*10);
    display.print(text);
    display.display();
}
void oled_overwritestr_d(int line, char *text){
    display.fillRect(0, line, 100, 10, BLACK);
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0,line);
    display.print(text);
    display.display();
}
void oled_drawtext(int posx,int posy, int textsize, char *text){
    display.setTextSize(textsize);
    display.setTextColor(WHITE);
    display.setCursor(posx,posy);
    display.print(text);
}

bool wifi_setup(){
     oled_drawstr("ESP8266 WiFi");
     sprintf(oledstrbuff,"AP :%s",ssid);
     oled_drawstr(oledstrbuff);
     Serial.printf("AP SSID:%s", ssid);
     WiFi.mode(WIFI_STA);
     if (String(WiFi.SSID()) != String(ssid)) {
          WiFi.begin(ssid, password);
     }

     int retrycount = 0;
     while (WiFi.status() != WL_CONNECTED) {
          delay(500);
          Serial.print(".");
          retrycount++;
          if (retrycount > 20){
               return false;
               oled_drawstr("conn timeout");
               Serial.println("connection timeout");
               return false;
          }
     }
     Serial.println("");
     lastwifi = WiFi.status();

     IPAddress ip = WiFi.localIP();
     sprintf(oledstrbuff,"IP :%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]);
     oled_drawstr(oledstrbuff);
     byte mac[6];
     WiFi.macAddress(mac);
     sprintf(oledstrbuff,"MAC:%02X:%02X:%02X:%02X:%02X:%02X",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
     oled_drawstr(oledstrbuff);

     if (!MDNS.begin(host)) {
          Serial.println("Error setting up MDNS responder!");
          return false;
     }
     Serial.println("mDNS responder started");

     WiFi.setSleepMode(WIFI_NONE_SLEEP);

     if (WiFi.status() != WL_CONNECTED)
          return false;
     return true;
}

void setup() {
     Serial.begin(74880);
     Serial.print("\n");
     Serial.setDebugOutput(true);

     pinMode(BUILTIN_LED, OUTPUT);
     digitalWrite(BUILTIN_LED, HIGH); //high to turn off

     pinMode(BTN_MODE,INPUT_PULLUP);
     pinMode(BTN_SEL,INPUT_PULLUP);

//     WiFi.disconnect();
//     WiFi.mode(WIFI_OFF);
//     WiFi.forceSleepBegin();
     initdata();
     loaddata();

     Wire.begin(ALT_SDA,ALT_SCL);
     display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr
     display.display();
     delay(500);

     display.clearDisplay();
     wifi_setup();

     //set sensor long range, high accuracy
     sensor.setTimeout(5000);
     sensor.init();
     sensor.setTimeout(500);
     sensor.setSignalRateLimit(0.1);
     sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodPreRange, 18);
     sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodFinalRange, 14);
     sensor.setMeasurementTimingBudget(200000);
     
     accelgyro.initialize();

     Serial.println("Ready");
}

#define S_HOFFSET        240.0 //laser range sensor horizontal offset from measurement point, in mm
#define S_VOFFSET        2.0   //laser range sensor vertical offset from measurement point, in mm
#define degtorad(angleDegrees) (angleDegrees * M_PI / 180.0)
#define radtodeg(angleRadians) (angleRadians * 180.0 / M_PI)
//alternate
//radians = (degrees * 71) / 4068
//degrees = (radians * 4068) / 71
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define degconvert 57.2957786
#define averagenum 10
double averaging[averagenum];
int avindex = 0;
int xangle;
int yangle;
uint16_t distance;
double m_height = -1;
int misscount;

#define MODE_MEASURE     0
#define MODE_SELECT      1
#define MODE_SEND        2
char s_person[3][8] = {"Choujyo","Jijyo","Sanjyo"};
int m_mode = MODE_MEASURE;    //mode
int m_person = 0;             //selected person
bool m_measure = true;        //measure on / pause
int m_pheight[3] = {0,0,0};   //measure per person
unsigned long btn_down_time = 0;
bool lastbtnmode = false;
bool lastbtnsel = false;

double calcheight(double hangle, double vangle, double olen){
     double reslen = 0;

     if (m_measure){
          //hangle : horizontal angle 
          //vangle : vertical angle 
          //len : laser range, in mm
          double len = olen + S_VOFFSET;
          double hadjlen; //horizontal adjusted length
          double aangle_r, aangle_d, hyplen;
          double bangle_r, bangle_d;
          
          hadjlen = cos(degtorad(hangle)) * len; //adjust horizontal length
          
          aangle_r = atan2(hadjlen,S_HOFFSET);
          aangle_d = radtodeg(aangle_r);
          Serial.print("aangle:");
          Serial.println(aangle_d);
          hyplen = sqrt(S_HOFFSET*S_HOFFSET + hadjlen*hadjlen);
          Serial.print("hyplen:");
          Serial.println(hyplen);
     
          if (vangle < 0){
               if (aangle_d + abs(vangle) < 90){
                    bangle_d = 90 - aangle_d - abs(vangle);
                    bangle_r = degtorad(bangle_d);
                    reslen = cos(bangle_r) * hyplen;
               }else if (aangle_d + abs(vangle) > 90){
                    bangle_d = (aangle_d + abs(vangle)) - 90;
                    bangle_r = degtorad(bangle_d);
                    reslen = cos(bangle_r) * hyplen;
               }else{
                    reslen = hyplen;
               }
          }else if (vangle > 0){
               bangle_d = 90 - (aangle_d - vangle);
               bangle_r = degtorad(bangle_d);
               reslen = cos(bangle_r) * hyplen;
          }else //vertical flat
               reslen = hadjlen;
     
          Serial.print("bangle:");
          Serial.println(bangle_d);
          averaging[avindex] = reslen;
          avindex = (avindex + 1) % averagenum;
     }
     
     reslen = 0;
     for (int i=0;i<averagenum;i++) reslen += averaging[i];
     reslen /= averagenum;
     
     return reslen;
}

void checkprocessbtn() {
     int btnstatemode = digitalRead(BTN_MODE);
     int btnstatesel = digitalRead(BTN_SEL);

     if (btnstatemode == LOW && !lastbtnmode){ //switch on
          btn_down_time = millis();
          lastbtnmode = true;
          if (m_mode == MODE_MEASURE)
               m_mode = MODE_SELECT;
          else
               m_mode = MODE_MEASURE;
          freezedisplay = false;
     }else if (btnstatemode == LOW){
          if (millis() - btn_down_time > 2000){ //btn hold down over 2 sec
               m_mode = MODE_SEND;
          }
     }else if (btnstatemode == HIGH){
          lastbtnmode = false;
     }
     
     if (btnstatesel == LOW && !lastbtnsel){
          lastbtnsel = true;
          if (m_mode == MODE_MEASURE){
               m_measure = !m_measure;
               if (!m_measure){
                    m_pheight[m_person] = (m_height+5)/10; //save current measure to personal data. add 5 for rounding.
                    savedata(m_person,m_pheight[m_person]);
               }
          }else if (m_mode == MODE_SELECT){
               m_person = (m_person + 1) % 3;
               m_measure = true;
          }else{
               wifi_transferdata();
          }
     }else if (btnstatesel == HIGH){
          lastbtnsel = false;
     }
}

void wifi_transferdata(){
     oled_overwritestr(5,"     Sending.");
     uint16_t len;
     String lendata;
     lendata = "lendata=";
     for (int i=0;i<3;i++){
          if (m_pheight[i] <= 10)
               lendata = lendata + "<td>---cm</td>";
          else
               lendata = lendata + "<td>" + m_pheight[i] + "cm</td>";
     }
     len = lendata.length();

     WiFiClient client;
     char buffer[512],chbuf[16];
     Serial.println("Starting connection to server...");
     oled_overwritestr(5,"     Sending..");
     if (client.connect("server.name",80)){
          oled_overwritestr(5,"     Sending...");
          client.println(F("POST /lenlogger.php HTTP/1.1"));
          client.println(F("Host: 192.168.0.1:80"));
          client.println(F("Content-Type: application/x-www-form-urlencoded"));
          client.print(F("Content-Length: "));
          client.println(len);
          client.println();
          client.print(lendata);
          client.println();
          client.stop();
          oled_overwritestr(5,"     Sending... OK");
          for (int i=0;i<3;i++){
               m_pheight[i] = 0;
               savedata(i,0);
          }
     }else{
          oled_overwritestr(5,"     Sending... NG");
          oled_overwritestr(5,"     Conn Error");
     }
     freezedisplay = true;
}

int siglevel;
void updatedisplay(){
     if (freezedisplay)
          return;
     display.clearDisplay();
     unsigned long currentMillis = millis();
     if (currentMillis - lastupdateMillis > 500){
          //http://www.speedguide.net/faq/how-does-rssi-dbm-relate-to-signal-quality-percent-439
          long rssi = WiFi.RSSI();
          if (rssi <= -96)
              siglevel = 1;
          else if (rssi <= -85)
              siglevel = 2;
          else if (rssi <= -75)
              siglevel = 3;
          else
              siglevel = 4;
          lastupdateMillis = currentMillis;
     }
     display.fillRect(115, 2, 17, 11, BLACK);
     if (siglevel >=1)
         display.fillRect(117, 12, 2, 2, WHITE);
     if (siglevel >=2)
         display.fillRect(120, 10, 2, 4, WHITE);
     if (siglevel >=3)
         display.fillRect(123, 8, 2, 6, WHITE);
     if (siglevel >=4)
         display.fillRect(126, 6, 2, 8, WHITE);

     if (m_mode == MODE_MEASURE){
          oled_drawtext(7,0,1,s_person[m_person]);
          if (!m_measure){
               display.fillRect(0, 0, 2, 7, WHITE);
               display.fillRect(3, 0, 2, 7, WHITE);
          }
          
          sprintf(buff,"H: % 2d%c",xangle,(char)247);
          oled_drawtext(0,55,1,buff);
          sprintf(buff,"V: % 2d%c",yangle,(char)247);
          oled_drawtext(63,55,1,buff);
     
          if (distance == 999)
               sprintf(buff,"Dist: --- mm");
          else
               sprintf(buff,"Dist: %4dmm",distance);
          oled_drawtext(0,45,1,buff);
     
          if (xangle > 45 || xangle < -45){
               oled_drawtext(30,10,4,"///");
          }else if (yangle > 45 || yangle < -45){
               oled_drawtext(30,10,4,"///");
          }else{
               if (distance == 999){
                    if (m_height == -1 || misscount > 5) //retain previous display for while
                         oled_drawtext(30,10,4,"---");
                    else{
                         sprintf(buff,"%3d",(int)m_height/10);
                         oled_drawtext(20,10,4,buff);
                         sprintf(buff,".%d",(int)m_height%10);
                         oled_drawtext(90,10,2,buff);
                         oled_drawtext(95,30,2,"cm");
                    }
               }else{
                    m_height = calcheight(xangle,yangle,distance);
                    sprintf(buff,"%3d",(int)m_height/10);
                    oled_drawtext(20,10,4,buff);
                    sprintf(buff,".%d",(int)m_height%10);
                    oled_drawtext(90,10,2,buff);
                    oled_drawtext(95,30,2,"cm");
               }
          }
     }else if (m_mode == MODE_SELECT){
          oled_drawtext(5,5,1,"Select Person");
          sprintf(buff,"%s%8s % 3dcm",m_person == 0?">>":"  ",s_person[0],m_pheight[0]);
          oled_drawtext(15,20,1,buff);
          sprintf(buff,"%s%8s % 3dcm",m_person == 1?">>":"  ",s_person[1],m_pheight[1]);
          oled_drawtext(15,35,1,buff);
          sprintf(buff,"%s%8s % 3dcm",m_person == 2?">>":"  ",s_person[2],m_pheight[2]);
          oled_drawtext(15,50,1,buff);
     }else{
          display.drawXBitmap(0,0,pic_cloud,64,32,WHITE);
          oled_overwritestr(4,"    Send to Sever");
     }

     display.display();
}

void initdata(){
     SPIFFS.begin();
     //SPIFFS.format(); //only need to be done once
}
void savedata(int index,int data){
     char fname[32];
     sprintf(fname,"/data%d.txt",index);
     File file = SPIFFS.open(fname, "w");
     if (!file)
          return;
     sprintf(fname,"%d",data);
     file.write((uint8_t*)&fname,32);
     file.close();
}
void loaddata(){
     char fname[32];
     for (int i=0;i<3;i++){
          sprintf(fname,"/data%d.txt",i);
          if (SPIFFS.exists(fname)){
               File file = SPIFFS.open(fname, "r");
               if (file){
                    file.readBytes(fname,32);
                    m_pheight[i] = atoi(fname);
                    file.close();
               }
          }
     }
}

void loop() {
     checkprocessbtn();
     
     if (m_mode == MODE_MEASURE && m_measure){
          accelgyro.getAcceleration(&ax, &ay, &az);
          yangle = atan2(ay, az)*degconvert;
          xangle = atan2(-ax, az)*degconvert;
          distance = sensor.readRangeSingleMillimeters();

          if (sensor.timeoutOccurred() || distance > 8000){
               distance = 999;
               misscount++;
          }else
               misscount = 0;      
     }
     
     updatedisplay();   
}
Print Friendly, PDF & Email

コメントを残す

メールアドレスが公開されることはありません。

CAPTCHA


*

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください