ご覧いただきありがとうございます。
子供のころからものづくりが好きな
50代のおじさんです。
「PICマイコン」を使った電子工作や、
「Unity」というゲームエンジンを使った
遊びについて書いています。
ものづくりで悪戦苦闘している様子を
見て行ってください。
前回、ボールをさばいて中にセンサー基板を入れました。
ボールからセンサー値が取得できるようになったので、それらの情報をどう調理して画面上で見せるかを考えていこうと思います。
磁気センサーのキャリブレーション
ジャイロセンサーと同様に
磁気センサーも測定値に誤差
を持っているので
補正を考えます
やり方をネットで調べたところ、
こちらの記事の考え方が
簡単そうだったので試してみます
Unityのスクリプトを編集し
ソフトを立ち上げた直後から
799回目まで取得したデータ
を基に補正値を決定します
(回数は適当。
も少し少なくてもよさげ)
この0~799回取得するまでの間
センサー入りのボールを
いろんな向きに回転させて
なるべく多くの向きでの値を
取り込むようにします
800回分のセンサー値から
X,y,zそれぞれについて
最大値と最小値を記録し
(最大値+最小値)÷2
したものを補正値とします
PIC側出力
センサー値とセンサー基板が
出力する何番目のデータかが
判るようにPICのコードを
変更しておきました
Unityスクリプト
using System.Collections;
using System.Collections.Generic;
using System.IO.Ports;
using System;
using UnityEngine;
using System.IO;
using System.Text;
public class Bluetooth_to_Unity : MonoBehaviour
{
private SerialPort port;
private float cpx, cpy, cpz;
private float rcpx, rcpy, rcpz;
private float x_max, y_max, z_max;
private float x_min, y_min, z_min;
private float difx, dify, difz;
private StreamWriter sw;
private int i;
private float num;
void Start()
{
port = new SerialPort("COM13", 9600, Parity.None, 8, StopBits.One);
Debug.Log("start");
port.NewLine = "\r\n";
port.ReadBufferSize = 64;
port.ReadTimeout = 50;
port.Open();
i = 0;
num = 0;
x_max = 0;
y_max = 0;
z_max = 0;
x_min = 0;
y_min = 0;
z_min = 0;
difx = 0;
dify = 0;
difz = 0;
rcpx = 0;
rcpy = 0;
rcpz = 0;
}
// Update is called once per frame
void Update()
{
if (port.IsOpen)
{
try
{
String data = port.ReadLine();
string[] arr = data.Split(',');
if (arr.Length == 8)
{
cpx = float.Parse(arr[1]);
cpy = float.Parse(arr[2]);
cpz = float.Parse(arr[3]);
num = float.Parse(arr[6]);
Debug.Log(i.ToString() + " num= " + num.ToString() + " cpx= " + cpx.ToString() + " cpy= " + cpy.ToString() + " cpz= " + cpz.ToString() + "\r\n");
//0~799回目までの取得データで補正値を決定
if (i < 800)
{
if (cpx < x_min) x_min = cpx;
if (cpx > x_max) x_max = cpx;
if (cpy < y_min) y_min = cpy;
if (cpy > y_max) y_max = cpy;
if (cpz < z_min) z_min = cpz;
if (cpz > z_max) z_max = cpz;
i++;
Debug.Log(i.ToString() + " xmax= " + x_max.ToString() + " ymax= " + y_max.ToString() + " zmax= " + z_max.ToString() + "\r\n");
Debug.Log(i.ToString() + " xmin= " + x_min.ToString() + " ymin= " + y_min.ToString() + " zmin= " + z_min.ToString() + "\r\n");
if (i == 800)
{
difx = (x_max + x_min) / 2.0f; //(最大値+最小値)÷2
dify = (y_max + y_min) / 2.0f;
difz = (z_max + z_min) / 2.0f;
}
return;
}
//取得値を800回分の補正値で補正
cpx = cpx - difx;
cpy = cpy - dify;
cpz = cpz - difz;
// transformを取得
Transform myTransform = this.transform;
// 2つのベクトルを定義
Vector3 vec1 = new Vector3(cpx, cpy, cpz); //今回取得した値
Vector3 vec2 = new Vector3(rcpx, rcpy, rcpz); //前回取得した値
// 2つのベクトルから回転クォータニオンを計算
Quaternion rotation = Quaternion.FromToRotation(vec1, vec2);
// オブジェクトを回転クォータニオンで回転
myTransform.rotation = rotation;
rcpx = cpx;
rcpy = cpy;
rcpz = cpz;
}
else //センサー値取得失敗した場合
{
}
}
catch (TimeoutException)
{
Debug.Log("取得失敗\r\n");
}
}
}
}
結果
キャリブレーションなしの場合
![UFO](https://stat100.ameba.jp/blog/ucs/img/char/char2/130.gif)
キャリブレーションありの場合
![ハッ](https://stat100.ameba.jp/blog/ucs/img/char/char3/104.png)
オブジェクトを回転させる
その後はセンサーの
読み取り値(北を指すベクトル)の
前回と今回、2つのベクトルから
回転クォータニオンを計算し
それをUnity画面上のオブジェクトに
与えて回転させます
ボールの回転に合わせて
画面上のオブジェクトにも
回転してほしいのですが
動きが全然リンク
してませんね
原因を調べます
ではまた
時間があればこちらもどうぞ