ESP-WROOM-02単体でWi-Fi通信とNeoPixel両方動かしたい(2)

ESP-WROOM-02単体でWi-Fi通信とNeoPixel両方動かしたい(2)

ESP-WROOM-02単体でWi-Fi通信とNeoPixel両方動かしたい(1)の続きです。
給電の問題がまだ解決できていません。

ESP-WROOM-02単体の給電でどのくらいのことができるのか?

各所の記事を見ていると、やはりWi-Fi通信するときにかなりの電力を消費するので電源は頭を悩ませるようです。

ちなみに私が使っているのはこのボード。

これは5Vを出力できるピンがついていて、NeoPixelに対してはここから給電しています。
NeoPixel16連リングは、動作電圧:5V(最大7V)、最大消費電流(LED1つにつき):18mAとのことなので、まあ動くかなと思ってつないだら動いてる、という感じです。

5Vを出力できるのはUSB給電時のみらしい。
ということは、もしこの開発ボードを使わないのであれば、

・WROOM02に対する給電
・NeoPixelに対する給電
・CDSセンサーに対する給電

を何か別の大きな電源から分圧?なりなんなりしなければいけないと思われます。
WROOM02とNeoPixelへの給電を分けるのであれば、CDSセンサーはWROOM02の3V3あたりから流せばいいのかな?とは思いますが…

今までに試したこととその結果としては

  1. WROOM02でWi-Fi通信せずにNeoPixelを光らせる
    →安定して動く。
  2. WROOM02でWi-Fi通信してCDSセンサーの値を送信する
    →安定して動く。
  3. WROOM02でWi-Fi通信してdelayしながらNeoPixelを光らせる
    →たぶん安定して動いてる。
  4. WROOM02でWi-Fi通信しながらNeoPixelを光らせる
    →ときどきWi-Fiが切れる
  5. WROOM02でWi-Fi通信しながらCDSセンサーの値を送受信してNeoPixelを光らせる
    →光らなかったりセンサーの値がずっと1桁

という感じ。

Milkcocoaを使ってNeoPixelのサンプルアニメを切り替える

前述の「4. WROOM02でWi-Fi通信しながらNeoPixelを光らせる」について、どのくらい動かせてどのくらい不安定なのかというのがわかる微妙なシステムを作りました。

動画ではわかりませんが、WROOM02を起動してWi-Fi接続が成功したあと、1~9まで順番にクリックしていくとだいたい10をクリックするときに固まります。
2、3回クリックして放っておくと、しばらくしてダダダッと3回分のログがシリアルモニタに流れて、10番のアニメーションになったりします。

それくらいならまだいいほうで、止まったかと思ったらそのままWi-Fi再接続、なんてことになります。
10番が悪いというわけでもなく、固まったあとは1番でも5番でも、クリックしてもなかなか反映されません。

ただ気になっているのは、8番9番のアニメーションが全LEDが同時に点灯していて輝度も高いということです。
ここで電力が足りなくなってWROOM02が落ちている可能性もあるのかなと思っています。

やってることは、
・ブラウザ側は、ボタンを押すとそれぞれの番号をMilkcocoaにsendするプログラムを実装
・MilkcocoaのArduino/ESP8266用のSDKを使ってWi-Fi接続
・Milkcocoaのデータストアをonsendで監視
・onsendで取れた値に応じてNeoPixelのサンプルスケッチ「strandtest」の各アニメーションを実行

MilkcocoaのライブラリとNeoPixelのライブラリを共存させるのはそれほど大変ではありませんでした。

ただ、サンプルスケッチのままコピーすると前の記事で書いたようにコンパイル時にエラーが出ます。
アニメーションやMilkcocoaのonsendは、loopよりあとにあるとエラーになりましたので手前に持ってきます。
さらに、WheelPosはアニメーションの中で使われる設定なので、これもアニメーションの記述よりも手前に持ってこないとダメでした。

ソースを公開してみます。
NeoPixel使ってる人以外にはあんまり意味ないですが、コピってWi-Fi設定のところとMilkcocoaアプリIDを変更してもらえれば、動くと思います。

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>NeoPixel</title>
<script src="https://cdn.mlkcca.com/v2.0.0/milkcocoa.js"></script>
<script src="jquery.js"></script>
<script src="common.js"></script>
</head>

<body>

<button data-num="1">01</button>
<button data-num="2">02</button>
<button data-num="3">03</button>
<button data-num="4">04</button>
<button data-num="5">05</button>
<button data-num="6">06</button>
<button data-num="7">07</button>
<button data-num="8">08</button>
<button data-num="9">09</button>
<button data-num="10">10</button>

</body>
</html>
//common.jsの中身
var milkcocoa = new MilkCocoa('自分のアプリID.mlkcca.com');
var ds = milkcocoa.dataStore('esp8266');

$(function(){
	$('button').on('click', function(){
		ds.send({ 'v' : $(this).data('num')},function(err){
		  console.log(err);
		});
	});
});
#include <Adafruit_NeoPixel.h>
#include <ESP8266WiFi.h>
#include <Milkcocoa.h>
extern "C" {
#include "user_interface.h"
}
#ifdef __AVR__
  #include <avr/power.h>
#endif

/************************* WiFi Access Point *********************************/

#define WLAN_SSID       "自分のWi-FiルータのSSID"
#define WLAN_PASS       "自分のWi-Fiルータのパスワード"

/************************* Your Milkcocoa Setup *********************************/

#define MILKCOCOA_APP_ID      "自分のアプリID"
#define MILKCOCOA_DATASTORE   "esp8266"

/************* Milkcocoa Setup (you don't need to change this!) ******************/

#define MILKCOCOA_SERVERPORT  1883

/************ Global State (you don't need to change this!) ******************/

// Create an ESP8266 WiFiClient class to connect to the MQTT server.
WiFiClient client;

const char MQTT_SERVER[] PROGMEM    = MILKCOCOA_APP_ID ".mlkcca.com";
const char MQTT_CLIENTID[] PROGMEM  = __TIME__ MILKCOCOA_APP_ID;

Milkcocoa milkcocoa = Milkcocoa(&client, MQTT_SERVER, MILKCOCOA_SERVERPORT, MILKCOCOA_APP_ID, MQTT_CLIENTID);

// NeoPixelにつなぐピン番号の指定と、LEDの個数(16)の指定
#define PIN 13
Adafruit_NeoPixel strip = Adafruit_NeoPixel(16, PIN, NEO_GRB + NEO_KHZ800);

// ここからNeoPixelのアニメーション設定
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();
    delay(wait);
  }
}

void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*5; j++) {
    for(i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

void theaterChase(uint32_t c, uint8_t wait) {
  for (int j=0; j<10; j++) {
    for (int q=0; q < 3; q++) {
      for (int i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, c);
      }
      strip.show();

      delay(wait);

      for (int i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, 0);
      }
    }
  }
}

void theaterChaseRainbow(uint8_t wait) {
  for (int j=0; j < 256; j++) {
    for (int q=0; q < 3; q++) {
      for (int i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, Wheel( (i+j) % 255));
      }
      strip.show();

      delay(wait);

      for (int i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, 0);
      }
    }
  }
}

//アニメーションの番号を格納する変数定義
int animation = 0;

//Milkcocoaのonsendを受け取ったときの処理
void onsend(DataElement elem) {
  animation = elem.getInt("v");
};

//setup
void setup() {
  Serial.begin(115200);
  delay(10);

  // Connect to WiFi access point.
  Serial.println(); Serial.println();
  Serial.print("Connecting to ");
  Serial.println(WLAN_SSID);

  WiFi.begin(WLAN_SSID, WLAN_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();

  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  Serial.println( milkcocoa.on(MILKCOCOA_DATASTORE, "send", onsend) );

  //NeoPixelライブラリのsetupの中身
  #if defined (__AVR_ATtiny85__)
    if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
  #endif
  strip.begin();
  strip.show();
}

//loop
void loop() {
  milkcocoa.loop();
  switch(animation){
    case 1:colorWipe(strip.Color(255, 0, 0), 50);break;
    case 2:colorWipe(strip.Color(0, 255, 0), 50);break;
    case 3:colorWipe(strip.Color(0, 0, 255), 50);break;
    case 4:theaterChase(strip.Color(127, 127, 127), 50);break;
    case 5:theaterChase(strip.Color(127, 0, 0), 50);break;
    case 6:theaterChase(strip.Color(0, 127, 0), 50);break;
    case 7:theaterChase(strip.Color(0, 0, 127), 50);break;
    case 8:rainbow(20);break;
    case 9:rainbowCycle(20);break;
    case 10:theaterChaseRainbow(50);break;
  };
}

ひとまずここまで…