기억하기 위해서 기록해 놓음..
처음 다이어그램인데..수정.
수정 다이어그램은 아래와 같다.
기존 대비 S11을 지워 버렸다. S10에서 S11로 transiton이 발생할 때, 모터 동작이 끝나기 때문에 굳이 S11을 만들 필요가 없다. self transition으로 처리했다. state machine을 내가 제대로 이해하고 있는지 모르겠으나..
S13에서도 self transition을 추가 했는데, 회전 동작시 장애물을 완전하게 피했는지를 확인하기 위해서이다. S13에서 이벤트를 다시 한번 확인하고, 장애물에 걸리면 전진동작 없이 회피 동작을 하도록 했다.
가장 고민했던 부분은 S0은 event driven program이고 S1은 data driven program 방식으로 접근해야 할 것 같은데, 모든 ir센서로 읽어 들이는 모든 데이터를 event로 분류하기가 힘들었다. 이벤트로 설정하려면 배타적 관계도 확인해 봐야 하는데, 버튼 눌림여부 * 버퍼의 수치별 이벤트를 한개의 event로 처리하려면 경우의 수가 너무 많았다. 쿨하게 evnet는 아래와 같이 몇가지 경우만 잡았다. 나머지는 S1에 들어갔으므로 대략 무시하기로 했다.
package hsm; import lejos.hardware.Button; public class Event { public enum mEvent {EnterPressed,DownPressed,GapIsWide,GapIsNarrow,Nothing}; //Ir센서를 읽기 위한 부분.. private float irValue; public Event(float tmp){ this.irValue = tmp; } /* public void setEventBuffer(float value){ this.irValue = value; } */ public mEvent getID(){ mEvent thisEvent = mEvent.Nothing; //버퍼에서 데이터를 읽어 들임 if(Button.ENTER.isDown() == true) return mEvent.EnterPressed; if(Button.DOWN.isDown() == true) return mEvent.DownPressed; if(irValue > 10) return mEvent.GapIsWide; if(irValue <= 10) return mEvent.GapIsNarrow; return thisEvent; } }
일단 S1에 들어가면, irRead -> ir 버퍼 가공 -> 모터 동작의 방식으로 처리했는데, 이 방법도 좋지 않았다. 각 state별 process가 다른데, thread로 돌리면 이를 구분할 수 없게 된다. 따라서 아래와 같이 수정했다.
S10,S13에서만 irRead 동작, S10,S12,S13에서는 모터 동작, 각 transition에 따른 버퍼값 수정..
S0에서는 버튼이 눌림만 감시하기 때문에 event driven programming으로 접근했다.
hsm의 c++ -> java 이식은 인터넷의 코드를 그대로 사용했다.
hsm의 구조는 대략 아래와 같다.
package hsm; import mypackage.IrBufferv2; import mypackage.MotorData; public class myHsmForLego extends Hsm{ private MotorData mMotorData; Runnable myIrRun; Runnable myMotorRun; Runnable myProcessRun; public myHsmForLego(MotorData motor,Runnable irTh, Runnable motorTh, Runnable ProcessTh){ this.mMotorData = motor; //thread를 전달하기 위한 부분 this.myIrRun = irTh; this.myMotorRun = motorTh; this.myProcessRun = ProcessTh; } @Override public void init() { // TODO Auto-generated method stub System.out.print("Top-INIT;" ); //초기화시 모터 목표를 0으로 설정 super.init(); } @Override public State fireInit() { // TODO Auto-generated method stub System.out.print("INIT>>s;" ); return s0; } @Override public void enter() { // TODO Auto-generated method stub System.out.print("ENTRY>>s;" ); } @Override public State fireEvent(Event e) { // TODO Auto-generated method stub return getParent(); }//fireEvent @Override public void exit() { // TODO Auto-generated method stub System.out.print("EXIT<<s;" ); System.out.print("\n"); } Hsm s = this; // This is just alias of current instance State s0 = new State(s){ @Override public State fireEvent(Event e) { // TODO Auto-generated method stub switch(e.getID()) { case EnterPressed : transition(s1); return null; default : break; } return getParent(); }//fireEvent @Override public State fireInit() { // TODO Auto-generated method stub System.out.print("INIT>>s0;" ); return null; } @Override public void enter() { // TODO Auto-generated method stub System.out.print("ENTRY>>s0;" ); } @Override public void exit() { // TODO Auto-generated method stub System.out.print("EXIT<<s0;" ); System.out.print("\n"); } };//sate s0 State s1 = new State(s){ @Override public State fireInit() { // TODO Auto-generated method stub System.out.print("INIT>>s1;" ); return s10; } @Override public void enter() { // TODO Auto-generated method stub System.out.print("ENTRY>>s1;" ); } @Override public State fireEvent(Event e) { // TODO Auto-generated method stub switch(e.getID()) { case DownPressed : transition(s0); return null; default : break; } return null; } @Override public void exit() { // TODO Auto-generated method stub System.out.print("EXIT<<s1;" ); System.out.print("\n"); } };//state s1; State s10 = new State(s1){ @Override public State fireInit() { // TODO Auto-generated method stub System.out.print("INIT>>s10;" ); return null; } @Override public void enter() { // TODO Auto-generated method stub // IR 센서값을 버퍼에 저장.. // 이벤트를 판단할 수 있게됨.. myIrRun.run(); System.out.print("ENTRY>>s10;" ); } @Override public State fireEvent(Event e) { // TODO Auto-generated method stub switch(e.getID()) { case GapIsWide : //모터 이동부분 추가. // 아래 process run은 삭제필요.. // thread를 인수로 줄수 없음.. //myProcessRun.run(); mMotorData.storeTargetDistance(10, 10); myMotorRun.run(); //seft transition transition(s10); return null; case GapIsNarrow : mMotorData.storeTargetDistance(-50, -50); myMotorRun.run(); transition(s12); return null; default : break; } return getParent(); }//fireEvent @Override public void exit() { // TODO Auto-generated method stub System.out.print("EXIT<<s10;" ); System.out.print("\n"); } };//state s10 /* 아래 부분은 삭제..2016.09.08 State s11 = new State(s1){ @Override public State fireInit() { // TODO Auto-generated method stub System.out.print("INIT>>s11;" ); return null; } @Override public void enter() { // TODO Auto-generated method stub System.out.print("ENTRY>>s11;" ); } @Override public State fireEvent(Event e) { // TODO Auto-generated method stub switch(e.getID()) { case GapIsWide: //seft transition //모터 이동부분 추가. myIrRun.run(); myProcessRun.run(); myMotorRun.run(); transition(s11); //모터 이동부분 추가. return null; case GapIsNarrow: //모터 이동부분 추가. mMotorData.storeTargetDistance(-10, -10); myMotorRun.run(); transition(s12); return null; default : break; } return getParent(); }//fireEvent @Override public void exit() { // TODO Auto-generated method stub System.out.print("EXIT<<s11;" ); System.out.print("\n"); } };//State s11 */ State s12 = new State(s1){ @Override public State fireInit() { // TODO Auto-generated method stub System.out.print("INIT>>s12;" ); return null; } @Override public void enter() { // TODO Auto-generated method stub System.out.print("ENTRY>>s12;" ); } @Override public State fireEvent(Event e) { // TODO Auto-generated method stub //모터 이동부분 추가. mMotorData.storeTargetDistance(50, -50); myMotorRun.run(); transition(s13); return getParent(); }//fireEvent @Override public void exit() { // TODO Auto-generated method stub System.out.print("EXIT<<s12;" ); System.out.print("\n"); } };//State s12 State s13 = new State(s1){ @Override public State fireInit() { // TODO Auto-generated method stub System.out.print("INIT>>s13;" ); return null; } @Override public void enter() { // TODO Auto-generated method stub // 충분하게 돌았는지 확인. myIrRun.run(); System.out.print("ENTRY>>s13;" ); } @Override public State fireEvent(Event e) { // TODO Auto-generated method stub switch(e.getID()) { case GapIsWide : //모터 이동부분 추가. // 아래 process run은 삭제필요.. // thread를 인수로 줄수 없음.. //myProcessRun.run(); transition(s10); return null; case GapIsNarrow : //충분하게 돌지 못해더 더 돌아야 된단고 판단. mMotorData.storeTargetDistance(50, -50); myMotorRun.run(); transition(s10); return null; default : break; } return getParent(); }//fireEvent @Override public void exit() { // TODO Auto-generated method stub System.out.print("EXIT<<s13;" ); System.out.print("\n"); } };//State 13 }//myHsmForLego
다음에는 iR센서에 모터를 달아서 한바퀴 돌려보고 몇도로 움직여야 판단까지 하고 싶으나, 갈길이 멀어 보인다. 일단 이걸 다 뜯을 생각을 하니 머리가 아프다..한번 뜯으면 다시 조립 못할 것 같다..