回って回って回って回~らんのかい! | おやじクリエイターがお小遣いで楽しむ工作室

おやじクリエイターがお小遣いで楽しむ工作室

趣味のことを中心に書きます。

 

 

 ご覧いただきありがとうございます。ニコニコ

 

 子供のころからものづくりレンチが好きな

 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
 
 
 
 

キャリブレーションありの場合

 

 
ボールを置いたら
ピタッハッと止まります
 
 
 

   オブジェクトを回転させる

 

 その後はセンサーの

読み取り値(北を指すベクトル)の

前回と今回、2つのベクトルから

回転クォータニオンを計算し

それをUnity画面上のオブジェクトに

与えて回転させます

 

 

 

 

ボールの回転に合わせて

画面上のオブジェクトにも

回転してほしいのですが

動きが全然リンク

してませんね ショボーン

 

原因を調べます

ではまた

 

 

時間があればこちらもどうぞ