레이블이 Android인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Android인 게시물을 표시합니다. 모든 게시물 표시

2016년 7월 26일 화요일

[android] RecyclerView 에서의 setOnItemClickListener (흉내내기)

[개요]


RecyclerView는 ListView에서의 비효율적인 리스트 아이템 생성과 같은 점을 극복하고자 좀 더 유연하고 좀 더 효율적으로 사용되기 위해 만들어졌다고 합니다.
RecyclerView이 만들기 이전에도 ListView에서 ViewHolder개념을 응용? 도입? 해서 효율적으로 사용하였지만 RecyclerView에선 강제적으로 사용하게 되었다고 합니다.

하지만 Listview에서 setOnItemClickListener 와 같은 기능을 지원하지 않습니다.  addOnItemTouchListener와 같은 기능이 있지만 listview에서와 같이 직접적으로 position에 접근을 할 수 없고 여러 이슈가 있다고 합니다.

[흉내내보자]


RecyclerView에서 onBindViewHolder해줄 때에 각각의 아이템에 OnClickListener를 등록해 주는 것으로 접근했습니다.
코드는 핵심적인 부분만 중략해서 작성했습니다.


public class RecyclerAdapter extends RecyclerView.Adapter{
    private ArrayList strings;

    //아이템 클릭시 실행 함수
    private ItemClick itemClick;
    public interface ItemClick {
        public void onClick(View view,int position);
    }

    //아이템 클릭시 실행 함수 등록 함수
    public void setItemClick(ItemClick itemClick) {
        this.itemClick = itemClick;
    }

    public static class ViewHolder extends RecyclerView.ViewHolder{
        View view;
        public ViewHolder(View view) {
            super(view);
            this.view = view;
        }
    }

    @Override
    public RecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                         int viewType) {
        // create a new view
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.list_items, null);
        ViewHolder vh = new ViewHolder(v);

        return vh;
    }


    //중략 ...................

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        final int Position = position;
        //중략 ...................
        holder.view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(itemClick != null){
                    itemClick.onClick(v, Position);
                }
            }
        });
    }
    //중략 ...................

}


adapter 부분에서 이와 같은 방식으로 작성하였습니다.
이후에 recycler 호출부분에서 아래와 같이 작성한다면, listview에서 setOnItemClickListener 와같이 작동할 수 있습니다.

        mAdapter.setItemClick(new RecyclerAdapter.ItemClick() {
            @Override
            public void onClick(View view, int position) {
                //클릭시 실행될 함수 작성
            }
        });

코드가 길어져 상당히 중략을 하였습니다.

제가 작성한 예제 코드는
안드로이드 스터디 프로젝트 git에 공유하고 있습니다.

2015년 11월 16일 월요일

안드로이드 http통신 retrofit 2.0

retrofit은 http통신모듈로서 android에서 많이 사용한다고 합니다.

  • 파싱 & value object로의 변환이 편하고
  • template 방식으로의 사용
  • 동기 & 비동기 지원

의 장점을 뽑을 수 있을 것 같습니다.
spring framework를 공부하면서 동시에 개발하고 있는데 사용방식이 많이 유사함이 느껴집니다.

2.0을 기준 입니다.

저의 환경으로는  json으로 서버와 값을 주고 받게 됩니다.

기본적인 튜토리얼은 http://square.github.io/retrofit/ 를 참고했습니다.

먼저 라이브러리 추가. (GRADLE)


compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
//json파싱을 위한 주입
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
//xml파싱을 위한 주입
compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta1'

value object 작성

public class test {
    private String ret;

    public String getRet() {
        return ret;
    }

    public void setRet(String ret) {
        this.ret = ret;
    }
}

Service작성


public interface TestService {
    @FormUrlEncoded
    @POST("/test")
    public Call<test> retroTest(@Field("param") String aa);
}


어노테이션을 몇개 정리.
@POST("상세주소")를 이용하여 상세 주소를 설정합니다.
@GET/PUT/DELETE등도 사용가능합니다.
@HEARs를 이용해서 헤더 설정도 가능하고

@FormUrlEncoded을 사용하여 x-www-form-urlencoded를 설정하고
@Multipart를 이용한 파일전송 등도 설정 가능합니다.

동기/비동기 방식이 1.9버전에서는 선언하는 방식이 서로 달랐는데 2.0버전에서는 두가지의 차이가 없습니다. 사용에 따라서 동기/비동기가 나눠지는데 아래 설명하겠습니다.


Service생성 및 반환

public class repo {
    public TestService getService(){
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://192.168.25.24:8080")
                .addConverterFactory(GsonConverterFactory.create())
//              .addConverterFactory(SimpleXmlConverterFactory.create())
                .build();
        TestService service =  retrofit.create(TestService.class);
        return service;
    }
}

baseUrl을 설정하고, 저는 json만을 사용하기 때문에 GsonConverterFactory만 설정하였고 xml을 사용하시려면 SimpleXmlConverterFactory까지 설정 하시면 됩니다.

getService()를 이용하여 TestService에 대한 설정,생성,반환을 받습니다.

동기방식 사용

String result = null;
TestService service = new repo().getService();
Call<test> c = service.retroTest("aa");
try {
    result = c.execute().body().getRet();
} catch (IOException e) {
    e.printStackTrace();
}
위 방식은 동기방식 입니다. Call<test>를 받은 이후 실행(execute) -> 결과(body)를 하게 되면 위의 결과는 test객체에 담겨져 오게 됩니다.

비동기방식 사용

final String[] result = {null};
TestService service = new repo().getService();
Call<test> c = service.retroTest("aa");
c.enqueue(new Callback() {

    @Override
    public void onResponse(Response response, Retrofit retrofit) {
        result[0] = response.body().getRet();
    }

    @Override
    public void onFailure(Throwable t) {
        result[0] = "false";
    }
});
위 방식은 비동기방식 입니다. Call<test>를 받은 이후 enqueue를 통해 구현합니다.
onResponse를 통하여 결과값을 받을 때 처리, 즉 callback방식으로의 처리를 하게 됩니다.

위의 방법으로 안드로이드(또는 다른 java플렛폼)에서 사용을 간단하게 http통신을 하게 됩니다.

2014년 5월 17일 토요일

Android+COCOS2D-x 3.0 개발환경 구성하기

진짜 욕나오는 cocos2d 환경 구성하기. 걍 따라하시면 됩니다....

하기전에.....잡담.. 생략하셔도 됩니다.
우선 저의 안드로이드 테스트까지의 파란만장한 시도를 떠들자면... 눈물이 나네요 ㅠ
먼저 cocos2d-x는 버전이 여러가지 있습니다. 비교적 쉬운 플랫폼이라길래 인터넷에서 잘 올라온 과정을 따라할려고 했죠. 2.2.1버전을 설치를 하였는데 과정이 장난 아니더군요. 하지만 막상 작업을 하려고 하니 아는건 쥐뿔도 없고 아래 화면만 보게 되더군요.
그래서 이왕 시작한거 책을 구매하였습니다. 책을 찾아보니 대부분 3.0버전을 기준으로 하였고 지금 2.2.3버전을 많이 쓴다지만 좋은 플렛폼일수록 높은 버전에 대한 준비와 배움이 필요하기에 그렇게 3.0버전을 기준으로 한 책을 샀습니다. 그래도 나름 2.2.1버전을 설치해 봤다고 책에 나온 과정을 무시하고 제 멋대로 설치한 결과!.. 예제가 실행이 안되다니......... 
알고보니 2.2.1에서 빈프로젝트를 template\multi-platform-cpp\proj.win32를 이용하여 실행하면 됬지만, 3.0에서는 \build에 찾아서 실행을 해야 하는 거였습니다. 결국 위와 같은 화면을 다시 보게 되었죠.
이게 끝이 아닌게, 빌드폴더의 파일을 가지고 작업을 하는 것이 아니라 프로젝트 생성을 하고 그걸 이용하여 작업을 해야하는데 책에 나온 create_project.py라는 파일이 없.............
버전이 달라서 없답니다. 같은 3.0기준인데? 책은 정확히 3.0beta2를 기준으로 했더군요. 그래서 다시 3.0beta2로 ㄱㄱ~
이게 끝이 아닙니다. 프로젝트 생성까지 성공했습니다. 근데? 안드로이드 설치가 안되더군요. 해외 페이지까지 해석해가며 내린 결론은. 3.0 다시 설치하기. 그래서 다시 3.0으로 ㄱㄱ
하지만 3.0에는 create_project.py에 대한 부분은 cocos2d 홈페이지에서 자세히 나와 있어서 다시만난 난관이였지만 해결.. 할 뻔했는데?
아...아...아...아...아...아...아...
. 상식적으로 높은 버전은 하위 버전을 포용하는데 3.0버전으로 프로젝트를 생성할 경우 python 2.7버전이 필요하다는 군요. 2010년도에 나온 버전인데... 최신은 3.4버전인데 ㅡㅡ;;
이틀을 삽질하고(물론 별것도 아닌거 가지고 스스로 삽질한 것도 있지만..) 다른 분들은 이러한 피해를 입지 않도록 cocos2d-x 3.0 (beta버전 아님) 개발 환경 구성하기 포스팅을 해보려 합니다.

전체적인 준비물
  1. java SE
  2. eclipse
  3. ADK plugin
  4. NDK
  5. 비주얼스튜디오 2012 이상
  6. Cocos2d-x
  7. python (2.7 *중요)

1. 설치


우선 사용하는 저의 개발 환경은  Window x64 를 사용합니다.

자바 환경 구성을 순서로 나열한다면
  1. Java SE JDK 다운로드
  2. Java 환경 변수 설정하기(Path 설정)
로 나눌 수 있습니다.

1. Java SE 다운로드 하기



Java SE JDK를 다운로드하기 위해서는 오라클 홈페이지로 접속하여 DownLoad를 찾고 Java for Develpoers를 찾습니다.



좌측에 보면 Java SE, EE, ME 등등 여러가지가 있습니다. 이것들을 자바 가상머신의 플랫폼들인데 대표적으로  Java SE,EE,ME로 나누어집니다. SE는 Standard Edition이란 흔히 PC라 불리우는 기기에서의 자바 플랫폼 '표준'입니다. 때문에 JVM의 모든 기능을 지원하고 API를 포함하고 있습니다.
 EE는 Enterprise Edition의 약자입니다. EE는 서버측을 위한 자바 플랫폼으로서 대부분 서버측의 역활은 기업이 맡아왔기 때문에 Enterprise란 용어가 붙은 듯 싶네요.
 ME는 Mobile Edition, 즉 모바일 기기를 위한 플랫폼으로 휴대폰 뿐만 아니라 소형 임베디드 기기, PDA, 셋톱박스 등을 지원합니다.
 안드로이드, Java를 하기 위해선 SE를 필요로 하고 하나의 서버를 두고 통신을 하게 만들려면 EE 또한 필요하게 될 것입니다. 안드로이드는 Java ME을 기반으로 만든 것이 아니고 달빅 가상 머신을 통해 자바로 작성된 운영체제이기 때문에 ME가 아닌 SE를 필요로 한다고 합니다. 

버전 별로 지원하는 것과 지원하지 않는 것들이 다르기 때문에 신중히 선택하여 다운로드 해야 하지만 나는 큰 영향이 없을 것으로 예상하기 때문에 가장 최신 버전으로 다운로드 할 것입니다.
 파란테두리를 클릭하여 JDK 다운로드 페이지로 이동하고
 자신의 운영체제에 맞는 JDK를 다운로드&설치를 진행하면 되겠습니다.

2.Java 환경변수 설정하기

사실 Java 환경 변수를 설정하지 않아도 실행하는 데에는 아무런 문제가 되지 않지만 실행할 파일이 java가 설치된 폴더안에 있지 않으면 Full Path를 입력을 하거나 실행이 되지 않습니다. Path 변수를 설정함으로서 컴퓨터 어떠한 곳이라도 Java프로그램을 접근할 수 있도록 할수 있습니다.

크게 Path,ClassPath와 Java_HOME을 설정을 하게 됩니다. 설정은 GUI환경에서 쉽게 할수 있게 되어있습니다. 저를 기준으로 Window7에서는

'컴퓨터' 우 클릭 ->
고급 시스템 설정 ->
환경 변수 ->


이렇게 찾아오시면 됩니다.


설정을 해야하는 것은 Java_Home,CLASSPATH,Path 이렇게 3가지입니다. 각각을 설명하자면 Path는 앞서 설명한 것처럼 Java가 설치된 경로를 설정함으로서 Java의 프로그램들을 접근하기 위해 설정을 하고, CLASSPATH는 폴더나 파일을 설정하여 그 경로에 있는 Class또는 설정된 파일의 Class파일을 호출하여 사용할 수 있도록 합니다. Java_Home은 다른 어플리케이션들이 Java를 이용할 떄에 JAVA_HOME이라는 환경변수를 참조하기 때문에 설정을 하게 됩니다.

윗 부분에 해당하는 사용자 변수 부분에서 '새로 만들기'를 통하여

  • 변수이름 : JAVA_HOME
  • 변수값 : C:\Program Files\Java\jdk1.8.0_05 (자바 jdk 를 설치한 위치)
설정을 하게 되고

아랫 부분에 해당하는 시스탬 변수 부분에서 '새로 만들기'를 통하여

  • 변수이름 : CLASSPATH
  • 변수값 : C:\Program Files\Java\jdk1.8.0_05\lib\tools.jar (java_home 하위경로 파일)
CLASSPATH를 설정하고 'path' 클릭 후 편집을 눌려

  • 변수이름 : Path
  • 변수값 : (기존 Path)C:\Program Files\Java\jdk1.8.0_05\bin;
기존의 path에 추가를 해줍니다.

이렇게 함으로서 Java JDK 설치와 환경변수를 설정을 하였습니다.

확인을 하기 위해서는 '윈도우키+R' 또는 '시작->모든프로그램->보조프로그램->명령프롬프트'를 실행하여 javac,javaw,javaws등 Path에 편집한 위치에 존재하는 파일을 실행해보면 됩니다. 만약 실행이 된다면 컴퓨터의 다른 위치에서도 실행이 된다는 것이므로 환경변수 설졍이 잘 되었다고 할수 있습니다.


1)이클립스+ADK

ADK란 Android Software Development Kit, 즉 개발도구이긴한데 Android를 지원하는 개발도구 입니다. 보통 이클립스를 많이 사용하실텐데 이클립스에서 Android를 지원하기 위해서 필요한 것이 SDK 플러그인 입니다. 제가 마지막으로 배웠을 때에는 기존 이클립스에서 ADK플러그인 다운받는 식으로 사용하였는데 지금은 안드로이드 개발 페이지에 가보니 1~2을 한번에 만들어 제공을 하더군요. 


다운로드 페이지에 가셔서 ADK Bundle을 다운 받으면 됩니다. 설치를 하시고 압축을 풀어줍니다.
이제 ADK Manager를 이용하여 각 버전에 맞는 API들을 다운받아 설치를 하면 기본적으로 안드로이드 앱을 개발할 수 있습니다.


Window -> ADK Manager 을 찾아가 실행시켜줍니다.


이제 여기서 자신이 개발하려는 버전에 맞춰 다운받아주시면 해당 버전으로 개발을 할 수 있습니다. 여기서 다운로드 서버가 작은지 시간이 오래 걸리므로 빠릿빠릿하게 하면 될듯? 싶네요. 참고로 작년(2013)까지의 버전 점유율 2.3.3버전이상으로 하게되면 대부분에 적용할 수 있네요.


2)NDK

안드로이드에서 C/C++ 코드로 된 모듈을 불러오기 위해서는 NDK (Native Development Kit) 를 이용해야만 합니다. 때문에 설치를 해줍니다. 이것 또한 구글의 안드로이드 개발페이지에서 다운로드 할 수 있습니다.

3)COCOS2D-X

cocos2d-x는 멀티플렛폼 오픈소스 엔진 입니다. 기본적으로 폰 게임 분야에서 많이 쓰이고 전 세계적으로 많은 사용을 받는 엔진이라고 합니다. 이거에 대한 블로그 강좌나 정보를 가장 쉽게 접할 수 있어 cocos2d-x로 정했습니다. 이것도 그냥 다운로드해서 압축을 풀어주면 됩니다. 저는 2.2.3버전을 기준으로 작업하고 있습니다.

4)Python

cocos2d-x 프로젝트를 생성하기 위해서 필요합니다. 이것도 다운로드하고 설치를 해줍니다.

5) 비주얼 스튜디오 2012

우리 모두 구할 수 있자나요? 그렇죠?
사실 제가 처음 2010으로 해봤는데 서비스팩깔면 됩니다. 하지만 2012를 깔아줍니다. 언제 또 어디서 막힐지 모르니..

2.설정

자바 SDK를 설치했을 때와 마찬가지로 환경변수를 설정해 줘야 합니다. 설정하기 위해선

여기(우클릭)

여기

여기

이렇게 찾아오시면 됩니다.

설정은 총 3가지만 하면 됩니다. 아래는 저를 기준이니 경로 설정 잘해줍니다. 경로 구분은 ; 로 구분해줍니다.(저는 cocos2d-x관련 파일들을 E:\Android_cocos2d-x\폴더에 모았습니다.)
  • 시스템 변수 - Path   기존에 추가
    • ~~;E:\Android_cocos2d-x\Python27;E:\Android_cocos2d-x\android-ndk-r9d
  • 사용자 변수 - NDK_MODULE_PATH   새로 만들기
    • E:\Android_cocos2d-x\cocos2d-x-2.2.3;E:\Android_cocos2d-x\cocos2d-x-2.2.3\cocos2dx\platform\third_party\android\prebuilt
  • 사용자 변수 - NDK_ROOT   새로 만들기
    • E:\Android_cocos2d-x\android-ndk-r9d

  • cocos2d-x의 루트폴더의 setup.py 실행
setup.py를 실행하게 되면 위의 것들과 cocos2d-x에 관련된 환경변수를 자동 등록 해줍니다. 하지만 못 찾는 경우도 많아서 위의 것들은 그냥 직접 등록 해주도록 합니다.

  • 명령프롬프트(cmd) 또는 python 에서 "cocos run"을 입력해 줍니다.
이로서 모든 설정이 완료 되었습니다.. 저는 여기까지 2틀걸렸네요. 멍청한듯


바로 다음 포스팅으로 win32랑 android환경에서의 예제 실행을 하겠습니다.

--------------------------------------------------------------------------------

2014년 3월 10일 월요일

mpu 6050 가속도 센서값 활용 공식 : ROLL,PITCH

앞서...
  • 앞서 아두이노 프로젝트에서 제가 MPU 6050의 값을 처리를 못한 것으로 끝난 것으로 포스팅을 마친것과는 달리 최근 MPU 6050의 값을 이용하여 값을 활용하여 안드로이드에서 보일수 있게 만들었습니다. 정확히 말씀드리자면 Roll,Pitch,Yaw 값중에 Roll,Pitch의 값만 구할수 있었으니 반만 구했다고 할수 있습니다. 먼저 이유를 말씀드리자면 Yaw값을 구하기 위해서는 gyro값을 처리하여 accel값과 같이 처리를 하여야 하는데 제가 만든 작품의 특성상 GYRO값을 누적시킬 만큼의 데이터를 활용하지 못하였고 적분을 하지 못하였기 때문입니다. 

MPU6050으로 얻을 수 있는 값

  • 먼저 MPU 6050의 출력값으로는 우측과 같습니다. 제가 아두이노 센서 관련 포스팅을 할때 많이 보여드린 결과값이죠.
  • accel의 값으로는 x,y,z축을 기준으로 -16384~+16384만큼의 범위를 가집니다. 저의 결과 값은 자동차키트(센서)를 정방향으로 가만히 두었을 때 값이지만 위와 아래의 값이 다르고 z의 값이 유난히 큰것을 볼수 있습니다.
  • 기본적으로 MPU6050에서 값을 파형 형태로 전달하기 때문에 항상 정확히 같은 값을 기대할 수 없으며 accel값은 중력의 영향을 받기 때문에 수직의 값을 측정하는 z의 값이 유난히 크게 나오게 됩니다.





 Roll,Pitch???

  • 공식에 있어서 x y z의 값은 accel의 값이 사용 됩니다. 이 글의 목적인 센서의 값을 이용한 공식을 적어드리면
    • pitch = arctan(x/z)
    • roll = arctan(y/z)
  • 자바 공식으로 적으면

    • float pitch = (float) (Math.atan2(y, z) * 180/PI);
    • float roll = (float) (Math.atan2(x, z) * 180/PI);
  • 이렇게 사용할 수 있습니다. 자바에서 뒤에 180/PI를 붙이는 이유는 atan2의 리턴값이 라디안값으로 리턴되기 때문입니다.
  • Roll,Pitch는 아래의 사진을 보면 이해하기 쉬운데 기울기 값입니다. 즉 값을 이용해서 MPU6050센서의 앞뒤,좌우의 기울기 값을 알수 있습니다. Roll은 센서의 좌우로의 기울기, Pitch는 앞뒤로의 기울기를 알수 있습니다.

  • 오른쪽의 스마트폰에서의 값은 제 자동차 키트에서의 값입니다. 나침판 그림은 각각의 값을 보기 쉽게 표현하기 위한 것입니다. 이런식으로 활용할 수 있습니다.

Yaw??
  • yaw값을 알면 mpu6050센서에서의 방향상태를 x,y,z축으로 알수 있지만 yaw값은 제일 까다로운 값입니다. 제가 전문성이 떨어지기 때문에 간단히 설명을 드리자면 yaw값을 구하기 위해서는 gyro값을 계속 누적시켜 적분을 한 값이 필요로 한데, 이 값은 위에서 적은 거와 같이 센서값은 파형의 형태로 전달되기 때문에 순간순간 미세한 오차가 있으며 계속 누적할 경우 오차가 커지게 됩니다. 이를 위해선 필터의 값이 필요합니다. 저 같은 경우는 아두이노에서 자동차의 컨트롤값의 처리와 센서의 처리에 있어 컨트롤의 값이 실시간으로 이루어져야하고 우선시 되기때문에 센서의 값을 누적시킬수 없기 때문에 구하지 못하였습니다.
참조사이트 입니다.
http://www.geekmomprojects.com/mpu-6050-dmp-data-from-i2cdevlib/

2014년 2월 16일 일요일

아두이노 스케치 및 회로도 - 블루투스를 이용한 자동차 키트 + 안드로이드 컨트롤러


---------------------------------------------------------------------------------

 우선 허접하게나마 만들었던 회로도 입니다.



우선 이름이 안적힌 왼쪽 아래의 것은 모터 제어 모듈입니다. 모터들은 모터 제어 모듈에 연결하고요. 여기에서 10핀에 대한 부분만 그려놓았고요. 사실과 다른 부분이 있다면 mpu6050에서의 vcc는 3.3v에 연결한부분만 다르네요..

실제 사진은 


이렇기에....
흰색은 브레드보드(빵판)입니다.


이 아래부터는 저의 완성된 자동차에 쓰인 소스입니다,



주의 하여 볼점은 a라는 값입니다,
모터에 넣어줘야 할 값은 계속해서 지속적으로 값을 넣어줘야 하지만
센서의 값들은 빠르게 지속적으로 넣어줘야 할 필요는 없습니다.
만약 만약 모든 센서의 값도 들어오는 데로 처리하게 된다면 아두이노의 처리가 빠르지 않기 때문에 처리해야 할 양이 오버되어 작동을 멈추는 연상이 일어나게 됩니다.
a라는 값을 넣어줘서 모터 제어의 처리와 센서의 처리의 비율을 500:1로 만들어 작동하게 만들었습니다.
방법은 제일 간단하게 a값을 자동으로 증가시키고 500이라는 수에 도달하면 작동하도록 if문을 사용하는 방식으로 했습니다.

모터제어의 방법은 16전진, 32후진, 4좌회전,8후회전 으로 정하여
전진 좌회전일 경우는 합한 20이 들어오게 되어 작동하는 방식입니다. 사실 이 방법은 BluCar라는 외국의 자동차 키트 개발한 곳에서 사용한 방법을 복잡한 것을 다 때고 간단하게 사용한 방식입니다.

제 소스에서는 자동차 모듈의 왼쪽과 오른쪽 바퀴에서 전후진 값이 다른데 그것은 핀을 연결할 때 반대로 연결하는 걸 실험해보다가 바꾸지 않고 소스로만 바꿔서 그렇다는점 유의 바랍니다.

그리고 원래 모드에서는 충격센서를 이용해서 키트에 충격이 가해지면 차량이 멈추도록 하였었는데 아예 삭제를 했습니다...
이유는 그 당시 교수님께 검사를 받아야 하는데 충격실험 하기가 검나서 하고 설명과 충격의 결과만 보여드리고 끝을 냈었습니다.

그외의 모든 소스는 여태것 정리했던 소스를 짜집기 한 수준으로 앞의 내용과 다른 점은 없습니다.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
#include <SoftwareSerial.h> //아두이노 우노에서 시리얼 통신은 기본으로 0번과 1번을 쓴다.
#define dht11_pin 54 //Analog port 0 on Arduino Mega2560
// 이 포트를 중복해서 사용하지 않고 다른 포트를 사용하기 위해서는
// 아두이노에서 제공하는 라이브러리 SoftwareSerial을 사용하면 된다.
#include <Wire.h>
//----------------------------------MPU6050 연결핀 및 설정값------
#define MPU6050_ACCEL_XOUT_H 0x3B // R
#define MPU6050_PWR_MGMT_1 0x6B // R/W
#define MPU6050_PWR_MGMT_2 0x6C // R/W
#define MPU6050_WHO_AM_I 0x75 // R
#define MPU6050_I2C_ADDRESS 0x68
//----------------------------------모터제어모듈 연결핀-------
#define LE 52
#define RE 53
#define LM 50
#define RM 51
#define LS 9
#define RS 12
//----------------------------------기타 핀----------------
#define dp 1 //display to BT and serial
#define shock 7
#define sonicPin 8
#define led 13

SoftwareSerial BTserial(10,11); // BTserial이라는 이름의 통신장치로 2(TX), 3(RX)포트로 시리얼 통신한는 설정

long sonicval = 0;
long cm, inch;
int a = 0;
int b = 0;
int s = 0;
static int n=4;

int pwm = 120;//모터의 속도
int turn = 80;//좌우회전시 추가해야할 속도

byte read_dht11_dat()
{
  byte i = 0;
  byte result=0;
  for(i=0; i< 8; i++)
  {
    while (!digitalRead(dht11_pin));
    delayMicroseconds(30);
    if (digitalRead(dht11_pin) != 0 )
      bitSet(result, 7-i);
    while (digitalRead(dht11_pin));
  }
  return result;
}
long cmtomicro(long a){
  return a/29/2;
}
long inchtomicro(long b){
  return b/74/2;
}

typedef union accel_t_gyro_union
{
  struct
  {
    uint8_t x_accel_h;
    uint8_t x_accel_l;
    uint8_t y_accel_h;
    uint8_t y_accel_l;
    uint8_t z_accel_h;
    uint8_t z_accel_l;
    uint8_t t_h;
    uint8_t t_l;
    uint8_t x_gyro_h;
    uint8_t x_gyro_l;
    uint8_t y_gyro_h;
    uint8_t y_gyro_l;
    uint8_t z_gyro_h;
    uint8_t z_gyro_l;
  }
  reg;
  struct
  {
    int x_accel;
    int y_accel;
    int z_accel;
    int temperature;
    int x_gyro;
    int y_gyro;
    int z_gyro;
  }
  value;
};


void setup() {
  // initialize the LED pin as an output:
  Serial.begin(9600);
  BTserial.begin(9600); // 통신모듈의 baudrate값을 써 통신을 시작
  pinMode(led, OUTPUT);
  pinMode(dht11_pin, OUTPUT);
  digitalWrite(dht11_pin, HIGH);
  pinMode(sonicPin, OUTPUT);
  digitalWrite(sonicPin, HIGH);
  pinMode(shock, OUTPUT);
  digitalWrite(shock, HIGH);
  pinMode(LE,OUTPUT);
  pinMode(RE,OUTPUT);
  pinMode(LM,OUTPUT);
  pinMode(RM,OUTPUT);
  pinMode(LS,OUTPUT);
  pinMode(RS,OUTPUT);
  digitalWrite(LE,LOW); // 왼쪽 모터 정지 정보 핀
  digitalWrite(RE,LOW); // 왼쪽 모터 정지 정보 핀

  int error;
  uint8_t c;
  Wire.begin();

  error = MPU6050_read (MPU6050_WHO_AM_I, &c, 1);
  Serial.print(F("WHO_AM_I : "));
  Serial.print(c,HEX);
  Serial.print(F(", error = "));
  Serial.println(error,DEC);
  error = MPU6050_read (MPU6050_PWR_MGMT_2, &c, 1);
  Serial.print(F("PWR_MGMT_2 : "));
  Serial.print(c,HEX);
  Serial.print(F(", error = "));
  Serial.println(error,DEC);
  MPU6050_write_reg (MPU6050_PWR_MGMT_1, 0);
}

void loop(){
  //---------------------------------led on off----------------------------
  /*
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
   delay(300); // wait for a second
   digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
   delay(300); // wait for a second
   BTserial.println("check"); // 블루투스를 통해 다른 장치에 출력
   Serial.println(a);
   */
  if(a==500)
  {
    //--------------------------------dht11-------------------------------------
    byte dht11_dat[5];
    byte dht11_in;
    byte i;// start condition
    digitalWrite(dht11_pin, LOW);
    delay(10);
    digitalWrite(dht11_pin, HIGH);
    delayMicroseconds(1);
    pinMode(dht11_pin, INPUT);
    delayMicroseconds(40);
    if (digitalRead(dht11_pin))
    {
      Serial.println("dht11 start condition 1 not met"); // wait for DHT response signal: LOW
      delay(1000);
      return;
    }
    delayMicroseconds(80);
    if (!digitalRead(dht11_pin))
    {
      Serial.println("dht11 start condition 2 not met"); //wair for second response signal:HIGH
      return;
    }
    delayMicroseconds(80);// now ready for data reception
    for (i=0; i<5; i++)
    {
      dht11_dat[i] = read_dht11_dat();
    } //recieved 40 bits data. Details are described in datasheet
    pinMode(dht11_pin, OUTPUT);
    digitalWrite(dht11_pin, HIGH);
    byte dht11_check_sum = dht11_dat[0]+dht11_dat[2];// check check_sum
    if(dht11_dat[4]!= dht11_check_sum)
    {
      Serial.println("DHT11 checksum error");
    }
    //------------------------------------sonic----------------------------------
    digitalWrite(sonicPin,LOW);
    delayMicroseconds(2);
    digitalWrite(sonicPin,HIGH);
    delayMicroseconds(5);
    digitalWrite(sonicPin,LOW);
    pinMode(sonicPin, INPUT);

    sonicval = pulseIn(sonicPin,HIGH); // 초음파가 반사하여 되돌아온 시간을 저장

    pinMode(sonicPin, OUTPUT);

    cm = cmtomicro(sonicval); // cm거리계산
    inch = inchtomicro(sonicval); //inch거리계산
    //-------------------------------shock---------------------------------------
    digitalWrite(shock,HIGH);
    delay(5);
    digitalWrite(shock,LOW);
    delay(5);
    pinMode(shock,INPUT);
    if(digitalRead(shock))
    {
      Serial.println("충격이 감지되었습니다.");
    }
    pinMode(shock,OUTPUT);
    //-------------------------------gyro----------------------------------------
    int error;
    double dT;
    accel_t_gyro_union accel_t_gyro;
    Serial.println(F(""));
    Serial.println(F("MPU-6050"));
    // Read the raw values.
    // Read 14 bytes at once,
    // containing acceleration, temperature and gyro.
    // With the default settings of the MPU-6050,
    // there is no filter enabled, and the values
    // are not very stable.
    error = MPU6050_read (MPU6050_ACCEL_XOUT_H, (uint8_t *) &accel_t_gyro, sizeof(accel_t_gyro));
    Serial.print(F("Read accel, temp and gyro, error = "));
    Serial.println(error,DEC);
    // Swap all high and low bytes.
    // After this, the registers values are swapped,
    // so the structure name like x_accel_l does no
    // longer contain the lower byte.
    uint8_t swap;
#define SWAP(x,y) swap = x; x = y; y = swap
    SWAP (accel_t_gyro.reg.x_accel_h, accel_t_gyro.reg.x_accel_l);
    SWAP (accel_t_gyro.reg.y_accel_h, accel_t_gyro.reg.y_accel_l);
    SWAP (accel_t_gyro.reg.z_accel_h, accel_t_gyro.reg.z_accel_l);
    SWAP (accel_t_gyro.reg.t_h, accel_t_gyro.reg.t_l);
    SWAP (accel_t_gyro.reg.x_gyro_h, accel_t_gyro.reg.x_gyro_l);
    SWAP (accel_t_gyro.reg.y_gyro_h, accel_t_gyro.reg.y_gyro_l);
    SWAP (accel_t_gyro.reg.z_gyro_h, accel_t_gyro.reg.z_gyro_l);
    // Print the raw acceleration values

    //-------------------------------display-------------------------------------
    if(dp == 1)
    {
      Serial.print(cm);
      Serial.print("cm ");
      Serial.print(inch);
      Serial.println("inch");

      Serial.print("Current humdity = ");
      Serial.print(dht11_dat[0], DEC);
      Serial.print("% ");
      Serial.print("temperature = ");
      Serial.print(dht11_dat[2], DEC);
      Serial.println("C ");

      BTserial.print(cm);
      BTserial.print("cm ");
      BTserial.print(inch);
      BTserial.println("inch"); // 블루투스를 통해 다른 장치에 출력
      BTserial.println();
      BTserial.print("Current humdity = ");
      BTserial.print(dht11_dat[0], DEC);
      BTserial.print("% ");
      BTserial.print("temperature = ");
      BTserial.print(dht11_dat[2], DEC);
      BTserial.println("C ");
      BTserial.println();
      Serial.print(F("accel x,y,z: "));
      Serial.print(accel_t_gyro.value.x_accel, DEC);
      Serial.print(F(", "));
      Serial.print(accel_t_gyro.value.y_accel, DEC);
      Serial.print(F(", "));
      Serial.print(accel_t_gyro.value.z_accel, DEC);
      Serial.println(F(""));
      BTserial.print(F("accel x,y,z: "));
      BTserial.print(accel_t_gyro.value.x_accel, DEC);
      BTserial.print(F(", "));
      BTserial.print(accel_t_gyro.value.y_accel, DEC);
      BTserial.print(F(", "));
      BTserial.print(accel_t_gyro.value.z_accel, DEC);
      BTserial.println(F(""));
      BTserial.println();
      // The temperature sensor is -40 to +85 degrees Celsius.
      // It is a signed integer.
      // According to the datasheet:
      // 340 per degrees Celsius, -512 at 35 degrees.
      // At 0 degrees: -512 - (340 * 35) = -12412
      Serial.print(F("temperature: "));
      BTserial.print(F("temperature: "));
      dT = ( (double) accel_t_gyro.value.temperature + 12412.0) / 340.0;
      Serial.print(dT, 3);
      Serial.print(F(" degrees Celsius"));
      Serial.println(F(""));
      BTserial.print(dT, 3);
      BTserial.print(F(" degrees Celsius"));
      BTserial.println(F(""));
      BTserial.println();
      // Print the raw gyro values.
      Serial.print(F("gyro x,y,z : "));
      Serial.print(accel_t_gyro.value.x_gyro, DEC);
      Serial.print(F(", "));
      Serial.print(accel_t_gyro.value.y_gyro, DEC);
      Serial.print(F(", "));
      Serial.print(accel_t_gyro.value.z_gyro, DEC);
      Serial.print(F(", "));
      Serial.println(F(""));
      BTserial.print(F("gyro x,y,z : "));
      BTserial.print(accel_t_gyro.value.x_gyro, DEC);
      BTserial.print(F(", "));
      BTserial.print(accel_t_gyro.value.y_gyro, DEC);
      BTserial.print(F(", "));
      BTserial.print(accel_t_gyro.value.z_gyro, DEC);
      BTserial.print(F(", "));
      BTserial.println(F(""));
      BTserial.println();
      BTserial.println();
      BTserial.println();
    }
    if(a==300)
      a=0;
  }



  //s= Drive_Count();
  b = BTserial.read(); // 스마트폰에서 블루투스 모듈로 들어오는 신호를 a에 저장
  if(dp == 0){
    //BTserial.print("car control_num : ");
    //BTserial.println(s);
    BTserial.print("car bt_num : ");
    BTserial.println(b);
    //Serial.print("car control_num : ");
    //Serial.println(s);
    Serial.print("car bt_num : ");
    Serial.println(b);
  }
  switch (b){
  case 0: // 0이면 정지
    digitalWrite(LM,HIGH); // 왼쪽 모터 전후진 정보 핀
    analogWrite(LS,LOW);
    digitalWrite(RM,HIGH); // 오른쪽 모터 전후진 정보 핀
    analogWrite(RS,HIGH);
    delay(20);
    break;
  case 4: // 4면 제자리 좌회전
    digitalWrite(LM,HIGH); // 왼쪽 모터 전후진 정보 핀
    analogWrite(LS,pwm);
    digitalWrite(RM,HIGH); // 오른쪽 모터 전후진 정보 핀
    analogWrite(RS,pwm);
    delay(20);
    break;
  case 8: // 8이면 제자리 우회전
    digitalWrite(LM,LOW); // 왼쪽 모터 전후진 정보 핀
    analogWrite(LS,pwm);
    digitalWrite(RM,LOW); // 오른쪽 모터 전후진 정보 핀
    analogWrite(RS,pwm);
    delay(20);
    break;
  case 16: // 16이면 전진
    digitalWrite(LM,LOW); // 왼쪽 모터 전후진 정보 핀
    analogWrite(LS,pwm);
    digitalWrite(RM,HIGH); // 오른쪽 모터 전후진 정보 핀
    analogWrite(RS,pwm);
    delay(20);
    break;
  case 20: // 20이면 좌회전
    digitalWrite(LM,LOW); // 왼쪽 모터 전후진 정보 핀
    analogWrite(LS,pwm-turn);
    digitalWrite(RM,HIGH); // 오른쪽 모터 전후진 정보 핀
    analogWrite(RS,pwm+turn);
    delay(20);
    break;
  case 24: // 24이면 우회전
    digitalWrite(LM,LOW); // 왼쪽 모터 전후진 정보 핀
    analogWrite(LS,pwm+turn);
    digitalWrite(RM,HIGH); // 오른쪽 모터 전후진 정보 핀
    analogWrite(RS,pwm-turn);
    delay(20);
    break;
  case 32: // 32이면 후진
    digitalWrite(LM,HIGH); // 왼쪽 모터 전후진 정보 핀
    analogWrite(LS,pwm);
    digitalWrite(RM,LOW); // 오른쪽 모터 전후진 정보 핀
    analogWrite(RS,pwm);
    delay(20);
    break;
  case 36: // 36이면 좌후진
    digitalWrite(LM,HIGH); // 왼쪽 모터 전후진 정보 핀
    analogWrite(LS,pwm-turn);
    digitalWrite(RM,LOW); // 오른쪽 모터 전후진 정보 핀
    analogWrite(RS,pwm+turn);
    delay(20);
    break;
  case 40: // 40이면 우후진
    digitalWrite(LM,HIGH); // 왼쪽 모터 전후진 정보 핀
    analogWrite(LS,pwm+turn);
    digitalWrite(RM,LOW); // 오른쪽 모터 전후진 정보 핀
    analogWrite(RS,pwm-turn);
    delay(20);
    break;
  }
  a++;
  delay(10); //fresh time
}



int MPU6050_read(int start, uint8_t *buffer, int size)
{
  int i, n, error;
  Wire.beginTransmission(MPU6050_I2C_ADDRESS);
  n = Wire.write(start);
  if (n != 1)
    return (-10);
  n = Wire.endTransmission(false); // hold the I2C-bus
  if (n != 0)
    return (n);
  // Third parameter is true: relase I2C-bus after data is read.
  Wire.requestFrom(MPU6050_I2C_ADDRESS, size, true);
  i = 0;
  while(Wire.available() && i<size)
  {
    buffer[i++]=Wire.read();
  }
  if ( i != size)
    return (-11);
  return (0); // return : no error
}
int MPU6050_write(int start, const uint8_t *pData, int size)
{
  int n, error;
  Wire.beginTransmission(MPU6050_I2C_ADDRESS);
  n = Wire.write(start); // write the start address
  if (n != 1)
    return (-20);
  n = Wire.write(pData, size); // write data bytes
  if (n != size)
    return (-21);
  error = Wire.endTransmission(true); // release the I2C-bus
  if (error != 0)
    return (error);
  return (0); // return : no error
}
int MPU6050_write_reg(int reg, uint8_t data)
{
  int error;
  error = MPU6050_write(reg, &data, 1);
  return (error);
}


2014년 2월 13일 목요일

모터 제어 모듈(AM-DC2-2D) - 블루투스를 이용한 자동차 키트 + 안드로이드 컨트롤러


---------------------------------------------------------------------------------

자동차라는 이름이 붙게 하게끔 만드는 장치인 모터 제어 모듈 입니다.
저는 AM-DC2-2D 라는 모듈을 이용하였습니다.
완성품을 보면 4륜 자동차의 모습을 가지고 있는데, 이 모듈은 좌우 2방향밖에 컨트롤 하지 못합니다. 때문에 저는 좌,우 회전은 좌우의 속도차를 이용하여 하는 방법을 하였습니다. 

AM-DC2-2D 모터제어모듈

이 모듈은 기본적으로 보이는 것과 같이 연결할 부분이 상당히 많습니다. 핀 갯수로만 보면 총 12개인데요.

이거는 AM-DC2-2D의 사진이 아니지만 구성은 비슷합니다. 다른점이 있다면 Motor이라는 부분이 녹색을 기준으로 2개씩 있습니다. 위의 AM-DC2-2D를 보면 알수 있습니다.

Control Signal 이라는 부분, Power Supply, Moter(흰부분 만 사용하면 됨) 라는 부분을 연결해야 합니다.

Power Supply는 모듈의 파워가 아닌 구동시킬 모터의 power를 연결 해야합니다. 저는 12V를 사용하는 모터를 사용했기 때문에 1.5V*8의 전원을 연결 하였습니다.

실물에서 Motor라는 부분을 보면 아래쪽에 CH1A,B라고 적혀있는데 이 모터와 연결하면 됩니다.



Control Signal

Control Signal 부분에 위 사진을 활용하여 신호를 주어야 합니다. 메뉴얼에서 정말 정말 편하게 설명해줍니다.  3줄정리를 하자면

PWM은 속도
DIR은 방향
/Enable은 작동 on/off

Enable은 /(not)이 있으므로 0입력시 on 1입력시 off입니다.
그리고 대부분의 모터는 "?V~??V"이런식으로 허용 범위가 정해져 있는 편인데요. 전원에 따라 파워(속도)의 차이가 있으므로 충분한 파워를 사용하는 것을 추천합니다.

 Dir와 Enable 신호는 on,off의 개념으로 작동하기 때문에 Digital 신호로 연결을 하였고 PWM신호는 PWM신호로 연결하였습니다.

이렇게 연결을 하면 모든 부분이 연결이 됩니다.

아래 부분은 스케치 입니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
.....
#define LE 52
#define RE 53
#define LM 50
#define RM 51
#define LS 9
#define RS 12
.....//저의 설정입니다. 개인에 따라 변경하시면 됩니다.

int pwm = 120;// 속도

....
void setup(){
....
  pinMode(LE,OUTPUT);
  pinMode(RE,OUTPUT);
  pinMode(LM,OUTPUT);
  pinMode(RM,OUTPUT);
  pinMode(LS,OUTPUT);
  pinMode(RS,OUTPUT);//핀 출력모드
  digitalWrite(LE,LOW); // 왼쪽 모터 정지 정보 핀
  digitalWrite(RE,LOW); // 왼쪽 모터 정지 정보 핀
}

///
void loop(){
...

    digitalWrite(LM,HIGH); // 왼쪽 모터 전후진 정보 핀
    analogWrite(LS,LOW);
    digitalWrite(RM,HIGH); // 오른쪽 모터 전후진 정보 핀
    analogWrite(RS,LOW);
    delay(20);

...

    digitalWrite(LM,HIGH); // 왼쪽 모터 전후진 정보 핀
    analogWrite(LS,pwm);
    digitalWrite(RM,HIGH); // 오른쪽 모터 전후진 정보 핀
    analogWrite(RS,pwm);

...
}

digitalWrite는 0,1의 값을 즉 디지털 값을 쓸수 있고
alnalogWrite는 pwm값을 입력할수 있습니다. pwm값은 0~255값입니다.

위의 스케치에서와 같이 각 연결한 dir,enable,pwm을 통하여 전진 후진 속도를 컨트롤 할수 있습니다.