Detecting change in device orientation

I would like to be able to calculate the change in device orientation but can’t figure out to achieve it. Specifically, I want to track changes of camera focus vector, e.g. assuming that if in local coordinates at time 0 camera looks along x axis, find it’s vector representation at time 1 in current (time 1) local coordinate system. I already have gravity vector, so adding compass vector would make it simple, but is compass reading available in codea? Can’t find it, location.course seems to work in very different way. RotatioRate seems promising but what those numbers are: absolute angle changes since last reading, rate of angle change per sec since last reading? Whatever it is, they seem to come as raw data with bias still in?

Thank you

@Rusty Not really sure what you’re doing, but Gravity.x, .y, and .z gives a good representation of how the iPad is orientated.

PS. There’s also a location.course variable that’s supposed to give a compass reading, but I haven’t gotten it to work. I just get -1 which means it’s not working. Maybe the iPad needs to be moving a large distance for it to work.

@dave1707 it could be the case you get -1 for course (an invalid reading) if your iPad does not have GPS, which the WiFi model does not have

(It’s the direction you’re travelling based on location samples over time)

@Simeon I thought maybe it could determine the compass direction based on the change in location.latitude and location.longitude if the iPad moved far enough. For instance while moving in a car there would be a large enough change in latitude and longitude.

Argh! I still can’t figure what RotationRate means: is it speed of rotation in radians per sec around each three axis? What function supplies the result: is it CMRotationRate from CMDeviceMotion?


@Rusty I think RotationRate is radians per draw cycle. I haven’t been able to prove that yet with code.

PS. radians per draw cycle is probable too fast, so that’s probably not it.

PS. Playing around with a program, so far it looks like it’s radians per second.

PS. What I’m seeing with my program is the time it takes to rotate the iPad 90 degrees times the average rotation rate equals 1 radian.

@Rusty I may be over complicating things, but what I’m seeing with my program using rotation rate is:

If I rotate my iPad from 0 to 90 degrees, then the (average rotation rate times the time to rotate it some angle) divided by (some angle divided by 90) gives a value of approx 1.57 . Like I said this is over complicated, but I’m still playing with it.

@Rusty Here’s a simpler calculation I came up with.

Average rotation rate times time times 57 gives degrees of rotation.

@dave1707 that is correct, but I think it only works on iPads which have GPS

@Rusty it is the rotation rate provided by CMDeviceMotion

Thanks Dave and Simeon! It start making sense to me now!

@Simeon I have a WiFi only iPad and the rotation rate works OK. Is that what you were referring to above about GPS only iPad’s.

@dave1707 that was about location.course — I think that’s only on GPS/cellular iPads

In my vector extension code (available on github) then I have a function that converts the RotationRate to a quat suitable for keeping track of a device’s rotation. Namely, if you keep multiplying the current rotation by this quat then the resulting transformation will keep your scene steady in space (within the bounds of accuracy).

I’m not on my iPad right now, but I have some code that uses it to keep a cube steady. I’ll dig it out later.

This uses RotationRate directly:

function setup()
    local size = math.min(HEIGHT, WIDTH) / 2
    d = 1000
    m = cubeMesh(size)
    dirz = vec3(0, 0, 1)
    diry = vec3(0, 1, 0)
    dirx = vec3(1,0,0)
    mat = matrix()

function draw()
    local mat = matrix()
    local dxa = RotationRate.x
    local dya = RotationRate.y
    local dza = RotationRate.z
    mat = mat:rotate(dza, dirz.x,dirz.y,dirz.z)
    mat = mat:rotate(dya, diry.x,diry.y,diry.z)
    mat = mat:rotate(dxa, dirx.x,dirx.y,dirx.z)
    dirx = mult(mat, dirx)
    diry = mult(mat, diry)
    dirz = mult(mat, dirz)
    local x = dirz.x * d
    local y = dirz.y * d
    local z = dirz.z * d
    camera(x, y, z, 0, 0, 0, diry.x, diry.y, diry.z)

function cubeMesh(size)
    local v = {}
    local c = {}
    for i = 0, 7 do
        local x = (i % 2) * 2 - 1
        local y = (math.floor(i / 2) % 2) * 2 - 1
        local z = (math.floor(i / 4) % 2) * 2 - 1
        v[i] = vec3(x, y, z) * size / 2
        c[i] = color(127 + 127 * x, 127 + 127 * y, 127 + 127 * z)
    local ver = {}
    local col = {}
    for v1 = 1, 3 do
        local v2 = v1 * 3 % 7
        local v3 = 7 - v1
        local v4 = 7 - v2
        local vt = {v[0], v[v1], v[v2], v[0], v[v3], v[v4], 
            v[7], v[v2], v[v1], v[7], v[v4], v[v3]}
        for i = 1, #vt do
            ver[(v1 - 1) * #vt + i] = vt[i]
        local ct = {c[0], c[v1], c[v2], c[0], c[v3], c[v4], 
            c[7], c[v2], c[v1], c[7], c[v4], c[v3]}
        for i = 1, #ct do
            col[(v1 - 1) * #ct + i] = ct[i]
    local m = mesh()
    m.vertices = ver
    m.colors = col
    return m

function mult(mat, vec)
    local v1 = mat[1] * vec.x + mat[5] * vec.y + mat[9] * vec.z
    local v2 = mat[2] * vec.x + mat[6] * vec.y + mat[10] * vec.z  
    local v3 = mat[3] * vec.x + mat[7] * vec.y + mat[11] * vec.z
    return vec3(v1, v2, v3)