Shop OBEX P1 Docs P2 Docs Learn Events
Memsic 2125 - getting tilt angle? — Parallax Forums

Memsic 2125 - getting tilt angle?

fiddejohfiddejoh Posts: 6
edited 2010-03-10 14:44 in Propeller 1
Sorry if the topic has been answered, I did a search but couldn't find any threads that answered my question.

I recently got a Memsic 2125 accelerometer and I'm getting the raw values (both X and Y is ~397000).
I found this code to convert it to degrees

offset := 90 * (clkfreq / 200)   'offset value for sensor data conversion
scale  := clkfreq / 800             'scale value for sensor data conversion




Not entirely sure how those formulas work though..
I also found this PDF: http://www.parallax.com/Portals/0/Downloads/docs/cols/nv/vol3/col/nv92.pdf which is using another formula to calculate the tilt angle.

Could someone kindly clarify what I should use?

Thanks in advance!

Comments

  • Graham StablerGraham Stabler Posts: 2,510
    edited 2010-03-08 20:21
    Could you say where that code came from?

    Graham
  • fiddejohfiddejoh Posts: 6
    edited 2010-03-08 20:52
    Hi,

    it's from a Parallax Demo that I found here: http://obex.parallax.com/objects/235/

    From the file: MX2125 Demo.spin

    / Fredrik
  • Graham StablerGraham Stabler Posts: 2,510
    edited 2010-03-08 22:38
    OK, I think I get it. It took some figuring out. Firstly I hate the way 12.5% is used to mean 0.125 but that is something else.

    Firstly Paul is using the system clock to measure time not the Pulsein routine so the resolution is 1/clkfreq. He also changes the equation to be in terms of the difference between the pulse length T1 measured (accel.x) and what it would be at 50% duty cycle when T1 = T2/2 and A = 0g.

    T2 is clkfreq/100 so at 50% duty when T1 = T2/2:

    T1@50% = clkfreq/200

    This is basically the offset he uses (ignore the 90 for now)

    So what is T1 when A = 1g? This is when the sensor is at 90 degrees

    1 = (T1/T2 - 0.5)/0.125 from datasheet and Jon's article
    0.125 = T1/T2 - 0.5
    0.625 = T1/T2
    0.625T2 = T1
    T1@1g = 0.652(clkfreq/100) because T2 = clkfreq/100

    So what is the difference when A = 1g?

    difference = T1 - (clkfreq/200)
    difference@1g = T1@1g - (clkfreq/200)
    difference@1g = 0.625(clkfreq/100)- (clkfreq/200) Substitute fot T1@1g from above
    difference@1g = (clkfreq/100)(0.625 - 0.5)
    difference@1g = (clkfreq/100)(0.125)

    So when the difference between measured T1 and T1@50% is equal to difference@1g then we want the equation to be equal to 90.

    To do this we multiply both sides of the equation for difference by 1/difference@1g this will make the equation equal to one when the sensor is at 1g. We then multiply the equation by 90 so that it is actually 90 when at 1g.

    difference*100*90*8/clkfreq (8 because 1/0.125 is 8)

    = (T1 - (clkfreq/200))*800*90/clkfreq
    = (T1*90 - (clkfreq*90/200)) * (800/clkfreq)

    Then let:

    offset = (clkfreq*90/200)
    scale = clkfreq/800
    accel.x = T1

    So:

    Angle = (accel.x*90 - offset)/scale

    I hope that makes some sense, he also just assumes the relationship between g and angle is linear.

    Graham
  • Graham StablerGraham Stabler Posts: 2,510
    edited 2010-03-08 22:41
    Or to put it another way, if you only want accuracy to a degree then Paul's method is fine. The code in Jon's article needs to be modified a little because of the increased resolution when measuring the pulse lengths.

    Graham
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2010-03-09 02:47
    fiddejoh,


    There is an updated object I did awhile ago that should provide individual Tilt angle information.

    obex.parallax.com/objects/140/

    Here is a You-Tube video of that DEMO in action...

    www.youtube.com/user/ICPolyman#p/u/7/ef7ZAb5fOv8


    If there is a question as to where the large numbers (~400K) come from and how they relate to the measured value, it has to do with the speed of the Propeller running at 80MHz

    The 'raw' values are simply returning THx which at 0g should be reporting a pulse width of 5ms. 5ms divided by 12.5ns (<-80MHz) equals 400,000. So to get values like you might be more familiar with from the BS2 you could divide the Raw ~400K value by 160. This would in effect give you a 2us resolution (<-- that of the BS2). So a 5ms pulse at 0g divided by 160 would produce an expected value of 2500


    Can you please also site the URL where you are finding the deg conversion? In the context that you have provided them they don't seem correct, but looking at the rest of the code it might make more sense.

    Typically to convert the 32-Bit Angle returned from the Memsic Coordic operation into something more 'human readable' you typically do a 'shift right' of 19 or divide by 524288... this does an immediate conversion from a 32-Bit Angle into a 13-Bit Angle.

    Likewise since all of the graphics routines are localized around a 13-bit Angles, to convert an ordinary Deg value into a 13-Bit Angle you typically apply a formula similar to this...

    Angle13 := (Deg *1024)/45

    To go the other direction a derivative of these formulas would be used. .i.e.

    Deg := (Angle13 * 45)/1024

    ...I don't really see a need to create a 32-Bit Angle, but if you needed to just shift left the Angle13 value.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.

    Post Edited (Beau Schwabe (Parallax)) : 3/9/2010 3:50:42 PM GMT
  • fiddejohfiddejoh Posts: 6
    edited 2010-03-09 06:41
    Graham, Beau,

    thank you VERY much! Excellent explanations, it helped me a lot. [noparse]:)[/noparse]


    / Fredrik
  • Graham StablerGraham Stabler Posts: 2,510
    edited 2010-03-09 09:57
    Beau,

    5ms would be 0g because it's 50% duty?

    > "Can you please also site the URL where you are finding the deg conversion?"

    The code Fredrik posted is a snippet from Paul's object (http://obex.parallax.com/objects/235/) but your object contains exactly the same code for offset and scale.

    Fredrik,

    Glad to be of help.

    Graham
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2010-03-09 16:06
    Graham Stabler,

    right you are, Corrections have been made. It's been awhile since I visited that code, and I was looking at the "Graphics_Demo_v2" program where I didn't see it.

    I do see it now in the actual 'core' driver "Memsic2125_v1.2" ... I think when I modified the "Memsic2125_v1.2" I either borrowed some of Pauls code ideas or resolved down a similar path.


    Looking at it now it looks like it could be simplified and the *90 could at least be taken out of the equation, but I don't want to mess with anything right now.

    If you look at offset ... assuming that the clkfreq is 80MHz ... it resolves to 36,000,000
    likewise, if you look at scale ... it resolves to 100,000

    How offset and scale are used later basically divides them ... offset / scale = 360 ... to obtain your deg value.

    The scaling and offset is necessary to bring the levels to the raw output of the Memsic, and since the output is clock dependent, it must be factored in.

    My thinking as far as simplifying is that the existing code below...

        offset := 90 * (clkfreq / 200)                        'offset value for Tilt conversion
    
    


    ...
    PUB MxTilt
        return (_xraw*90-offset)/scale
    
    PUB MyTilt
        return (_yraw*90-offset)/scale
    
    



    ... Could be simplified to something like the code below with the same results (keep in mind it's untested)

        offset := clkfreq / 200                        'offset value for Tilt conversion
    
    


    ...
    PUB MxTilt
        return (_xraw-offset)/scale
    
    PUB MyTilt
        return (_yraw-offset)/scale
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.
  • ServoMServoM Posts: 10
    edited 2010-03-09 23:06
    Beau:

    Thanks very much for that; the thread has cleared up a nagging question in my head as I explored the Memsic driver. I could not figure out why that factor of 90 was in there. In fact, I was, quite literally writing you an email about this very issue when I came across this thread....

    I am using this module with the Analog Devices ADXL 213 accelerometer, and the scaling for this device is different, as is the PWM period (actually, the period is user-settable). Moreover, the ADXL213 has a CAL pin, which enables one to quickly check the correctness of the implementation for reading it.

    FWIW, my first foray into Propellerland went quite well as I used a PWM spin module to drive the Memsic spin module, so that I could diagnose what was going on, and this enabled me to quickly sort the matter and get the ADXL 213 going. The overall project is an inertial dynomometer for use in automotive applications.
  • Graham StablerGraham Stabler Posts: 2,510
    edited 2010-03-10 10:41
    Beau, to make the code clearer you could use a different word other than offset as I don't think it is really appropriate, something like T1_at_zero_g or something, then it is clear you are looking at the offset from that point when you take the difference. Also I think you are right to factorize out the 90 but scale needs to be modified.

    Graham
  • ServoMServoM Posts: 10
    edited 2010-03-10 13:05
    Graham and Beau:



    Here's what I am using for the ADXL213 (this is the start proc in the Memsic2125_V1.2.spin source):

    PUB start(xpin, ypin) : okay

    '' Start driver - starts a cog
    '' returns false if no cog available
    ''
    '' xpin = x input signal
    '' ypin = y input signal
    ''
    stop
    'MAM: can't see what the 90 is in the next line. But, clkfreq/200 is 50% of the duty cycle @ 100Hz
    'MAM: for the ADXL213, with a duty cycle of 1 Khz, this should be: clkfreq/2000
    offset := clkfreq/2000 '90 * (clkfreq / 200) 'offset value for Tilt conversion
    'MAM: clkfreq/800 is 12.5% of the duty cycle of 100 Hz. 12.5% is the sensitivity of the Memsic 2125
    'MAM: for the ADXL213, with a duty cycle of 1 Khz, this should be: clkfreq/3000. 30% is the sensitivity of the ADXL213
    scale := clkfreq/3000 'clkfreq / 800 'scale value for Tilt conversion
    ctra_value := $6800_0000 + xpin
    ctrb_value := $6800_0000 + ypin
    mask_value := |<xpin + |<ypin
    okay := cog := cognew(@entry, @calflag) + 1

    If one uses the Mx and My procs to retrieve the raw values, you will find that this works for obtaining the (correct) raw accelerometer output in mg. On the ADXL213, as I mentioned, there is a cal pin, which when used, will cause the ADXL to output 750 mg (23% duty). This can easliy be verified by looping back a PWM spin driver into the Memsic driver. Furthermore, it can be verified on the device itself. One of the consequences of not having such a cal function is that one cannot easily confirm the correctness of an implementation for the driver. If all you're interested is an output proportional to acceleration (for example, a feedback on an attitude control system), I suppose it's not a big deal. But, if you are after a reasonably accurate output, it becomes more of an issue. The Memsic would also liikey require some temperature correction if the accel values were to be used on an absolute basis, depending on how it is to be used.

    Finally, I have not checked the cordic routines, but the question I have on this part of the implementation is, are those routines computing based on angles in degrees or angles in radians? That was part of what was confusing me on the factor of 90 in the scaling (I was expecting the transcendentals to be done in radians...). It appears that the angles are being computed in degrees. Anyone confirm? I will find out empirically, otherwise.

    Thanks,

    Mike
  • Graham StablerGraham Stabler Posts: 2,510
    edited 2010-03-10 14:44
    IIRC the cordic is not using degrees or radians I think it represents 360 degrees by $2000 hence the division by 8192

    Graham
Sign In or Register to comment.