Let’s go!

  • 아이들 1월 사진

    아이들 1월 사진

    Sorry you have no rights to view this post!

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

    가속도 센서로 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.

  • mp3태그로 plexmedia server 정보 업데이트

    mp3태그로 plexmedia server 정보 업데이트

    mp3 tag, id3로 Plexmediaserver의 정보 업데이트 하기

    나는 plexmediaserver로 mp3를 저장하여 듣고 있다. plex에서 라이브러리로 mp3가 있는 경로를 알려주면, agent가 파일을 검색하여 그에 알맞는 가수, 앨범, 노래명을 정리한다. 내가 가진 mp3는 대부분 인터넷에서 받은 파일이라, tag 정보가 완전 제각각대로 되어 있다. 이 태그를 정리하지 않고, 곡 추가를 하면, plex가 같은 가수인데 철자가 달라 다른 사람으로 인식한다. 따라서 데이터베이스가 완전 개판이 된다. 전에는 태그를 수정을 했었는데, plexrk 이 수정분을 인식하지 못했다. 왜 그런지 궁금해 하다가 포기 했었다. 오늘 다시 좀 해보니 알 것 같다.
    plex agent는 처음 곡을 추가할 때만 mp3의 태그 정보를 자신의 DB로 읽어 들이는 듯 하다. plex가 자기가 가진 데이터베이스로 복사를 하면, 사용자가 tag를 수정했다고, plex가 자신의 DB로 업데이트를 안한다. 사용자가 한번 정보를 잘못 입력하면, 이를 마우스+클릭으로 수정해야 하는데, 시간이 많이 걸린다. 라이브러리 전체를 지운 다음에, 다시 추가를 하면 id3에서 plex DB로 다시 옮긴다.
    정리를 위해서, mp3에 있는 쓰레기 태그를 다 지워버리고, 내가 관리할 정보만 남겨 놓았다.
    stack overflow에 이와 관련된 스크립이 공개되어 있다.

    find ./ -type f -iname "*.mp3" -exec /usr/bin/mid3v2 --delete-frames=AENC,ASPI,COMM,COMR,ENCR,EQU2,ETCO,GEOB,GRID,LINK,MCDI,MLLT,OWNE,PRIV,PCNT,POPM,POSS,RBUF,RVA2,RVRB,SEEK,SIGN,SYLT,SYTC,TBPM,TCOM,TCOP,TDEN,TDLY,TDOR,TDRL,TDTG,TENC,TEXT,TFLT,TIPL,TIT3,TKEY,TLAN,TLEN,TMCL,TMED,TMOO,TOAL,TOFN,TOLY,TOPE,TOWN,TPE3,TPE4,TPOS,TPRO,TPUB,TRSN,TRSO,TSOA,TSOP,TSOT,TSRC,TSSE,TSST,TXXX,UFID,USER,USLT,WCOM,WCOP,WOAF,WOAR,WOAS,WORS,WPAY,WPUB,WXXX '{}' +

    tag를 수정하는 유틸리티는 여러개가 있으나, 셸에서 사용이 가능한 mid3v2를 선택했다.
    MP3 tag의 주요정보 내용은 아래와 같다.
    APIC A picture for the track, usually the albumcover.
    TIT1 Content group description (I guess could be deleted too)
    TIT2 The song title
    TPE1 The album artist
    TPE2 The artists (includes featurings)
    TRCK Tracknumber
    TALB Albumtitle
    TCON Genre
    TDRC Year of release

    이 정보에서 곡 이름, 앨범의 이름, 가수가 누구인지 등 몇 개의 정보만 관리한다. 나머지 정보는 관리하기 힘들기 때문에 지워야 된다. 여기에 엄한 정보가 들어가면, plex가 파일을 잘못 인식한다.
    가수는 동일하니, 아래의 명령어로 엄한 정보가 들어가 있는 파일을 찾았다. TPE1과 TPE2 두 종류가 있는데, plex는 이를 제대로 인식하지 못한다. TPE2는 지워주는게 좋다.

    now0930@:10cm$ find ./ -type f -exec mid3v2 {} \; | grep -e 'TPE1\|TIT2'
    now0930@:10cm$ find ./ -type f -exec mid3v2 {} \; | grep TALB
    

    plex는 앨범, 가수명, 트랙 이 세가지를 기준으로 보여준다. 트랙까지는 관리하기 힘들어 보인다. 일단 앨범 정보부터 아래와 같이 맞춘다.

    now0930@:10cm$ mid3v2 --TALB="10cm" *.mp3

    다음으로 가수명도 같은 방식으로 맞춘다. 수정 후 plex 라이브러리에 넣으면 제대로 정보가 올라간다.

    한가지 아쉬운 점이라면, 내가 TIT2에 곡 이름을 넣어야 됬는데, 파일이름이 대부분 곡 이름이다. basename으로 파일 이름을 뽑고, 이를 TIT2의 파라미터로 전달해야 하는데, 별도 스크립트를 만들어야 하는 작업처럼 보인다. 몇번 입력하다보니, 힘들어서 못하겠다.

  • tensorflow로 gps 좌표를 Kmean 방법으로 분류하기

    tensorflow kmean으로 gps 분류 연습 예제, 2일차

    내가 참조한 예제에서 원래 제작자는 임의의 샘플을 만들고, 그 중에서 한 개를 중심으로 선택하였다. 나는 데이터를 가지고 있어, 임의의 샘플을 만들 필요가 없다. 이에 따라 내가 가진 여러 개의 데이터 중, 임의 한 점을 중심으로 선택해야 했다. 내가 가진 예제는 이 부분이 없어, 예제를 이해하고, 새로 작성하는데 시간이 오래 걸렸다. 여러 삽질끝에 대략 아래와 같이 했다.
    1일차에는 그룹을 설정하지 않았는데, 이렇게 되면 의미가 없다. 이를 수정하기 위해서 gps 좌표를 요일별로 모은 다음 출력으로 내보냈다. 요일별 모은 데이터에서 두 개의 요일을 선택했고, 여기에서 아무점이나  중심으로 선택했다. 일단 sql에서 요일별로 gps 값을 다시 출력하여 아래와 같은 값을 얻었다.

         latitude  longitude  updated
    0     37.3700    126.935        6
    1     37.3698    126.935        6
    2     37.3698    126.935        6
    3     37.3697    126.935        6
    4     37.3697    126.935        6
    79    37.0344    126.773        5
    80    37.0344    126.773        5
    81    37.0344    126.773        5
    82    37.0343    126.773        5
    83    37.0343    126.773        5
    235   37.0325    126.773        4
    236   37.0325    126.773        4
    237   37.0325    126.773        4
    238   37.0325    126.773        4
    239   37.0325    126.773        4
    401   37.0344    126.773        3
    402   37.0344    126.773        3
    403   37.0344    126.773        3
    404   37.0343    126.773        3
    405   37.0343    126.773        3
    544   37.0344    126.773        2
    545   37.0344    126.773        2
    546   37.0344    126.773        2
    547   37.0344    126.773        2
    548   37.3687    126.935        2
    695   37.0343    126.773        1
    696   37.0344    126.773        1
    697   37.0343    126.773        1
    698   37.0343    126.773        1
    699   37.0343    126.773        1
    900   37.3696    126.935        7
    901   37.3695    126.935        7
    902   37.3695    126.935        7
    903   37.3716    126.935        7
    904   37.3716    126.935        7
    

    pandas에서 dataFrame을 groupby로 정렬하면 python이 데이터 형식을 변경해 버린다. 요일로 선택한 데이터를 dataFrame으로 사용하기 위해서 아래와 같이 했다. append 할 경우, 새로운 dataFrame을 만들어야지, 기존 dataFrame에 넣으면 붙지 않는다.

    ipdGroupbyUpdated = ipd.groupby('updated')
    print ipdGroupbyUpdated.head()
    
    #updated에서 1일차 날짜, 3일차 날짜를 구해서 별도의 dataframe을 설정..
    #pd.show_versions()
    print ipdGroupbyUpdated.get_group(1)
    #print type(ipdGroupbyUpdated.get_group(1))
    ipdSliced=ipdGroupbyUpdated.get_group(1)
    print "1일차 데이터"
    print ipdSliced.head()
    print type(ipdSliced)
    
    ipdSliced1=ipdGroupbyUpdated.get_group(7)
    print "3일차 데이터"
    print ipdSliced1.head()
    print type(ipdSliced1)
    

    찾아보면 더 쉬운 방법이 있겠지만, 여기까지 하는데도 충분히 힘들었다.

    두 개 요일로 선택한 좌표를 그림을 그리기 위해서, 아래과 같이 함수를 정의하고, dataFrame을 인자로 넘겨 주었다. 굳이 함수로 정의한 이유는 원래의 예제가 함수로 되어 있었기 때문이다.

        def plot_clusters(df_ipd, centroids):
        print("plot_clusters was called")
        import matplotlib
        matplotlib.use('Agg')
        import matplotlib.pyplot as plt 
    
        for key, val in df_ipd.groupby('updated'):
            tmp_centoid=df_ipd[df_ipd.updated==key].sample()
            #print "tmp_centoid 출력\n"
            #print tmp_centoid[['longitude','latitude']]
            #print tmp_centoid[['longitude']]
    
            plt.scatter(val['longitude'], val['latitude'], label=key)
            plt.plot(tmp_centoid[['longitude']],tmp_centoid[['latitude']], markersize=35, marker="x", color='k', mew=10) 
            plt.plot(tmp_centoid[['longitude']],tmp_centoid[['latitude']], markersize=30, marker="x", color='m', mew=5)
    

    for문이 groupby의 기준인 날짜기준으로 key값을 변경하면서 루프를 만든다. dataFrame에서 임의의 점을 찾기 위해 tmp_centoid[‘longitude’]와 같은 방식을 선택했다. 마지막에 있는 marker관련 2개의 줄은 X의 색을 칠하는 부분이다. 필요 없다고 판단하여 한 줄만 사용하니 색이 안칠해 졌다.
    대략 아래와 같은 그림을 얻을 수 있다..

    전에 데이터와 달리 위도/경도의 축을 바꿨다.