WeMos Smart Car Motor Shield

学園祭のため、IoTぼいのスマート車を作る。

しかし、注文したMotor Shield とは、違うもの(base only)が来たので、急遽自作する。

そのためのコントロールするAppも作りたいが、時間がなくって、ネットからWebページでコントロールするものを探して、沢山手直して、動くようになった。

車数台用意して、各車のIPは固定にしたいので、WiFiManager使わない方法をとった。

Webページでコントロールするから、遅延は目たつ。

時間があったら、ちゃんとアクセルペダルなど追加して、アプリの形にしたい。

// include libraries
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

#define motor_lf D3
#define motor_lb D4
#define motor_rf D6
#define motor_rb D5

// configure server
ESP8266WebServer server(80);
const char *form = "<!DOCTYPE HTML>"
"<meta name='viewport' content='width=device-width'>"
"<html>"
"<center><form action='/'>"
"<button name='dir' type='submit' value='4'>Forward</button><p>"
"<button name='dir' type='submit' value='1'>Left</button> "
"<button name='dir' type='submit' value='2'>Right</button><p>"
"<button name='dir' type='submit' value='3'>Reverse</button><p><p>"
"<button name='dir' type='submit' value='5'>Stop</button>"
"</form></center>"
"</html>";
void stop(void)
{
    analogWrite(motor_lf, 0);
    analogWrite(motor_lb, 0);
    analogWrite(motor_rf, 0);
    analogWrite(motor_rb, 0);
}
void forward(void)
{
    analogWrite(motor_lf, 1023);
    analogWrite(motor_lb, 0);
    analogWrite(motor_rf, 1023);
    analogWrite(motor_rb, 0);
}
void backward(void)
{
    analogWrite(motor_lf, 0);
    analogWrite(motor_lb, 1023);
    analogWrite(motor_rf, 0);
    analogWrite(motor_rb, 1023);
}
void left(void)
{
    analogWrite(motor_lf, 0);
    analogWrite(motor_lb, 0);
    analogWrite(motor_rf, 1023);
    analogWrite(motor_rb, 0);
}
void right(void)
{
    analogWrite(motor_lf, 1023);
    analogWrite(motor_lb, 0);
    analogWrite(motor_rf, 0);
    analogWrite(motor_rb, 0);
}
void handle_form()
{
    // only move if we submitted the form
    if (server.arg("dir"))
    {
        // get the value of request argument "dir"
        int direction = server.arg("dir").toInt();
        // chose direction
        switch (direction)
        {
            case 1:
                left();
                break;
            case 2:
                right();
                break;
            case 3:
                backward();
                break;
            case 4:
                forward();
                break;
            case 5:
                stop();
                break;
        }
        // move for 300ms, gives chip time to update wifi also
        delay(300);
    }
    
    // in all cases send the response
    server.send(200, "text/html", form);
}
void setup()
{
    // connect to wifi network
    WiFi.begin("uislab003", "**password**");
    // static ip, gateway, netmask
    WiFi.config(IPAddress(192,168,11,10), IPAddress(192,168,11,1), IPAddress(255,255,255,0));
    // connect
    while (WiFi.status() != WL_CONNECTED)
    {
        delay(200);
    }
  
    // set up the callback for http server
    server.on("/", handle_form);
    // start the webserver
    server.begin();
    pinMode(motor_lf, OUTPUT); // 
    pinMode(motor_lb, OUTPUT); // 
    pinMode(motor_rf, OUTPUT); // 
    pinMode(motor_rb, OUTPUT); // 

}
void loop()
{
    // check for client connections
    server.handleClient();
}

 

WeMos (c6) Thingspeak

数回JSON関連の実験をしたが、いざTinyWebDBのAPIの実験を始まると、また引っかかるところが多い。

色々と検索してところ、ThingspeakのAPIサンプルが見つかったので、ちょっと曲がり道して試すことに。

センサーの温度と気圧をThingspeakにアップして、動きを見て見る。

まずThingspeakのアカウントを申請して、THINGSPEAK_API_KEYを取得する。

https://thingspeak.com/users/sign_up

次はサンプルを見ながら、プログラミング。

#include <Adafruit_BMP280.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
 
#define OLED_RESET 0  // GPIO0
Adafruit_SSD1306 OLED(OLED_RESET);

#define BMP_SCK 13
#define BMP_MISO 12
#define BMP_MOSI 11 
#define BMP_CS 10

Adafruit_BMP280 bmp; // I2C
//Adafruit_BMP280 bmp(BMP_CS); // hardware SPI
//Adafruit_BMP280 bmp(BMP_CS, BMP_MOSI, BMP_MISO,  BMP_SCK);


#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

/***************************
 * Begin Settings
 **************************/

const char* host = "http://api.thingspeak.com";
const char* THINGSPEAK_API_KEY = "***********";

// Update every 600 seconds = 10 minutes. Min with Thingspeak is ~20 seconds
const int UPDATE_INTERVAL_SECONDS = 600;

//needed for library
#include <DNSServer.h>
#include "WiFiManager.h"          //https://github.com/tzapu/WiFiManager

void configModeCallback (WiFiManager *myWiFiManager) {
  Serial.println("Entered config mode");
  Serial.println(WiFi.softAPIP());
  //if you used auto generated SSID, print it
  Serial.println(myWiFiManager->getConfigPortalSSID());
}

/***************************
 * End Settings
 **************************/
 
void setup() {
  OLED.begin();
  OLED.clearDisplay();
 
  //Add stuff into the 'display buffer'
  OLED.setTextWrap(false);
  OLED.setTextSize(1);
  OLED.setTextColor(WHITE);
  OLED.setCursor(0,0);
  delay(10);
  
  Serial.begin(115200);
  delay(10);

  // We start by connecting to a WiFi network

  // Connect to WiFi network
  OLED.println("wifiManager autoConnect...");
  OLED.display(); //output 'display buffer' to screen  
 
  //WiFiManager
  //Local intialization. Once its business is done, there is no need to keep it around
  WiFiManager wifiManager;
  //reset settings - for testing
  //wifiManager.resetSettings();

  //set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode
  wifiManager.setAPCallback(configModeCallback);

  //fetches ssid and pass and tries to connect
  //if it does not connect it starts an access point with the specified name
  //here  "AutoConnectAP"
  //and goes into a blocking loop awaiting configuration
  if(!wifiManager.autoConnect()) {
    Serial.println("failed to connect and hit timeout");
    //reset and try again, or maybe put it to deep sleep
    ESP.reset();
    delay(1000);
  } 

  // Print the IP address
  OLED.print("http://");
  OLED.print(WiFi.localIP());
  OLED.println("/");
  OLED.println("WiFi connected");
  OLED.display(); //output 'display buffer' to screen  
  
  //if you get here you have connected to the WiFi
  Serial.println("connected...yeey :)");

  if (!bmp.begin(0x76)) 
  {
    OLED.println("Could not find BMP180 or BMP085 sensor at 0x77");
    OLED.display(); //output 'display buffer' to screen  
    while (1) {}
  }

}

void loop() {      
  // read values from the sensor
  float pressure = bmp.readPressure();
  float temperature = bmp.readTemperature();
  
  // We now create a URI for the request
  String url = host;
  url += "/update?api_key=";
  url += THINGSPEAK_API_KEY;
  url += "&field1=";
  url += String(temperature);
  url += "&field2=";
  url += String(pressure);
  
  Serial.print("Requesting URL: ");
  Serial.println(url);

  HTTPClient http;
  Serial.print("[HTTP] begin...\n");
  // configure targed server and url
  http.begin(url);
  
  Serial.print("[HTTP] GET...\n");
  // start connection and send HTTP header
  int httpCode = http.GET();

  if(httpCode == HTTP_CODE_OK) {
    String buffer = http.getString();
    Serial.println(buffer);
  }

  Serial.println("closing connection");

  // Go back to sleep. If your sensor is battery powered you might
  // want to use deep sleep here
  delay(1000 * UPDATE_INTERVAL_SECONDS);
}

 

こちら問題なくデータの蓄積ができた。

WeMos (c5) JSON exchange rate

WeMosをRESPのクライアントとして機能するため、JSONと、HTTPClientを検証する。

前回ArduinoJsonというライブラリを使用したので、ESP8266ならではのWiFi機能を使い、インターネットから情報を取得して表示させてみる。

JSON データ形式

為替レートの情報は、

Foreign exchange rates and currency conversion JSON API

から取得する。

ドル円レートの情報を取得する場合、URLはhttp://api.fixer.io/latest?base=USD&symbols=JPY

応答は下記の通り

HTTP/1.1 200 OK
Server: nginx/1.13.6
Date: Sat, 04 Nov 2017 13:40:46 GMT
Content-Type: application/json
Content-Length: 57
Connection: close
Cache-Control: public, must-revalidate, max-age=900
Last-Modified: Fri, 03 Nov 2017 00:00:00 GMT
Vary: Origin
X-Content-Type-Options: nosniff
{"base":"USD","date":"2017-11-03","rates":{"JPY":113.94}}

closing connection

プログラム

下記の処理をする

  1.  WiFiManagerでWiFi自動接続
  2. get_exchange_rate処理
    1. api.fixer.io JSONデータ取得
    2. parse json data
    3. OLEDへ表示
  3. 60秒待ち
  4. 2へ続き
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
 
#define OLED_RESET 0  // GPIO0
Adafruit_SSD1306 OLED(OLED_RESET);

const char* URL = "http://api.fixer.io/latest?base=USD&symbols=JPY";  // http resource
//sample json data used in this sketch
// {"base":"USD","date":"2017-11-03","rates":{"JPY":113.94}}

//needed for library
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include "WiFiManager.h"          //https://github.com/tzapu/WiFiManager

void configModeCallback (WiFiManager *myWiFiManager) {
  Serial.println("Entered config mode");
  Serial.println(WiFi.softAPIP());
  //if you used auto generated SSID, print it
  Serial.println(myWiFiManager->getConfigPortalSSID());
}

void setup() {
  OLED.begin();
  OLED.clearDisplay();
 
  //Add stuff into the 'display buffer'
  OLED.setTextWrap(false);
  OLED.setTextSize(1);
  OLED.setTextColor(WHITE);
  OLED.setCursor(0,0);
  delay(10);
  
  Serial.begin(115200);
  Serial.println("");
  delay(10);

  // Connect to WiFi network
  OLED.println("wifiManager autoConnect...");
  OLED.display(); //output 'display buffer' to screen  
 
  //WiFiManager
  //Local intialization. Once its business is done, there is no need to keep it around
  WiFiManager wifiManager;
  //reset settings - for testing
  //wifiManager.resetSettings();

  //set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode
  wifiManager.setAPCallback(configModeCallback);

  //fetches ssid and pass and tries to connect
  //if it does not connect it starts an access point with the specified name
  //here  "AutoConnectAP"
  //and goes into a blocking loop awaiting configuration
  if(!wifiManager.autoConnect()) {
    Serial.println("failed to connect and hit timeout");
    //reset and try again, or maybe put it to deep sleep
    ESP.reset();
    delay(1000);
  } 

  // Print the IP address
  OLED.print("http://");
  OLED.print(WiFi.localIP());
  OLED.println("/");
  OLED.println("WiFi connected");
  OLED.display(); //output 'display buffer' to screen  
  
  //if you get here you have connected to the WiFi
  Serial.println("connected...yeey :)");
 
}

void get_exchange_rate() {
  const int BUFFER_SIZE = JSON_OBJECT_SIZE(4) + JSON_ARRAY_SIZE(1);
  StaticJsonBuffer<BUFFER_SIZE> jsonBuffer;
  HTTPClient http;

  Serial.print("[HTTP] begin...\n");
  // configure targed server and url
  http.begin(URL);
  
  Serial.print("[HTTP] GET...\n");
  // start connection and send HTTP header
  int httpCode = http.GET();

  if(httpCode != HTTP_CODE_OK) {
    return;
  }
  String buffer = http.getString();
  Serial.println(buffer);

  //parse json data
  char json[buffer.length() + 1];
  buffer.toCharArray(json, sizeof(json));
  Serial.println(json);
  JsonObject& root = jsonBuffer.parseObject(json);
  if (!root.success()) {
    Serial.println("parseObject() failed");
    return;
  }
  const char* date = root["date"];
  Serial.println(date);
  const char* base = root["base"];
  Serial.println(base);
  JsonObject& rates = root["rates"];
  rates.printTo(Serial);
  Serial.println();
  const char* rate = rates["JPY"];
  Serial.println(rate);
  Serial.println();
  
  Serial.println("closing connection");

  OLED.clearDisplay();
  OLED.setCursor(0,0);
  // Print the IP address
  OLED.print("http://");
  OLED.print(WiFi.localIP());
  OLED.println("/");

  OLED.setCursor(0, 16);
  OLED.print(date);
  OLED.setCursor(0, 24);
  OLED.print("JPY/");
  OLED.print(base);
  OLED.print(": ");
  OLED.print(rate);
  OLED.display(); //output 'display buffer' to screen  

}

void loop() {
  get_exchange_rate();
  delay(60000);
}

 

参考

  • http://blog.boochow.com/article/425016458.html — ESP8266版Arduinoでネットから情報を取ってきてLCDに表示する