[ev3dev×Python]   SSH Control (キーボードでの遠隔操作)

この記事はPythonでev3を操作してみたい人のための記事です。
今回はキーボードを使った遠隔操作をしていきたいと思います。
具体的にはwキーを押したら前に進むというような感じです。


#目次
0 . 用意するもの
1 . SSH Control
2 . プログラムの実行
3 . 用語説明





#0.用意するもの
◯ ev3(タンク) + Mモータ
◯ パソコン(VSCode)
◯ bluetooth
◯ microSD
◯ [資料](https://buildmedia.readthedocs.org/media/pdf/python-ev3dev/latest/python-ev3dev.pdf)(これをみながら進めていくのがオススメです。)
◯ 参考サイト : [SSH Control](https://www.ev3dev.org/projects/2018/08/14/EV3D4-ssh-control/)


#1.SSH Control

○押されたキーを取得してSSHで遠隔操作するプログラム

```sshcontrol.py
#!/usr/bin/env python3

#必要なものだけをimportする
import termios, tty, sys
from ev3dev2.motor import OUTPUT_A,OUTPUT_B,OUTPUT_C,MoveTank,MediumMotor

#インスタンスの生成
tank_drive = MoveTank(OUTPUT_A,OUTPUT_B)
m_c = MediumMotor(OUTPUT_C)

#押されたキーを取得する関数を定義する
def getch():
    #標準入力のファイルディスクリプタを取得
    fd = sys.stdin.fileno()
    #ファイルディスクリプタの端末属性を取得する
    old_settings = termios.tcgetattr(fd)
    #エンターキーを押さなくてもいいようにする
    tty.setcbreak(fd)
    #キーボードで入力された文字を受け取る
    ch = sys.stdin.read(1)
    #ファイルディスクリプタの端末属性を設定する
    termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    #ch(character = この場合は押されたキー)を返す
    return ch

#==============================================
#Mモータを動かす関数を定義する
def fire():
   m_c.on(80)
#==============================================
#タンクが前進する関数を定義する
def forward():
   tank_drive.on(80,80)
#==============================================
#タンクが後進する関数を定義する
def back():
   tank_drive.on(-80,-80)
#==============================================
#タンクが左折する関数を定義する
def left():
   tank_drive.on(50,80)
#==============================================
#タンクが右折する関数を定義する
def right():
   tank_drive.on(80,50)
#==============================================
#全てのモータが停止する関数を定義する
def stop():
   tank_drive.stop()
   m_c.stop()
#==============================================

#無限ループ
while True:
   #getch()が返す値をkに代入する
   k = getch()
   #k(押されたキー)を表示する
   print(k)
   
   #押されたキーに対応する動きを決める
   if k == 'w':
      forward()
   if k == 's':
      back()
   if k == 'd':
      right()
   if k == 'a':
      left()
   if k == 'f':
      fire()
   #もし押されたキーがスペースキーなら
   if k == ' ':
      stop()
   if k == 'q':
      exit()
```

#2.プログラムの実行
1.緑のランプが点灯しているev3devを右クリックして、Open SSH Terminal をおす。

2.`ssh robot@ev3dev.local` と入力する。

3.パスワードを聞かれるので、`maker`と入力する。

4.`pwd`と入力してカレントディレクトリを確認しよう。(今現在の居場所)

5.`cd ディレクトリ` というようにして、自分のプログラムが存在するディレクトリまで移動しよう！(ディレクトリはフォルダ)

6.移動できたら`python3 プログラムの名前.py` と入力してエンターを押す。

7.インテリジェントブロックの画面などは変化しないが実行できる。





#3.用語解説

今回はたくさんわからない単語が出ていたと思うので、簡単に解説します。

◯**SSH** :
ネットワークを経由して他のコンピュータ（主にサーバ）に接続し、遠隔操作するための仕組み。
通信の際、扱われる情報は暗号化される。

◯**termios モジュール** : 
低水準端末制御インターフェース。

・**端末** :
情報の入出力を受け持つ部分。
主となるコンピュータに対して入出力や通信を行う機器。

・**インターフェース**
異なる種類のものを結びつける共用部分。

◯**tty モジュール** :
一般的な端末制御操作のための便利な関数群。

・**tty** :
任意のテキスト端末を意味する略称。
ウィンドウシステムでの擬似端末デバイスを介した**端末エミュレータ**などを指す。

・**テキスト端末** :
テキスト（文字列）の入力と表示を行う入出力機器

・**端末エミュレータ** :
端末として動くソフトのこと。

・**関数群** :
関数の集まり

◯**ファイルディスクリプタ** :
ファイル記述子、fd。
ファイル（への通り道）に割り振られる番号で、ファイルを識別するための目印

・**ファイル** :
バイト列としてデータを読み込んだり書き込んだりできるもの

・**バイト列** :
バイト列とは、文字や数値といった特定の形式や意味が与えられていない、任意のビットパターンからなる1バイトのデータが並んだデータ集合のこと。

・**ビットパターン** :
コンピュータが扱うことのできる最小単位である「0」と「1」のビットの組み合わせのこと

・**バイト** :
コンピューターで情報量を表す単位で「B」と略す。 1バイトは、0か1かを表すビットという単位が8つ並んで構成される。メモリーやディスクの容量、プログラムの最小命令コードなどに使われる。

◯**sys モジュール** :
Pythonのインタプリタや実行環境に関する情報を扱うためのモジュール

・**モジュール** :
(Python)コードをまとめたファイルのこと。

・**Python標準ライブラリ** :
モジュールを集めたもの。
[公式](https://docs.python.org/ja/3/library/index.html)
[標準ライブラリチュートリアル](https://docs.python.org/3.3/tutorial/stdlib.html)

・**インタプリタ** :
ソースコードを１行ずつ読み込んではコンピュータが実行出来る命令に変換しながら動くソフトウェア。
プログラムを1行ずつ処理するので、処理速度は速くない。


◯**stdin** :
キーボードからの標準入力。standard input.
キーボードで入力された文字を受け取ることができる。
fd = 0

◯**fileno** :
 = file-number = file.No 0,1,2..
ファイルオブジェクトのファイル記述子(fd)を得る関数
整数のファイル記述子を返す
今回は、
ファイルオブジェクト = キーボードで入力された文字

◯**tcgetattr(fd)** :
ファイル記述子 fd の端末属性を含むリストを返す。

・tc = terminal computer = 端末コンピュータ
・get = 取得する
・attr = attribute = 属性

◯**setcbreak()** :
エンターキーを押さなくて文字入力できるようにする。
逆にこれがないと1文字での入力ができない。

◯**read()** :
ファイルの読み出し

◯**termios.tcsetattr(fd, when, attributes)** :
ファイル記述子 fd の端末属性を attributes から取り出して設定する。
attributes(=属性) は tcgetattr() が返すようなリスト。
引数 when は属性がいつ変更されるかを決定します: 
・TCSANOW は即時変更を行う。
・TCSADRAIN は現在キューされている出力を全て転送した後に変更を行う。
・TCSAFLUSH は現在キューされている出力を全て転送し、全てのキューされている入力を無視した後に変更を行う。



参考記事 :
[Pythonでキー入力を検出する(Enter無しで)](https://qiita.com/tortuepin/items/9ede6ca603ddc74f91ba)
[標準入力・標準出力ってなに?](https://qiita.com/angel_p_57/items/03582181e9f7a69f8168)
[Macのターミナルコマンド一覧（基本編）](https://qiita.com/ryouzi/items/f9dee1540a04a0bfb9a3)
[TERMIOS](https://linuxjm.osdn.jp/html/LDP_man-pages/man3/termios.3.html)



#最後に

読んで頂きありがとうございました！！

より良い記事にしていきたいので
　◯こうした方がわかりやすい
　◯ここがわかりにくい
　◯ここが間違っている
　◯ここをもっと説明して欲しい
などの御意見、御指摘のほどよろしくお願い致します。