├── .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 |
--------------------------------------------------------------------------------