├── .gitignore ├── LICENSE ├── README.md ├── README_en.md ├── data └── yaml │ └── SC_BasicConfig.yaml ├── lib └── stackchan-arduino ├── platformio.ini └── src ├── formatString.hpp └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | .pio 35 | .vscode 36 | lib/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Takao Akaki 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # stack-chan-tester 2 | 3 | 日本語 | [English](README_en.md) 4 | 5 | スタックチャンを作成するときに、PWMサーボの調整及びテストを行うためのアプリケーションです。
6 | stack-chan test application for pwm servo 7 | 8 | # 対応キット 9 | BOOTHで頒布している [スタックチャン M5GoBottom版 組み立てキット](https://mongonta.booth.pm/)の動作確認及び組立時の設定用に開発しました。ピンの設定を変えることによりスタックチャン基板にも対応可能です。 10 | 11 | ※ ArduinoFramework及びPWMサーボのみです。 12 | 13 | # デフォルト設定 14 | SDカードに/yaml/SC_BasicConfig.yamlという名前のファイルを置くことにより、PWMサーボ以外にも対応可能です。 15 | 16 | デフォルト値はPWMサーボ向けになっています。(SG90) 17 | 18 | CoreS3はPort.A(G1, G2)、Core2はPort.A(G33,G34)、Core1は Port.A(G22,G21)を使うようになっています。違うピンを使用する場合はSDカードに設定ファイルをおいて変更してください。 19 | 20 | 21 | # サーボのオフセット調整 22 | SG90系のPWMサーボは個体差が多く、90°を指定しても少しずれる場合があります。その場合は下記のオフセット値を調整してください。(90°からの角度(±)を設定します。) 23 | 調整する値は、ボタンAの長押しでオフセットを調整するモードに入るので真っ直ぐになる数値を調べてください。 24 | 25 | オフセットの調整方法はおきもくさんの[スタックチャンの作り方 M5Burner版 分解なし【後半】](https://www.youtube.com/watch?v=YRQYYrQh0oE&t=329s)を参照してください。 26 | 27 | 調整後の値の設定方法については、書き込むファームウェアによって変わります。 28 | 29 | - ソース内の初期値を書き換えるもの。
初期設定で90を指定している箇所を書き換えて再ビルドします。 30 | - 設定ファイルを書き換えるもの。
[stackchan-bluetooth-simple](https://github.com/mongonta0716/stackchan-bluetooth-simple)は設定ファイルでオフセットを指定します。 31 | - Webで設定するもの。
NoRiさんの[WebServer-with-stackchan](https://github.com/NoRi-230401/WebServer-with-stackchan)はWebで設定する機能があります。 32 | 33 | 34 | # 使い方 35 | * ボタンA: X軸、Y軸のサーボを90°にします。固定前に90°にするときに使用してください。(90°の位置はPWMサーボによって若干異なるためオフセット値の調整値を調べる必要があります。) 36 | * ボタンB: X軸は0〜180, Y軸は90〜50まで動きます。
ダブルクリックすると、Groveの5V(ExtPower)出力のON/OFFを切り替えます。Stack-chan_Takao_Baseの後ろから給電をチェックする場合OFFにします。 37 | * ボタンC: ランダムで動きます。 38 | * ボタンC: ランダムモードの停止 39 | * ボタンAの長押し:オフセットを調整して調べるモードに入ります。 40 | * ボタンA: オフセットを減らす 41 | * ボタンB: X軸とY軸の切り替え 42 | * ボタンC: オフセットを増やす 43 | * ボタンB長押し: 調整モードの終了 44 | 45 | 46 | 47 | ## CoreS3のボタン操作 48 | CoreS3はCore2のBtnA、B、Cの部分がカメラやマイクに変わってしまったためボタンの扱いが変わりました。
49 | 画面を縦に3分割して左:BtnA、中央:BtnB、右:BtnCとなっています。 50 | 51 | # 必要なライブラリ(動作確認済バージョン) 52 | ※ 最新の情報はplatformio.iniを確認してください。最新で動かない場合はライブラリのバージョンを合わせてみてください。 53 | - [M5Unified](https://github.com/m5stack/M5Unified) v0.1.6で確認 54 | - [M5Stack-Avatar](https://github.com/meganetaaan/m5stack-avatar) v0.8.2で確認
v0.7.4以前はM5Unifiedに対応していないのでビルド時にM5の二重定義エラーが出ます。 55 | - [ServoEasing](https://github.com/ArminJo/ServoEasing) v3.1.0で確認 56 | - [ESP32Servo](https://github.com/madhephaestus/ESP32Servo) v0.13.0で確認
CoreS3はv0.13.0じゃないと動かない場合があります。 57 | 58 | ArduinoIDEでの詳しいライブラリの追加方法は下記のブログを参照してください。(日本語) 59 | 60 | [スタックチャン M5GoBottom版のファームウェアについて | M5Stack沼人の日記](https://raspberrypi.mongonta.com/softwares-for-stackchan/) 61 | 62 | 63 | # ビルド方法 64 |  v0.1はArduinoIDEでしたが、現在はPlatformIOでのビルドを想定しています。 65 | 66 | # スタックチャンについて 67 | スタックチャンは[ししかわさん](https://github.com/stack-chan)が公開しているオープンソースのプロジェクトです。 68 | 69 | https://github.com/stack-chan/stack-chan 70 | 71 | # author 72 | Takao Akaki 73 | 74 | # LICENSE 75 | MIT -------------------------------------------------------------------------------- /README_en.md: -------------------------------------------------------------------------------- 1 | # stack-chan-tester 2 | 3 | [日本語](README.md) | English 4 | 5 | stack-chan test application for pwm servo 6 | 7 | # Supported kits 8 | This kit was developed to check the operation of [Stack-Chan M5GoBottom version assembly kit](https This application was developed to check the operation of [Stack-Chan M5GoBottom version kit](https://mongonta.booth.pm/) and to set up when assembling the kit. It can also be used for stacked-channel boards by changing the pin settings. 9 | 10 | This is only for ArduinoFramework and PWM servos. 11 | 12 | # Pin settings for servo 13 | CoreS3 uses Port.C(G18,G17), Core2 uses Port.C(G13,G14), Fire uses Port.A(G22,G21), and Core1 uses Port.C(G16,G17). If you want to use different pins, please rewrite the following section. 14 | 15 | https://github.com/mongonta0716/stack-chan-tester/blob/main/src/main.cpp#L7-L35 16 | 17 | # Adjustment of servo offset 18 | 19 | PWM servos of the SG90 series have many individual differences, and even if 90° is specified, the servo may shift slightly. In this case, please adjust the offset value below. (Set the angle (±) from 90°.) 20 | For the value to be adjusted, press and hold button A to enter the mode to adjust the offset, and find out the value that makes it straight. 21 | 22 | Please refer to Okimoku's [How to make a stack chan M5Burner version without disassembly [second half]](https://www.youtube.com/watch?v=YRQYYrQh0oE&t=329s) for how to adjust the offset.(Japanese) 23 | 24 | The method of setting the adjusted value depends on the firmware to be written. 25 | 26 | - The one that rewrites the initial value in the source.
Rewrite the part where 90 is specified in the initial settings and rebuild. 27 | - Rewriting the configuration file.
[stackchan-bluetooth-simple](https://github.com/mongonta0716/stackchan-bluetooth-simple) specifies the offset in the configuration file. 28 | - The one to be configured on the web.
NoRi's [WebServer-with-stackchan](https://github.com/NoRi-230401/WebServer-with-stackchan) has the ability to configure on the web. 29 | 30 | # Usage 31 | * Button A: Rotates the X-axis and Y-axis servos to 90°. Use this button to rotate the servo 90° before fixing. 32 | * Button B: X-axis moves from 0 to 180, Y-axis moves from 90 to 50.
Double-click to toggle Grove's 5V (ExtPower) output ON/OFF; turn OFF when checking power feed from behind Stack-chan_Takao_Base. 33 | * Button C: Moves in random mode. 34 | * Button C: Stop random mode. 35 | * Button A long press: Enter the mode to adjust and examine the offset. 36 | * Button A: Decrease offset. 37 | * Button B: toggles between X and Y axis 38 | * Button C: Increase offset 39 | * Button B long press: Out the mode to adjust. 40 | 41 | ## Button handling in CoreS3 42 | CoreS3 has changed the handling of buttons because the BtnA, B, and C parts of Core2 have been replaced by cameras and microphones.
43 | The screen is divided vertically into three parts: left: BtnA, center: BtnB, and right: BtnC. 44 | 45 | # Requirement Libraries 46 | ※ If it does not work with the latest version, try matching the library version. 47 | - [M5Unified](https://github.com/m5stack/M5Unified) v0.0.7 48 | - [M5Stack-Avatar](https://github.com/meganetaaan/m5stack-avatar) v0.8.0
Prior to v0.7.4, M5Unified is not supported, so M5 double definition errors occur at build time. 49 | - [ServoEasing](https://github.com/ArminJo/ServoEasing) v2.4.0 50 | - [ESP32Servo](https://github.com/madhephaestus/ESP32Servo) v0.11.0 51 | 52 | Please refer to the following blog for detailed instructions on how to add libraries in ArduinoIDE. (in Japanese) 53 | 54 | [スタックチャン M5GoBottom版のファームウェアについて | M5Stack沼人の日記]( https://raspberrypi.mongonta.com/softwares-for-stackchan/) 55 | 56 | # How to build 57 | 58 | v0.1 was ArduinoIDE, but now it is intended to be built with PlatformIO. 59 | 60 | # About stack chan 61 | Stack chan is [meganetaaan](https://github.com/meganetaaan) is an open source project. 62 | 63 | https://github.com/meganetaaan/stack-chan 64 | 65 | # author 66 | Takao Akaki 67 | 68 | # LICENSE 69 | MIT -------------------------------------------------------------------------------- /data/yaml/SC_BasicConfig.yaml: -------------------------------------------------------------------------------- 1 | servo: 2 | pin: 3 | # ServoPin 4 | # Core1 PortA X:22,Y:21 PortC X:16,Y:17 5 | # Core2 PortA X:33,Y:32 PortC X:13,Y:14 6 | # CoreS3 PortA X:1,Y:2 PortB X:8,Y:9 PortC X:18,Y:17 7 | # Stack-chanPCB Core1 X:5,Y:2 Core2 X:19,Y27 8 | # When using SCS0009, x:RX, y:TX (TX not used) 9 | x: 18 10 | y: 17 11 | offset: 12 | # Specified by +- from 90 degree during servo initialization 13 | x: 0 14 | y: 0 15 | center: 16 | # SG90 X:90, Y:90 17 | # SCS0009 X:150, Y:150 18 | # Dynamixel X:180, Y:270 19 | x: 180 20 | y: 270 21 | lower_limit: 22 | # SG90 X:0, Y:60 23 | # Feetech SCS0009 X:0, Y:120 24 | # Dynamixel XL330 X:0, Y:240 25 | x: 0 26 | y: 240 27 | upper_limit: 28 | # SG90 X:180, Y:100 29 | # Feetech SCS0009 X:300, Y:160 30 | # Dynamixel XL330 X:360, Y:280 31 | x: 360 32 | y: 280 33 | speed: 34 | normal_mode: 35 | interval_min: 3000 36 | interval_max: 6000 37 | move_min: 500 38 | move_max: 1500 39 | sing_mode: 40 | interval_min: 500 41 | interval_max: 1000 42 | move_min: 500 43 | move_max: 1000 44 | bluetooth: 45 | device_name: "M5Stack" 46 | starting_state: false 47 | start_volume: 100 48 | auto_power_off_time: 0 # Core2 Only. time(msec) of auto power off(0 is disable.) 49 | balloon: 50 | font_language: "CN" # "JA or CN or Default" 51 | lyrics: # A maximum of 10 can be specified. 52 | - "こんにちは" 53 | - "Hello" 54 | - "Bonjour" 55 | - "你好" 56 | - "私はスタックチャン" 57 | - "我是Stack-chan" 58 | - "I'm Stack-chan" 59 | - "Je suis Stack-chan" 60 | led_lr: 0 # 0:stereo, 1:left_only, 2:right_only 61 | led_pin: 15 # GoBottom1:15 GoBottom2:25 62 | takao_base: false # Whether to use takaobase to feed power from the rear connector.(Stack-chan_Takao_Base https://ssci.to/8905) 63 | servo_type: "DYN_XL330" # "PWM": SG90PWMServo, "SCS": Feetech SCS0009, "DYN_XL330": Dynamixel XL330 64 | extend_config_filename: "" # Configuration file for the application. 65 | extend_config_filesize: 2048 # Buffer size for feature extensions 66 | secret_config_filename: "" # Configuration file for the File for personal information. 67 | secret_config_filesize: 2048 # Buffer size for personal information. 68 | secret_info_show: true # Whether personal information is output to the log or not. -------------------------------------------------------------------------------- /lib/stackchan-arduino: -------------------------------------------------------------------------------- 1 | /home/mongonta/Nextcloud/MyGit/stackchan-arduino/ -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [platformio] 12 | default_envs = m5stack-core2 13 | 14 | [env] 15 | platform = espressif32 @ 6.5.0 16 | framework = arduino 17 | upload_speed = 1500000 18 | monitor_speed = 115200 19 | board_build.f_flash = 80000000L 20 | board_build.filesystem = spiffs 21 | board_build.partitions = default_16MB.csv 22 | build_flags = -DCORE_DEBUG_LEVEL=4 23 | ;lib_extra_dirs = lib 24 | lib_deps = 25 | meganetaaan/M5Stack-Avatar@0.10.0 26 | tobozo/M5Stack-SD-Updater 27 | ;m5stack/M5Unified@^0.2.0 28 | mongonta0716/stackchan-arduino@^0.0.3 29 | ;https://github.com/stack-chan/stackchan-arduino#develop 30 | gob/gob_unifiedButton 31 | 32 | 33 | lib_ldf_mode = deep 34 | 35 | [env:m5stack-core2] 36 | board = m5stack-core2 37 | 38 | [env:m5stack-grey] 39 | ; Flash16MBのBasicはこちらを使ってください。 40 | board = m5stack-grey 41 | 42 | [env:m5stack-fire] 43 | ; fireはespressif32最新版(5.x)で動かない場合は下記の1行をコメントアウトしてください。 44 | ; platform = espressif32 @ 4.4.0 45 | board = m5stack-fire 46 | 47 | [env:m5stack-core-esp32] 48 | ; Flash 16MBのBasicはm5stack-greyを使ってください。 49 | board = m5stack-core-esp32 50 | board_build.partitions = huge_app.csv 51 | 52 | [env:m5stick-c] 53 | ; Flash 16MBのBasicはm5stack-greyを使ってください。 54 | board = m5stick-c 55 | board_build.partitions = huge_app.csv 56 | 57 | [env:m5atoms3] 58 | platform = espressif32 @ 6.2.0 59 | board = m5stack-atoms3 60 | build_flags = -DARDUINO_USB_MODE=1 61 | -DARDUINO_USB_CDC_ON_BOOT=1 62 | ;monitor_port = COM6 63 | monitor_rts = 1 64 | monitor_dtr = 1 65 | board_build.partitions = huge_app.csv 66 | 67 | [env:m5atoms3-release] 68 | platform = espressif32 @ 6.2.0 69 | board = m5stack-atoms3 70 | board_build.partitions = huge_app.csv 71 | 72 | [env:m5stack-cores3] 73 | board = esp32s3box 74 | build_flags = 75 | -DARDUINO_M5STACK_CORES3 76 | 77 | board_build.arduino.memory_type = qio_qspi 78 | 79 | -------------------------------------------------------------------------------- /src/formatString.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | see also https://stackoverflow.com/questions/7315936/which-of-sprintf-snprintf-is-more-secure/35401865#35401865 3 | If you leave memory management to std::string, you don't have to free it yourself. 4 | formatString.hppは、snprintfのバグを解消するために必要な関数です。 5 | */ 6 | 7 | // Using template 8 | #include 9 | template std::string formatString(const char* fmt, Args... args) 10 | { 11 | size_t sz = snprintf(nullptr, 0U, fmt, args...); // calculate length 12 | char buf[sz + 1]; 13 | snprintf(buf, sizeof(buf), fmt, args...); 14 | return std::string(buf, buf + sz + 1); 15 | } 16 | 17 | // Using vsnprintf 18 | #include 19 | #include 20 | std::string formatString(const char* fmt, ...) 21 | { 22 | va_list args; 23 | va_start(args, fmt); 24 | 25 | size_t sz = vsnprintf(nullptr, 0U, fmt, args); // calculate length 26 | char buf[sz + 1]; 27 | vsnprintf(buf, sizeof(buf), fmt, args); 28 | va_end(args); 29 | return std::string(buf, buf + sz + 1); 30 | } 31 | 32 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Stack-chan-tester 3 | * 4 | * @author TakaoAkaki 5 | * Copyright (c) 2021-2024 Takao Akaki. All right reserved 6 | */ 7 | 8 | // ------------------------ 9 | // ヘッダファイルのinclude 10 | // 11 | #include // Arduinoフレームワークを使用する場合は必ず必要 12 | #include // SDカードを使うためのライブラリです。 13 | #include // 定義しないとエラーが出るため追加。 14 | #include // 定義しないとエラーが出るため追加。 15 | #include // M5Stack SDUpdaterライブラリ 16 | #include // M5Unifiedライブラリ 17 | #include // stack-chanの初期設定ファイルを扱うライブラリ 18 | #include // stack-chanのサーボを動かすためのライブラリ 19 | #ifdef ARDUINO_M5STACK_CORES3 20 | #include 21 | goblib::UnifiedButton unifiedButton; // M5CoreS3のタッチパネルをボタンA,B,Cとして使うためのライブラリ。 22 | #endif 23 | #include // 顔を表示するためのライブラリ https://github.com/meganetaaan/m5stack-avatar 24 | #include "formatString.hpp" // 文字列に変数の値を組み込むために使うライブラリ https://gist.github.com/GOB52/e158b689273569357b04736b78f050d6 25 | // ヘッダファイルのinclude end 26 | // ================================== End 27 | 28 | // --------------------------------------------- 29 | // グローバル変数の定義エリア 30 | // プログラム全体で利用する変数やクラスを決める 31 | int servo_offset_x = 0; // X軸サーボのオフセット(サーボの初期位置からの+-で設定) 32 | int servo_offset_y = 0; // Y軸サーボのオフセット(サーボの初期位置からの+-で設定) 33 | 34 | using namespace m5avatar; // (Avatar.h)avatarのnamespaceを使う宣言(こうするとm5avatar::???と書かなくて済む。) 35 | Avatar avatar; // (Avatar.h)avatarのクラスを定義 36 | ColorPalette *cps[2]; 37 | 38 | #define SDU_APP_PATH "/stackchan_tester.bin" // (SDUpdater.h)SDUpdaterで使用する変数 39 | #define TFCARD_CS_PIN 4 // SDカードスロットのCSPIN番号 40 | 41 | StackchanSERVO servo; // (Stackchan_servo.h) サーボを扱うためのクラス 42 | StackchanSystemConfig system_config; // (Stackchan_system_config.h) プログラム内で使用するパラメータをYAMLから読み込むクラスを定義 43 | 44 | uint32_t mouth_wait = 2000; // 通常時のセリフ入れ替え時間(msec) 45 | uint32_t last_mouth_millis = 0; // セリフを入れ替えた時間 46 | bool core_port_a = false; // Core1のPortAを使っているかどうか 47 | 48 | const char* lyrics[] = { "BtnA:MoveTo90 ", "BtnB:ServoTest ", "BtnC:RandomMode ", "BtnALong:AdjustMode"}; // 通常モード時に表示するセリフ 49 | const int lyrics_size = sizeof(lyrics) / sizeof(char*); // セリフの数 50 | int lyrics_idx = 0; // 表示するセリフ数用の変数 51 | // ================================== End 52 | 53 | // ------------------------------------------------ 54 | // Stack-chan-testerの各モードを定義するエリア 55 | // adjustOffset(): オフセットを調べるモード 56 | // moveRandom() : ランダムでStack-chanが動くモード 57 | // testServo() : サーボをテストするときのモード 58 | 59 | // オフセットの設定モード(loop()でBtnAが押されると実行されます。) 60 | void adjustOffset() { 61 | // サーボのオフセットを調整するモード 62 | // 関数内のみで使用する変数の初期化 63 | servo_offset_x = 0; 64 | servo_offset_y = 0; 65 | servo.moveXY(system_config.getServoInfo(AXIS_X)->start_degree, system_config.getServoInfo(AXIS_Y)->start_degree, 2000); // サーボを中央にセット 66 | bool adjustX = true; // X軸とY軸のモードを切り替えるためのフラグ 67 | for (;;) { // 無限ループ(BtnBが長押しされるまで繰り返します。) 68 | #ifdef ARDUINO_M5STACK_CORES3 69 | unifiedButton.update(); // M5.update() よりも前に呼ぶ事 70 | #endif 71 | M5.update(); 72 | if (M5.BtnA.wasPressed()) { 73 | // オフセットを減らす 74 | if (adjustX) { 75 | servo_offset_x--; 76 | } else { 77 | servo_offset_y--; 78 | } 79 | } 80 | if (M5.BtnB.pressedFor(2000)) { 81 | // 調整モードを終了(loop()へ戻る) 82 | break; 83 | } 84 | if (M5.BtnB.wasPressed()) { 85 | // 調整モードのXとYを切り替え 86 | adjustX = !adjustX; 87 | } 88 | if (M5.BtnC.wasPressed()) { 89 | // オフセットを増やす 90 | if (adjustX) { 91 | servo_offset_x++; 92 | } else { 93 | servo_offset_y++; 94 | } 95 | } 96 | // オフセットを反映した位置にサーボを移動 97 | servo.moveXY(system_config.getServoInfo(AXIS_X)->start_degree + servo_offset_x, system_config.getServoInfo(AXIS_Y)->start_degree + servo_offset_y, 1000); 98 | 99 | std::string s; 100 | 101 | if (adjustX) { 102 | // X軸の値を設定する。 103 | s = formatString("%s:%d:BtnB:X/Y", "X", servo_offset_x); // 吹き出し用のStringを作成 104 | } else { 105 | // Y軸の値を設定する。 106 | s = formatString("%s:%d:BtnB:X/Y", "Y", servo_offset_y); // 吹き出し用のStringを作成 107 | } 108 | // 109 | avatar.setSpeechText(s.c_str()); // 作成したStringをChar型に変換して吹き出しに表示する。 110 | 111 | } 112 | } 113 | 114 | // ランダムモード(loop()でBtnCが押されると実行されます。) 115 | void moveRandom() { 116 | for (;;) { // 無限ループ(BtnCが押されるまでランダムモードを繰り返します。 117 | // ランダムモード 118 | int x = random(system_config.getServoInfo(AXIS_X)->lower_limit + 45, system_config.getServoInfo(AXIS_X)->upper_limit - 45); // 可動範囲の下限+45〜上限-45 でランダム 119 | int y = random(system_config.getServoInfo(AXIS_Y)->lower_limit, system_config.getServoInfo(AXIS_Y)->upper_limit); // 可動範囲の下限〜上限 でランダム 120 | #ifdef ARDUINO_M5STACK_CORES3 121 | unifiedButton.update(); // M5.update() よりも前に呼ぶ事 122 | #endif 123 | M5.update(); 124 | if (M5.BtnC.wasPressed()) { 125 | // ランダムモードを抜ける処理。(loop()に戻ります。) 126 | break; 127 | } 128 | uint16_t base_delay_time = 0; 129 | if (system_config.getServoType() == ServoType::SCS || system_config.getServoType() == ServoType::DYN_XL330) { 130 | base_delay_time = 500; 131 | } 132 | int delay_time = random(10); 133 | servo.moveXY(x, y, 1000 + (100 + base_delay_time) * delay_time); 134 | delay(2000 + 500 * delay_time); 135 | if (!core_port_a) { 136 | // Basic/M5Stack Fireの場合はバッテリー情報が取得できないので表示しない 137 | avatar.setBatteryStatus(M5.Power.isCharging(), M5.Power.getBatteryLevel()); 138 | } 139 | //avatar.setSpeechText("Stop BtnC"); 140 | avatar.setSpeechText(""); 141 | } 142 | } 143 | void testServo() { 144 | // サーボのテストの動き 145 | for (int i=0; i<2; i++) { // 同じ動きを2回繰り返す。 146 | avatar.setSpeechText("X center -> left "); 147 | servo.moveX(system_config.getServoInfo(AXIS_X)->lower_limit, 1000); // 初期位置から左へ向く 148 | avatar.setSpeechText("X left -> right "); 149 | servo.moveX(system_config.getServoInfo(AXIS_X)->upper_limit, 3000); // 左へ向いたあと右へ向く 150 | avatar.setSpeechText("X right -> center "); 151 | servo.moveX(system_config.getServoInfo(AXIS_X)->start_degree, 1000); // 前を向く 152 | avatar.setSpeechText("Y center -> lower "); 153 | servo.moveY(system_config.getServoInfo(AXIS_Y)->lower_limit, 1000); // 上を向く 154 | avatar.setSpeechText("Y lower -> upper "); 155 | servo.moveY(system_config.getServoInfo(AXIS_Y)->upper_limit, 1000); // 下を向く 156 | avatar.setSpeechText("Initial Pos."); 157 | servo.moveXY(system_config.getServoInfo(AXIS_X)->start_degree, system_config.getServoInfo(AXIS_Y)->start_degree, 1000); // 初期位置に戻る(正面を向く) 158 | } 159 | } 160 | 161 | // ぼっちちゃんのむむむを再現するために遊びで作った関数。 162 | // 使わないでください。 163 | void mumumuServo() { 164 | for (int i=0; i<30; i++) { 165 | servo.moveX(120, 250); 166 | servo.moveX(240, 250); 167 | } 168 | } 169 | // ============================================== End 170 | 171 | 172 | // ------------------------------------------------------------------ 173 | // Arduinoフレームワークで一番最初に実行される関数の定義 174 | // void setup()とvoid loop()は必ず必要です。 175 | // void setup()は、最初に1回だけ実行します。 176 | void setup() { 177 | auto cfg = M5.config(); // 設定用の情報を抽出 178 | cfg.serial_baudrate = 115200; 179 | M5.begin(cfg); // M5Stackをcfgの設定で初期化 180 | #ifdef ARDUINO_M5STACK_CORES3 // CORES3のときに有効になります。 181 | // 画面上のタッチパネルを3分割してBtnA, B, Cとして使う設定。 182 | unifiedButton.begin(&M5.Display, goblib::UnifiedButton::appearance_t::transparent_all); 183 | #endif 184 | M5.Log.setLogLevel(m5::log_target_display, ESP_LOG_NONE); // M5Unifiedのログ初期化(画面には表示しない。) 185 | M5.Log.setLogLevel(m5::log_target_serial, ESP_LOG_INFO); // M5Unifiedのログ初期化(シリアルモニターにESP_LOG_INFOのレベルのみ表示する) 186 | M5.Log.setEnableColor(m5::log_target_serial, false); // M5Unifiedのログ初期化(ログをカラー化しない。) 187 | M5_LOGI("Hello World"); // logにHello Worldと表示 188 | SD.begin(GPIO_NUM_4, SPI, 25000000); // SDカードの初期化 189 | delay(2000); // SDカードの初期化を少し待ちます。 190 | 191 | system_config.loadConfig(SD, ""); // SDカードから初期設定ファイルを読み込む 192 | if (M5.getBoard() == m5::board_t::board_M5Stack) { // Core1かどうかの判断 193 | if (system_config.getServoInfo(AXIS_X)->pin == 22) { // サーボのGPIOが22であるか確認(本当は21も確認してもいいかもしれないが省略) 194 | // M5Stack Coreの場合、Port.Aを使う場合は内部I2CをOffにする必要がある。バッテリー表示は不可。 195 | M5_LOGI("I2CRelease"); // ログに出力 196 | avatar.setBatteryIcon(false); // avatarのバッテリーアイコンを表示しないモードに設定 197 | M5.In_I2C.release(); // I2Cを使わないように設定(IMUやIP5306との通信をしないようにします。)※設定しないとサーボの動きがおかしくなります。 198 | core_port_a = true; // Core1でポートAを使用しているフラグをtrueに設定 199 | } 200 | } else { 201 | avatar.setBatteryIcon(true); // Core2以降の場合は、バッテリーアイコンを表示する。 202 | } 203 | // servoの初期化 204 | M5_LOGI("attach servo"); // ログへ出力 205 | // サーボの初期化を行います。(このとき、初期位置(正面)を向きます。) 206 | servo.begin(system_config.getServoInfo(AXIS_X)->pin, system_config.getServoInfo(AXIS_X)->start_degree, 207 | system_config.getServoInfo(AXIS_X)->offset, 208 | system_config.getServoInfo(AXIS_Y)->pin, system_config.getServoInfo(AXIS_Y)->start_degree, 209 | system_config.getServoInfo(AXIS_Y)->offset, 210 | (ServoType)system_config.getServoType()); 211 | 212 | M5.Power.setExtOutput(!system_config.getUseTakaoBase()); // 設定ファイルのTakaoBaseがtrueの場合は、Groveポートの5V出力をONにする。 213 | 214 | M5_LOGI("ServoType: %d\n", system_config.getServoType()); // サーボのタイプをログに出力 215 | //USBSerial.println("HelloWorldUSBSerial"); 216 | avatar.init(); // avatarを初期化して実行開始します。(このときに顔が表示されます。) 217 | cps[0] = new ColorPalette(); 218 | cps[0]->set(COLOR_PRIMARY, TFT_BLACK); 219 | cps[0]->set(COLOR_BACKGROUND, TFT_WHITE); 220 | avatar.setColorPalette(*cps[0]); 221 | 222 | last_mouth_millis = millis(); // loop内で使用するのですが、処理を止めずにタイマーを実行するための変数です。一定時間で口を開くのとセリフを切り替えるのに利用します。 223 | //moveRandom(); 224 | //testServo(); 225 | } 226 | 227 | 228 | // メインのloop処理。(必ず定義が必要。) 229 | // 基本的にはずっと繰り返し実行されます。 230 | // stack-chan-testerの場合は、ボタンを押して、各モードの関数が実行されると一時停止します。 231 | void loop() { 232 | #ifdef ARDUINO_M5STACK_CORES3 233 | unifiedButton.update(); // M5.update() よりも前に呼ぶ事 234 | #endif 235 | M5.update(); // M5Stackのボタン状態を更新します。 236 | if (M5.BtnA.pressedFor(2000)) { // ボタンAを2秒長押しを検出したら。 237 | adjustOffset(); // サーボのオフセットを調整するモードへ 238 | } else if (M5.BtnA.wasPressed()) { // ボタンAが押された場合 239 | servo.moveXY(system_config.getServoInfo(AXIS_X)->start_degree, system_config.getServoInfo(AXIS_Y)->start_degree, 2000); // サーボを初期位置へ変更 240 | } 241 | 242 | if (M5.BtnB.wasSingleClicked()) { // ボタンBが1回クリックされたとき 243 | testServo(); // サーボのテストを実行します。 244 | } else if (M5.BtnB.wasDoubleClicked()) { // ボタンBをダブルクリックしたとき 245 | // Groveポートの出力を切り替えます。 246 | if (M5.Power.getExtOutput() == true) { 247 | M5.Power.setExtOutput(false); 248 | avatar.setSpeechText("ExtOutput Off"); 249 | } else { 250 | M5.Power.setExtOutput(true); 251 | avatar.setSpeechText("ExtOutput On"); 252 | } 253 | delay(2000); // 2秒待ちます。(吹き出しをしばらく表示させるため) 254 | avatar.setSpeechText(""); // 吹き出しの表示を消します。 255 | } 256 | if (M5.BtnC.pressedFor(5000)) { // ボタンCを5秒長押しした場合(この処理はあまり使わないでしょう。) 257 | M5_LOGI("Will copy this sketch to filesystem"); // ログへ出力 258 | if (saveSketchToFS( SD, SDU_APP_PATH, TFCARD_CS_PIN )) { // SDUpdater用のbinファイルをSDカードに書き込みます。 259 | M5_LOGI("Copy Successful!"); 260 | } else { 261 | M5_LOGI("Copy failed!"); 262 | } 263 | } else if (M5.BtnC.wasPressed()) { // ボタンCが押された場合 264 | //mumumuServo(); // 左右に高速で首を振ります。(サーボが壊れるのであまり使わないでください。)コメントなので実行されません。 265 | moveRandom(); // ランダムモードになります。 266 | } 267 | 268 | if ((millis() - last_mouth_millis) > mouth_wait) { // 口を開けるタイミングを待ちます。時間を図ってmouth_waitで設定した時間が経つと繰り返します。 269 | const char* l = lyrics[lyrics_idx++ % lyrics_size]; // セリフを取り出します。 270 | avatar.setSpeechText(l); // 吹き出しにセリフを表示します。 271 | avatar.setMouthOpenRatio(0.7); // アバターの口を70%開きます。(70%=0.7) 272 | delay(200); // 200ミリ秒口を開いたまま 273 | avatar.setMouthOpenRatio(0.0); // 口を閉じます。(0%=0.0) 274 | last_mouth_millis = millis(); // 実行時間を更新。(この時点からまたmouth_wait分待ちます。) 275 | if (!core_port_a) { // Core1でポートA「以外」のとき(!はnot) 276 | avatar.setBatteryStatus(M5.Power.isCharging(), M5.Power.getBatteryLevel()); // バッテリー表示を更新します。 277 | } 278 | } 279 | 280 | } 281 | --------------------------------------------------------------------------------