英国ですべての中学生に配られたマイコン・ボードmicro:bitは、GUIのプログラミング・ツールが利用できます。いくつかのセンサ(加速度センサはMMA8653もしくはLSM303 )が搭載されていて、センサから読み出した値をBLEで簡単に送ることができます。最初に、磁気センサ(磁力センサもしくはコンパス)を利用できるようにします。
micro:bitを磁気センサのペリフェラルに設定
BLEの用途に限らず、micro:bitのファームウェアは最新にしておきます。執筆時点では、Interface Version: 0254でした(DETAILS.TXT)。
https://makecode.microbit.org/
へ行き、ホームから新しいプロジェクトをクリックします。画面右上の歯車のアイコンをクリックします。
プロジェクトの設定を選びます。
No Pairing Required:...を選び、保存します。
同じく歯車のメニューから拡張機能を選びます。
Bluetoothを選択します。
Bluetoothがメニューに追加されています。クリックして、その中から「磁力計サービス」を選択します。
「最初だけ」の中に「磁力計サービス」をドロップします。「ずっと」は不要なので消します。
接続されたとき、接続が切断されたときのLED表示を追加します。
「基本」から「アイコンを表示」を選びます。
「Bluetooth」から「Bluetooth接続されたとき」を選びます。
「Bluetooth接続されたとき」に「アイコンを表示」を入れます。
「アイコンを表示」の▼マークをクリックし、任意の表示を選びます。四角形を選びました。
同様に、「Bluetooth接続が切断されたとき」も作ります。バツを選びました。
完成です。
温度計の事例は、こちら
https://www.denshi.club/cookbook/wireless/ble/microbitble.html
を参照してください。
画面右下のダウンロードをクリックし、ダウンロードしたファイルをmicro:bitのフォルダにドラッグすると、プログラムがコピーされ、終了するとリセットがかかり、ペリフェラルとしてアドバタイジングを開始します。
公式の情報
Bluetooth Magnetometer Serviceのページに、磁気センサのサービスUUID、三つのキャラUUIDが掲載されています。
public static String MAGNETOMETERSERVICE_SERVICE_UUID = "E95DF2D8251D470AA062FA1922DFA9A8";
public static String MAGNETOMETERDATA_CHARACTERISTIC_UUID = "E95DFB11251D470AA062FA1922DFA9A8";
public static String MAGNETOMETERPERIOD_CHARACTERISTIC_UUID = "E95D386C251D470AA062FA1922DFA9A8";
public static String MAGNETOMETERBEARING_CHARACTERISTIC_UUID = "E95D9715251D470AA062FA1922DFA9A8";
このマイコン・ボードでは、NXPもしくはSTマイクロ(LSM303) のどちらかのデバイスが使われています。筆者のは表面の文字がMAGと読めたので、MAG3110と思われます。データシートを読むと、BEARINGは存在しないようです。
実際、オン・セミコンダクターのBLEであるRSL10 Bluetooth Low Enaergy Exploerを使って情報を見ると、BEARING(E95D9715251D470AA062FA1922DFA9A8)データは送られてきません。PERIODは固定された値(100)で、使いません。
したがって、DATAのnotifyを有効にすれば、どんどん磁気データを送ってくると推測できます。DATAの内容は、X、Y、Zの三つで、それぞれ16ビットです。上位バイト、下位バイトの構成で、2の補数形式であることが、データシートから読み取れます。ただし、ビッグ・エンディアンかリトル・エンディアンかどうかは、読んでみるまでわかりません。
Matlabの設定
matlabを動かしているPCでBluetoothが利用できるようにした状態でプログラムを作ります。
clear all
list = blelist("Timeout",10);
探してきます。BBC micro:bit[xxx]というlocal nameを見つけてくると思います。
b = ble("BBC micro:bit [gavag]");
bの内容を見ます。公式の情報のUUIDが見つかると思います。
Magnetometer_Service_UUID = "E95DF2D8-251D-470A-A062-FA1922DFA9A8"; % 磁力計サービス
Magnetometer_Characteristic_Data_UUID = "E95DFB11-251D-470A-A062-FA1922DFA9A8"; % 磁力データ
Magnetometer_Characteristic_Period_UUID = "E95D386C-251D-470A-A062-FA1922DFA9A8"; % 取得間隔
Magnetometer_Characteristic_Bearing_UUID = "E95D9715-251D-470A-A062-FA1922DFA9A8"; % 方角データ
利用するのは磁力データだけです。
% 磁力データ
c1 = characteristic(b, Magnetometer_Service_UUID, Magnetometer_Characteristic_Data_UUID);
fprintf('start');
subscribe(c1); % notify enable
送られてくるデータを表示し、ボードを微妙に動かします。
data1 = read(c1)
6桁のうち、1,3,5番目のデータが変化します。したがって、
x下位バイト、x上位バイト、y下位バイト、y上位バイト、z下位バイト、z上位バイト
の順番だと推測します。リトル・エンディアンでしたね。
x = double(bitor( bitshift(int16(data1(2)), 8) , (data1(1)) )) /1000;
y = double(bitor( bitshift(int16(data1(4)), 8) , (data1(3)) )) /1000;
z = double(bitor( bitshift(int16(data1(6)), 8) , (data1(5)) )) /1000;
このデコードで、uT単位の数値が得られます。
x = (double(data1(2)*256) + double(data1(1)) ) / 1000;
y = (double(data1(4)*256) + double(data1(3)) ) / 1000;
z = (double(data1(6)*256) + double(data1(5)) ) / 1000;
このデコードでもよいように思えますが、符号が消えてしまいました。シフトbitshiftを使ったほうは、最上位が'1'のとき、マイナスの数値になります。
この後の処理がわかっていません。X,Yから方向を導くようなのですが、当然、経度の補正や、オフセットの修正が必要です。さらにz軸の補正も必要ですが、特にz軸の補正方法の資料が見つかりません。資料が見つかれば、matlabの行列処理機能ですぐに補正ができそうです。
とりあえず、生データを使ってcompassグラフと、極座標へ変換した後のcompassグラフを描きました。
全体のソースです。
clear all
list = blelist("Timeout",20)
b = ble("BBC micro:bit [gavag]");
Magnetometer_Service_UUID = "E95DF2D8-251D-470A-A062-FA1922DFA9A8"; % 磁力計サービス
Magnetometer_Characteristic_Data_UUID = "E95DFB11-251D-470A-A062-FA1922DFA9A8"; % 磁力データ
Magnetometer_Characteristic_Period_UUID = "E95D386C-251D-470A-A062-FA1922DFA9A8"; % 取得間隔
Magnetometer_Characteristic_Bearing_UUID = "E95D9715-251D-470A-A062-FA1922DFA9A8"; % 方角データ
% 磁力データ
c1 = characteristic(b, Magnetometer_Service_UUID, Magnetometer_Characteristic_Data_UUID);
fprintf('start');
subscribe(c1); % notify enable
X = [];
Y = [];
Z = [];
U = [];
for i = 1:20
data1 = read(c1);
x = double(bitor( bitshift(int16(data1(2)), 8) , (data1(1)) )) /1000;
y = double(bitor( bitshift(int16(data1(4)), 8) , (data1(3)) )) /1000;
z = double(bitor( bitshift(int16(data1(6)), 8) , (data1(5)) )) /1000;
th = atan( y / x);
azimuth = 90- th;
%fprintf('%08s %08s %08s \n', dec2bin(x), dec2bin(y), dec2bin(z));
%fprintf('read x,y,z %.3f %.3f %.3f \n', x, y, z);
fprintf('read x,y,z %.3f %.3f %.3f || %.3f %.3f \n', x, y, z, th, azimuth);
pause(0.5);
X(i) = x;
Y(i) = y;
Z(i) = z;
U(i) = th;
%compass(x,y)
end
fprintf('done');
figure
compass(X,Y)
[theta,rho] = cart2pol(X,Y);
polarplot(theta,rho,'o');
pax = gca;
angles = 0:45:360;
pax.ThetaTick = angles;
labels = {'東','NE','北','NW','西','SW','南','SE'};
pax.ThetaTickLabel = labels;
clear b
通信を始めると、micro:bitのLEDは □ の表示になり、clear bを実行したらディスコネクトなので、× の表示に変わります。