磁気サンサー値から回転数 | おやじクリエイターがお小遣いで楽しむ工作室

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

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

ずっと考えていた 回転数 の出し方ですが、Unityが準備してくれている関数を使った方法に挑戦します。

 

 

  考え方

 

前回までの確認で、磁気センサーを回転させた時にセンサーからの出力値を使って北向きのベクトルを得られることが解ったので、Unity上で直前のフレームと今のフレーム間の「経過時間」と、ベクトルの差分から得た「角度」をもとに、回転数を算出します。

 

 

 

  2つのベクトル間の角度を求める

 

Unityに Vector3.Angle() という関数があるのでこれを今回使います。

 

 

 
 

  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 StreamWriter sw;
    private int i;
    private float d_time;
    private float k_time;
    private float ang;
    private float rpm;

    private Vector3 from_v; //前フレームのベクトル
    private Vector3 to_v;    //今のフレームのベクトル

    void Start()
    {
        port = new SerialPort("COM11", 38400, Parity.None, 8, StopBits.One);
        Debug.Log("start");

        port.NewLine = "\r\n";
        port.ReadBufferSize = 64;
        port.ReadTimeout = 50;
        port.Open();
        
        i = 0;
        d_time = 0.0f;
        k_time = 0.0f;

        from_v= new Vector3(0, 0, 0);
        to_v = new Vector3(0, 0, 0);
    }

    // Update is called once per frame
    void Update()
    {        

        if (port.IsOpen)
        {
            try
            {
                String data = port.ReadLine();
                string[] arr = data.Split(',');
                if (arr.Length == 3)
                {
                    cpx = float.Parse(arr[0]);
                    cpy = float.Parse(arr[1]);
                    cpz = float.Parse(arr[2]);

                    to_v= new Vector3(cpx, cpy, cpz); //センサー値でベクトルを作成
                    ang = Vector3.Angle(from_v, to_v);  //前と今のベクトルから角度を取得                                      
                    d_time = k_time + Time.deltaTime;
                    rpm = ang / d_time * 60 / 360;  //回転数(rpm)の計算

                    Debug.Log(i.ToString() + " :  " + data + " : ang= " + ang.ToString() + " deltatime= " + d_time.ToString() + " : " + rpm.ToString() + "RPM\r\n");
                    
                    System.Array.Resize(ref arr, 0);
                    i++;
                    k_time = 0.0f;
                    from_v = to_v;
                }
                else //センサー値取得失敗した場合
                {
                    k_time = k_time + Time.deltaTime;
                }
            }
            catch (TimeoutException)
            {
                k_time = k_time + Time.deltaTime;
            }
        }
    }   
}
 

 

  実行結果

 

プログラム起動後、センサー基板を1方向にだいたい1秒かけて180°回転させた結果です。

1秒間に180°なので、1分間だと10,800°(30回転)。

下記の結果をみると5~46rpmになっているので考え方は合っているようです。 

 

 

 

  考察

 

今回使った Vector3.Angle() という関数の戻り値は0°~180°の範囲です。

 

以前のブログ で調べたように、プロ野球投手が投げるボールの回転数の平均が2300rpmなので、きりがいいように2,400rpmとした場合、40回転/秒=14,400°/秒となり、最低でも180°÷14,400°/秒=0.0125秒毎にセンサー値をUnity側に取り込まなければなりません。

 

しかし、上記結果の deltatime(フレーム間の時間差分)をみると0.1秒前後かかっていることから、この方法を計測ボールのシステムとして使用することは残念ながらできません。

 

また別の方法を考えねば...

ではまた。