ラベル sketch の投稿を表示しています。 すべての投稿を表示
ラベル sketch の投稿を表示しています。 すべての投稿を表示

2016年6月27日月曜日

ArduinoでJSON


javaでJacksonなんかをいじっていると、 "{\"name\" …なんて書いていくのは面倒くさいというか、どうせミスするのがオチなんだよ俺なんかー(血の叫び

と、つい人は不良化してしまいます。

というわけで、また楽な道を探しましたところ、良いライブラリ見つけました。

これ使いやすいですよ。ちょっとバッファを食うので、nano / unoあたりだと大きなデータは作りにくいかもしれないですが、例えばAmbient(thingspeak.comのようなクラウドサービス)に送るデータをserializeする場合なんか、これだけで書けてしまいます。dictionaryもarrayもかなり直感的に書くことができてとてもラクです。

//
//  send to Ambient
//
const int kMaxJsonBuffer = 2048;
StaticJsonBuffer<kMaxJsonBuffer> jsonBuffer;
char jsonPrintBuffer[kMaxJsonBuffer];
bool sendStorageToAmbient() {
  int n = storage.uni.datas.counter;
  JsonObject& root = jsonBuffer.createObject();
  root["writeKey"] = "*****************";    // ambientのapi write key
  JsonArray& dataArray = root.createNestedArray("data");
  for (int i = 0; i < n; i++) {
    OneData_t *pSrc = &storage.uni.datas.blocks[i];
    JsonObject& one = jsonBuffer.createObject();
    one["created"] = pSrc->created;
    one["d1"] = pSrc->temperature;
    one["d2"] = pSrc->humidity;
    one["d3"] = pSrc->pressure;
    one["d4"] = pSrc->airQuality;
    dataArray.add(one);
  }
  root["data"] = dataArray;
  Serial.print("text size = ");
  Serial.println(root.measureLength());
  root.printTo(jsonPrintBuffer, sizeof(jsonPrintBuffer));
  Serial.println(jsonPrintBuffer);
  int sent = ambient.bulk_send(jsonPrintBuffer);
  return true;
}

お勧め。

上の例ではバッファサイズを2048バイトにしているのでArduinoだと一発アウトですが、一度に送るレコード数を制限する等でカバーしてみてください。

なお、写真は特にこの記事とは関係ありませんが、次期モデルのプロトタイプ。LEDの色をちょっくら変えてみました。緑色LEDが明るすぎるので少し抵抗を大きくしないといけないの図。

2016年6月18日土曜日

Arduino:関数への構造体渡しで大ハマリ

■訂正訂正訂正■

またまた電子工作部で教えていただきました。ダメなのはstruct typedefです。typedefをやめてstructなら問題ありません。

誤った情報を流してしまい申し訳ありませんでした。

出典のブログ主さんにもコメント欄から訂正をお願いしました。

Arduino(4) ブロック崩しを作ってみる(1)

記事より引用:
しかし残念なことに、「構造体を引数とする関数」はスケッチの中では定義できません。
これを行うには、構造体を別ファイルで定義する必要があるようです。

「原典に当たる」という基本を疎かにしたため、誤報を流布してしまいましたことをお詫び申し上げます。


■typedef渡しでエラー■

このコードをコンパイルしてみてくださひ。ESPの人はそのまま、Arduinoなら最初の3行をコメントアウトして。

extern "C" {
#include "user_interface.h"
}

typedef struct {
  float temperature;
  float humidity;
  float pressure;
  float airQuality;
} OneData;

void func(OneData *inData) {

}


void setup() {
  // put your setup code here, to run once:
}
void loop() {
  // put your main code here, to run repeatedly:
}

そうすると…

Arduino:
Arduino_Function_Sample.ino:7:11: error: variable or field 'func' declared void
Arduino_Function_Sample.ino:7:11: error: 'OneData' was not declared in this scope
Arduino_Function_Sample.ino:7:20: error: 'inData' was not declared in this scope
variable or field 'func' declared void

ESP-WROOM-02:
Arduino_Function_Sample.ino:2:11: error: variable or field 'func' declared void
Arduino_Function_Sample.ino:2:11: error: 'OneData' was not declared in this scope
Arduino_Function_Sample.ino:2:20: error: 'inData' was not declared in this scope
variable or field 'func' declared void

こんなエラーが出ます。

で、どちらでもエラーとして表示されていないLine 14-16のvoid funcをコメントアウトするとビルド通ります。

なんじゃそりゃあああ

■答え■

Arduino言語ではスケッチ中で関数の引数として構造体を渡すことはできない

そうです(出典:Arduino(4) ブロック崩しを作ってみる(1))。

今まで知りませんでした…。ヘッダなどで定義してC言語としてコンパイルすれば通りますが、うーん、dependencyが…。

しかし…どーしよう。上のソースは28行しかないけど、久しぶりに気合入れてコーディングしちゃったです。300行ぐらい…構造体渡し使いまくりで…。void *で渡してキャストすればいいけど、事故の元だしなぁ…。でもglobalでベターっと書くよりマシかなぁ…。

どーしましょw

スケッチではstructのtypedefを関数の引数として構造体に渡すことができない

仕様だそうです。上記の定義を以下のように書き換えるとコンパイル通ります。

struct DneData_t {
  float temperature;
  float humidity;
  float pressure;
  float airQuality;
};

void func(struct OneData_t *inData) {

}

良かった良かった。でも、書いてたコードはもうtypedef渡しではなくGlobal仕様に書き換えちゃったんですよね…まぁ動いてるからいいけど…今後は気をつけます。

今週はやることなすことうまくいかない。

ちゃんと勉強してから使えって話なんですけどねorz