2015. 5. 15. 15:00

C#의 구조가 자바랑 비슷해서 그런 것인지 자마린 컨샙이 안드로이드가 베이스인지는 모르겠습니다.

이게 IOS에서도 그대로 적용되는 것인지 모르겠네요.

 

어찌 됐건 자마린을 이용하여 안드로이드의 센서값을 가지고 오는 것은 안드로이드 어플리케이션과 비슷합니다.

(참고 : Xamarin Recipes - Get Accelerometer Readings)

 

 

1. 센서값 받아오기 테스트

 

안드로이드와 같은 방법으로 가지고 올 수 있습니다.

먼저 메인 엑티비티에 'ISensorEventListener'인터페이스를 추가합니다.

public class MainActivity : Activity, ISensorEventListener

 

 

이제 클래스 안에 센서 매니저를 선언하고 'OnCreate'안에서 초기화해줍니다.

/// <summary>
/// 센서 메니저
/// </summary>
private SensorManager m_SM;

protected override void OnCreate(Bundle bundle)
{
	base.OnCreate(bundle);

	// Set our view from the "main" layout resource
	SetContentView(Resource.Layout.Main);

	//센서메니저 세팅
	m_SM = (SensorManager)GetSystemService(Context.SensorService);
}

 

 

다음 메소드들을 오버라이드 해줍니다.

OnResume

OnPause

 

다음 메소드는 추가합니다.

OnAccuracyChanged

OnSensorChanged

public void OnAccuracyChanged(Sensor sensor, SensorStatus accuracy)
{
}

public void OnSensorChanged(SensorEvent e)
{
}

protected override void OnResume()
{
	base.OnResume();
}

protected override void OnPause()
{
	base.OnPause();
}

 

 

'OnResume'과 'OnPause'를 통해 어플리케이션이 동작 중에만 센서리스너가 동작하도록 작성합니다.

이때 읽어들이 센서의 타입과 딜레이를 지정합니다.

(여기선 가속도계를 사용할 것이니 'Accelerometer'를 지정합니다.)

protected override void OnResume()
{
	base.OnResume();
	m_SM.RegisterListener(this, m_SM.GetDefaultSensor(SensorType.Accelerometer), SensorDelay.Ui);
}

protected override void OnPause()
{
	base.OnPause();
	m_SM.UnregisterListener(this);
}

 

 

이제 'OnSensorChanged'의 매개변수인 'SensorEvent e'를 통해 센서의 데이터를 가지고 올 수 있습니다.

public void OnSensorChanged(SensorEvent e)
{
	lock (m_objSyncLock)
	{
		//e.Values[0], e.Values[1], e.Values[2]를 통해 x, y, z값을 가지고 올 수 있습니다.
	}
}

 

 

2. 사용 가능한 센서 타입

'SensorType'에 있는 센서는 사용할 수 있습니다.

 

(참고 : Xamarin APIs - Android.Hardware.SensorType Enumeration)

 

Accelerometer 가속도계 가속도계 센서값
0 : x
1 : y
2 : z
All 전체 센서 모든 센서를 의미 합니다.
AmbientTemperature 주위 온도 주위 온도 센서.
(기계 밖온도)
GameRotationVector 게임 회전 방위 자기장을 사용하지 않은 방위.
GeomagneticRotationVector 지자기 회전 방위 자기장을 사용하는 방위.
Gravity 중력 중력 센서
Gyroscope 자이로스코프 자이로스코프
0 : x
1 : y
2 : z
GyroscopeUncalibrated 보정되지 않은 자이로스코프 자이로 드리프트 교정이 없는 자이로스코프
0 : x
1 : y
2 : z
HeartRate 심장박동  
Light  
LinearAcceleration 선형 가속  
MagneticField 자기장  
MagneticFieldUncalibrated 보정되지 않은 자기장 외부에 의한 자기장외곡(자석등에 의한..)을 보정 하지 않는다.
Orientation 방향  
Pressure 압력  
Proximity 근접  
RelativeHumidity 상대 습도  
RotationVector 회전 방위  
SignificantMotion 중요 모션  
StepCounter 단계 카운터  
StepDetector 단계 감지기  
Temperature 온도(내부 온도인듯?)  

 

 

p.s. 안드로이드 문서와 비교해서 확인하고 테스트해야 하는데......일단 시간이 없으니 리스트만 적어둡니다.

 

 

3. 필터

센서에서 읽어들인값은 노이즈(값이 흔들리는(?) 현상)이 있습니다.

읽은 값으로 포인트를 이동하게 해보면 확실하게 티가 납니다.

 

 

이런 값을 일정한 값으로 사용하기 위해 보정을 해야 하는데 이때 사용하는 것이 필터입니다.

 

안드로이드는 어느 정도 교정된 값이 넘어오기 때문에 넘어온 값을 확인하고 적절한 필터를 적용하면 됩니다.

(안드로이드는 'GyroscopeUncalibrated'의 항목에 있는 자이로 드리프트 같은 현상을 보정하여 값을 넘겨 줍니다. 하드웨어를 직접 다룰 때는 이런 현상을 직접 보정해야 합니다.)

 

보통 칼만필터를 많이 사용하는데 그건 다른 포스팅에서 설명하도록 하고 간단하게 사용할 수 있는 평균값으로 처리하겠습니다.

값을 쌓아둘 클래스를 만듭니다.

class claSensorData
{
	public float X { get; set; }
	public float Y { get; set; }
	public float Z { get; set; }

	public claSensorData()
	{
		this.X = 0;
		this.Y = 0;
		this.Z = 0;
	}

	public claSensorData(float x, float y, float z)
	{
		this.X = x;
		this.Y = y;
		this.Z = z;
	}

	/// <summary>
	/// 설정한 데이터를 더합니다.
	/// </summary>
	/// <param name="gyroData"></param>
	public void AddData(claSensorData gyroData)
	{
		this.X += gyroData.X;
		this.Y += gyroData.Y;
		this.Z += gyroData.Z;
	}

	public override string ToString()
	{
		return string.Format("x = {0}, y = {1}, z = {2}"
								, this.X.ToString("F3").PadLeft(6)
								, this.Y.ToString("F3").PadLeft(6)
								, this.Z.ToString("F3").PadLeft(6));
	}
}

 

 

이제 위 클래스를 사용하여 평균을 내는 클래스를 만듭니다.

class claDataAverage
{
	/// <summary>
	/// 평균을 낼 리스트에 쌓아둘 최대 갯수
	/// </summary>
	public int ListMaxCount { get; set; }

	/// <summary>
	/// 평균을 낼 데이터원본
	/// </summary>
	private List<claSensorData> m_listGyroData
		= new List<claSensorData>();

	/// <summary>
	/// 계산이 완료된 평균값
	/// </summary>
	public claSensorData AverageComplete { get; private set; }


	private void Reset()
	{
		this.m_listGyroData.Clear();

		claSensorData insTemp = new claSensorData(0f, 0f, 0f);

		//초기값을 넣어 준다.
		for (int i = 0; i < this.ListMaxCount; ++i)
		{
			this.m_listGyroData.Add(insTemp);
		}

		this.AverageComplete = new claSensorData(0f, 0f, 0f);
	}


	public claDataAverage(int nListMaxCount = 10)
	{
		ListMaxCount = nListMaxCount;

		this.Reset();
	}

	/// <summary>
	/// 데이터를 추가 합니다.
	/// </summary>
	/// <param name="x"></param>
	/// <param name="y"></param>
	/// <param name="z"></param>
	public void Data_Add(float x, float y, float z)
	{
		//맨 첫데이터를 지운다.
		this.m_listGyroData.RemoveAt(0);

		//데이터를 추가 한다.
		this.m_listGyroData.Add(new claSensorData(x, y, z));
	}

	public claSensorData AverageData()
	{
		claSensorData gyroReturn = new claSensorData();

		foreach (claSensorData gyroTemp in this.m_listGyroData)
		{
			gyroReturn.AddData(gyroTemp);
		}

		//더한값을 리스트갯수 만큼 나눈다.
		gyroReturn.X /= this.ListMaxCount;
		gyroReturn.Y /= this.ListMaxCount;
		gyroReturn.Z /= this.ListMaxCount;

		this.AverageComplete = gyroReturn;

		return this.AverageComplete;
	}
}

 

이제 'claDataAverage.Data_Add'를 이용하여 데이터를 넣고 ''claDataAverage.AverageData'를 호출하여 쌓여있는 데이터의 평균을 가지고 올 수 있습니다.

 

 

 

마무리

사실 이 포스팅의 내용은 안드로이드의 내용과 같다고 볼 수 있습니다.

단지 자마린에서는 C#의 모양에 가깝게 되어 있어서 정리를 한것이죠 ㅎㅎㅎㅎ

Sensor_Test.zip
다운로드