Lego MindStorm EV3 제어기

조종기 다음으로 Lego 마인드스톰으로 모터 제어기를 만들었다.

기본개념이 아래 그림에 표시되어 있다.

조종기의 역할

  • 서버.
  • 휴대폰 기울기를 확인하여, 공을 기울기 방향으로 이동.
  • 공이 화면 구석으로 이동하면, 기울기가 공 위치를 변경하지 않음
  • 공 위치를 135도 회전 후, 수평 이동시켜
    “Left;…, Right:…” 형식으로 소켓으로 전송

Lego Mindstorm의 역할
(전에 만들었던 부분을 재활용 하여, 지저분함.)

  • 클라이언트.
  • 링 버퍼를 만든 후, Left, Right 이동 위치를 버퍼에 저장.
  • Thread가 Socket으로 안드로이드 폰에 connect, receive, close.
  • 이 과정을 반복
  • 수신 데이터(“Left:….,Right:….”)에서
    “Left:”, “,Right:”의 위치를 찾음.
  • 숫자를 추출, trim 후 integer로 변경.
  • 변경된 integer만큼, Left, Right 모터를 이동.

EV3를 lejos 베타 버전을 사용해서인지, socket의 utf-8로 데이터가 전송되지 않았다. ascii로 변경, 전송하여 시간 좀 걸렸다.

중요한 사실이

  • 내가 생각한 만큼 잘 움직이지 않는다.
    차량 바퀴를 4개로 만들다 보니, Left 모터를 -방향, Right 모터를 +방향으로 돌리면, 확 돌아야 되는데, 지 몸체에 걸려 안돈다!!!
    또한 제품이 무거워서인지, 바퀴가 헛도는 경우가 많다.
  • 실행 순서에 따라, NullPointException이 너무 많다.
    try, throw로 도배를 해야 할 듯한데, 시간이 또 한없이 갈 듯하다.
  • 안드로이드 폰의 좌표 설정 문제.
    화면의 공이 디스플레이 중앙에 있는데, EV3이 후진한다.
    보정을 해야 하는데, 귀찮다.
  • 안드로이드 폰 화면이 꺼지면, 동작이 멈춰야 하는데 그렇지 않다. 링 버퍼에서 다 사용하면, 0으로 이동이 맞아 보이는데..계속 움직인다.

더 중요한 사실이,

  • 애가 별로 재미없어 한다!!
    차가 빨랑 빨랑 움직여야 하는데, 지정 위치로 가다 보니, 너무 느리다. 파워로 수정하려니 귀찮고.

누가 소켓을 잘 정리하여 인터넷에 올렸다.
여기여기.
DataInputStream을 그냥 사용했는데, 별 목적이 없으면 사용하지 않는게 맞아 보인다.
DataInputStream으로 안드로이드 폰과 EV3이 통신이 되지 않는다.
누가 이미 작성한 코드를 쓰다 보니, socket을 어떻게 쓰는지 정리되지 않아는데, 위 사이트가 정리하는데 도움을 줬다.

가속도 센서로 pitch, roll 구하기

가속도 센서로 pitch, roll 알아내기
생각을 정리하기 위해서 기록으로 남긴다..

처음에 3축 가속도 센서가 있으면 pitch, roll, yaw를 알 수 있다고 생각했다. 그러나 이는 불가능하다..
아래 문서를 읽어보니 pitch와 roll 2개의 값만 알 수 있다. 나머지 yaw는 compass 센서로 확인이 가능하다.
AN3461

위 문서를 읽다 보면, 아래와 같은 식이 어떻게 나왔는지 파악하는데 좀 걸렸다.


x축으로 돌렸을 경우(roll), y,z 평면으로 보면 위와 같은 그림이 된다. 나머지는 안해봤는데, 아마도 이런 식으로 하면 되지 않을까 한다. roll, pitch, yaw 적용하는 순서에 따라 6개의 방정식이 나오는데, 4개는 못쓰는 식이다. 경우의 수가 너무 많아서 그런 듯 싶다. 나머지 2개는 사용할 수 있는데, 두 개의 식이 다른 결과를 갖는다.
tan(pi)는 cos(theta)sin(pi)/cos(theta)cos(pi)로 간단하게 구할 수 있는데, tan(theta)는 3개의 식을 G_px, G_py, G_pz에 대해서 풀어써야 된다.

암튼 내가 가진 gyro+accelemeter는 배치가 아래와 같이 되어있다.

x에서 y로 갈 경우, z가 나와야 되는데, 들어가니 left handed coordinate system인듯 한데..
X표시가 들어가는 방향. ●가 나오는 방향이다.
left handed, right handed coordinate

left handed
right handed

배치된 그림의 z축을 흔들리게 설치를 했다. z축이 회전이라 yaw를 알아야 한다고 처음에 판단 했으나, z축을 x축으로 변환을 하고, roll을 구하는 방법으로 해야 겠다. 난 한개의 값만 필요하니..
몇번의 삽질로..아래 식을 참조하여…대략 구할 수 있었다.

가속도 센서로 각도를 구하는 공식..

accelerationX = (signed int)(((signed int)rawData_X) * 3.9);
accelerationY = (signed int)(((signed int)rawData_Y) * 3.9);
accelerationZ = (signed int)(((signed int)rawData_Z) * 3.9);
pitch = 180 * atan (accelerationX/sqrt(accelerationY*accelerationY + accelerationZ*accelerationZ))/M_PI;

roll = 180 * atan (accelerationY/sqrt(accelerationX*accelerationX + accelerationZ*accelerationZ))/M_PI;
roll = 180 * atan (-accelerationY/accelerationZ) / M_PI;

yaw = 180 * atan (accelerationZ/sqrt(accelerationX*accelerationX + accelerationZ*accelerationZ))/M_PI;

위 식이 틀린 부분도 있어 보인다.
MMA7455L 가속도 센서를 사용하는데, 첨부로 data sheet를 넣어둔다..
MMA7455L
여기서 더 나가면, 센서 드라이버를 어떻게 구현했는지도 찾아봐야 할 것도 같다..

Lego NXT에 dimu 사용하기

https://nxttime.wordpress.com/2011/11/22/imu-sensor-software/

By request I will publish the Lejos software for the dIMU sensor.

The software contains of drivers for the Dexter Industries IMU sensor, programs to calibrate the sensor and the IMU filter that I wrote about on this blog before. The filter can be used for other IMU sensors as well. Also included is the sample program that utilizes this filter. It is the very same program I used in the video’s published in a previous post. There is no formal support and no warranty. If you are going to use it you will have to rely on your own wit, the javadoc and on this blog.
Download and install

You can download the software from this link. After downloading you will have to extract it keeping the directory structure intact. Make sure yor compiler can find the code.
Using the IMU drivers

The dIMU consists of two sensors, a gyroscope and a accelerometer, each has it’s own driver. The gyroscope driver is called L3G4200D and the driver for the accelerometer is MMA7455L. (I use the technical names of the sensors a driver names.) On top of these drivers I made user interfaces that allowes you to examine, configure and calibrate the sensors. The user interfaces are called L3G4200D_E and MMA7455L_E respectively. You can use these programs as driver as well. It gives your programs access to the additional functionality but it needs the NXT screen and might result in larger programs. There is a sample program included that gives access to the user interfaces, it is called testDIMU.

This is how you enable the drivers in your code,

SensorPort.S4.i2cEnable(I2CPort.HIGH_SPEED);
MMA7455L accel = new MMA7455L(SensorPort.S4);
L3G4200D gyro = new L3G4200D(SensorPort.S4);

 

The first line instructs Lejos to use high speed I2C. The sensors support this.

This is how you get data (rate, acceleration and tilt) from the sensors.

float[] rate = new float[3];
gyro.fetchAllRate(rate);

float[] accel = new float[3];
accel.fetchAllAccel(accel);

float[] tilt = new float[3];
accel.fetchAllTilt(tilt);

As you can see the drivers return data from all three axis is one call. If you just need data from one axis you can get it from the arrays. The order is X, Y, Z. The gyro returns degrees per second by default. The accelerometer returns Milli-G for acceleration and Degrees for tilt, also by default. If you want to use other units in your programs you can change the default values like this.

gyro.setRateUnit(RateUnits.RPS);
accel.setAccelUnit(AccelUnits.MS2);
accel.setTiltUnit(TiltUnits.RADIANS);

This changes the default units to radians per second, meter per second^2 and radians respectively. Other units are available, check the javaDoc. The default unit can be overridden per data request by specifying the desired unit as second parameter in the FetchAll… methods.
Configuring the sensors

The gyro can be configured for dynamic range and sample rate using the setRange and setSampleRate methods. As a rule one should select the lowest value that your application allows for. This gives data of best possible quality.

The accelerometer cannot be configured. I found this of little use.
Calibrating the sensors

The gyro of my dIMU doesn’t really need calibrating. however there is the possibility to do so. Calibration is started b calling gyro.calculateOffset(). During calibration the sensor should remain motionless. Calibration settings of the gyro are not stored, so they are lost when your program terminates. (Storing calibration settings of gyro sensors is of no use as the calibration values depend on environmental factors and are not stable over time.)

The accelerometer needs calibration. The user interface driver provides functionality to calibrate the sensor and to store the calibration settings. The (base) driver looks for stored calibration settings upon initialization and loads these automatically when they are available. Calibration settings of the accelerometer are stable over time so you’ll need to do this just once. Each of the three axes has to be calibrated separately. To calibrate an axis one has to point it straight up first and hold still while the calibration routine collects data samples. Then the axis has to be pointed straight down and held still for some time. Follow the on screen instructions and do not forget to save the settings after calibration.
Using the IMU filter

The IMU filter can be used with any three-axis gyro and any three-axis accelerometer as long as their drivers implement the RataData and TiltData interfaces. This is how you initialise the filter

NLCFilter attitude = new NLCFilter(gyro, accel);
attitude.start();

The two parameters to the filter constructor are the gyro driver and accelerometer driver. One could leave out the accelerometer, the filter will work but values will drift over time. The second line of code starts the filter. The filter needs 2 to 5 seconds to settle at start up, therefore you need to keep the sensor motionless and more or less level for a few seconds. You can find out if the filter is ready settling with the Initializing() method.

The IMU filter keeps track of the attitude, or pose, of your sensor/robot. You can query the roll, pitch and yaw angles this way

attitude.setTiltUnit(TiltUnits.RADIANS);
float roll=attitude.getRoll();
float pitch=attitude.getPitch();
float yaw=attitude.getYaw();

or

float[] tilt = new float[3];
attitude.fetchAllTilt(tilt);

By default these methods return angles in radians. You can change this by setting a different unit with the setTiltUnit() method.

You can also use the filter to transform data from a body frame to a world frame. This is useful if another sensor returns data that needs to be corrected for the robots current attitude. the next example transforms a distance returned by a UltraSonic sensor to world coordinates. The example assumes the us and IMU sensors are aligned and that the US sensor measures along the X-axis.

Matrix usBody=new Matrix(1,3);
Matrix usWorld=null;
us = new UltrasonicSensor(SensorPort.S1);
usBody.set(0,0,us.getDistance());
usWorld=attitude.transformToWorld(usBody);

The matrix usWorld now contains the distance from sensor to the detected object over the X, Y and Z axis.
Configuring and tuning the IMU filter

By default the IMU filter updates as often as possible. It’s update frequency is over 100 Hertz. To free computer resources one can lower the update frequency by using the setFrequency() method. The filter will try to match the specified frequency. A parameter value of 0 will run the filter at maximum speed.

The filter can be tuned to increase the quality of its output. I advise you not to tune the filter until you are familiar with it and understand its inner workings. Tuning consists of altering the P and I values of it’s internal PI controller. The I value takes care of gyro drift cancellation and the P value controls how fast attitude is corrected by use of tilt data from the accelerometer. The values can be modified by using the setKp() and setKi() methods.

There are two ways the filter can assist you in tuning. It keeps track of the integral of absolute errors, or absI. This is a measure of the total error of the filter over time. The smaller the error (given a fixed period) the better the filter performs. /* The filter also allows you to send data over bluetooth to the pc for examination. For this one has to use the NXTChartingLogger on the pc that is part of the Lejos distribution. You instruct the filter to send its state to the pc by supplying a NXTDataLogger object with the setDataLogger() method. */
Running the demo program

The demo program is called testIMU. At startup of this program the sensor must be horizontal and motionless. The sensor is assumed to be aligned ith the NXT brick with the sensor plug facing to the same direction as the sensor ports. Once you see the wire frame you can start moving the sensor.The demo has four display modes:

Wire frame. Here it shows a wire frame of the sensor on the NXT screen
Rotation matrix. The screen will show the content of the rotation matrix. In this matrix the current attitude is stored. The matrix is also used to convert body coordinates to world coordinates by matrix multiplication..
Roll, Pitch, Yaw. The screen shows the Roll, Pitch, Yaw angles of the sensor.
Update speed. The screen shows the actual update speed of the filter.

You can browse through the display modes by using the arrow keys. The enter key resets the filter. The clip below shows the demo program in action in wire frame mode.

우분투+LEGO NXT(Lejos)를 eclipse로 bluetooth로 연결하기

전에 우분투에 lejos가 깔린 lego nxt를 eclipse로 연결을 해서 파일 전송을 했었는데, 간만에 하니 시간이 좀 걸렸다. 이번에 정리한다..

먼저 ubuntu의 bluetooth 모듈을 상태를 알아야 된다..

>hcitool dev
Devices:
hci0 00:1A:7D:DA:71:02

 

다음에 hci0의 상태를 알아낸다.

>hciconfig hci0
hci0: Type: BR/EDR Bus: USB
BD Address: 00:1A:7D:DA:71:02 ACL MTU: 310:10 SCO MTU: 64:8
UP RUNNING PSCAN ISCAN
RX bytes:15110 acl:283 sco:0 events:1300 errors:0
TX bytes:41343 acl:1147 sco:0 commands:88 errors:0

 

나의 경우에는 bluetooth 동글이 usb로 연결되어 있다..

다음에 nxt의 블루투스 모듈의 주소를 알아낸다.

>hcitool scan
Scanning ...
00:16:53:12:7A:83 NXT

 

이를 바탕으로 /etc/bluetooth/rfcomm.conf 파일을 아래와 같이 수정한다.

>sudo cat /etc/bluetooth/rfcomm.conf
#
# RFCOMM configuration file.
#

rfcomm0 {
# Automatically bind the device at startup
bind no;

# Bluetooth address of the device
device 00:16:53:12:7A:83;

# RFCOMM channel for the connection
channel 1;

# Description of the connection
comment "LegoNXT";
}

 

 

다음에 아래의 명령어로 연결한다.

>sudo rfcomm connect /dev/rfcomm0 00:16:53:12:7A:83 1
Connected /dev/rfcomm0 to 00:16:53:12:7A:83 on channel 1
Press CTRL-C for hangup

CTRL-C로 연결을 끊어주고..eclipse로 연결하면 된다…

nxt로 연결이 되었는지, 아닌지는 아래 명령으로 확인이 가능하다.

>sudo l2ping 00:16:53:12:7A:83
Ping: 00:16:53:12:7A:83 from 00:1A:7D:DA:71:02 (data size 44) ...
4 bytes from 00:16:53:12:7A:83 id 0 time 26.82ms
4 bytes from 00:16:53:12:7A:83 id 1 time 64.92ms
4 bytes from 00:16:53:12:7A:83 id 2 time 24.87ms
4 bytes from 00:16:53:12:7A:83 id 3 time 73.89ms
4 bytes from 00:16:53:12:7A:83 id 4 time 34.89ms
4 bytes from 00:16:53:12:7A:83 id 5 time 25.89ms
4 bytes from 00:16:53:12:7A:83 id 6 time 76.82ms

 

eclipse로 아래와 같이 설정 후, 연결하면 된다.
eclipse%ec%84%a4%ec%a0%95%ed%99%94%eb%a9%b4

eclipse에서 에러를 뿜어내는데 bluecove 어쩌고 나온다..

 >sudo apt-get install libbluetooth-dev

 

이렇게 관련 프로그램을 설치하면 된다.

KDE의 경우, PIN 입력이 안되는데, bluez-simple-agent로 연결하면 된다.

bluez-simple-agent hci# xx:xx:xx:xx:xx:xx

출처는 인터넷…

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

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

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

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

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

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