유니티와아두이노를활용한 VR 컨트롤러개발 헬로앱스코딩교육 김영준 공학박사, 목원대학교겸임교수前 Microsoft 수석연구원 splduino@gmail.com http://www.helloapps.co.kr
목차 1. 툴설치 2. 아두이노컨트롤러개발실습 3. 유니티기본명령어실습 4. 유니티 VR 콘텐츠개발실습 5. 블루투스를이용한아두이노컨트롤러연동실습
SW 설치
SW 설치 Java SE (JDK) 설치 http://www.oracle.com/technetwork/java/javase/downloads/index.html Google Android Studio 설치 https://developer.android.com/studio/index.html 유니티설치 http://www.unity3d.com ( 회원가입후로그인필요 ) 아두이노코딩 SW 설치 ( 초보자 ) http://www.helloapps.co.kr/download ( 전문가 ) http://www.arduino.cc
아두이노컨트롤러개발실습
조이스틱연결하기 아날로그 0 번 아날로그 1 번 디지털 2 번 Y 축 X 축 버튼 아두이노보드
아두이노명령어 digitalwrite ( 핀번호, 값 ) d = digitalread( 핀번호 ) delay( 밀리초 ) a = map(a, 0, 1023, 0, 500) a = analogread( 핀번호 )
LED 점멸제어실습 void setup() void setup() pinmode(13, OUTPUT); 실습 ) LED 점멸간격을더짧게조절하기 void loop() DigitalWrite(13, HIGH) Delay(1000) DigitalWrite(13, LOW) Delay(1000) void loop() digitalwrite(13, HIGH); delay(1000); digitalwrite(13, LOW); delay(1000);
버튼값읽기 실습 ) 버튼이눌려지면 LED 켜기 void setup() void loop() d2 = DigitalRead(2) PrintLine(d2) Delay(100) void setup() pinmode(2, INPUT); Serial.begin(115200); void loop() int d2 = digitalread(2); Serial.println(d2); delay(100);
구구단출력하기 Print 와 PrintLine 명령어를이용하여다음과같이출력하시오 7 x 1 = 7 7 x 2 = 14 7 x 3 = 21 7 x 4 = 28 7 x 5 = 35 7 x 6 = 42 7 x 7 = 49 7 x 8 = 56 7 x 9 = 63 Print 와 PrintLine 명령어를이용하여원하는문자열을생성해낼수있어야함
조이스틱값읽기 void setup() void loop() x = AnalogRead(0) y = AnalogRead(1) Print(x) Print(" / ") PrintLine(y) Delay(100) void setup() Serial.begin(115200); void loop() int x = analogread(0); int y = analogread(1); Serial.print(x); Serial.print(" / "); Serial.println(y); delay(100); 조이스틱의 Y축 -> 아날로그 0번에연결조이스틱의 X축 -> 아날로그 1번에연결조이스틱을옆으로회전하여사용하기때문에프로그램에서는 X축과 Y축을변경하여사용 아날로그 0번아날로그 1번 Y축 X축 디지털 2 번 버튼
Map 함수를이용하여값변환하기 void setup() void loop() x = AnalogRead(0) y = AnalogRead(1) x = map(x, 0, 1023, -500, 500) y = map(y, 0, 1023, -500, 500) void setup() Serial.begin(115200); void loop() int x = analogread(0); int y = analogread(1); x = map(x, 0, 1023, -500, 500); y = map(y, 0, 1023, -500, 500); Print(x) Print(" / ") PrintLine(y) Delay(100) Serial.print(x); Serial.print(" / "); Serial.println(y); delay(100);
Map 함수를이용하여값변환하기 void setup() void setup() Serial.begin(115200); void loop() x = AnalogRead(0) y = AnalogRead(1) void loop() int x = analogread(0); int y = analogread(1); x = map(x, 0, 1023, -500, 500) y = map(y, 0, 1023, -500, 500) x = map(x, 0, 1023, -500, 500); y = map(y, 0, 1023, -500, 500); if (abs(x) < 30) x = 0 if (abs(y) < 30) y = 0 Print(x) Print(" / ") PrintLine(y) Delay(100) if (abs(x) < 30) x = 0; if (abs(y) < 30) y = 0; Serial.print(x); Serial.print(" / "); Serial.println(y); delay(100);
외부전송데이터생성하기 void loop() d = DigitalRead(2) x = AnalogRead(0) y = AnalogRead(1) void setup() pinmode(2, INPUT); Serial.begin(115200); <d,x,y> x = map(x, 0, 1023, -500, 500) y = map(y, 0, 1023, -500, 500) if (abs(x) < 30) x = 0 if (abs(y) < 30) y = 0 Print("<") Print(d) Print(",") Print(x) Print(",") Print(y) PrintLine(">") Delay(100) void loop() int d = digitalread(2); int x = analogread(0); int y = analogread(1); x = map(x, 0, 1023, -500, 500); y = map(y, 0, 1023, -500, 500); if (abs(x) < 30) x = 0; if (abs(y) < 30) y = 0; Serial.print("<"); Serial.print(d); Serial.print(","); Serial.print(x); Serial.print(","); Serial.print(y); Serial.println(">"); delay(100);
유니티기본명령어실습
3D 물체생성하기 Object Component Component Component Cube Transform Box Collider Mesh Renderer Component
물체제어하기 Scene_Main으로씬저장 Cube 오브젝트추가 Scripts 폴더생성 새로운 C# 스크립트생성 스크립트이름은 RotateObject 로수정 Cube 오브젝트에스크립트연결
물체제어하기 using System.Collections; using System.Collections.Generic; using UnityEngine; public class RotateObject : MonoBehaviour Transform TR; void Start () TR = transform; void Update () TR.Rotate( new Vector3(0, 1, 0) );
키보드로물체제어하기 ( 회전 ) using System.Collections; using System.Collections.Generic; using UnityEngine; public class RotateObject : MonoBehaviour Transform TR; void Start () TR = transform; using System.Collections; using System.Collections.Generic; using UnityEngine; public class RotateObject : MonoBehaviour Transform TR; void Start () TR = transform; void Update () float h = Input.GetAxis("Horizontal"); TR.Rotate(new Vector3(0, h, 0)); void Update () float h = Input.GetAxis("Horizontal"); float v = Input.GetAxis("Vertical"); TR.Rotate(new Vector3(v, h, 0));
키보드로물체제어하기 ( 이동 ) using System.Collections; using System.Collections.Generic; using UnityEngine; public class RotateObject : MonoBehaviour Transform TR; void Start () TR = transform; void Update () float h = Input.GetAxis("Horizontal"); float v = Input.GetAxis("Vertical"); TR.Rotate(new Vector3(0, h, 0)); TR.Translate(TR.forward * v);
에셋추가하기 유니티에셋스토어접속 Free Sci-Fi Textures 검색 Download 및설치
에셋추가하기 Plane 추가 바닥에텍스처추가 Cube 에텍스처추가
키보드로물체생성하기 Cube 오브젝트에서 RotateObject 스크립트제거 Cube 오브젝트에질량을추가해준다. 빈오브젝트생성 이름을 GameControlObject로수정 새로운 C# 스크립트생성 스크립트이름은 MainControlScript 로수정 빈오브젝트에스크립트연결
키보드로물체생성하기 public class MainControlScript : MonoBehaviour public GameObject CubeObject; void Start () void Update () if (Input.GetKeyDown(KeyCode.Space)) Instantiate(CubeObject, new Vector3(0, 5, 0), Quaternion.identity);
랜덤위치에물체생성하기 public class MainControlScript : MonoBehaviour public GameObject CubeObject; void Start () void Update () if (Input.GetKeyDown(KeyCode.Space)) float x = Random.Range(-10f, 10f); float z = Random.Range(-10f, 10f); Instantiate(CubeObject, new Vector3(x, 10, z), Quaternion.identity);
임의의방향으로떨어지도록하기 public class MainControlScript : MonoBehaviour public GameObject CubeObject; void Start () void Update () if (Input.GetKeyDown(KeyCode.Space)) float x = Random.Range(-10f, 10f); float z = Random.Range(-10f, 10f); float o_x = Random.Range(-45f, 45f); float o_y = Random.Range(-45f, 45f); float o_z = Random.Range(-45f, 45f); GameObject new_object = Instantiate(CubeObject, new Vector3(x, 10, z), Quaternion.identity); new_object.transform.eulerangles = new Vector3(o_x, o_y, o_z);
유니티 VR 콘텐츠개발실습
탄성기능추가 바닥에 RigidBody 컴포넌트추가 IsKinematic 선택
탄성기능추가 Asset -> Create -> Physical Materials 생성 Cube 와 Plane 에할당
일정한간격으로자동으로떨어지도록기능수정 public class MainControlScript : MonoBehaviour public GameObject CubeObject; float temp_time = 0; void Start () void Update () if ((Time.time - temp_time) > 1) temp_time = Time.time; float x = Random.Range(-10f, 10f); float z = Random.Range(-10f, 10f); float o_x = Random.Range(-45f, 45f); float o_y = Random.Range(-45f, 45f); float o_z = Random.Range(-45f, 45f); GameObject new_object = Instantiate(CubeObject, new Vector3(x, 10, z), Quaternion.identity); new_object.transform.eulerangles = new Vector3(o_x, o_y, o_z);
종료기능추가 public class MainControlScript : MonoBehaviour public GameObject CubeObject; float temp_time = 0; void Start () void Update () if ((Time.time - temp_time) > 1) temp_time = Time.time; float x = Random.Range(-10f, 10f); float z = Random.Range(-10f, 10f); float o_x = Random.Range(-45f, 45f); float o_y = Random.Range(-45f, 45f); float o_z = Random.Range(-45f, 45f); GameObject new_object = Instantiate(CubeObject, new Vector3(x, 10, z), Quaternion.identity); new_object.transform.eulerangles = new Vector3(o_x, o_y, o_z); if (Input.GetKeyDown(KeyCode.Escape)) Application.Quit();
실행파일빌드테스트 ( 윈도우버전 )
VR 세팅
AR 카메라추가
AR 카메라설정
AR 카메라설정
AR 카메라설정
안드로이드빌드하기
안드로이드배포하기 생성된 APK 파일을 USB 케이블로복사후설치 케이블이없는경우, 본인의이메일로파일배포후설치
블루투스를이용한아두이노 컨트롤러연동실습
아두이노보드에블루투스연결하기 아두이노보드의디지털 0 번과 1 번에각각블루투스 Rx, Tx 케이블을연결한다. GND 와 5V 케이블도아두이노의 GND 와 5V 핀에연결한다.
블루투스패키지설치하기 강사를통해배포된 HelloApps 블루투스커스텀패키지복사및설치 HelloAppsBT.unitypackage
블루투스패키지설치하기
블루투스패키지설치하기
블루투스패어링하기 안드로이드스마트폰에서블루투스켜기 장치추가한후, 아두이노에연결되어있는블루투스이름검색후추가 비밀번호는 1234 입력
블루투스디바이스이름추가하기 using UnityEngine; using System.Collections; public class BTBasicScript : MonoBehaviour string fromarduino = "" ; void Start () BtConnector.moduleName ("SPL V3 B0015"); BtConnector.connect(); void Update() if (Input.GetKeyDown(KeyCode.Escape)) BtConnector.close(); if (BtConnector.isConnected() && BtConnector.available()) fromarduino = BtConnector.readLine(); void OnGUI() GUI.Label(new Rect(0, 20, Screen.width, Screen.height*0.1f),"Arduino : " + fromarduino); GUI.Label(new Rect(Screen.width * 0.5f, 20, Screen.width, Screen.height * 0.1f), Status : " + BtConnector.readControlData());
디바이스연결테스트 앱빌드후배포 프로그램상단에연결및메시지정보표시되는지확인 아두이노보드전원재연결 앱실행
카메라이동과회전제어 using System.Collections; using System.Collections.Generic; using UnityEngine; public class BTControl_Sample_01 : MonoBehaviour public GameObject AR_Camera_Container; public GameObject Cube_Object; string fromarduino = ""; void Update() if (Input.GetKeyDown(KeyCode.Escape)) BtConnector.close(); if (BtConnector.isConnected() && BtConnector.available()) fromarduino = BtConnector.readLine(); Transform TR = null; void Start() TR = AR_Camera_Container.transform; BtConnector.moduleName("SPL V3 B0015"); BtConnector.connect(); if (fromarduino.startswith("<") && fromarduino.endswith(">")) string data = fromarduino.trimstart('<').trimend('>'); string[] arr = data.split(new char[] ',' ); string btn = arr[0]; float x = float.parse(arr[1]); float y = float.parse(arr[2]); x = x / 500f; y = y / 500f; TR.Translate(transform.forward * Time.deltaTime * y * 5); TR.Rotate(new Vector3(0, Time.deltaTime * x * -10, 0));
박스발사하는기능추가 using System.Collections; using System.Collections.Generic; using UnityEngine; public class BTControl_Sample_02 : MonoBehaviour public GameObject AR_Camera_Container; public GameObject AR_Camera; public GameObject Cube_Object; string fromarduino = ""; Transform TR = null; void Start() TR = AR_Camera_Container.transform; BtConnector.moduleName("SPL V3 B0015"); BtConnector.connect(); void Update() if (Input.GetKeyDown(KeyCode.Escape)) BtConnector.close(); if (BtConnector.isConnected() && BtConnector.available()) fromarduino = BtConnector.readLine(); if (fromarduino.startswith("<") && fromarduino.endswith(">")) string data = fromarduino.trimstart('<').trimend('>'); string[] arr = data.split(new char[] ',' ); string btn = arr[0]; float x = float.parse(arr[1]); float y = float.parse(arr[2]); x = x / 500f; y = y / 500f; TR.Translate(transform.forward * Time.deltaTime * y * 5); TR.Rotate(new Vector3(0, Time.deltaTime * x * -10, 0)); if (btn == "0") GameObject new_object = Instantiate<GameObject>(Cube_Object, TR.position, TR.rotation); Rigidbody rb = new_object.transform.getcomponent<rigidbody>(); rb.addforce(ar_camera.transform.forward * 1000);