콘텐츠로 바로가기

now0930 일지

이런저런 생각

  • 홈
  • 비공개
  • 강좌
  • 잔여 작업 조회
  • 위치

HSM을 활용한 레고 장난감 만들기

기억하기 위해서 기록해 놓음..

처음 다이어그램인데..수정.
12113378_1289445931071053_7620380557359358782_o

수정 다이어그램은 아래와 같다.
20160908_225320

기존 대비 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센서에 모터를 달아서 한바퀴 돌려보고 몇도로 움직여야 판단까지 하고 싶으나, 갈길이 멀어 보인다. 일단 이걸 다 뜯을 생각을 하니 머리가 아프다..한번 뜯으면 다시 조립 못할 것 같다..
20160908_232920

이 글 공유하기:

  • Tweet
발행일 2016-09-05글쓴이 이대원
카테고리 LEGO, 생활코딩 태그 EV3, FSM, LEGO

댓글 남기기응답 취소

이 사이트는 Akismet을 사용하여 스팸을 줄입니다. 댓글 데이터가 어떻게 처리되는지 알아보세요.

글 내비게이션

이전 글

mysql을 사용한 견적 산출 방법

다음 글

Lego 조립 설명서

2025 7월
일 월 화 수 목 금 토
 12345
6789101112
13141516171819
20212223242526
2728293031  
6월    

최신 글

  • 자기 회로 정리 2025-06-22
  • common mode, differential mode 2025-05-11
  • signal conditioner, 신호 처리기 2025-05-10
  • strain gage 2025-05-09
  • 칼만 필터 2025-05-01

카테고리

  • 산업계측제어기술사
  • 삶 자국
    • 책과 영화
    • 투자
  • 생활코딩
    • LEGO
    • ROS
    • tensorflow
  • 전기기사
  • 피아노 악보

메타

  • 로그인
  • 엔트리 피드
  • 댓글 피드
  • WordPress.org

페이지

  • 소개
  • 잔여 작업 조회
    • 작업 추가
    • 작업의 사진 조회
    • 작업 수정 페이지
  • 사진
    • GPS 입력된 사진
    • 사진 조회
  • 위치
    • 하기 휴가 방문지
    • 해외 출장

태그

android bash c docker driver FSM gps java kernel LEGO linux mysql network program opcua open62541 plc programmers python raspberry reinforcementLearning ros state space system program tensorflow transfer function 경제 미국 민수 삼국지 세계사 실기 에너지 역사 유전자 일본 임베디드 리눅스 전기기사 조선 중국 채윤 코딩 테스트 통계 한국사 한국어

팔로우하세요

  • Facebook
now0930 일지
WordPress로 제작.
 

댓글 로드중...