진동 액션

01. 장애물을 만나면 부르르~

스마트 폰으로 로봇을 조종할 때 장애물을 만나면 스마트 폰에 진동이 울리도록 해보자.

알버트 로봇이 전진하다가 앞에 장애물이 나타나면 정지하고 스마트 폰의 진동을 울리는 프로그램을 작성하시오.

로봇을 움직이기 위해 RobotActivity 클래스를 상속한 액티비티를 만들고, onInitialized(Robot) 메소드와 onExecute() 메소드를 상속받아 새로 구현하자. Activity 클래스의 onDestroy() 메소드도 상속받아 새로 구현하고, 프로젝트에 스마트 로봇 라이브러리를 포함하는 것을 잊지 않기를 바란다.

 public class SampleActivity extends RobotActivity
 {
     @Override
     public void onCreate(Bundle savedInstanceState)
     {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.main);
     }

     @Override
     public void onDestroy()
     {
         super.onDestroy();
     }

     @Override
     public void onInitialized(Robot robot)
     {
     }

     @Override
     public void onExecute()
     {
     }
 }

Vibration 액션의 객체를 얻기 위해서는 Action 클래스의 obtain(Context context, String actionId) 메소드에서 actionId에 Action.Vibration.ID를 입력하면 된다.

 public class SampleActivity extends RobotActivity
 {
     private Action mAction;

     @Override
     public void onCreate(Bundle savedInstanceState)
     {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.main);

         mAction = Action.obtain(this, Action.Vibration.ID); // 액션 객체를 얻는다.
     }

     @Override
     public void onDestroy()
     {
         super.onDestroy();

         mAction.deactivate(); // 액션을 중지한다.
         mAction.dispose(); // 액션을 폐기한다.
     }

     @Override
     public void onInitialized(Robot robot)
     {
     }

     @Override
     public void onExecute()
     {
     }
 }

onCreate(Bundle savedInstanceState) 메소드에서 액션을 얻고 onDestroy() 메소드에서 액션을 중지 및 폐기하였지만 어디에서 해도 상관은 없다. 애플리케이션을 종료하기 전에 액션을 모두 폐기하여야 한다는 것만 잊지 않도록 하자.

Vibration 액션에는 진동의 지속 시간을 나타내는 디바이스로 COMMAND_TIME이 있다. 진동의 지속 시간을 1000분의 1초 단위(ms)로 나타내며, 0부터 65535까지의 값을 가질 수 있다.

 public class SampleActivity extends RobotActivity
 {
     private Action mAction;
     private Device mTimeDevice;

     @Override
     public void onCreate(Bundle savedInstanceState)
     {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.main);

         mAction = Action.obtain(this, Action.Vibration.ID);
         mTimeDevice = mAction.findDeviceById(Action.Vibration.COMMAND_TIME);
         mTimeDevice.write(100); // 진동의 지속 시간을 쓴다.
     }

     @Override
     public void onDestroy()
     {
         super.onDestroy();

         mAction.deactivate();
         mAction.dispose();
     }

     @Override
     public void onInitialized(Robot robot)
     {
     }

     @Override
     public void onExecute()
     {
     }
 }

이제 알버트 로봇이 전진하다가 장애물을 만나면 진동을 울리도록 해보자.

 public class SampleActivity extends RobotActivity
 {
     private Action mAction;
     private Device mTimeDevice;
     private Device mLeftProximityDevice;
     private Device mRightProximityDevice;
     private Device mLeftWheelDevice;
     private Device mRightWheelDevice;

     @Override
     public void onCreate(Bundle savedInstanceState)
     {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.main);

         mAction = Action.obtain(this, Action.Vibration.ID);
         mTimeDevice = mAction.findDeviceById(Action.Vibration.COMMAND_TIME);
         mTimeDevice.write(100);
     }

     @Override
     public void onDestroy()
     {
         super.onDestroy();

         mAction.deactivate();
         mAction.dispose();
     }

     @Override
     public void onInitialized(Robot robot)
     {
         mLeftProximityDevice = robot.findDeviceById(Albert.SENSOR_LEFT_PROXIMITY);
         mRightProximityDevice = robot.findDeviceById(Albert.SENSOR_RIGHT_PROXIMITY);
         mLeftWheelDevice = robot.findDeviceById(Albert.EFFECTOR_LEFT_WHEEL);
         mRightWheelDevice = robot.findDeviceById(Albert.EFFECTOR_RIGHT_WHEEL);
     }

     @Override
     public void onExecute()
     {
         int leftProximity = mLeftProximityDevice.read();
         int rightProximity = mRightProximityDevice.read();
         if(leftProximity > 50 || rightProximity > 50)
         {
             mLeftWheelDevice.write(0);
             mRightWheelDevice.write(0);
             mAction.activate(); // 액션을 시작한다.
         }
         else
         {
             mLeftWheelDevice.write(20);
             mRightWheelDevice.write(20);
         }
     }
 }

프로그램을 실행하고 앞으로 달려가는 알버트 로봇의 앞을 손으로 막으면 전방 센서의 값이 50보다 커져서 알버트 로봇이 정지하고 스마트 폰의 진동이 울릴 것이다.

02. 후진합니다. 비켜 나세요.

장애물을 만나면 뒤로 후진하면서 뚜뚜뚜 빠르게 진동을 울리도록 해보자. 대신, 전진할 때는 알버트 로봇의 심장 박동을 진동으로 표현하도록 하자.

알버트 로봇이 전진할 때는 진동을 천천히 울리고, 앞에 장애물이 나타나면 후진하면서 빠르게 진동을 울리는 프로그램을 작성하시오.

앞에서 작성한 프로그램을 약간 수정하면 되는데, 진동을 계속 울리는 것이 아니라 뚜뚜뚜 울리도록 하기 위해서는 진동 패턴을 만들어야 한다.

두 가지 진동 패턴이 있기 때문에 진동 액션을 두 개 얻어서 경우에 따라 다른 액션을 시작하면 된다고 생각할 수 있지만 같은 ID를 가진 액션은 여러 개 만들 수 없다. 따라서 전진할 때와 후진할 때 진동 패턴만 다르게 주면 된다.

또한 액션이 시작되어 실행되고 있는 중에 activate() 메소드를 호출하면 액션이 다시 시작되므로 플래그를 두어 다시 시작되지 않도록 하자.

 public class SampleActivity extends RobotActivity
 {
     private Action mAction;
     private Device mPatternDevice;
     private Device mRepeatDevice;
     private Device mLeftProximityDevice;
     private Device mRightProximityDevice;
     private Device mLeftWheelDevice;
     private Device mRightWheelDevice;
     private boolean mForward;

     @Override
     public void onCreate(Bundle savedInstanceState)
     {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.main);

         mAction = Action.obtain(this, Action.Vibration.ID);
         mPatternDevice = mAction.findDeviceById(Action.Vibration.COMMAND_PATTERN);
         mRepeatDevice = mAction.findDeviceById(Action.Vibration.COMMAND_REPEAT);
         mRepeatDevice.write(0); // 패턴의 처음부터 반복한다.
     }

     @Override
     public void onDestroy()
     {
         super.onDestroy();

         mAction.deactivate();
         mAction.dispose();
     }

     @Override
     public void onInitialized(Robot robot)
     {
         mLeftProximityDevice = robot.findDeviceById(Albert.SENSOR_LEFT_PROXIMITY);
         mRightProximityDevice = robot.findDeviceById(Albert.SENSOR_RIGHT_PROXIMITY);
         mLeftWheelDevice = robot.findDeviceById(Albert.EFFECTOR_LEFT_WHEEL);
         mRightWheelDevice = robot.findDeviceById(Albert.EFFECTOR_RIGHT_WHEEL);
     }

     @Override
     public void onExecute()
     {
         int leftProximity = mLeftProximityDevice.read();
         int rightProximity = mRightProximityDevice.read();
         if(leftProximity > 50 || rightProximity > 50)
         {
             mLeftWheelDevice.write(-20);
             mRightWheelDevice.write(-20);
             if(mForward)
             {
                 mForward = false;
                 mPatternDevice.write(new int[] { 0, 100, 100 }); // 빠른 진동 패턴을 쓴다.
                 mAction.activate();
             }
         }
         else
         {
             mLeftWheelDevice.write(20);
             mRightWheelDevice.write(20);
             if(!mForward)
             {
                 mForward = true;
                 mPatternDevice.write(new int[] { 0, 100, 1000 }); // 느린 진동 패턴을 쓴다.
                 mAction.activate();
             }
         }
     }
 }