2022/05/31(火)Processing AndroidModeのcontrolP5ボタン

最近Processingを始めましたが、AndroidModeっていうのがあり、これを使うとProcessingアプリがAndroidスマホで動作します。どちらかというと簡易的にAndroidアプリをProcessingで製作出来る、といった方が分かりやすいかもしれません。そこで早速何か簡単な自分用ツールを作ってみようと思ったのですがいきなり躓きました。
それは、定番なProcessingGUIライブラリのcontrolP5ライブラリをAndroidModeで利用する場合、ボタンイベントが所望の動作にならないというものです。ざっと調べた結果仕様っぽかったので、手軽に使いたい自分には悲しい状況になりました。

どうやらボタンイベントに関する挙動で、マウスXY/クリックによるボタン操作と画面タップによるボタン操作の違いに起因してるようです。
他の方法としては正攻法なAndroidSDKのコンポーネントを使うだとかあるみたいなのですが、難しいことは分かりませんし、カジュアルに使えてアプリ作っていきたいので今回簡易的にボタンコンポーネントクラスを作りました。
  • TapButton.pde
    public class TapButton
    {
      float x;
      float y;
      float w;
      float h;
      String s;
      int fontsize;
      boolean visible;
    
      TapButton(float _x, float _y, float _w, float _h, String _s)
      {
        x = _x;
        y = _y;
        w = _w;
        h = _h;
        s = _s;
        fontsize = int(w / s.length());
        visible = true;
      }
    
      void Draw()
      {
        if (visible)
        {
          rectMode(CENTER);
          textAlign(CENTER, CENTER);
          textSize(fontsize);
    
          fill(255);
          rect(x, y, w, h);
          fill(0);
          text(s, x, y, w, h);
        }
      }
    
      void Visible(boolean b)
      {
        visible = b;
      }
    
      boolean Tapped(TouchEvent touchEvent)
      {
        int tapNum = touchEvent . getNumPointers( ) ;
        float tap_x, tap_y;
        if (0 < tapNum)
        {
          tap_x = touchEvent . getPointer( 0 ).x ;
          tap_y = touchEvent . getPointer( 0 ).y ;
          if ( abs(tap_x - this.x) < (w/2) && abs(tap_y - this.y) < (h/2) && this.visible)
          {
            return true;
          }
        }
        return false;
      }
    }
    
    

  • Test.pde
    import android.os.Bundle;
    import android.view.WindowManager;
    
    static int LetterBox = 16; //Letterbox of application draw area
    int sizeW, sizeH;
    boolean flag_backpress = false;//back button press flag
    boolean flag_exit = false;
    
    TapButton tb1 = new TapButton(500, 400, 300, 100, "button1");
    TapButton tb2 = new TapButton(500, 600, 300, 100, "button2");
    
    public void settings()
    {
      sizeW = displayWidth - LetterBox;
      sizeH = displayHeight - LetterBox;
      size(sizeW, sizeH);
    }
    
    public void setup()
    {
    
      frameRate(30);
    }
    
    void backPressed()
    {
      flag_backpress = true;
    }
    
    public void draw()
    {
    
      //DRAWING PROCESS --------------------------------------------------------------
      background(150);
    
      if (mousePressed)
      {
        textSize(50);
        fill(0);
        textAlign(TOP, LEFT);
        text(Integer.toString(mouseX) + "," + Integer.toString(mouseY), 0, 500);
      }
    
      textSize(32);
      fill(0);
      textAlign(TOP, LEFT);
      text(Integer.toString(displayWidth), 0, 150);
      text(Integer.toString(displayHeight), 300, 150);
    
      ellipseMode(CENTER);  // Set ellipseMode to CENTER
      fill(100);  // Set fill to gray
      ellipse(mouseX, mouseY, 100, 100);  // Draw gray ellipse using CENTER mode
    
      //TapButton draw ---------------------------------------------------------------
      tb1.Draw();
      tb2.Draw();
    
      //MAIN LOOP PROCESS ------------------------------------------------------------
      if (flag_backpress)
      {
        flag_backpress = false;
        textAlign(CENTER, CENTER);
        textSize(100);
        fill(255);
        rect(0, sizeH/2 - 80, sizeW, 160, 32);
        fill(0);
        text("Exiting...", sizeW/2, sizeH/2);
        flag_exit = true;
      } else if (flag_exit)
      {
        delay(1000);
        exit();
      }
    }
    
    public void touchStarted(TouchEvent touchEvent)
    {
      int tapNum = touchEvent . getNumPointers( ) ;
      float x = touchEvent . getPointer( 0 ).x ;
      float y = touchEvent . getPointer( 0 ).y ;
    
      //TapButton
      if (tb1.Tapped(touchEvent))
      {
        tb1.Visible(false);
      }
      if (tb2.Tapped(touchEvent))
      {
        tb1.Visible(true);
      }
    }
    
    
テストプログラムは、button1を押すと、button1が消えてbutton2を押すとbutton1が表示されます。
グローバル変数の
TapButton tb1 = new TapButton(500, 400, 300, 100, "button1");
でボタンを定義して、Draw()内の
tb1.Draw();
で描画、タップイベントは
public void touchStarted(TouchEvent touchEvent)内で、
  if (tb1.Tapped(touchEvent))
  {
    tb1.Visible(false);
  }
のようにifで判定してタップ時の処理を書きます。
(ソースコード一部修正:2022/6/12)

2022/03/06(日)TTP224

数個のGPIOをタッチボタン入力にしたいと思い簡単なモジュールを探していたところ、Aliexpressなどでもよくみる定番デバイスにたどり着きました。
  • TTP223 1点タッチセンサ
  • TTP224 4点タッチセンサ
  • TTP226 8点タッチセンサ
検索すると似たようなモジュール製品がいたるところで売られています。これらのうちTTP224を購入しました。
TTP224_module.jpg

ちょうど同じものをご購入された先駆者の方がいらしたのでそれを参考にしました。
TTP224

データシートも上記の方のURLから辿れます。このモジュール基板はt0.8と薄くタッチが基板の裏からでも反応しました。ピンヘッダが手前に来ているのでモジュールをそのまま何かに利用する場合裏面側から使うこともできそうです。電源/IO電圧範囲が2.4~5.5Vなので3.3VIOでも5VIOでもそのまま使えます。

先の方の例ではジャンパ設定そのまま(CMOSドライブで出力)で2.7V程度の出力とありますが、自分が搭載LED負荷のみで計ったところ電源3.3Vで3.2Vほど出ていました。ドライブ能力の問題かと思われますので、ラッチアップ防止も兼ねて1kほど通してマイコンの入力に使うか、ODジャンパ設定でOpenDrain動作で動かすのが無難です。データシートには各ピンの出力仕様など記載がないので、この辺りは精査の上回路を決める必要がありそうです。


とはいっても、基本的に電源さえ繋げば動いてくれる簡単デバイスなので使い勝手は良いと思います。

2021/10/01(金)VSCodeでArduino開発するときのメモリ使用量の確認

VSCodeにArduino拡張を入れて開発するとき、本家IDEと違って、以下のようなメモリ使用量がでない。
"C:\\Program Files (x86)\\Arduino\\hardware\\tools\\avr/bin/avr-size" -A "R:\\/test.ino.elf"
最大32256バイトのフラッシュメモリのうち、スケッチが20776バイト(64%)を使っています。
最大2048バイトのRAMのうち、グローバル変数が896バイト(43%)を使っていて、ローカル変数で1152バイト使うことができます。
そこで、VSCodeのtask.jsonを書いて同等の情報出力をファイルに出すようにした。手順は以下の通り。
  1. Ctrl+Shift+Pでコマンドパレットを開く
  2. コマンドパレットに"task"と打ったら「タスクの構成を開く」とあるのでそれを選択
  3. 次に「テンプレートからtask.jsonを生成」とあるのでそれを選択
  4. そして「Others」を選択するとtask.jsonファイルが生成される
以下の例に従って記述を変更する。

{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "メモリ状況",
            "type": "shell",
            "presentation": {"echo": true},
            "command": "C:\\Program Files (x86)\\Arduino\\hardware\\tools\\avr\\bin\\avr-size.exe",
            "args": [">", "memory.txt", "-C", "--mcu=atmega328p", "R:\\test.ino.elf"]
        }
    ]
}

なお、ドライブレターやパス、ターゲットelfファイル名などすべてハードコーディングしているので適宜変更が必要。まずは動くことを重視した。task.jsonを保存したらメニューからターミナル->タスクの実行を選択すると「メモリ状況」という項目が増えているのでそれを選択して「タスクの出力をスキャンせずに続行」で実行する。
するとmemory.txtにFlashとSRAMの使用量が出力される。この処理はコンパイル直後に行う。

2020/11/19(木)8x8ドット キャラクターコード フォント

ArduinoとOLEDモジュールの組み合わせで使うとき、キャラクターLCDと違って自前でフォントを持たないといけないので、8x8ドットのキャラクターコード(アスキーコード)のフォントを作成しました。以前から5x8とか作ってたのですが、SSD1306なOLEDは128x64が定番なので8x8ドットで切りよく使いたいと思い新たに作りました。
8x8dot_font.png

本当は.hファイルにしてマイコンプログラミングで扱いやすくしてGithubにでも上げたらいいんですが、エクセル方眼紙で作ったやつをとりあえずそのまま置きます。(備忘録)
それでもなるべくソースコードにコピペしやすいように、16進数表記になった文字列のセルを作っています。
ダウンロード:8x8_dot_font.zip
【使用、複写、変更など自由にできるようにMITライセンスとしました。】

2020/11/18(水)秋月電子 AE-ATMEGA-UNO-R3

秋月電子の新発売で、「Arduino UNO 互換マイコンボード」が出ていたので買ってみました。
値段は1940円、本家が2940円で売られていますからかなり安いですね。

AE-UNO_1.jpg

パッケージは本家と違って簡易包装でした。本体とシリカゲルのみ。

AE-UNO_2.jpg

シルクなど見た目を除き裏面も特に本家と変わりなし、USBコネクタのショート半田修正とコテで引きずったあとがある以外は気になるところはありません。DCジャック部分の大きなPADのところで確認してわかる通り鉛フリー半田です。

AE-UNO_3.jpg

実物は明らかですが、本家は洗浄していますがこちらは無洗浄仕上げ。テカり具合がわかるショット。

AE-UNO_4.jpg

ピンソケットのフラックス残渣からスプレーフラクサーを通していることがわかります。

USBシリアル部には同様にATMEGA16U2が搭載されています。互換ボードであればFTDI系やCP2102、中華系チップならCH340あたりが載ってそうですがUSBデバイスとしてどのように認識するのか気になります。

AE-UNO_5.jpg


結果、Arduino IDEでは本家と同じ認識。USBデバイスも「Arduino UNO」と認識されています。ちなみに、VID=2341は"Arduino SA"でPID=0043は"Uno R3 (CDC ACM)"です。結論としては互換ボードではなくクローン製品のようです。

互換品を買うならamazonでとにかく安いのが売られていますね。

VKLSVAN UNO R3コントロールボード ATmega328P Arduinoと互換性 + USBケーブル