[태그:] LEGO

  • LegoEV3+갤럭시노트로 매트 위에서 안 떨어지기

    집에 놀고 있는 갤럭시 노트1을 LEGO EV3에 붙여 보았다. 갤럭시노트 센서중 가속도, 마그네틱 센서를 사용하면 휴대폰의 기울기를 쉽게? 구할수 있다고 한다. 이를 활용해서 매트 위에서 떨어짐을 감지해서 후진하도록 만들었다. 휴대폰이 수평으로 되어있으면 전진..처음 할때는 안될줄 알았는데, 안떨어지는걸 보니 신기하네.

    인터넷에 LEGO EV3용 센서를 고가에 파는데 구할 수 있는데, 사기에는 좀 많이 아깝다. 빠른 반응속도가 필요하지 않으면 휴대폰 센서를 쓰는것도 괜찮다.

    휴대폰은
    1. 서버 역할을 하고
    2. 휴대폰이 기울어져 있는지 판단한다.
    3. 이를 socket으로 열어놓는다.

    레고는
    1. 휴대폰의 소켓으로 접속하여 매순간 데이터를 받는다.
    2. 기울어졌다고 수신되면 후진
    3. 수평이라 판단되면 전진

    만들면서 부품이 좀 많이 부족했다. 특히 ㄱ자 브라켓?(핀 홀 방향을 바꿔주는 브라켓)이 없어서 애를 먹었다. 부품간 간격이 좀 있어 보이는데, 채윤이가 가지고 놀던 점토로 잘 붙였다.

  • 안드로이드 가속도 센서 구현, 칼만필터 적용

    추석때 집에 가니 엄마 구형 노트1이 놀고 있었다. 내가 가진 구형폰도 있었으나, 레고에 붙이기에는 좀 아까운듯하여 이 폰을 붙여보려고 한다.

    일단 내장된 센서의 값을 읽는 부분을 java로 구현했다. 여기에서 대부분 참조했고, 이번엔 좀 쉽게 따라할 수 있었다. 가속도센서값의 raw data는 도저히 그대로 사용할 수 없어 보인다.

    다시 찾아보니, 칼만 필터가 좋다고 하다니 적용해 보았다.

    eclipse에 지원하는 logcat에서 센서값을 파일로 저장 후, 필터 적용 전후 비교를 해 보았다. 전에는 데이터값을 파일로 저장하고 다시 읽었는데, eclipse에서 파일로 저장을 지원하니 엄청 편하다..
    rawdata
    위 그림이 raw data..

    filtereddata
    위 그림이 Kalman 필터를 통과한 그림..
    Kalman 필터가 제대로 적용되는 듯 하다.

  • Lego 조립 설명서

    Lego 조립 설명서

    Lego City 60022 Cargo Terminal

    index
    1번
    2번
    3번
    4번


     

     

    Lego City 60060 Auto Transporter
    60060-0000-XX-12-1
    1번
    2번
    3번


     

     

    Lego City 60083 Snowplow Truck
    60083-0000-XX-12-1
    1번

    Lego City 60042 HighSpeed Police Chase City Police
    60042-0000-XX-12-1
    1번


     

     

    Lego City 60043 Prisoner Transporter
    60043-0000-XX-12-1

    1번


     

     

    Lego City 60001 Fire Chief Car
    60001-0000-XX-12-1
    1번


     

     

    Lego Mindstorm EV3 31313
    index
    기본 메뉴얼


     

     

     

     

     

    Lego Mindstorm NXT 8527
    NXT1-8527Box
    기본 메뉴얼


    Lego Technic 42007 MotoCross Bike
    42007-0000-XX-12-1
    1번
    2번


     

     

    10507 My First Train Set DUPLO Town
    10507-0000-XX-12-1

    1번


     

     

    10506 Train Accessory Set DUPLO Town
    10506-0000-XX-12-1

    1번


     

     

     

     

    많이도 샀네..

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

    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