【Arduino自動化 番外編】マイコン導入にあたって気をつけるべきと思ったこと【ポケモン自動化 方法調査】

こんにちは。ますたーです。

今回は、ポケモン剣盾の自動化をするにあたってArduinoマイコンの比較と、参考Webサイトについてまとめます。
付け焼き刃な知識ですが、皆様の最初のマイコン選びの一助になると思い、素人なりに一生懸命調べたので、忘備録がてら記します(間違ってたらごめんなさい)。

長いので、忙しい人は「Arduino UNO・Leonardoそれぞれの剣盾自動化」以降を読むと、先駆者のブログ記事にリンク貼っていますので参考になると思います。

 

目次は下記の通りです。

※本ブログに初めてお越しの方は「本ブログについて」もぜひ、ご覧ください。

 

経緯(初心者が陥るマイコン選びの罠)

本当は4本目のポケモン剣盾自動化の記事…にしようかと思ったのですが、初心に立ち返ると、マイコンの購入がすごくハードルが高かったことを思い出しました。

(そりゃ、うまく行かないかもしれないものに3~4000円もかけてボード(互換機なら安いですが)を買うわけですから、うまく行かなかったらやるせない気持ちになるし、もったいない気持ちになりますよね)

 …で、Arduinoでのポケモン自動化を始めようと思った初心者の方々(私も含めて)は、まず、マイコンポケモン剣盾を自動化している、様々な紹介動画や導入記事を見て回ると思います。

そして、「どれも難しそう…」「結局どのマイコン買えばいいの…」「人によって持ってる機械(マイコン)が違う…」など、複雑な印象を受けたはずです。

また、少しプログラムやPC系を噛じった人なら「人によって呼び出している関数が違う…」「人によってArduino UNOがいいとか悪いとか言ってる…」というまばらな印象を持ったはずです。余計に混乱したかもしれません。

 それもそのはず。「マイコンポケモン剣盾を自動化する」という言葉がすごく曖昧なのです。テクニカルな話をしてもしょうがないので、ここではマイコンの種類やArduinoの種類については全く語りませんが、その種類はArduinoだけでも20種類を有に超えます

中には互換機と言って、オリジナルと同等の機能を備えた廉価版のボードもあります。互換機自体は素晴らしいものなのですが、最初のマイコン選びの観点からすると、目的が、ボード(Arduino)を選ぶことから、金額を抑えることに途中ですり替わってしまい何を買えばよいのかわからなくなってしまいます。また、互換機の中には、ボード上の印刷がない場合や、特殊な互換チップが搭載されている場合、ピンが少ない場合など、様々な差異もあるため、比較的上級者向けの商品といえます。

 

なぜArduino UNOかArduino Leonardoなのか

さて、結論を急ぎ、語弊を恐れずに言えば、ポケモン剣盾の自動化という目的に沿った最初のマイコン選び」なら、選択肢はたったの2つです

理由は明白で、日本においてSwitchの自動化についてまとめたブログ記事、日本において配布されているSwitchコントロール用のライブラリ・資料の多くは、ArduinoUNO・Leonardoのいずれかを利用しているからです(互換機を含む)。

ただし、これはあくまでもハードウェアの話です。その実装方法(プログラムの部分)は、これらの間で大きく異なりますし、さらに人によってまばらです。

 

Arduino UNOが持たないHID機能をLeonardoは持つ

ここで一つ余談をはさみます。Arduino UNOとLeonardoの機能的な違いです。
直接は関係ないので、読み飛ばしてもOKです→読み飛ばす

Arduino UNOかArduino Leonardoを使えばポケモン剣盾の自動化ができることは前述の通りですが、その実装方法は大きく異なります。

  • Arduino UNO:最もベーシックなArduino。Joy Conとして認識させる機能(HID機能)が標準で備わっていないためファームウェアも書き換えてJoy Conに擬態させる方法
  • Arduino Leonardo:UNOと違い、HID機能を持つため、ArduinoIDEを使って普通にプログラミング・書き込みを行う方法。ボード情報だけ書き換えることでSwitchの系列コントローラーに擬態させる方法

小難しく書きましたが、要するに、UNOとLeonardoではJoy Conになれるかどうかがそもそも違うのです(UNOはもともとなれない)。LeonardoはUSBのHID(ヒューマン・インターフェース・デバイス)クラスを予め持つため、有線コントローラとして認識する素地があるわけですね。

なので、素人の私からすれば、素直にArduino Leonardo使ったほうが確実なのでは?と思うわけですが、世の中は広いわけで、無いなら「ファームウェアを書き換えればいいじゃない!」となるわけです。マイコンを初めて購入する人には不思議な気がするかもしれませんが、やはり利用者の絶対数が多いArduino UNOならではの発想だと思います。

 

Arduino UNO・Leonardoそれぞれの剣盾自動化

まず、本ブログの導入記事でも扱っている通り、筆者としてはArduino Leonardo」+「SwitchControlLibrary」の組み合わせをおすすめしています。

ただし、先駆者のWebサイトは、駆け出しの当ブログと違い、内容も濃く、しっかりと記載されているため、これらを読んでから納得して選ぶのが妥当かと思います。

便宜上、Arduino UNO・Arduino Leonardoで大きく2つに分けて下記に記載します。
それぞれ、偉大な先駆者様のWebサイトへのリンクを載せますので、是非とも参考にしてください。

◆方法1:Arduino UNOを使う場合

Arduino UNOでは、原則としてWindowsPowershellや、Macのターミナルを使ってファームウェアを書き換えてJoy Conとして認識させます。

Arduinoの回路をショートさせたり、ターミナル(ハッカーとかがよくコマンドをカタカタ入れているアレ)を使う必要があるため、特にCUI初心者にはややハードルが高いのでは?と思います。逆に、少しでもターミナルを触れる人なら簡単に感じられると思います。また、海外を含め、プログラムの投稿数も多いらしいです。また、もとよりArduinoを触ったことがある方はArduinoといえばUNOという人も少なくなく、利用人口が多いというのも特徴です。

 

Arduino UNOの参考Webサイト】

sinonis826.hatenablog.com
blogenist.jp

 

rhapsx.blog.fc2.com

 

◆方法2:Arduino Leonardoを使う場合

前述の通り、Arduino LeonardoはHIDの機能を持っています。これがArduino Leonardoを使う最大の理由と言っても過言じゃないです。要するに、Arduino UNOと比較すると、プログラミングやマイコンに対する知識は少なくて済みます。
ただし、ライブラリが複数有志によって提供されており、これが初心者を混乱させる原因の一つでもあります。

1.ライブラリ「SwitchControlLibrary」を使った方法【本ブログおすすめ】

本ブログで紹介しているライブラリを使った方法です。私が個人的にArduinoの自動化を始めた今年の2月時点で勢いがあると思ったのでこれを採用しました。

ライセンスもMITライセンスとして提供されており、使える関数もそれほど難しく無いので、C言語が分かる人なら無理なくプログラミング・開発も始められます。

(ライブラリ:https://github.com/celclow/SwitchControlLibrary

【参考Webサイト】

qiita.com

 

sinonis826.hatenablog.com

 

2.ライブラリ「NintendoSwitchControll」を使った方法

もう一つ、Switchをコントロールできるライブラリの紹介です。

こちらは、interimadd氏、takeutchi氏、kurimoun氏の3名が合同で提供しているライブラリです。サンプルのソースや配布サイトも充実しており、こちらもおすすめです。

(ライブラリ:https://github.com/interimadd/NintendoSwitchControll

 

【参考Webサイト】

pokemonit.com

 

まとめ

むりやりですが、上述の内容をまとめたのが下図になります。

Arduino UNO・Leonardoで比較すると一長一短の関係になることがわかります。

f:id:tangential_star:20201108205357p:plain

Arduinoポケモン剣盾を自動化」の選択肢。

筆者としては、Arduino UNOには手続きが煩雑になる部分があるため、ポケモン剣盾の自動化だけを目的にするのであればArduino Leonardoを使うのが妥当だと考えます。

ただし、Arduinoを使ったプログラミングを楽しみたい、組み込み系の醍醐味を味わいたい、という方や、今までのバックボーンによっては、やはりコミュニティが活性になるArduino UNOを使うのも選択肢になるのかな、といったところでした。

 

ではではc⌒っ.ω.)っ

 

(宣伝)Arduino Leonardo+SwitchControlLibraryの導入記事:

【Arduino自動化01】Arduino開発環境の導入

 


【2020/11/11追記】続きを書きました。
Arduino Leonardoで使える自動化ソースコードのリンク集としても使えます。

【Arduino自動化 番外編2】NintendoSwitchControllライブラリの導入と、自動化できる作業の一覧【ポケモン剣盾自動化】

【2021/2/6追記】本ブログでおすすめしているArduino Leonardoとその他機器類について纏めました。筆者が使っている周辺機器の購入リンクも載せています。

【Arduino自動化 番外編3】筆者の使用機材一覧【紹介記事】

 

【Arduino自動化03】ワット稼ぎ・自動回収

ますたーです。こんにちは。

3つ目の記事では、n番煎じ感は否めませんが、日付バグによるワット自動回収Arduino Leonardoで自動化していきます。DLC含め大量のワットを消費する機会が増えたので、重宝すると思います。

なお、Arduino Leonardo自動化の導入・機材構成については前々記事を参考にしてください。

導入記事:【Arduino自動化01】Arduino開発環境の導入 

※本ブログに初めてお越しの方は「本ブログについて」もぜひ、ご覧ください。

 

概要

本記事では、日付バグの併用による巣穴の2,000Wの無限回収を実装します。
2020/12/5追記:NintendoSwitch Ver.11.0アップデート対応済です。
2021/9/20追記:NintendoSwitch Ver.13.0アップデート対応済です。
2022/10/23追記:NintendoSwitch Ver.15.0アップデート対応済です。

f:id:tangential_star:20201108131008g:plain

Arduino Leonardoを挿すだけで無限にワット回収ができる。

 

今回の目次です。かなりシンプルです。

 

作ったきっかけ

DLC第1弾「鎧の孤島」でのミツバへのワット貢ぎイベントや、前の記事でも取り上げた、DLC第2弾「冠の雪原」のワットショップの高額目玉商品など、シナリオに直結しない部分で使うワット数が増えたため、気軽に使えるワット回収スクリプトが欲しいと思ったので作りました。

また、先駆者の作成ソースコードは、プログラミング負荷軽減のため、仕様が制限されていて「1月1日に日付変更してから使うこと」「31日ある月で使うこと」「年を更新するタイプ」など、私の「気軽に使いたい」ニーズに応えるものではなかったので作りました。

 ※気軽に使いたい=巣穴に「ねがいのかたまり」入れてArduino挿すだけ!

 

使い方

至ってシンプルで、巣穴に「ねがいのかたまり」を投げ入れ、柱を立てたらそのままAを押して「みんなで挑戦」を押す手前の状態でArduino LeonardoをSwitchに挿すだけで使えます。

なお、挿して3~5秒ほど、何度かHomeボタンが押されるような挙動は仕様です。

挿してから数秒後、5秒ほどなんの操作もしていない時間がありますが、このタイミングでHome画面(Switchでゲームを選ぶ画面)になっていればOKです。もし、なっていなければ手動で1度Homeボタンを押しておいてください。

事前準備

正しく動作するための条件は下記の通りです。

  •  ポケモン剣盾側の設定
    • 巣穴に手動で柱を立てておく(近くに草むらなどが無い場所が良い)
  • NintendoSwitch側の設定
    • Switch設定「時刻と時刻」の「インターネットで時間をあわせる」をOFF
    • インターネットには接続しない

 

書いたプログラム

処理フロー

  1. みんなで挑戦を押す
  2. Homeボタンを押して「設定」へ
  3. 日付を1日進める
  4. Homeでゲームに復帰し、募集終了
  5. ワットを回収し、1へ戻る(ループ)

ソースコード

2020/12/5追記:NintendoSwitch Ver.11.0アップデート対応済(変更点はこちら

2021/9/20追記:NintendoSwitch Ver.13.0アップデート対応済(詳細はこちら

2022/10/23追記:NintendoSwitch Ver.15.0アップデート対応済
※Switch Liteをご利用の方は「#define SWITCH_VER (13)」を「#define SWITCH_VER (12)」に書き換えてご利用ください。

/* ★NintendoSwitchのファームウェアVer11に対応版(2020/12/1)★
 * ★NintendoSwitchのファームウェアVer13に対応版(2021/9/20)★
 * ★NintendoSwitchのファームウェアVer15に対応版(2022/10/23)★
 * ★自動ワット稼ぎ★
巣穴に「ねがいのかたまり」を投げ入れてA。
「みんなで挑戦」の手前でArduinoをSwitchに挿すだけ。
*/

#include <SwitchControlLibrary.h>

#define HOLDTIME (95)
#define INTERVAL (105)

#define SWITCH_VER (15)
// 2022/10/21、SwitchのVer15アップデートを受けて修正
// 2021/9/20、SwitchのVer13アップデートに伴う追記
// Switchのバージョンを整数で入力(例:12.2.1⇒12, 13.0.0⇒13, 15.0.0→15)

void PushHome(int delay_time_ms);
void PushA(int delay_time_ms);
void PushB(int delay_time_ms);
void move_for(char* Direction); // ex: "right" "left" "up" "down"
void move_for(char* Direction, int delay_time_ms);
void move_for(char* Direction, int hold_time_ms, int delay_time_ms);

void setup() {
  
  PushHome(1000);
  PushHome(1000);
  PushHome(1000);
  PushHome(1000);
  PushHome(1000);
  PushHome(5000); // 5秒待つ
  PushHome(1000);

  delay(100);
}

void loop() {

  // 開始 みんなで挑戦の直前から。
  PushA(4000); // 通信待機中・・・
  
  // Homeボタンを押して設定の画面へ移動
  PushHome(1000);

  // Home画面で「設定」を選ぶ
  move_for("down");
  move_for("right");
  move_for("right");
  move_for("right");
  move_for("right");
  move_for("right");
  PushA(1500);

  // 設定画面で「日付と時刻」を開く
  move_for("down", 1500, (int)INTERVAL/4); // 「↓」長押し
  move_for("right");

#if (SWITCH_VER >= 15)
  // Switchのver15アプデでBluetoothオーディオの設定が変わった?ので、微修正。
  // ※本体のバッテリー残量(%)にずれるようになったので。
  move_for("down", (int)750, (int)INTERVAL); 
#elif (SWITCH_VER >= 13)
  // Switchのアプデで「ドックの更新」項目が追加されたので
  // 日付変更をする場合には「↓」キー長押しが必要に。
  move_for("down", (int)780, (int)INTERVAL/2); 
#else
  // ver12まで(13アプデ前)は、1ページに収まるのでそのままでOK
  for(int i=0; i<4; i++){
    move_for("down", (int)HOLDTIME/2, (int)INTERVAL/2);
  }
#endif
  PushA(500);

  // 時間設定(現在の日付と時刻を選ぶ)
  move_for("down");
  move_for("down");
  PushA(500);

  // 時刻設定(日付の部分のみ回していく
  // 時間の変更
  move_for("right");
  move_for("right");
  move_for("up");
  PushA(INTERVAL);
  PushA(INTERVAL);
  PushA(INTERVAL);
  PushA(INTERVAL);
  PushHome(2000);
  PushA(1000);
  // ↑ここまでで設定画面おわり。

  // 募集終了処理
  PushB(500);  // 「募集終了」を選択
  PushA(1000); // 「はい」
  PushA(4500); // 「はい」

  // ★フィールド画面に戻ってくる(watt回収)
  // There's energy pouring out from the den! [Enter]
  PushA(500);  // 1回目は「A」
  // You gained 2,000W! [Quit]
  PushB(2500);  // 2回目は「B」(日付が1日に戻った時との共通処理のため遅めに)
  // [Enter]
  PushA(1500);  // 3回目は「A」(募集画面に入る)

}

void PushHome(int delay_time_ms){
  SwitchControlLibrary().PressButtonHome();
  delay(210);
  SwitchControlLibrary().ReleaseButtonHome();
  delay(delay_time_ms);
  return;
}

void PushA(int delay_time_ms){
  SwitchControlLibrary().PressButtonA();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonA();
  delay(delay_time_ms);
  return;
}
void PushB(int delay_time_ms){
  SwitchControlLibrary().PressButtonB();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonB();
  delay(delay_time_ms);
  return;
}

void move_for(char* Direction){
  // ex: "right" "left" "up" "down"
  
  switch(Direction[0]){
    case 'r':
    case 'R':
    SwitchControlLibrary().MoveHat(2); // right
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    case 'l':
    case 'L':
    SwitchControlLibrary().MoveHat(6); // left
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    case 'u':
    case 'U':
    SwitchControlLibrary().MoveHat(0); // up
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    case 'd':  
    case 'D':
    SwitchControlLibrary().MoveHat(4); // down
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    default:
    break;  
  }
  
}

void move_for(char* Direction, int delay_time){
  // ex: "right" "left" "up" "down"
  
  switch(Direction[0]){
    case 'r':
    case 'R':
    SwitchControlLibrary().MoveHat(2); // right
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    case 'l':
    case 'L':
    SwitchControlLibrary().MoveHat(6); // left
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    case 'u':
    case 'U':
    SwitchControlLibrary().MoveHat(0); // up
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    case 'd':  
    case 'D':
    SwitchControlLibrary().MoveHat(4); // down
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    default:
    break;  
  }
  
}

void move_for(char* Direction, int hold_time_ms, int delay_time_ms){
  // ex: "right" "left" "up" "down"
  
  switch(Direction[0]){
    case 'r':
    case 'R':
    SwitchControlLibrary().MoveHat(2); // right
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    case 'l':
    case 'L':
    SwitchControlLibrary().MoveHat(6); // left
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    case 'u':
    case 'U':
    SwitchControlLibrary().MoveHat(0); // up
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    case 'd':  
    case 'D':
    SwitchControlLibrary().MoveHat(4); // down
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    default:
    break;  
  }

}

 

f:id:tangential_star:20201108131008g:plain

動作例(再掲)


あとがき

今回は自動でワット回収ができるプログラムを紹介しました。

実は、このプログラムのみは、日本語版・英語版・中国語版(繁体字)で動作を確認済です。ソースコードのコメント行でゲーム中のセリフを英語で書いているのは、英語版の文字送り速度に合わせてDelay()の数値を調整したからなのです。
余談ですが、文字送り速度はゲーム中の設定から「早い 普通 遅い」と選べますが、同じ「早い」でも英語の「Fast」とは文字の送られる時間が違います(日本語や中国語のほうが短いです)。

理由は明白で、我々漢字圏の人は2バイト文字なので単純計算で英語版の文字送りの2倍速になるんですね(流石に2倍はないかもですが)。

日本語版でしかデバッグしていないArduinoでの自動化プログラムを英語版で使うと「あれ、なんで動作がズレるんだ?」となりますが、意外な落とし穴が文字送り速度に隠れているんですね(体験談)。

ちなみに、本ブログでは原則として日本語版でのみ動作確認したものしか載せません。ただ、もしかしたら、プログラム中の定数「INTERVAL」や「HOLDTIME」を増やすとうまく動くかもしれません。

 

余談が長くなってしまいました。

ではではc⌒っ.ω.)っ

 

前の記事:

【Arduino自動化02】雪中渓谷のワットショップの目玉商品を全自動回収【カンムリ雪原】

次の記事:

【Arduino自動化04】パッチルドン自動受け取り(中国語・英語対応)

【Arduino自動化02】雪中渓谷のワットショップの目玉商品を全自動回収【カンムリ雪原】

ますたーです。こんにちは。

2つ目の記事は、剣盾DLC第2段カンムリ雪原で新たに増えたワットショップ、雪中渓谷の「目玉商品」交換に主眼をおいたArduino Leonardo自動化の記事です。

ソースコードの紹介と、使い方を載せていきます。

なお、Arduino Leonardo自動化の導入・機材構成については前記事を参考にしてください。

前記事:【Arduino自動化01】Arduino開発環境の導入 

※本ブログに初めてお越しの方は「本ブログについて」もぜひ、ご覧ください。

 

概要

本記事では、日付バグの併用による目玉商品の無限回収を実装します。
2020/12/5追記:NintendoSwitch Ver.11.0アップデート対応済です。
2021/9/20追記:NintendoSwitch Ver.13.0アップデート対応済です。
2022/10/23追記:NintendoSwitch Ver.15.0アップデート対応済です。

f:id:tangential_star:20201108025830j:plain
f:id:tangential_star:20201108025408g:plain
雪中渓谷のワットショップで「目玉商品」を自動購入し、日付更新

今回のもくじです。

 

作ったきっかけ

色々なWebサイトを見て調べた限りでは、DLC対応のArduino自動化プログラムで、この「目玉商品の自動回収」は見当たらなかったので作りました。ぼんぐりの回収とレアアイテムの回収が同時にできてハッピーです。

ちなみに、私はまだ見たことありませんが、ここのワットショップでは「ドリームボール」もラインナップにあるそうです。ほしい…

f:id:tangential_star:20201108040932j:plain
f:id:tangential_star:20201108041013p:plain
無限回収していると、まれに「ぼんぐり10個セット」や「サンのみ」、
「キョダイパウダー」など魅力的なラインナップに巡り会える。

 

使い方

ソースコードは本ページ最下部(コチラ)にございます。「使い方はいいから早くソースコードを寄越せ!」という方は本項を読み飛ばしてください。

一応、日付更新・ワット回収部分・話しかけ部分に工夫しており、任意の日付から始めてもうまく稼働すると思います(つまり予め1/1に戻したり31日まである月に変更したりしなくてOK)。

事前準備

正しく動作するための条件は下記の通りです。

  • ポケモン剣盾側の設定
    • しっかりと充分なワットをあらかじめ貯めておく
    • 一度はワットショップのおじさんに話しかけておく
      (初回の専用ルート云々のくだりを回収しておく)
    • ワットショップおじさんの隣にある巣穴に手動で柱を立てておく
    • 自転車からは降りておく
    • Xでメニューを開いた際のカーソルを「タウンマップ」にあわせておく
  • NintendoSwitch側の設定
    • Switch設定「時刻と時刻」の「インターネットで時間をあわせる」をOFF
    • インターネットには接続しない

ポケモン剣盾での操作

基本的に難しい操作はないのですが、雪中渓谷に「空飛ぶタクシー」で移動し、ワットショップの隣(奥)にある巣穴に「ねがいのかたまり」を投げ入れてください。

あとは、「自転車に乗っていないこと」「Xボタンでメニューを開いたときに『タウンマップ』がカーソルされていること」さえクリアしていれば多分動きます。

f:id:tangential_star:20201108103542j:plain
f:id:tangential_star:20201108025830j:plain
Xボタンでメニューを開いた際に、「タウンマップ」にカーソルがあっていればOK
f:id:tangential_star:20201108103408j:plain
f:id:tangential_star:20201108103538j:plain
自転車から降りて、ワットショップの隣の巣穴に「ねがいのかたまり」を投げ入れる
f:id:tangential_star:20201108103927p:plain
f:id:tangential_star:20201108103824p:plain
ワットを回収し、「みんなで挑戦」にカーソルをあてたら準備OK

レイドバトルの「みんなで 挑戦!」を押す前の状態で、スケッチを書き込んだArduino LeonardoをSwitchに差し込むと、自動化が始まります。

挿して3~5秒ほど、何度かHomeボタンが押されるような挙動をするかもしれませんが、これは仕様です(SwitchがArduinoをコントローラーとして認識するまでにかかる時間を調整しています)。

挿してから数秒後、5秒ほどなんの操作もしていない時間がありますが、このタイミングでHome画面(Switchでゲームを選ぶ画面)になっていればOKです。もし、なっていなければ手動で1度Homeボタンを押しておいてください。

書いたプログラム

処理フロー

setup()関数内の PushHome()連打は、挿してから認識されるまでの時間合わせです。

処理フローとしては、下記になります。

  1. 「みんなで挑戦」を押して、日付を進める
  2. 雪中渓谷に空を飛ぶ
  3. ワットショップに向かい、目玉商品を購入
  4. 雪中渓谷に空を飛ぶ
  5. 巣穴に向かい、ワット回収。
  6. 1に戻る(ループ)

空を飛ぶのは、天候や出現ポケモンによる負荷の違い?によって移動する向きが微妙にずれたり、オフセット誤差が溜まったりするのでこれらを是正するために入れています。効率ではなく安定性重視です。筆者環境では、このソースコードで3日間放置できました。

ワット回収ならびにワットショップ購入部分に工夫してあり、日付更新は、任意の月・日付から始められます。「1月1日から始めないと動かない」「31日ある月じゃないと動かない」みたいな煩雑な前準備は不要なはずです。

ソースコード

2020/12/5追記:NintendoSwitch Ver.11.0アップデート対応済(変更点はこちら

2021/9/20追記:NintendoSwitch Ver.13.0アップデート対応済(詳細はこちら

2022/10/23追記:NintendoSwitch Ver.15.0アップデート対応済
※Switch Liteをご利用の方は「#define SWITCH_VER (13)」を「#define SWITCH_VER (12)」に書き換えてご利用ください。

/* ★NintendoSwitchのファームウェアVer11に対応版(2020/12/1)★
 * ★NintendoSwitchのファームウェアVer13に対応版(2021/9/20)★
 * ★NintendoSwitchのファームウェアVer15に対応版(2022/10/23)★
 * 
★カンムリの雪原 目玉商品自動回収
※十分にWattをためておくこと!

参考URL: https://qiita.com/sobassy/items/cb707e50f2f27a851886
インストールしたライブラリ:https://github.com/celclow/SwitchControlLibrary
インストールしたライブラリ2:https://okwave.jp/qa/q9702388.html
変更したBoard.txtの内容:https://qiita.com/Eitok/items/ab29e0e6404dfc709823
  ●変更1
    #leonardo.vid.1=0x2341
    #leonardo.pid.1=0x8036
    leonardo.vid.1=0x0f0d
    leonardo.pid.1=0x0092
  ●変更2
    #leonardo.build.vid=0x2341
    #leonardo.build.pid=0x8036
    leonardo.build.vid=0x0f0d
    leonardo.build.pid=0x0092

★使い方
 - - - -
Step1: Nintendo Switchの設定(日付)の「インターネットで自動設定」をOFFに。【重要】
-Step2: おっさんの右上のDennにねがいのかたまりを投げて、手動で作った柱を準備【重要】
-Step2: Xでメニューを開いたときにタウンマップにカーソルがあっていること【重要】
-Step2: じてんしゃは降りておくこと【重要】
Step3: オンライン通信を切断しておく
Step4: 柱のWattを回収し、「みんなで挑戦」にカーソルをあわせて待機。
 - - - - -
Step5: ArduinoをSwitchに接続。
Step6: 何回かHomeボタン繰り返し押されるような挙動をする。
Step7: 3秒くらいHomeがおされていないな?というふうになったときにHome画面ならOK
 ※違うなら急いで手動でHomeボタンを押す!
Step8: Homeが1回押されて自動処理開始

*/

#include <SwitchControlLibrary.h>

#define HOLDTIME (95)
#define INTERVAL (105)

#define SWITCH_VER (15)
// 2021/9/20、SwitchのVer13アップデートに伴う追記
// Switchのバージョンを整数で入力(例:12.2.1⇒12, 13.0.0⇒13, 15.0.0→15)

void PushHome(int delay_time_ms);
void PushA(int delay_time_ms);
void PushB(int delay_time_ms);
void PushX(int delay_time_ms);
void PushL(int delay_time_ms);
void move_for(char* Direction); // ex: "right" "left" "up" "down"
void move_for(char* Direction, int delay_time_ms);
void move_for(char* Direction, int hold_time_ms, int delay_time_ms);

void setup() {

  PushHome(1000);
  PushHome(1000);
  PushHome(1000);
  PushHome(1000);
  PushHome(1000);
  PushHome(3000); // 3秒待つ
  PushHome(1000);

  delay(100);
}

void loop() {

  // 開始 みんなで挑戦の直前から。
  PushA(4000); // 通信待機中・・・
  
  // Homeボタンを押して設定の画面へ移動
  PushHome(1000);

  // Home画面で「設定」を選ぶ
  move_for("down");
  move_for("right");
  move_for("right");
  move_for("right");
  move_for("right");
  move_for("right");
  PushA(1500);

  // 設定画面で「日付と時刻」を開く
  move_for("down", 1500, (int)INTERVAL/4); // 「↓」長押し
  move_for("right");

#if (SWITCH_VER >= 15)
  // Switchのver15アプデでBluetoothオーディオの設定が変わった?ので、微修正。
  // ※本体のバッテリー残量(%)にずれるようになったので。
  move_for("down", (int)750, (int)INTERVAL); 
#elif (SWITCH_VER >= 13)
  // Switchのアプデで「ドックの更新」項目が追加されたので
  // 日付変更をする場合には「↓」キー長押しが必要に。
  move_for("down", (int)780, (int)INTERVAL/2); 
#else
  // ver12まで(13アプデ前)は、1ページに収まるのでそのままでOK
  for(int i=0; i<4; i++){
    move_for("down", (int)HOLDTIME/2, (int)INTERVAL/2);
  }
#endif
  PushA(500);

  // 時間設定(現在の日付と時刻を選ぶ)
  move_for("down");
  move_for("down");
  PushA(500);

  // 時刻設定(日付の部分のみ回していく
  // 時間の変更
  move_for("right");
  move_for("right");
  move_for("up");
  PushA(INTERVAL);
  PushA(INTERVAL);
  PushA(INTERVAL);
  PushA(INTERVAL);
  PushHome(2000);
  PushA(1000);
  // ↑ここまでで設定画面おわり。

  // 募集終了処理
  PushB(500);  // 「募集終了」を選択
  PushA(1000); // 「はい」
  PushA(4500); // 「はい」


  // ★フィールド画面に戻ってきて空を飛んでおっさんに話しかける
  PushX(700);  // Xでメニューを開く
  PushA(2700); // Aでタウンマップを開く

  // PushX(150);
  SwitchControlLibrary().MoveLeftStick((128+70), (128+100)); // 右下(下強め)にカーソル合わせ
  delay(170);
  SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す
  delay(100);

  // 空を飛ぶ(A)
  PushA(650);
  PushA(1700);// 天候によって画面切り替わりの時間がかわるっぽい。1700だと足りない場合あり?要検証
  // おっさんに向かって走る
  SwitchControlLibrary().MoveLeftStick((128+100), (128-115)); // 右上(ちょい上強め)を向く
  delay(230);
  SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す
  delay(100);
  PushL(400);
  SwitchControlLibrary().MoveLeftStick((128), (128-128)); // 上にあるく
  delay(1800);
  SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す
  
  PushA(650); // いらっしゃいませ
  PushA(650); // 何をご覧になりますか?
  move_for("d");
  PushA(650); // 今日の目玉商品は… or 目玉商品は売り切れです
  PushA(650); // ●●! 早いもの勝ち お値段 たったの ●●W  or 他に見たいものはありますか?
  PushA(650); // 買う?   or 普通の商品
  PushA(2600); // はい(購入処理入るので遅い)→お目が高い!お買い上げありがとうございます
  PushB(2600); // ●●は ●● を 手に入れた!(SEなる) ★ここ以降はBにして共通処理
  PushB(750);
  PushB(550);
  PushB(550);
  PushB(550);
  PushB(550);
  PushB(550); // 余計なB(1日にループした際の共通処理&2個セットのときなど2行に分かれたときの共通処理&きのみ購入時の1行ズレ吸収)

 
  // ★フィールド画面に戻ってきて空を飛んでDennに歩く
  PushX(700);  // Xでメニューを開く
  PushA(2700); // Aでタウンマップを開く
  // PushX(150);
  SwitchControlLibrary().MoveLeftStick((128+70), (128+100)); // 右下(下強め)にカーソル合わせ
  delay(170);
  SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す
  delay(100);

  // 空を飛ぶ(A)
  PushA(650);
  PushA(1700);
  
  // Dennに向かって走る
  SwitchControlLibrary().MoveLeftStick((128+28), (128-115)); // 右上(上強め)を向く
  delay(230);
  SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す
  delay(100);
  PushL(400);
  SwitchControlLibrary().MoveLeftStick((128), (128-128)); // 上にあるく
  delay(4300);
  SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す

  // ★Denに話しかける(Watt回収)
  // There's energy pouring out from the den! [Enter]
  PushA(500);  // 1回目は「A」
  // You gained 2,000W! [Quit]
  PushB(2500);  // 2回目は「B」(日付が1日に戻った時との共通処理のため遅めに)
  // [Enter]
  PushA(1500);  // 3回目は「A」(募集画面に入る)

}

void PushHome(int delay_time_ms){
  SwitchControlLibrary().PressButtonHome();
  delay(210);
  SwitchControlLibrary().ReleaseButtonHome();
  delay(delay_time_ms);
  return;
}

void PushA(int delay_time_ms){
  SwitchControlLibrary().PressButtonA();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonA();
  delay(delay_time_ms);
  return;
}
void PushB(int delay_time_ms){
  SwitchControlLibrary().PressButtonB();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonB();
  delay(delay_time_ms);
  return;
}
void PushX(int delay_time_ms){
  SwitchControlLibrary().PressButtonX();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonX();
  delay(delay_time_ms);
  return;
}
void PushL(int delay_time_ms){
  SwitchControlLibrary().PressButtonL();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonL();
  delay(delay_time_ms);
  return;
}
void move_for(char* Direction){
  // ex: "right" "left" "up" "down"
  
  switch(Direction[0]){
    case 'r':
    case 'R':
    SwitchControlLibrary().MoveHat(2); // right
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    case 'l':
    case 'L':
    SwitchControlLibrary().MoveHat(6); // left
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    case 'u':
    case 'U':
    SwitchControlLibrary().MoveHat(0); // up
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    case 'd':  
    case 'D':
    SwitchControlLibrary().MoveHat(4); // down
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    default:
    break;  
  }
  
}

void move_for(char* Direction, int delay_time){
  // ex: "right" "left" "up" "down"
  
  switch(Direction[0]){
    case 'r':
    case 'R':
    SwitchControlLibrary().MoveHat(2); // right
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    case 'l':
    case 'L':
    SwitchControlLibrary().MoveHat(6); // left
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    case 'u':
    case 'U':
    SwitchControlLibrary().MoveHat(0); // up
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    case 'd':  
    case 'D':
    SwitchControlLibrary().MoveHat(4); // down
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    default:
    break;  
  }
  
}

void move_for(char* Direction, int hold_time_ms, int delay_time_ms){
  // ex: "right" "left" "up" "down"
  
  switch(Direction[0]){
    case 'r':
    case 'R':
    SwitchControlLibrary().MoveHat(2); // right
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    case 'l':
    case 'L':
    SwitchControlLibrary().MoveHat(6); // left
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    case 'u':
    case 'U':
    SwitchControlLibrary().MoveHat(0); // up
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    case 'd':  
    case 'D':
    SwitchControlLibrary().MoveHat(4); // down
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    default:
    break;  
  }

}

 

/* ★NintendoSwitchのファームウェアVer11に対応版(2020/12/1)★
 * ★NintendoSwitchのファームウェアVer13に対応版(2021/9/20)★
 * ★カンムリの雪原 目玉商品自動回収★

※十分にWattをためておくこと!
★使い方 - - - - Step1: Nintendo Switchの設定(日付)の「インターネットで自動設定」をOFFに。【重要】 -Step2: おっさんの右上のDennにねがいのかたまりを投げて、手動で作った柱を準備【重要】 -Step2: Xでメニューを開いたときにタウンマップにカーソルがあっていること【重要】 -Step2: じてんしゃは降りておくこと【重要】 Step3: オンライン通信を切断しておく Step4: 柱のWattを回収し、「みんなで挑戦」にカーソルをあわせて待機。 - - - - - Step5: ArduinoをSwitchに接続。 Step6: 何回かHomeボタン繰り返し押されるような挙動をする。 Step7: 3秒くらいHomeがおされていないな?というふうになったときにHome画面ならOK  ※違うなら急いで手動でHomeボタンを押す! Step8: Homeが1回押されて自動処理開始 */ #include <SwitchControlLibrary.h> #define HOLDTIME (95) #define INTERVAL (105) #define SWITCH_VER (13)
// 2021/9/20、SwitchのVer13アップデートに伴う追記
// Switchのバージョンを整数で入力(例:12.2.1⇒12,13.0.0⇒13)
void PushHome(int delay_time_ms); void PushA(int delay_time_ms); void PushB(int delay_time_ms); void PushX(int delay_time_ms); void PushL(int delay_time_ms); void move_for(char* Direction); // ex: "right" "left" "up" "down" void move_for(char* Direction, int delay_time_ms); void move_for(char* Direction, int hold_time_ms, int delay_time_ms); void setup() { PushHome(1000); PushHome(1000); PushHome(1000); PushHome(1000); PushHome(1000); PushHome(3000); // 3秒待つ PushHome(1000); delay(100); } void loop() { // 開始 みんなで挑戦の直前から。 PushA(4000); // 通信待機中・・・ // Homeボタンを押して設定の画面へ移動 PushHome(1000); // Home画面で「設定」を選ぶ move_for("down"); move_for("right"); move_for("right"); move_for("right"); move_for("right"); move_for("right"); PushA(1500); // 設定画面で「日付と時刻」を開く move_for("down", 1500, (int)INTERVAL/4); // 「↓」長押し move_for("right"); #if (SWITCH_VER >= 13) // Switchのアプデで「ドックの更新」項目が追加されたので // 日付変更をする場合には「↓」キー長押しが必要に。 move_for("down", (int)780, (int)INTERVAL/2); #else // ver12まで(13アプデ前)は、1ページに収まるのでそのままでOK for(int i=0; i<4; i++){ move_for("down", (int)HOLDTIME/2, (int)INTERVAL/2); } #endif PushA(500); // 時間設定(現在の日付と時刻を選ぶ) move_for("down"); move_for("down"); PushA(500); // 時刻設定(日付の部分のみ回していく // 時間の変更 move_for("right"); move_for("right"); move_for("up"); PushA(INTERVAL); PushA(INTERVAL); PushA(INTERVAL); PushA(INTERVAL); PushHome(2000); PushA(1000); // ↑ここまでで設定画面おわり。 // 募集終了処理 PushB(500); // 「募集終了」を選択 PushA(1000); // 「はい」 PushA(4500); // 「はい」 // ★フィールド画面に戻ってきて空を飛んでおっさんに話しかける PushX(700); // Xでメニューを開く PushA(2700); // Aでタウンマップを開く // PushX(150); SwitchControlLibrary().MoveLeftStick((128+70), (128+100)); // 右下(下強め)にカーソル合わせ delay(170); SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す delay(100); // 空を飛ぶ(A) PushA(650); PushA(1700);// 天候によって画面切り替わりの時間がかわるっぽい。1700だと足りない場合あり?要検証 // おっさんに向かって走る SwitchControlLibrary().MoveLeftStick((128+100), (128-115)); // 右上(ちょい上強め)を向く delay(230); SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す delay(100); PushL(400); SwitchControlLibrary().MoveLeftStick((128), (128-128)); // 上にあるく delay(1800); SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す PushA(650); // いらっしゃいませ PushA(650); // 何をご覧になりますか? move_for("d"); PushA(650); // 今日の目玉商品は… or 目玉商品は売り切れです PushA(650); // ●●! 早いもの勝ち お値段 たったの ●●W  or 他に見たいものはありますか? PushA(650); // 買う?  or 普通の商品 PushA(2600); // はい(購入処理入るので遅い)→お目が高い!お買い上げありがとうございます PushB(2600); // ●●は ●● を 手に入れた!(SEなる) ★ここ以降はBにして共通処理 PushB(750); PushB(550); PushB(550); PushB(550); PushB(550); PushB(550); // 余計なB(1日にループした際の共通処理&2個セットのときなど2行に分かれたときの共通処理&きのみ購入時の1行ズレ吸収) // ★フィールド画面に戻ってきて空を飛んでDennに歩く PushX(700); // Xでメニューを開く PushA(2700); // Aでタウンマップを開く // PushX(150); SwitchControlLibrary().MoveLeftStick((128+70), (128+100)); // 右下(下強め)にカーソル合わせ delay(170); SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す delay(100); // 空を飛ぶ(A) PushA(650); PushA(1700); // Dennに向かって走る SwitchControlLibrary().MoveLeftStick((128+28), (128-115)); // 右上(上強め)を向く delay(230); SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す delay(100); PushL(400); SwitchControlLibrary().MoveLeftStick((128), (128-128)); // 上にあるく delay(4300); SwitchControlLibrary().MoveLeftStick((128), (128)); // 真ん中に戻す // ★Denに話しかける(Watt回収) // There's energy pouring out from the den! [Enter] PushA(500); // 1回目は「A」 // You gained 2,000W! [Quit] PushB(2500); // 2回目は「B」(日付が1日に戻った時との共通処理のため遅めに) // [Enter] PushA(1500); // 3回目は「A」(募集画面に入る) } void PushHome(int delay_time_ms){ SwitchControlLibrary().PressButtonHome(); delay(210); SwitchControlLibrary().ReleaseButtonHome(); delay(delay_time_ms); return; } void PushA(int delay_time_ms){ SwitchControlLibrary().PressButtonA(); delay(HOLDTIME); SwitchControlLibrary().ReleaseButtonA(); delay(delay_time_ms); return; } void PushB(int delay_time_ms){ SwitchControlLibrary().PressButtonB(); delay(HOLDTIME); SwitchControlLibrary().ReleaseButtonB(); delay(delay_time_ms); return; } void PushX(int delay_time_ms){ SwitchControlLibrary().PressButtonX(); delay(HOLDTIME); SwitchControlLibrary().ReleaseButtonX(); delay(delay_time_ms); return; } void PushL(int delay_time_ms){ SwitchControlLibrary().PressButtonL(); delay(HOLDTIME); SwitchControlLibrary().ReleaseButtonL(); delay(delay_time_ms); return; } void move_for(char* Direction){ // ex: "right" "left" "up" "down" switch(Direction[0]){ case 'r': case 'R': SwitchControlLibrary().MoveHat(2); // right delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(INTERVAL); break; case 'l': case 'L': SwitchControlLibrary().MoveHat(6); // left delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(INTERVAL); break; case 'u': case 'U': SwitchControlLibrary().MoveHat(0); // up delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(INTERVAL); break; case 'd': case 'D': SwitchControlLibrary().MoveHat(4); // down delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(INTERVAL); break; default: break; } } void move_for(char* Direction, int delay_time){ // ex: "right" "left" "up" "down" switch(Direction[0]){ case 'r': case 'R': SwitchControlLibrary().MoveHat(2); // right delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(delay_time); break; case 'l': case 'L': SwitchControlLibrary().MoveHat(6); // left delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(delay_time); break; case 'u': case 'U': SwitchControlLibrary().MoveHat(0); // up delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(delay_time); break; case 'd': case 'D': SwitchControlLibrary().MoveHat(4); // down delay(HOLDTIME); SwitchControlLibrary().MoveHat(8); // center delay(delay_time); break; default: break; } } void move_for(char* Direction, int hold_time_ms, int delay_time_ms){ // ex: "right" "left" "up" "down" switch(Direction[0]){ case 'r': case 'R': SwitchControlLibrary().MoveHat(2); // right delay(hold_time_ms); SwitchControlLibrary().MoveHat(8); // center delay(delay_time_ms); break; case 'l': case 'L': SwitchControlLibrary().MoveHat(6); // left delay(hold_time_ms); SwitchControlLibrary().MoveHat(8); // center delay(delay_time_ms); break; case 'u': case 'U': SwitchControlLibrary().MoveHat(0); // up delay(hold_time_ms); SwitchControlLibrary().MoveHat(8); // center delay(delay_time_ms); break; case 'd': case 'D': SwitchControlLibrary().MoveHat(4); // down delay(hold_time_ms); SwitchControlLibrary().MoveHat(8); // center delay(delay_time_ms); break; default: break; } }

f:id:tangential_star:20201205131649g:plain

2020/12/5対応;動作例(NintendoSwitchVer11アプデ対応済)

 

あとがき

剣盾の自動化は、今年の2/2にArduino Leonardoを買って以来、色々と試してきましたが、こんなふうにDLCが出てから更に魅力的になったと思います。

入手方法や個数が実質的に限られていたアイテム・ポケモンがちゃんと後からでも手に入れられるようになることは、改造やセーブデータ改竄など非合法な方法を撲滅する上でも必要だと思います。一方で、きのみ集めやレイド周回、ウッウロボガチャなど、通常プレイでは苦行と言わざるを得ないパートが残っているのもまた事実で、やりこみ要素としてのバランスは難しいのでしょう。

ここは、ゲームに対するプレイスタイルに依るところが大きいので、それぞれがポリシーを持って向き合っていただければと思います。

なお、本記事を始めとするArduinoを使った自動化は、コントローラー操作の代替手段の一つです。いわば、連射コントローラーや、マクロ対応コントローラーと同じカテゴリのものです。すなわち、ポケモン剣盾の仕様の範囲内で完結でき、前述の非合法的な手段(改造やセーブデータ改竄など)を使わない、プレイスタイルの一つとして位置づけられると考えます。

本記事を読んでいただいた皆様にはそれぞれに考え方があるかと存じますが、それぞれのプレイスタイルに応じた使い方を演出いただければ幸いです。 

 

ではではc⌒っ.ω.)っ

 

前の記事:

【Arduino自動化01】Arduino開発環境の導入

次の記事:

【Arduino自動化03】ワット稼ぎ・自動回収

 

【Arduino自動化01】Arduino開発環境の導入

本記事では、

  • 機材とソフトウェアの準備
  • ArduinoIDE(開発環境)の導入
  • サンプルプログラムを動かす(コンパイルと書き込み)
  • ArduinoNintendo Switchにつなぐ(動作確認)

を紹介します。

もくじは下記の通りです。

 

準備するもの(PC以外)

最低限、準備するものは「switch本体」「Arduino Leonardo」「ケーブル」の3つです。

ただ、自動化することを前提にする場合は、switchの給電をしながらArduinoをつなぎたい場面が多く、上記に加え「純正充電器(Switchについてるやつ)」「ホリのUSBハブスタンド(または純正のswitchドック)」があるとさらに捗ります。

給電しながらSwitchとArduinoをつなぐ場合
給電せずSwitchとArduinoをつなぐ場合
機材構成イメージ(左:おすすめ/右:最低限の構成)

ちなみに、ArduinoとSwitch本体をつなぐケーブルは、USBハブスタンドやドックを使う場合はUSB Aオス、直接つなぐ場合にはUSB Cオスでそれぞれケーブルの種類が変わるので注意しましょう。USBケーブルはデータ通信可能なものなら適当に変換アダプタを噛ませてもOKです。ただし、充電ACアダプターは任天堂純正のものを使いましょう。

なお、当然のことですが、PCを使ってArduinoにプログラムを書き込むので、PCとArduinoをつなぐUSBケーブルも必要に応じてご用意ください(PCのUSB端子をあらかじめ確認しておきましょう)。

Arduino Leonardo
NintendoSwitch用USBハブスタンド
NintendoSwitch純正ACアダプター
USB microB-USB A通信アダプタ
筆者が使っている機材

2021年1月5日追記:Arduino Leonardoのみ、商品リンク貼っておきます。

 

2021年2月4日追記:その他筆者使用機材は下記記事にまとめました。

【Arduino自動化 番外編3】筆者の使用機材一覧【紹介記事】

 

準備するもの(PCソフトウェア)

ハードウェアは買えば終わりですが、ソフトウェアはダウンロードとインストールの作業が必要になります。PCに慣れている人なら20-30分ほどで終わるかと思います。

大まかには

  1. ArduinoIDEのインストール
  2. AVR更新
  3. ライブラリ(STL・SwitchControlLibraryの2つ)のインストール
  4. Arduinoのボード情報更新

になります。 

筆者はWindows 10なので基本的にスクショも説明もこれに準じます。あしからず。

Arduino IDEのダウンロード

基本的に、PCはWindowsだろうがMacだろうがLinuxだろうが、Arduino公式がサポートしているものであればなんでもOKです。ちなみに筆者の使用PCはWindows 10です。

公式サイト(https://www.arduino.cc/en/software)から自身にあったバージョンのものをダウンロード・インストールしてください。

なお、Windows App版は色々と不具合があるようなのでおすすめしません。仕様を理解できる人以外は素直にインストーラー版のものをダウンロードしてください。

ダウンロードするのは、Legacy IDE (1.8.X)です*1

【重要】Arduino IDEのバージョンは「Legacy(1.8.X)」を選ぶこと

Arduino公式Webでのダウンロードリンクの場所

Windowsの人(10含む)は、インストーラー版がおすすめ

ちなみに、ダウンロードの画面に進むと、寄付(Donation)を募られます。支援したい方やArduinoに協賛・共感できる人は是非とも、金額を選択または入力して「Contribute & Download」を押しましょう。無論、持ち合わせがない人や今回の寄付を見送る人は「Just Download」でも問題ありません。

ダウンロードしたら、そのままインストールしてください。Windowsインストーラー版の人は「arduino-x.x.x-windows.exe(x.x.xはバージョン)」をダブルクリックすると勝手にインストールされるはずです。

 

Arduino AVR boards 1.8.2のインストール

Arduino IDEをインストールしたら、まずはAVR boardsをインストールします。これは、Arduino Leonardoをちゃんと使えるようにするためのおまじないです。おそらく、ダウンロード時にデフォルトでインストールされているはずですが、もしなければインストールしてください。

ArduinoIDEを起動し、上部のメニューバーから「ツール」→「ボード」→「ボードマネージャ」を押し、出てきた画面で「Arduino Leonardo」と検索すると出てくるはずです。

なお、2020/11/7現在、AVR boardsの最新版は1.8.3ですが、1.8.2にしないと次にインストールする「ArudunoSTL」と競合してコンパイルができないという既知のバグ(同様の投稿)があるようなので、もし、1.8.3がすでにインストールされていたら1.8.2にダウングレードしてください

(上級者向けインフォメーション:AVR boardsを1.8.3のまま進める場合は、次にインストールするArduinoSTLのバージョンを1.3.3にしてください)。

Arduino AVR Boardsは「ボードマネージャ」からインストールできる。

最新版は1.8.3だが、1.8.2にしないとエラーになる既知のバグあり(2020/11/7現在)。

 

ArduinoSTLのインストール

次に、ArduinoSTLをインストールします。STLというのはStandard Template Libraryの略です。ライブラリというのは、よく使うプログラムの機能をひとまとめにしたパッケージのことです。

インストール方法は、公式WebからZIP形式でダウンロードして所定フォルダにインストールする方法と、ArduinoIDE上でライブラリマネージャを使う方法があります。本記事では、バージョン管理が楽でわかりやすい後者を採用します。

上部のメニューバーから「スケッチ」→「ライブラリをインクルード」→「ライブラリを管理」を押し、ライブラリマネージャを開きます。そこで、「Arduino STL」と検索し、インストールを押してください。

なお、2020/11/7現在のバージョンは1.1.0です*2上記の手順でAVR boardsを1.8.2にダウングレードした人は必ず「1.1.0」を選択してインストールしてください。

インストールが終わったら、一度ArduinoIDEを閉じてください。

ArduinoSTLは「ライブラリマネージャ」からインストールできる

 

 SwitchControlLibraryのダウンロード

本記事では、Arduino Leonardoで、Switchコントローラー機能をプログラムするにあたって、「SwitchControlLibrary」というライブラリを使います。「SwitchControlLibrary」はGithubhttps://github.com/celclow/SwitchControlLibrary)からダウンロードできます。

【重要】2021年2月27日追記:今年の1月24日にこのライブラリのメジャーアップデート(ver 2.0.0)がありました。下方互換性が無いため、本記事を参考にする場合は「ver 1.0.0」をダウンロードしてください。

f:id:tangential_star:20210227023006p:plain
f:id:tangential_star:20210227023016p:plain
SwitchControlLibrary(ver1.0.0)のダウンロード手順(2021/2/27画像差し替え)
※2021/1/24にver2.0.0が公開されましたが、当ブログでは旧バージョンのver1.0.0を利用します。

なお、本ライブラリはcelclow氏がMITライセンスにて無償で配布しているものとなります。ライブラリの詳細説明は他サイトや同梱のReadMeに譲りますが、そもそも無保証のものであるという前提と、有志による提供であることを念頭に使用しましょう。

ZIPをダウンロードしたら解凍し、Arduinoのライブラリフォルダにフォルダごと入れてください。なお、この作業はArduino IDEが終了している状態で行うことを推奨します

ArduinoのライブラリフォルダはWindows版の場合、下記2種類あります。どちらでも同じように動くはずですが、個人的にはユーザドキュメント側のほうが良いと思います。

  • ユーザドキュメント直下のArduinoフォルダ【おすすめ】
     (例 C:\Users\<ユーザ名>\Documents\Arduino\libraries )
  • 本体インストールフォルダ(Program files(x86))のArduinoフォルダ
     (例 C:\Program Files (x86)\Arduino\libraries )

Windowsインストーラー版の場合、ドキュメントフォルダ直下にArduinoフォルダがある。Arduino→librariesにフォルダごとドラッグ&ドロップでライブラリの追加が完了する。

 

boards.txtの書き換え

実は、ここまでの作業で開発環境は完成しているのですが、NintendoSwitchの自動化にはあとひとつ、ステップを踏む必要があります。

この状態でプログラムを書いて、Arduino LeonardoをNintendo Switchにつないでも、Switch本体からコントローラーとして認識されず、自動化ができません。そこで、ArduinoをSwitchコントローラーとして騙すために、ボード情報を書き換えます。

この作業はArduinoIDEを終了している状態で行うことを強く推奨します。

Windows版の場合、ユーザの権限などによって参照される「boards.txt」の場所が違うらしく、下記フォルダに同じファイル構成で存在します。よくわからなければAppDataフォルダの方を更新してみて、様子を見てみましょう。Switchに挿して動かなければ、ここのboards.txtの書き換えが怪しいです。

なお、環境によって、boards.txtがどこにあるのか、あるいは複数あるのかなどが変わります。ともかく、下記フォルダを辿ってみてください*3

 ※AppDataフォルダが見つからない場合、「隠しファイル」の表示をオンにしてください。
 ※Windows標準の「メモ帳」では正しく動かない報告があります。テキストエディタを利用してください。

  • AppDataフォルダ内【原則こちらを書き換える】
    C:\Users\<ユーザ名>\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.2
  • Program filesフォルダ内【上記でうまく行かなければこちらも書き換える】
    C:\Program Files (x86)\Arduino\hardware\arduino\avr

AppDataフォルダのboards.txtを書き換えよう。

書き換える内容は下記4箇所です。デフォルトのboard.txtなら285行目・286行目・311行目・312行目が書き換え対象になると思います。

  • leonardo.vid.1=0x2341 ⇒ leonardo.vid.1=0x0f0d
  • leonardo.pid.1=0x8036 ⇒ leonardo.pid.1=0x0092
  • leonardo.build.vid=0x2341 ⇒ leonardo.build.vid=0x0f0d
  • leonardo.build.pid=0x8036 ⇒ leonardo.build.pid=0x0092

※280行目~320行目「Arduino Leonardo」の設定項目部分(書き換え済)

 

余談ですが、今回書き換えたvidとpidはそれぞれ、「ベンダー・アイディ」「プロダクト・アイディ」と呼ばれるもの。要するに、Switchがこの情報を参照してコントローラーの種類を把握しているので、ここを書き換えれば、Switchをだまくらかせる仕組みです。今回使う「SwitchControlLibrary」では、ホリの「ポッ拳DXプロパッド」に擬態させるので、上記の「board.txt」のleonardo.vid.1・leonardo.build.vidを「0x0f0d」に、leonardo.pid.1・leonardo.build.pidを「0x0092」にそれぞれ変更します。

本来、Arduino Leonardoはvid=0x2341,pid=0x8036だが、これらを
vid=0x0f0d,pid=0x0092に書き換えて、ホリのポッ拳DXコントローラーに擬態する。

なお、ネットで拾ってきた情報だと↓のような騙し方があるようです。
プログラミングやエンジニアリングに興味のある方は色々と調べてみると面白いかもしれません。

VID,PID → 対応するコントローラー
0x0f0d, 0x00c1 → HORI HORIPAD for Nintendo Switch
0x0f0d, 0x0092→ HORI Pokken Tournament DX Pro Pad(今回擬態したもの)
0x057e, 0x2009 → Nintendo Switch Pro Controller
0x057e, 0x2007 → Nintendo Switch Joy-Con (Right)
0x057e, 0x2006 → Nintendo Switch Joy-Con (Left)

 

サンプルスケッチのコンパイル

ここまでお疲れさまでした。以上で開発環境のインストールは完了です。

念の為、動くことを確認するために、ArduinoIDEを起動して、「ファイル」→「新規作成」を押して、下記スケッチをコピペしてください。
ちなみに、「スケッチ」というのはArduinoのプログラムという意味です。

 

※Aを連打するだけのスケッチ(プログラム)

 

 コピペしたら、ArduinoIDEの検証ボタン(左上のチェックマーク)をクリックします。下側にステータスバー(コンソール)に「コンパイルが完了しました」と出れば正常にコンパイル機械語に変換)ができています。なお、もし、「エラーが発生しました」などが出てくる場合は、その内容でGoogleやYahooで検索すると、似たような内容が出てくるので、それで対処してください。

 

そのままArduinoをPCとつないで、こんどは「マイコンボードに書き込み」をクリックします。この際、「ツール」→「ボード」→「Arduino Leonardo」にチェックが入っていることを確認してください。また、「ツール」→「シリアルポート」→Arduino Leonardoが刺さっているCOMポート番号になっていることを確認してください。

「ボードへの書き込みが完了しました」となれば正常終了です。

ボード・シリアルポートがArduino Leonardoになっていることを確認

 

動作確認

ここまでできていれば、あとは実際に動作確認のみです。

スケッチを書き込んだArduino LeonardoをNintendoSwitchに差し込みます。

差し込んでからおおよそ3~5秒ほどでコントローラー(ポッ拳DXコントローラー)と認識して入力を受付始めます。

上記のサンプルプログラムはひらすらAを連打するプログラムですので、A連打で動作確認できる場所で動作確認します。

 

ポケモン剣盾なら、ワイルドエリアの「ハシノマはらっぱ」にいる穴掘り兄弟で試すとわかりやすいです。兄弟の前でArduino LeonardoをSwitchに差し込むと、ひたすら話しかけてくれます。これでワットがある限りいつまでも穴を掘り続けてくれますね。

「ハシノマはらっぱ」の位置
穴掘り兄弟でA連打
ハシノマ原っぱの穴掘り兄弟で動作確認。A連打がわかりやすい。


以上、Arduino Leonardoを使ったポケモン剣盾の自動化にあたり、開発環境の構築と、サンプルスケッチの動作確認でした。
かなり大変だったかと思いますが、ここまでできてしまえば後はいろんなWebサイトからプログラムを拝借して使うもよし、自分でプログラムを書いて自動化するもよし、素敵な自動化ライフが待っていることでしょう。

 

このブログ記事が、その一助となれば幸いです。

 

ではでは。 c⌒っ.ω.)っ 

 

【注意】ライブラリやボード、Arduino IDEのアップデートは慎重に

以下2024/1/7追記:(Switch自動化をこれからやろうと思っている人に向けて)

Switch自動化の環境構築を目的としてArduino IDEを導入した場合は、不用意にアップデートをしないようにしてください(無論、自己責任です。セキュリティ的な脆弱性などをはらむ可能性があるので)。

Arduino IDE側のおせっかい機能(正しい話なのですが…)により、アップデートを促す内容が出てくることがあります。よくわからない人は、下記画像のような「新しいバージョンが入手可能になりました」とか「ボードとライブラリにアップデートがあります」という文言が出てきても無視をしてください

アップデートを促すポップアップが表示されるが、Switch自動化のために導入した場合は無視しよう。
(アップデートすると、せっかく構築した環境が上書きされてしまう)

不用意にアップデートをすると、せっかく構築した環境が変わってしまい、例えば、ソースコードコンパイルできなくなったり、コンパイルはできても、SwitchからArduinoが認識されなくなったりします

具体的には、ボード(Arduino AVR)のバージョンが変わるとboards.txtが書き換えられてしまうため、SwitchがArduinoをコントローラーとして認識できなくなってしまいます。他にも、その他予期しない部分のバージョン競合が起こる可能性があります。

また、ライブラリのアップデートにおいても、ArduinoSTLのバージョンは、上記Arduino AVR(ボード)のバージョンと相互に干渉するため、これらのバージョンを正しく理解して更新せねばなりません。

このあたりは、他のツール類やソフトウェアにも当てはまります。アップデートをすることで、何が変化しどうなるのか、自身が正しく理解できるように努めてください。

(追記ここまで)

 

ではでは。c⌒っ.ω.)っ 

 

次の記事:

【Arduino自動化02】雪中渓谷のワットショップの目玉商品を全自動回収【カンムリ雪原】

*1:本記事では、公開当初に動作確認ができた組み合わせでのバージョンを紹介しております。筆者は2022/9頃に2.0.0に更新をしてコンパイル不可に陥った経験があるためArduino Legacy IDEに戻す運用をしました。2024年現在は治っている可能性はあります。Arduino IDE 2.2.XでのSwitch自動化の動作確認の報告はあるようです。すでにArduino IDE 2.X.Xで動作している方はダウングレードは不要です

*2:2022/12/25追記:先の手順でArduino AVRを1.8.2にしたらSTLは必ず1.1.0にしてください。やむなくArduino AVRを1.8.3にする場合は、STLを1.3.3にしてください

*3:2023/1/7追記:コンパイルの際に使われているboards.txtの場所については、Arduino IDEの「環境設定」内部の「設定」タブにある「より詳細な情報を表示する」のチェックボックスを「コンパイル」側に入れて、任意のinoファイルをコンパイル(検証)することで、コンソール(ログ欄)の3行目あたりに「Using board 'leonardo' from platform in folder: <boards.txtの場所>」と表示されます。どうしても見つからない場合はこちらを確認してください

はじめに

はじめに

こんにちは。ますたーです。

忘備録がてら、Arduino Leonardoを使ったポケモン剣盾自動化について書いていきます。

多分、様々なウェブサイトに買うもの・用意するもの・使うものなど載っているかと思いますが、1から書きます。

私自身、偉大な先駆者のいろいろなWebを見て自動化に挑戦しましたが、やっぱりどれか一つのブログなりWebサイトなりに情報が集約されているので、色々調べてハイブリッドするのはおすすめしません。

例えば、それぞれの人で環境が違うため、その人はうまく行ったけど、他の人はうまく行かないという例もあります(一番多そうなのは、Arduinoなど使うマイコンの種類の違いによる挙動の変化)。

なので、自分にあったブログ記事なりWebサイトなりを見つけて良い自動化ライフを過ごしてください。

当方の環境は↓です(関係ない部分載せてるかもですが)。

ますたーのPCまわりの環境

このブログ記事でできるようになること

  • Arduinoポケモン剣盾の一部動作が自動化できるようになる
  • 環境セットアップの参考に

このブログ記事でできるようにならないこと(提供しないこと)

  • プログラミングや組み込み系について学ぶ
  • アルゴリズム(動作の仕組み)を理解する
  • かゆいところに手が届くカスタマイズほか
  • サポートはしません!

 

以上、よろしくお願いします。

※飽きたら更新終了します。 

 

 

プライバシーポリシー

「ますたーの忘備録」(以下、本ブログ)を閲覧ならびに記載内容をご活用いただくにあたり、下記の通りプライバシーポリシーを掲載しております。

個人情報の取り扱い

個人情報を取り扱うにあたっては、「個人情報の保護に関する法律」をはじめとする個人情報の保護に関する法令、ガイドラインおよび本プライバシーポリシーを遵守いたします。

広告およびバナー

本ブログでは、第三者配信の広告挿入サービス(楽天アフィリエイトプログラム)を活用しております。当該広告においては、ユーザーの興味関心に適した商品やサービスの広告を表示するため、クッキー(Cookie)を使用しております。

また、本ブログは、Amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイトプログラムである、Amazonアソシエイト・プログラムの参加者です。これらのバナー・リンクなどの表示・クリックならびにトラッキングなどのために、クッキー(Cookie)を使用しております。

また、本ブログでは、Googleが提供する広告挿入サービス「Google Adsense」を利用しています。同サービスによる広告配信においては、本ブログやその他のサイトへのアクセス情報などに基づき、ユーザーの興味関心に適した商品やサービスの広告を表示するために、クッキー(Cookie)を使用しております。Googleアカウントの広告設定ページ(https://adssettings.google.com/u/0/authenticated )にアクセスすることで、パーソナライズ広告を無効にすることができます。

アクセス解析ツールについて

当サイトでは、Googleによるアクセス解析ツール「Googleアナリティクス」を利用しています。

このGoogleアナリティクスはトラフィックデータの収集のためにCookieを使用しています。このトラフィックデータは匿名で収集されており、個人を特定するものではありません。この機能はCookieを無効にすることで収集を拒否することが出来ますので、お使いのブラウザの設定をご確認ください。この規約に関して、詳しくはここをクリックしてください。

免責事項

本ブログで取り扱う内容(記事・コンテンツ・情報など)について、執筆時点において正確な情報を掲載するよう努めますが、不十分・不完全・誤った内容などが含まれる場合があることをご了承ください。

本ブログに掲載された内容によって生じた損害等については、直接的・間接的の別を問わず、一切の責任を負いかねますのでご了承ください。

また、本ブログからのリンクやバナーなどによってリンクされている他のサイトについて、当該サイト内で提供される情報、サービス等についても一切の責任を負いかねます。

また、本ブログでは、「はてなブログ」 サービスの無料版を利用しており、上記に定めるリンク・広告プログラムなどとは別に、広告が挿入されます。これらを含め、リンク先に関する情報、サービス等についても一切の責任を負いかねますので予めご了承ください。

また、筆者が別途必要と判断した場合に、本プライバシーポリシーは追記・修正・項目の削除などを行うことがあります。

ソースコードの取り扱いについて

本ブログで紹介する記事の中で、筆者がコーディングしたプログラムのソースコードが含まれることがあります。筆者はこれについて著作権の一切を放棄しませんが、常識的かつ良識のある範囲内、また、商用に当たらない場合において、自由にお使いいただけます。ご自宅や学校での開発、利用、複製などにお役立てください。

本項の記載は、本ブログで利用または紹介しているライブラリ群、IDEを含むソフトウェアやハードウェアなどには適用されません。これらについてはご自身の責任のもと、それぞれの情報提供元をご確認の上、ご利用ください。

お問い合わせ先

お問い合わせは下記Googleフォームより入力をお願いいたします。

※クレジットカードの番号やパスワード、住所など、個人情報あるいは個人の特定につながる情報は入力しないようお願いいたします。

docs.google.com

 

ブログ開設しました

本日2020/11/7 16:46に、じぶんのサイトを持つ、という小さな夢の第一歩を踏み出しました。

興味のあるもの、役に立ったものほか、飽きない範囲で載せていきます。
(所信表明

気が向いたらドメイン変えてちゃんとしたWebページ作るかもですが、それはまた先のお話かなぁ