본문 바로가기

Raspberry Pi

라즈베리파이 GPIO 활용강좌 : 안드로이드의 가속 센서를 이용한 RC카 제어(하)

출처 : http://cafe.naver.com/openrt/4718



라즈베리파이 GPIO 활용강좌 
안드로이드의 가속 센서를 이용한 RC카 제어(하)

Created Date: 2014.04.12
Modified Date: 2014.04.12
revision 1

 

 

지난 포스트 라즈베리파이 GPIO 활용강좌 : 안드로이드의 가속 센서를 이용한 RC카 제어(상)에서 안드로이드 AccelerometerPlayActivity를 실행해 보았다.
이번 포스트에서는 AccelerometerPlayActivity을 이용해 라즈베리파이의 GPIO를 제어해 보자.

 


아래는 최종 목표의 Software 구성도 이다.

swconfig src

  1. 라즈베리파이는 TCP 서버 프로그램으로 통신하고, JVM(Java Virtual Machine)에 pi4j 라이브러리를 사용하여 GPIO를 제어 하였다.
    이 프로그램은 [오로카 강좌] 라즈베리파이 활용 강좌 : 10. 안드로이드로 제어하는 라즈베리파이 무선 자동차를 참조하도록 하자.
  2. 다음으로, 안드로이드 기기는 Accelerometer(가속센서)의 값을 읽어들이는 Java기반 프로그램이며, 통신은 역시 TCP를 사용하여 라즈베리파이에 값을 전달하도록 하였다.
    이 프로그램은 AccelerometerPlayActivity에 [오로카 강좌] 안드로이드 기초 강좌 06. TCP를 이용한 원격 제어 (하)의 통신 부분을 ctrl+c, ctrl+v 해서 만들었다.

  3. 오로카 강좌의 TCP 통신 프로그램은 세개의 java 파일로 되어 있다. 
    1. teleopclient.java : Main File로 볼 수 있으며, 이벤트 발생이나 조건에 따라 Data를 만들고 rcvthread를 호출해 통신을 시작하는 작업을 한다.
    2. rcvthread.java :  수신한 Data를 TCP를 통해 라즈베리파이에 송신한다.
    3. logger.java : 현재 상태를 안드로이드 기기에 Text로 표시한다.

우리가 AccelerometerPlayActivity에 추가로 필요한 기능은 TCP통신을 하는 부분이다.
따라서, 위의 세 파일 중 2. rcvthread.java를 그대로 복사하고, 1.teleopclient.java를 참고하여 AccelerometerPlayActivity.java를 수정해보자.

 

2) 새로운 Class 추가하기

  1. AccelerometerPlayActivity Package에서 New->Class를 선택하자.

newClass 2014 04 14 00 18 38

 
2. New Java Class 팝업에서 Name: 항목에 “rcvthread”를 입력하고 Finish를 클릭한다.

newClasspop 2014 04 14 00 21 57

 
3. rcvthread.java 파일이 생성되었다. 여기에 추가할 rcvthread.java 파일의 내용을 복사하여 붙여넣기 하자.
아래와 같이 에러가 나는 부분이 있을 것이다.

rcvthread src

이는 logger.java 파일이 없어서 나는 에러로, 우리는 logger class를 사용하지 않을 것이므로, 삭제하도록 하자.


package com.example.android.accelerometerplay;

import java.io.IOException;

import java.net.Socket;

public class rcvthread implements Runnable {
     //[logger Deleted] private logger logger;
     private final int sizeBuf = 50;
     private int flag;
     private Socket socket;
     private String rcvData = "Error";
     private byte[] rcvBuf = new byte[sizeBuf];
     private int rcvBufSize;
     //[logger Deleted] public rcvthread(logger logger, Socket socket){
     public rcvthread(Socket socket){
         //[logger Deleted] this.logger = logger;
         flag = 1;
         this.socket = socket;
     }
     public void setFlag(int setflag) {
         flag = setflag;
     }
     public void run() {
         while(flag == 1){
             try{
                 rcvBufSize = socket.getInputStream().read(rcvBuf);
                 rcvData = new String(rcvBuf, 0, rcvBufSize, "UTF-8");
                 if (rcvData.compareTo("[close]")==0){
                     flag = 0;
                 }
                 //[logger Deleted] logger.log("Recive Data : " + rcvData);
             } catch (IOException e){
                 e.printStackTrace();
             }
         }
         //[logger Deleted] logger.log("Exit loop");
     }
}

 

3) TCP 통신 부분


1. TCP 통신을 하기 위해서는 간단하게,

  1. 서버-클라이언트가 접속하기 위한 작업
  2. 데이타를 송수신하는 작업
  3. 서버-클라이언트가 접속을 끊기 위한 작업

이상의 구조가 필요하다.  

2. 서버-클라이언트를 접속하기 위한 부분을 teleopclient.java에서 찾아서 AccelerometerPlayActivity.java에 connectingServer() 메소드를 만들었다.

void connectingServer(){
    try{
        if(socket!=null)
        {
            socket.close();
            socket = null;
        }
        socket = new Socket(server, port);
        outs = socket.getOutputStream();
        rcvThread = new Thread(new rcvthread(socket));
        rcvThread.start();
        //logger.log("Connected");
    } catch (IOException e){
        //logger.log("Fail to connect");
        e.printStackTrace();
    }
}

  
3. 서버-클라이언트의 접속을 끊기 위한 부분은 disconnectingServer() 메소드로 만들었다.

void disconnectingServer(){
    if(socket!=null)
    {
        exitFromRunLoop();
        try{
            socket.close();
            socket = null;
            //logger.log("Closed!");
            rcvThread = null;
        } catch (IOException e){
            //logger.log("Fail to close");
            e.printStackTrace();
        }
    }
}

4. 두 함수에서 사용되는 변수들을 정의하기 위해 AccelerometerPlayActivity 클래스 내부의 맨 앞부분에 다음을 추가하자.
<div style="TEXT-ALIGN: justify"><p class="txc-textbox" style="LIST-STYLE-TYPE: none; FONT-SIZE: 10px; BORDER-TOP: rgb(121,165,228) 1px dashed; FONT-FAMILY: 돋움; BORDER-RIGHT: rgb(121,165,228) 1px dashed; BORDER-BOTTOM: rgb(121,165,228) 1px dashed; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; PADDING-LEFT: 10px; BORDER-LEFT: rgb(121,165,228) 1px dashed; PADDING-RIGHT: 10px; BACKGROUND-COLOR: rgb(224,251,218)">private Socket socket;private String server = "192.168.0.14";private int port = 8888;private OutputStream outs;private Thread rcvThread;</p></div>
5. Socket 에러에 커서를 옮겨보면 import Socket으로 이 에러를 처리할 수 있다고 나온다. 클릭한다.

socketimporterror src

OutputStream도 동일하게 import 한다.

아래로 내려보면 IOExeption도 마찬가지.

exitFromRunLoop()는 참고하고 있는 teleopclient.java에 있다.
다시 가서 복사, 붙여넣기 하자.

 

지금까지 만든 세개의 메소드는

class SimulationView extends View implements SensorEventListener

라인 위에 추가하면 된다. 


 

6. 메소드를 만들었으니 이 메소드를 언제 사용할지 정하면 된다.

TCP 접속은 어플리케이션을 구동할 때(onCreate(),onResume()), TCP 차단은 어플리케이션이 중지될 때(onPause()) 사용한다.

각각의 onCreate(), onResume() 메소드 맨 아래에 다음과 같이 추가한다.

connectingServer();

 

onPause()의 맨 아래에는 disconnetingServer()를 추가한다. 

disconnectingServer();

 
7. 다음으로, 어떠한 조건에서 Data를 송신할지 결정해야 한다.

AccelerometerPlayActivity.java의 소스를 보면, 모든 변수의 기능, 메소드의 기능을 알면 좋겠지만, 그럴 필요도 없고(OOP가 그렇다.) 시간도 없다.

대충 둘러보니 onDraw가 있다. 메소드명에서 알 수 있듯이 화면에 그림을 그리기 위한 메소드이다.

센서의 값을 파악하여 값에 맞게 그림을 그려주고 있다.

우리는 그림이 그려지기 직전에 센서의 값이 30%를 넘어가면 전진/후진/좌/우 로 인식하도록 하자.

onDraw()에 추가되는 라인은 다음과 같다.

/*
* Send Communication Data
*/
String sndOpkey = "CMD";
if (sy&lt;-0.30) sndOpkey = "LeftTurn";
else if (sy&gt;0.30) sndOpkey = "RightTurn";
else if (sx&lt;-0.30) sndOpkey = "Up";
else if (sx&gt;0.30) sndOpkey = "Down";
else sndOpkey = "Stop";System.out.println(sndOpkey);
if(socket!=null){
    try{
        outs.write(sndOpkey.getBytes("UTF-8"));
        outs.flush();
    } catch (IOException e){
        System.out.println("Fail to send");
        e.printStackTrace();
    }}


8. 마지막으로, 필요한 부분에 System.out.println()으로 로그를 남기면 파악하기 쉬울 것이다. 


9. 실행을 해보면 에러가 난다. 에러의 내용은 권한이 없어서 socket을 열 수 없다는 것이다.

AndroidManifest.xml 파일의 맨 아래줄에 다음과 같이 권한을 넣어준다.

<uses -permission android:name="android.permission.INTERNET"></uses>


socketpermissionerror src

 

지금까지, 안드로이드 가속도센서로 라즈베리파이의 GPIO를 제어하는 법을 알아보았다.

아주 복잡하면서도 간단한 프로그램이라 생각된다.

간단한 구조와 기능만을 알기위한 프로그램이므로, 실제 사용하기에는 정말 짜증날 정도일 것이다.

아주 조금의 수정판이 github에 있으니 사용하도록하고, 아무쪼록 소스를 비교해가며 한가지라도 스킬이 늘었으면 하는 바램이다.
라즈베리파이 측 소스

$ git clone https://github.com/rasplay/raspberrypi_projects.git
$ cd raspberrypi_projects
$ cd smartphoneControl1
$ javac -classpath .:classes:/opt/pi4j/lib/'*' Racar.java
$ sudo java -classpath .:classes:/opt/pi4j/lib/'*' Racar

 

안드로이드 측 소스 

$ git clone https://github.com/rasplay/AccelerometerTCP.git

 



End.

written by Fendergold

이 저작물은 크리에이티브 커먼즈 저작자표시-비영리 3.0 Unported 라이선스에 따라 이용할 수 있습니다.

[출처] 라즈베리파이 GPIO 활용강좌

  1. #include<stdio.h>aaa
  2.  
  3. void main() {
  4. printf("aasdfasf\n");
  5. }
  6. #include<stdio.h>
  7.  
  8. void main() {
  9. printf("aasdfasf\n");
  10. }
  11. #include<stdio.h>
  12.  
  13. void main() {
  14. printf("aasdfasf\n");
  15. }
  16. #include<stdio.h>
  17.  
  18. void main() {
  19. printf("aasdfasf\n");
  20. }

 : 안드로이드의 가속 센서를 이용한 RC카 제어(하) (오픈소스 소프트웨어 & 하드웨어: 로봇 기술 공유 카페 (오로카)) |작성자 팬더골드