주사위 사용하기

01. 주사위 눈을 읽자

주사위를 던져 보드 게임을 해보자. 주사위를 사용하기 위해서는 그림 1과 같이 먼저 스마트 로봇 론처의 환경 설정 > 주변기기에서 주사위를 등록해야 한다. 각각의 주사위는 제품 번호로 구분되는데, 주사위의 제품 번호는 그림 1과 같이 등록할 때 표시된다(주사위 종류 #1).

그림 1. 주변기기 등록

주사위를 던져 나오는 눈을 읽는 프로그램을 작성하시오.

웹 페이지 만들기를 참고하여 안드로이드 프로젝트와 웹 페이지 파일을 만들고, onInitialized(robot) 콜백 함수와 onExecute() 콜백 함수를 만들자.

 <script type="text/javascript">

 function onInitialized(robot)
 {
 }

 function onExecute()
 {
 }
 </script>

주사위의 눈에 해당하는 디바이스로 EVENT_VALUE가 있다. 주사위의 윗면이 수직으로 위를 향하고 있을 때는 1부터 6까지의 값을 가지고, 주사위가 기울어져 있는 경우에는 -1부터 -6까지의 값을 가진다.

펜과 마찬가지로 Robot 객체의 findPeripheralDeviceById(productId, deviceId) 함수를 사용하여 필요한 디바이스의 객체를 얻을 수 있다. 디바이스 ID만으로는 어느 주사위의 디바이스인지 구분할 수가 없기 때문에 productId에 제품 번호를 넣어주어야 한다. 여기서는 제품 번호가 1인 경우라고 가정하자.

 <script type="text/javascript">

 var valueDevice;

 function onInitialized(robot)
 {
     valueDevice = robot.findPeripheralDeviceById(1, Dice.EVENT_VALUE); // 1번 주사위의 눈 디바이스
 }

 function onExecute()
 {
     var value = 0;
     if(valueDevice.e())
     {
         value = valueDevice.read();
     }
 }
 </script>

주사위 눈 디바이스는 이벤트 디바이스라는 것에 주의해야 한다. 이벤트가 발생하였을 때만 데이터가 갱신되기 때문에 데이터를 읽기 전에 반드시 Device 객체의 e() 함수를 사용하여 이벤트가 발생하였는지 확인해야 한다.

주사위를 살짝 놓으면 반칙이다. 주사위를 던졌다는 것은 어떻게 알 수 있을까? 다행히 주사위에는 자유 낙하 디바이스가 있어서 주사위를 던졌다는 것을 알 수 있다. 자유 낙하 디바이스로 EVENT_FALL이 있는데, 주사위를 던질 때마다 값이 1씩 증가한다.

 <script type="text/javascript">

 var valueDevice;
 var fallDevice;
 var fall = false;

 function onInitialized(robot)
 {
     valueDevice = robot.findPeripheralDeviceById(1, Dice.EVENT_VALUE);
     fallDevice = robot.findPeripheralDeviceById(1, Dice.EVENT_FALL);
 }

 function onExecute()
 {
     var value = 0;
     if(fallDevice.e())
     {
         fall = true;
     }
     if(fall)
     {
         if(valueDevice.e())
         {
             value = valueDevice.read();
         }
     }
 }
 </script>

자유 낙하 디바이스도 이벤트 디바이스인데, 값 자체는 중요하지 않다. 자유 낙하 이벤트가 발생하였는지만 확인하면 된다.

그런데, 한 가지 문제가 있다. 주사위를 던지면 데구르르 굴러가기 때문에 주사위 눈이 계속 바뀌게 된다. 어떻게 해결해야 할까? 주사위가 굴러가다가 멈추면 더이상 주사위 눈이 바뀌지 않을 것이다. 따라서 일정 시간동안 주사위의 눈이 바뀌지 않는지 확인하면 된다. 여기서는 1초동안 확인해 보자. 1초는 onExecute 메소드가 50번 호출되는 시간이다.

 <script type="text/javascript">

 var valueDevice;
 var fallDevice;
 var fall = false;
 var oldValue = 0;
 var count = 0;

 function onInitialized(robot)
 {
     valueDevice = robot.findPeripheralDeviceById(1, Dice.EVENT_VALUE);
     fallDevice = robot.findPeripheralDeviceById(1, Dice.EVENT_FALL);
 }

 function onExecute()
 {
     var value = 0;
     if(fallDevice.e())
     {
         fall = true;
         count = 0;
     }
     if(fall)
     {
         if(valueDevice.e())
         {
             value = valueDevice.read();
             if(value != oldValue)
                 count = 0;
             oldValue = value;
         }
         if(++ count > 50)
         {
             // 주사위가 멈추었다.
             count = 0;
             fall = false;
         }
     }
 }
 </script>

이번에는 onDeviceDataChanged(device, values, timestamp) 콜백 함수를 사용하여 구현해 보자.

 <script type="text/javascript">

 var fall = false;
 var oldValue = 0;
 var count = 0;

 function onExecute()
 {
     if(fall)
     {
         if(++ count > 50)
         {
             // 주사위가 멈추었다.
             count = 0;
             fall = false;
         }
     }
 }

 function onDeviceDataChanged(device, values, timestamp)
 {
     var value = 0;
     if(device.getProductId() == 1)
     {
         switch(device.getId())
         {
         case Dice.EVENT_FALL:
             fall = true;
             count = 0;
             break;
         case Dice.EVENT_VALUE:
             if(fall)
             {
                 value = values[0];
                 if(value != oldValue)
                     count = 0;
                 oldValue = value;
             }
             break;
         }
     }
 }
 </script>

Device 객체의 getProductId() 함수를 사용하여 제품 번호가 1인 경우인지 확인하였는데, 어느 주사위를 던져도 상관이 없다면 이 조건문은 없어도 된다.

02. 멀리 가면 안되요

주사위는 지그비 무선 통신으로 로봇에 데이터를 전달한다. 와이파이 존에서 멀어지면 통신이 안되듯이 주사위도 로봇에서 멀어지면 데이터를 전달하지 못한다.

지그비 신호 세기를 알아내는 프로그램을 작성하시오.

주사위에는 지그비 신호 세기에 해당하는 디바이스로 SENSOR_SIGNAL이 있다. 신호 세기는 0부터 255까지의 값을 가지는데 주사위가 로봇 가까이 있으면 신호 세기가 커져서 값이 증가하고, 멀어지면 신호 세기가 작아져서 값이 감소하게 된다.

 <script type="text/javascript">

 var signalDevice;

 function onInitialized(robot)
 {
     signalDevice = robot.findPeripheralDeviceById(1, Dice.SENSOR_SIGNAL);
 }

 function onExecute()
 {
     var signal = signalDevice.read();
 }
 </script>

이번에는 onDeviceDataChanged(device, values, timestamp) 콜백 함수를 사용하여 구현해 보자.

 <script type="text/javascript">

 function onDeviceDataChanged(device, values, timestamp)
 {
     var signal;
     switch(device.getId())
     {
     case Dice.SENSOR_SIGNAL:
         signal = values[0];
         break;
     }
 }
 </script>

03. 다른 센서는 없나요?

주사위에는 알버트 로봇과 마찬가지로 가속도 센서와 배터리 센서, 온도 센서가 있다. 각 센서의 값을 읽는 프로그램을 작성해 보자.

주사위의 가속도 센서에 해당하는 디바이스는 SENSOR_ACCELERATION이다. 3축 가속도 센서이므로 가속도 데이터는 크기 3의 배열로 되어 있으며, 각각 -8192부터 8191까지의 값을 가진다. 그림 2와 같이 가속도 센서의 X축은 주사위의 눈 2의 방향이 양수 값이고 반대 방향인 눈 5의 방향이 음수 값이다. Y축은 눈 3의 방향이 양수 값, 눈 4의 방향이 음수 값이며, Z축은 눈 1의 방향이 양수 값, 눈 6의 방향이 음수 값이다.

그림 2. 주사위의 가속도 센서 방향

주사위에 내장된 배터리의 상태를 알려 주는 센서 디바이스는 SENSOR_BATTERY이며, 0부터 100까지의 값을 가지고 배터리의 잔량을 %로 나타낸다. 주사위 내부의 온도를 알려 주는 온도 센서 디바이스는 SENSOR_TEMPERATURE이며, -40부터 88까지의 값을 가지고 온도를 섭씨(oC)로 나타낸다.

 <script type="text/javascript">

 var accelerationDevice;
 var batteryDevice;
 var temperatureDevice;

 function onInitialized(robot)
 {
     accelerationDevice = robot.findPeripheralDeviceById(1, Dice.SENSOR_ACCELERATION);
     batteryDevice = robot.findPeripheralDeviceById(1, Dice.SENSOR_BATTERY);
     temperatureDevice = robot.findPeripheralDeviceById(1, Dice.SENSOR_TEMPERATURE);
 }

 function onExecute()
 {
     var accelerationX = accelerationDevice.readAt(0);
     var accelerationY = accelerationDevice.readAt(1);
     var accelerationZ = accelerationDevice.readAt(2);
     var battery = batteryDevice.read();
     var temperature = temperatureDevice.read();
 }
 </script>

onDeviceDataChanged(device, values, timestamp) 콜백 함수를 사용하여 구현하면 다음과 같다.

 <script type="text/javascript">

 function onDeviceDataChanged(device, values, timestamp)
 {
     var acceleration = new Array(3);
     var battery;
     var temperature;
     switch(device.getId())
     {
     case Dice.SENSOR_ACCELERATION:
         acceleration[0] = values[0];
         acceleration[1] = values[1];
         acceleration[2] = values[2];
         break;
     case Dice.SENSOR_BATTERY:
         battery = values[0];
         break;
     case Dice.SENSOR_TEMPERATURE:
         temperature = values[0];
         break;
     }
 }
 </script>