詳解 確率ロボティクス 2.3 確率モデル

前回の投稿に引き続き,詳解 確率ロボティクスの2.3 確率モデルを通して学んだことやコードを実行してみた結果のメモです.この投稿はGithubでもご覧になれます(こちら).

ガウス分布*は(例えば)センサ値zがa以上b未満( [a, b) )に入る確率を

 P (a \leq z < b) = \int_{a}^{b} p(z) dz

ここで,

p(z) = \cfrac{1}{\sqrt{2\pi\sigma^{2}}}\exp \left\{ - \cfrac{(z - \mu)^{2}}{2 \sigma^{2}} \right\}

を表します. また,\sigma^{2}は分散,\muは平均値を表します.

 *ガウス分布正規分布は同義です.

センサ値の平均値\mu = 209.7[mm],分散\sigma^{2} = 23.4を代入してP, pを描画するには以下のようにします.

import math

def p(z, mu = 209.7, dev = 23.4):
    return math.exp(-(z -mu)**2 / (2*dev))/math.sqrt(2*math.pi*dev)
zs = range(190, 230)
ys = [p(z) for z in zs]
 
import matplotlib.pyplot as plt
%matplotlib inline
plt.plot(zs, ys)
plt.show()

zsは横軸の数値のリスト,ysは縦軸の関数pの値のリストです.

さらに,$p$を積分して,センサ値が整数に限定される場合の確率分布を作ってみます.
センサ値$x$に対して,区間$[ x - 0.5, x + 0.5)$の範囲で積分することにします(ここでは台形公式で近似).

def prob(z, width = 0.5):
    return width*(p(z - width) + p(z + width))
 
zs = range(190, 230)
ys = [prob(z) for z in zs]
 
import pandas as pd
data = pd.read_csv("sensor_data_200.txt", delimiter = " ",
                   header = None, names = ("data", "time", "ir", "lidar"))
freqs = pd.DataFrame(data["lidar"].value_counts())
freqs["probs"] = freqs["lidar"] / len(data["lidar"])
 
plt.bar(zs, ys, color = "red", alpha = 0.3) # Make graphs transparent with alpha
f = freqs["probs"].sort_index()
plt.bar(f.index, f.values, color = "blue", alpha = 0.3) 
plt.show()
ガウス分布\mu, \sigma^{2}を決めると形状が決まるので,式を記述する必要がなければ
\mathcal{N}(z|\mu, \sigma^{2}) \ あるいは $\mathcal{N}(\mu, \sigma^{2})
などと略記します.
  • モデル化:ある現象を説明するために適切な確率分布の数式を用いてパラメータを決めること
  • 確率モデル:モデル化で分布に当てはめられる数式
ガウス分布確率密度関数(probability density function, pdf)
p(z) = \cfrac{1}{\sqrt{2\pi\sigma^{2}}}\exp \left\{ - \cfrac{(z - \mu)^{2}}{2 \sigma^{2}} \right\}
ガウス分布などの確率密度関数を扱うにはSciPyが便利です.
このモジュール下にあるサブモジュールstatsにはガウス分布確率密度関数norm.pdfが実装されています.
mean1 = sum(data["lidar"].values)/len(data["lidar"].values)
 
zs = data["lidar"].values
mean = sum(zs) / len (zs)
diff_square = [(z -mean)**2 for z in zs]
sampling_var = sum(diff_square)/(len(zs))
stddev1 = math.sqrt(sampling_var)
 
from scipy.stats import norm
 
zs = range(190, 230)
ys = [norm.pdf(z, mean1, stddev1) for z in zs]
 
plt.plot(zs, ys)
plt.show()
変数$z$が実数のとき,確率密度関数p積分したものは累積分布関数(cumulated distribution function, cdf)と呼ばれます.
p(z < a) = \int_{-\infty}^{a} p(z) dz
zs = range(190, 230)
ys = [norm.cdf(z, mean1, stddev1) for z in zs]
 
plt.plot(zs, ys, color = "red")
plt.show()
先に台形公式で近似計算を行なった下式の計算は,確率の計算に置き換えられます.
P(a \leq z < b) = \int_{a}^{b} p(z) dz = \int_{-\infty}^{b} p(z) dz - \int_{-\infty}^{a} p(z) dz = P(z < b) -P(z < a)
上式を使って確率分布を描くには以下のようにします.
zs = range(190, 230)
ys = [norm.cdf(z + 0.5, mean1, stddev1) - norm.cdf(z - 0.5, mean1, stddev1) for z in zs]
 
plt.bar(zs, ys)
plt.show()
確率密度関数は,確率質量関数が大文字$P$で表記されるのに対して,多くの場合,区別のために小文字pと表記されます.
  • 期待値:確率分布$P$について$z \sim P(z)$を無限に繰り返した場合に,$z$の平均値がどれくらいになるかを表す値(確率分布$P$から$z$を発生させる).
zが離散的な場合,期待値は
\sum_{z = \infty}^{\infty} z P(z)
で計算できます.

zが連続的な場合は
\int_{- \infty}^{\infty} zP(z) dz
で計算できます.
期待値は具体的な値をドローしなくても分布が決まっていれば,下式のいずれか(離散的な場合は上の式,連続的な場合は下の式)
\sum_{z = \infty}^{\infty} z P(z)
 
\int_{- \infty}^{\infty} zP(z) dz
で計算できます(定義通りに何回もドローして値をサンプリングし,平均を取ることでも期待値を近似的に求めることが可能).
z \sim p(z)や,z \sim P(z)のとき,$z$の期待値は
E_{p(z)} [z, \ E_{P(z)} [z] \ あるいは \ _{p(z)}, \ _{P(z)}]
と表記されます.

期待値をさらに一般化して,z \sim p(z)から計算される関数の値$f(z)$の期待値を考えると
[tex:<f(z)>_{p(z)} = \int_{- \infty}^{\infty} f(z)p(z) dz]
と定義できます.この式は,ある確率も出るから別の確率モデルのパラメータを求める時に頻出します.

詳解 確率ロボティクス 2.2 度数分布と確率分布

UASの自律飛行にあたって,ロボティクスに興味を持ちました.上田隆一先生の書籍 詳解 確率ロボティクスが出版され,非常に分かり易そうだったので,詳解 確率ロボティクスの2.1センサデータの収集とJupyter Notebook場での準備,2.2 度数分布と確率分布を通して学んだことやコードを実行してみた結果のメモです.この投稿はGithubでもご覧になれます(こちら).

  • 頻度ヒストグラムの縦軸の値のこと.
  • 雑音(ノイズ):計測値(センサ値)の変動(e.g. LiDARの計測値).例えば,LiDARの場合は,外乱光や電気回路中の電圧や電流を乱す"何か(原因は複雑にあって,互いに影響し合っていることが多い)"が影響して雑音が発生する.
  • 誤差:何らかの測りたいものの"真の値"とセンサ値の差のこと.
  • 偶然誤差(accidental error, random error):雑音によって発生する誤差のこと.
  • 偏り(バイアス):計測機器の取り付け位置がずれていたり,取り付けた本体が傾いていたりするときに生じるずれのこと.
  • 系統誤差(Systematic error):バイアスによって生じる定常的な誤差のこと.系統誤差の量はセンサ値から推定することができないので,別のセンサや計測方法で突き止める必要がある.しかし,別の計測方法やセンサにも雑音やバイアスが存在する.
  • 系統誤差は,アルゴリズムの出力にも悪影響を及ぼす.対策は取りにくいが,バイアスや系統誤差の存在を頭の隅に置いて,ロボットのアルゴリズムを考えていく必要がある.
書籍 詳解 確率ロボティクスの中では,Python 3系とJupyter Notebookを用いてコードの実行結果を確認する方法が取られています.コードは著者の上田隆一先生GitHubで公開されています.書籍中のコードの閲覧はこちらから可能です.完成したコードのみを見たい場合はこちらから閲覧が可能です.
 
以下は,詳解 確率ロボティクス 2.2.2 頻度,雑音,バイアス にあるコードを実行してみた際のメモです.
 
まずは,Pythonのバージョン等のチェック(Python 2系だとコードが動かないため,3系であることを確認)
import sys
sys.version    # Check Python version
 
実行すると,以下のように返ってくるはずです(バージョンなどは環境によって異なります).
'3.7.5 (default, Nov 1 2019, 02:16:32) \n[Clang 11.0.0 (clang-1100.0.33.8)]'
続いて,Pandasモジュールの"read_csv"関数を使って data という変数に既存の計測データ(ファイル名:sensor_data_200.txt, 計測した日付,時間,光センサの計測値,LiDARの計測値)*を読み込んでいます.
import pandas as pd
data = pd.read_csv("sensor_data_200.txt", delimiter = " "
                  header = None, names = ("date", "time", "ir", "lidar"))
data
実行すると,以下のように返ってくるはずです(長いので途中を省略しています).

date time ir lidar
0 20180122 95819 305 214
1 20180122 95822 299 211
2 20180122 95826 292 199
3 20180122 95829 321 208
4 20180122 95832 298 212
5 20180122 95835 327 212
         
... ... ... ... ...
         
         
58983 20180124 120023 313 208
58984 20180124 120026 297 200
58985 20180124 120030 323 204
58986 20180124 120033 326 207
58987 20180124 120036 321 208
58988 rows × 4 columns

続いて,sensor_data_200.txt における,LiDARのセンサ値値の規則性の有無を調べるために,センサ値のヒストグラムの描画を行います.
%matplotlib inline    #necessary if the graph is not displayed.
import matplotlib.pyplot as plt
data["lidar"].hist(bins = max(data["lidar"]) - min(data["lidar"]), align = 'left')
plt.show()


実行すると,以下のようなヒストグラムが描画されます.



* 計測データの中身は以下のようになっています.
20180122 095819 305 214
20180122 095822 299 211
20180122 095826 292 199
20180122 095829 321 208
20180122 095832 298 212
...途中省略...
20180124 120023 313 208
20180124 120026 297 200
20180124 120030 323 204
20180124 120033 326 207
20180124 120036 321 208

雑音の原因を突き止めたり除去するのは困難な場合が多いので,原因はわからないままにして,雑音の傾向を把握する(分からないことは放っておく).
傾向を把握するためには以下の値を求めます.

  1. センサ値の平均値を求める.
  2. センサ値の分散を求める.
  3. センサ値の標準偏差を求める.

なお,分散と標準偏差は各センサ値のばらつきを表します.

{\bf{Z}}_{LiDAR} = \{ z_{i} | i = 0, 1, 2, \cdots, N-1\}

ここで,[tex:{\bf{Z}}_{LiDAR}]はリスト(ベクトル)を表し,[tex:z_{i}]のiは(0からの)要素番号を表し,要素数Nとなります.

  • 分散:集合の要素の値を全て足して,要素数で割ったもの
\mu = \cfrac{1}{N} \sum_{i = 0}^{N-1} z_{i}
  • 分散には標本分散と不偏分散の二つがある.
  • 標本分散:各値と平均値(\mu)の差を二乗したものの平均値(各値と平均値(\mu)が離れているほど大きい)
\sigma^{2} = \cfrac{1}{N} \sum_{i = 0}^{N-1} (z_{i} - \mu)^{2} \ \ \ (N &gt; 0)
  • 不偏分散標本分散の割り算の分母が N ではなく N-1 としたもの.
(s^{2} = )\sigma^{2} = \cfrac{1}{N-1} \sum_{i = 0}^{N-1} (z_{i} - \mu)^{2} \ \ \ (N &gt; 1)
  • 標本分散と不偏分散は,Nの値が小さい時に違いが現れる.

上記の分散を実際に計算するコードは以下のようになります.

# Calculate from definition
zs = data["lidar"].values
mean = sum(zs) / len(zs)
diff_square = [(z - mean)**2 for z in zs]
 
sampling_var = sum(diff_square) / (len(zs))     # sample variance
unbiased_var = sum(diff_square) / (len(zs) - 1) # unbiased sample variance
 
print(sampling_var)
print(unbiased_var)
 
# Use Pandas
pandas_sampling_var = data["lidar"].var(ddof = False) # sample variance
pandas_default_var = data["lidar"].var()              # default(unbiased sample variance)
 
print(pandas_sampling_var)
print(pandas_default_var)
 
# Use Numpy
import numpy as np
 
numpy_default_var = np.var(data["lidar"])            # default(sample variance)
numpy_unbiased_var = np.var(data["lidar"], ddof = 1) # unbiased sample variance
 
print(numpy_default_var)
print(numpy_unbiased_var)


最初の# Calculate from definition以下は,定義から計算するもので,次の# Use Pandas以下はPandasを使って計算するもの,最後の# Use Numpy以下はNumpyを使って計算するものです.各計算結果を表示するように命令してあり,実行結果は以下のようになります.
この結果からPandasとNumpyを使った結果は一致していることがわかります.Pythonでは,上記のように定義から計算するよりもPandasやNumpyを使って計算することが推奨されており,計算速度もそちらの方が速いようです.
計算結果は以下のようになります.

23.407709770274106
23.40810659855441
23.4077097702742
23.408106598554504
23.4077097702742
23.408106598554504


続いて標準偏差を求めます(標準偏差は分散の正の平方根).

import math
 
# Calculate from definition
stddev1 = math.sqrt(sampling_var)
stddev2 = math.sqrt(unbiased_var)
 
# Use Pandas
pandas_stddev = data["lidar"].std() # Pandas calculates standard deviation from unbiased variance
 
print(stddev1)
print(stddev2)
print(pandas_stddev)
 

計算結果は以下のようになります.

4.838151482774605
4.83819249292072
4.838192492920729

計算結果から,Pandasでは不偏分散を用いて標準偏差を求めていることがわかります.

  • 確率:値の出やすさを数値化したもの

まず,各センサ値の頻度を集計してみます.以下では,value_countsでlidar列のセンサ値の頻度を数え上げて,pd.DataFrameでデータフレームにしています.

freqs = pd.DataFrame(data["lidar"].value_counts())
freqs.transpose() # Output horizontally


集計結果は以下のようになります.

1 rows × 35 columns


続いて,変数freqsに確率の列を追加してみます.1行目では,lidar列に入っているそれぞれの頻度を,dataの要素数で割っています.

freqs["probs"] = freqs["lidar"]/len(data["lidar"])
freqs.transpose()
2 rows × 35 columns

(表は途中-右側-を省略しています)

確率の合計が1になっていることを確認します.

sum(freqs["probs"])


合計の計算結果は以下のようになります.

1.0


出力結果を並べ替えて,横軸にセンサ値を,縦軸に確率を描いてみます.
ヒストグラムと似ていますが,縦軸は頻度ではなく確率であることに注意が必要です.

freqs["probs"].sort_index().plot.bar()
plt.show() # The vertical axis changes from frequency to establishment

描画結果は以下のようになります.
 
  • 確率質量関数:個別の確率$P(z)$を与える関数$P$
  • 確率分布:各変数に対して確率がどのように分布するのかを表す実体

最後に,確率分布を用いたシミュレーションを行ってみた結果です.
シミュレーションでは,先に求めた確率分布($P_{{\bf{Z}}LiDAR}$と記する)に従って$z$を選びます.Pandasでは,sampleメソッドを使用することで確率分布から値を選ぶことができます.
上記の処理を数式で表すと

z_{N} \sim P_{{\bf{Z}}LiDAR}

となります.
ここで,左辺のz_{N}は実際に選ばれた値を表します.

def drawing(): # Define as a function
    return freqs.sample(n = 1, weights = "probs").index[0]
 
 
drawing() # meaning of execution, not drawing graph
 
実行結果は以下のようになります.
211

sampleの引数nが選ぶ個数,weights = "probs"がデータフレームの"probs"の列に選ぶときの確率が入っていることを意味しています.sampleの後ろの.index[0]は,データフレームのレコードの名前(この場合はセンサ値)を取り出すためのもので,これによってセンサ値を得ることができます.
上記の処理を数式で表すと
z_{N} \sim P_{{\bf{Z}}LiDAR}

となります.
ここで,左辺の$z_{N}$は実際に選ばれた値を表します.

Pandasでsamplesメソッドを使って確率分布から値を選ぶことが可能です.N-1回目までのセンサ値で作った分布からz_{N}を発生させるには以下のようにします.

samples = [drawing() for i in range(len(data))]
# samples = [drawing() for i in range(100)]
simulated = pd.DataFrame(samples, columns = ["lidar"])
p = simulated["lidar"]
p.hist(bins = max(p) - min(p), color = "orange", align = 'left')
plt.show()

描画結果は以下のようになります.
  • ドローイング(drawing):母集団から個々のものを抽出すること
  • サンプリング(sampling):母集団から集団の一部を抽出すること
 

Tello Programming 006 -Telloの状態確認(LED)-

Telloには機体前方のカメラ横にLEDがついています.このLEDの点灯,点滅パターンはTelloの状態を表します.LEDの状態は通常,警告,充電の3つに分けることができます.トイドローンなので,LEDの点滅,点灯からしか状態を把握することができませんが,何か異常があると感じた場合は,LEDを確認すると現状が把握できます.
以下に各場合の機体の状態を示します.

通常時のLED点滅

LEDの色 パターン 機体の状態
交互点滅 セルフチェック(飛行準備)
2回づつ点滅 ビジョンポジショニングシステム稼動中
点滅(ゆっくり) ATTIモード


警告時のLED点滅

LEDの色 パターン 機体の状態
点滅(速い) 送信機と未接続
点滅(ゆっくり) バッテリー残量小(低電圧)
点滅(速い) バッテリー残量極小(超低電圧)
点灯 何らかの致命的エラーが発生


充電時のLED点灯,点滅

LEDの色 パターン 充電の状態
点灯 充電完了
点滅(ゆっくり) 充電中
点滅(速い) 何らかの充電エラー


充電はチャージャーがある場合はそちらの方が急速に充電されますが,ない場合は本体左のUSB端子を接続して充電します.

 

 

Tello Programming 005 -Scratchでプログラミング Test Flight 01-

これまでに数回に分けて,TelloScratchでプログラミングする準備やテストを行ってきました.これまでの投稿は以下のようになります.

前回は,一つのコマンドを送信すると,受信したTelloがコマンドにある動作を行う(離陸,前進,後退,着陸)プログラムを作ってテストをしてみました.

前回の投稿にあるように,ターミナルを立ち上げ,nodeを起動させます.

$ cd Tello.jsのあるディレクトリの場所 
$ node Tello.js

そして,Scratch2.0 Offline Editorを起動させ,Scratch2.0 Offline Editorの"File"メニューをShiftキーを押しながらクリックして,"Import Experimental HTTP Extension (実験的なHTTP拡張の読み込み)"をクリックして,Tello.s2eを読み込みます(手順の詳細は前回の投稿を参照して下さい).

ブロックパレットからブロックを移動させて,以下のように連続して動作を行うプログラムを作成します.
ブロックパレットに,以下のような動作をプログラミングしてみました.

動作は,
  1. 離陸
  2. 50cm前進
  3. 50cm上昇
  4. 100cm前進
  5. 反時計回りに90°旋回
  6. 100cm前進
  7. 反時計回りに90°旋回
  8. 150cm前進
  9. 反時計回りに180°旋回
  10. 右方向に100cm移動
  11. 50cm下降
  12. 着陸

の1〜12を途中に2秒間の静止時間を挟みながら連続的に行うという流れです.
一応,緊急時のために"space"キーを押したら緊急停止するコマンドも作成してあります(画面右上).
Telloがコマンドの通りに飛行すれば,元の場所に戻ってくるはずです.
上記のプログラムを実行してみた結果の動画は以下のようになります.
Y.P.S. が上手く動作していないと,1回目のフライトのように離陸場所と着陸場所がずれますが,2回目のフライトでは,離着陸の場所がほぼ同じなので,V.P.S. がそれなりに上手く動作したようです.
各命令が実行されると,nodeを立ち上げているターミナルには以下のように表示されます.
send: takeoff
Data received from server : ok
Received 2 bytes from xxx.xxx.xx.x:xxxx
 
send: forward 50
Data received from server : ok
Received 2 bytes from xxx.xxx.xx.x:xxxx
 
send: up 50
Data received from server : ok
Received 2 bytes from xxx.xxx.xx.x:xxxx
 
send: forward 100
Data received from server : ok
Received 2 bytes from xxx.xxx.xx.x:xxxx
 
send: ccw 90
Data received from server : ok
Received 2 bytes from xxx.xxx.xx.x:xxxx
 
send: forward 100
Data received from server : ok
Received 2 bytes from xxx.xxx.xx.x:xxxx
 
send: ccw 90
Data received from server : ok
Received 2 bytes from xxx.xxx.xx.x:xxxx
 
send: forward 150
Data received from server : ok
Received 2 bytes from xxx.xxx.xx.x:xxxx
 
send: ccw 180
Data received from server : ok
Received 2 bytes from xxx.xxx.xx.x:xxxx
 
send: right 100
Data received from server : ok
Received 2 bytes from xxx.xxx.xx.x:xxxx
 
send: down 50
Data received from server : ok
Received 2 bytes from xxx.xxx.xx.x:xxxx
 
send: land
Data received from server : ok
Received 2 bytes from xxx.xxx.x
上記の"x"には数字が入ります.

Tello Programming 004 -Scratchでプログラミング-

TelloScratchで動かすには,
・Scratchオフラインエディター(現在、Ver.2.0)
・Node.js
Adobe AIR
が必要です.これらのセットアップに関しては,過去の投稿(macOS編Windows編)を参照して下さい.また,Scratchの基本についても過去の投稿を参照して下さい.

TelloScratchでプログラミングして動かすには
Scratchでプログラム作成
・Nodeプログラム起動
Wi-Fi接続(Telloとコンピュータ)
が必要になります.以下は,トライアルでプログラミングしてみた際のメモです.

まずは,Telloの電源を入れます.しばらくするとWifi接続が可能になるので,とコンピューターを接続します.

ターミナルを起動して,事前にダウンロードしてあるTello.jsのあるディレクトリに移動して,nodeを起動してTello.jsを読み込みます*Scratchのセットアップについては以前の投稿Windows編macOS編を参照して下さい).
$ cd Tello.jsのあるディレクトリの場所 
$ node Tello.js
 
*毎回Tello.jsのあるディレクトリを探してそこに移動するのは面倒なので,作業用のディレクトリをデスクトップにでも作成して,その中にTello.js, Tello.s2e, TelloChs.s2eを入れておくと便利です.そして,ターミナルを起動して,"cd"と入力した後に,そのディレクトリをターミナルにドラッグ&ドロップすると,そのディレクトリの場所が表示されます.
下図は,作業用フォルダとして"Tello Project"というディレクトリを作成して,その中に必要なファイル(Tello.js, Tello.s2e, TelloChs.s2e)を入れた場合の例です.
ターミナルで"node Tello.js"と入力すると以下のように表示されます.
$ node Tello.js
---------------------------------------
Tello Scratch Ext running at http://xxx.x.x.x:xxxx/
---------------------------------------
(node:655) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
server listening x.x.x.x:xxxx
send: command
Data received from server : ok
Received 2 bytes from xxx.xxx.xx.x:xxxx
なお,上記で"x"と表示されている箇所には数字が入ります.
 
Scratch2.0 Offline Editorを起動します.Scratch2.0 Offline Editorの"File"メニューをShiftキーを押しながらクリックして,"Import Experimental HTTP Extension (実験的なHTTP拡張の読み込み)"をクリックして,Tello.s2eを読み込みます.
 
Scratch2.0 Offline Editorを使って,プログラムを作成します.
例えば,Scratchブロックパレット,Script(スクリプト)>More Blocks(その他)から[takeoff] をスクリプトエリアにドラッグ&ドロップすると,離陸(Take Off)の命令をプログラムしたことになります.
 
以下に,離陸(takeoff)と着陸()だけの命令を持っているプログラム例を示します.
下図はブロックパレットの拡大です.
このプログラムは,

  • "t"を押したときに離陸(takeoff)
  • "l"を押したときに着陸(land)
するという命令を持っています.安全のために,一番下にある"space"を押した時には緊急停止(emergency stop)する命令も付けてあります.このプログラムでは,離陸して着陸するという操作しかできません.
 
そこで,離陸,着陸に加えて,50cm前に進む,50cm後ろに下がるという命令を持つプログラムを作成してみます.
ブロックパレットを拡大すると,以下のようになります.
先の例と同じように
 
  • "t"を押すと離陸(takeoff)
  • "l"を押すと着陸,"space"を押すと緊急停止(emergency stop)
  • "f"を押すと50cm前進(fly forward 50cm)
  • "b"を押すと50cm後進(fly backward 50cm)

という命令を出すことができます.

 
このプログラムを実行してみた際の動画は,以下のようになります.

なお,上記の動画を実行した際に,nodeを起動しているターミナルには,各命令が実行されると,以下のように表示されます.
send: takeoff
Data received from server : ok
Received 2 bytes from xxx.xxx.xx.x:xxxx
 
send: forward 50
Data received from server : ok
Received 2 bytes from xxx.xxx.xx.x:xxxx
 
send: back 50
Data received from server : ok
Received 2 bytes from xxx.xxx.xx.x:xxxx
 
send: land
Data received from server : ok
Received 2 bytes from xxx.xxx.xx.x:xxxx
 
send: reset_all

上記の"x"には数字が入ります.

Tello Programming 003 -Scratchの基本-

前回(Windows)前々回(Mac)Telloをプログラミングによって飛行させるためにScratchのセットアップを行いました.以下は,Scratchの基本についてのメモです.

前回(Windows)前々回(Mac)はデスクトプエディター(オフラインで利用できるScratch)のセットアップでしたが,Scratchはオンラインであればブラウザ上で利用することができます.
Scratchのトップページの左上にある「作る」をクリックします.

 

すると,Scratchの画面が立ち上がります.

 

 

Scratchの画面はステージ,スプライトリスト,ブロックパレット,コード(スクリプトエリア)の四つのエリアに分かれています.
 
ステージについて
ステージにはキャラクター(スプライト)が配置されています.
ステージ(猫のスプライトが表示)
ステージ上の位置は座標で表され,横方向は$x$軸で -240(左端)から+240(右側)の数値で表されます.また,縦方向は$y$軸で-180(下端)から+180(上端)の数値で表されます.中心は (0, 0)になります.上図のステージでは猫のスプライトは中心(0, 0)に配置されています.

Telloのプログラミングで使用するScratch 2.0 オフラインエディターでは,ステージは以下のような表示で,左上に表示されます.
Scratch 2.0 オフラインエディターのステージ
 
スプライトリストについて
スプライトリストには,スプライトの一覧が表示されています.
スプライトリスト
 
スプライトの一覧が表示されています.最初は猫のスプライトのみですが,右下の猫のアイコンをクリックすると別のスプライトが表示され,選んだものを追加することができます.

Telloのプログラミングで使用するScratch 2.0 オフラインエディターでは,スプライトリストは以下のような表示で,左下に表示されます.
Scratch 2.0 オフラインエディターのスプライトリスト
 
ブロックパレットについて
ブロックパレットには,スプライトへ命令を出すためのブロックが並んでいます.
コードタブ
 
ブロックには,スプライトの「動き」「見た目」「音」などと数種類があり,同じ種類のブロックは同色になっています.
上図は,ブロックパレット内の「コード」タブが選ばれた状態で,(スプライトを動かすための)命令ブロックが配置されています.ブロックパレットから下図のように命令を右側のエリアにドラッグ&ドロップしてこのエリアの中で各命令を組み合わせます.
「10 歩動かす」ブロックをドラッグ&ドロップした結果
 
「コスチューム」タブをクリックすると,コスチュームエリアが表示されます.ここは,スプライトのコスチュームを編集するためのタブです.
コスチュームタブ
 
「音」タブをクリックすると,音エリアが表示されます.ここでは効果音などの変数ができ,録音したサウンドを使用することもできます.
音タブ

なお,Telloのプログラミングで使用するScratch 2.0 オフラインエディターでは,ブロックパレットは以下のような表示で,右側に表示されます.
Scratch 2.0 オフラインエディターのブロックパレット,Scriptタブ
Scratch 2.0 オフラインエディターのブロックパレット,Costumesタブ
Scratch 2.0 オフラインエディターのブロックパレット,Soundsタブ

Tello Programming 002 -プログラミングの準備(Windows)-

前回,macOS環境でのプログラミングの準備に関して投稿しました.
今回は,Windows環境でのセットアップについてのメモです.

まずは,macOSの場合と同様にAdobe Airをインストールします.こちらからAdobeAIRInstaller.exeをダウンロードして実行します.
以下の画像のように「同意する」「完了」をクリックするだけです.

 
 

手順はmacOSと同じで,Ryze Tech社のサイトにある手順の通りに準備を進めます.Tello ScratchのREADMEには以下のように書かれています.

 

macOSの場合はScratch Desktop(ver. 3.6.0)をインストールしたものの,Shiftキーが効かなかったので,最初からScratch 2.0 オフラインエディターをインストールします.

まずは,Scratchのインストールです.ScratchのWebページからローカル環境でScratchを使用できる

の.exeファイル(Scratch-461.exe)をダウンロードします.

 

この.exeファイルは解凍(ダブルクリック)して,アイコンをアプリケーションフォルダに移動させるだけでインストールが始まります.

 
 
インストールが終了するとScratchが自動的に立ち上がります.
 
 

Nodeのインストールを行います.
Tello ScratchのREADMEには以下のように書かれています.

 

Node.jsのサイトからNodeのパッケージファイルをダウンロードします.
LTSでもCurrentでも良いと思いますが,とりあえず安定しているLTSをダウンロードします.

 
ダウンロードした実行ファイル(node-v10.16.3-x64.exe)をダブルクリックすると以下のようにインストールが始まります.
 
 
 
 
 
(これで,Nodeのインストールは完了)
 
TelloScratchファイルをダウンロードします.
Tello ScratchのREADMEには以下のように書かれています.
Scratch用のTelloデータをダウンロードするのはリンクをクリックするだけです.ダウンロードしした圧縮ファイル(Scratch_For Tello.7z)を解凍すると Scratch_普通版 というフォルダが作られます.そのフォルダ内に,以下の3つのファイルがあることを確認します.
 
  • Tello.s2e
  • TelloChs.s2e
  • Tello.js
これらのファイルのTello.jsをエディター等のソフトで開きます.
 
 
コマンドプロンプトを立ち上げて,以下のようにして tello.js をnode経由で読み込みます.
 
なお,上記のコマンドプロンプトの操作は,デスクトップ上に解凍した Scratch_普通版 フォルダがある前提です(モザイクがかかっている部分にはユーザー名が入ります).
コマンドプロンプトでの操作は,以下のようになります(太字部分が入力)
    C:\Users\ユーザー名>cd desktop
    C:\Users\ユーザー名\Desktop>cd Scratch_普通版
    C:\Users\ユーザー名\Desktop\Scratch_普通版>node tello.js
このように入力して,以下のように表示されれば成功です.
 
---------------------------------------
Tello Scratch Ext running at http://127.0.0.1:8001/
---------------------------------------
server listening 0.0.0.0:8890
 
次の設定はScratchTelloのデータを取り込むことになります.ここでの設定は,Tello ScratchのREADMEには以下のように書かれている箇所になります.
 
Scratch2.0オフラインエディターで,以下のように,Shift + File をクリックすると表示が変わり,"Import experimental HTTP extension"と表示されます(READMEでは"Import Experimental HTTP"とありますが,表示が異なる).
 
続いてScratchTelloのインターフェースをデータを読み込みます.Tello ScratchのREADMEには以下のように書かれている箇所になります.

 
先に書いたように,Scratch2.0オフラインエディターで"Shiftキー+File"をクリック(Shiftキーを押しながらFileをクリック)します.すると,以下のようなウィンドウが開くので,ダウンロードした Scratch_普通版 フォルダー内の"Tello.s2e"を選択します.

この段階で,Scratchの中にTelloのデータが読み込まれているので,Tello ScratchのREADMEの5に書かれている"More Blocks"をクリックします.
すると,以下のようにTello Controlというコマンドが表示されます.
 
以上で,プログラミングの準備は完了です.