Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Scripting gyroscope - tilting device around one axis

Discussion in 'Scripting' started by Cato11, Apr 17, 2022.

  1. Cato11

    Cato11

    Joined:
    Jan 5, 2021
    Posts:
    193
    I would really appreciate some help with a problem I have been struggling with the past few days. I am developing a game where I need to tilt a mobile device to steer a ship as it flies in a straight line. The steering should be consistently accurate in any orientation, e.g. if the player holds the device directly in front of their face, if they are slouched over facing the ground, reclining back with the phone pointing up etc.

    This is shown in the image below.

    ScIzg.png

    Basically what I need to achieve is:
    • Tilting the device to alter the on-screen ship's rotation. I need the real-world tilting to be about the device's local z-axis, i.e. a yaw about the axis going through the screen.
      • In my game-world this will be mapped to an object's y-axis since it is a top-down 3D game. This is why I say "tilt" (think Temple Run), panning around in space to change all axes is not what I want.
    • I need to know how quickly the user is tilting their device to control the steering speed
    • I need to know the current tilt angle at any instance, relative to the "local z-axis"

    So far I have been trying to implement this using the gyroscope but I am really struggling to get the tilting working. My code is:

    Code (CSharp):
    1.  
    2. // Define a forward axis
    3. Vector3 fwd = Quaternion.Inverse(gyro.attitude) * Vector3.back;
    4. // Calculate yaw about this axis
    5. float yawDegs = Mathf.Asin(fwd.x) * Mathf.Rad2Deg;
    6.  
    This code works very well, i.e. if I tilt the phone 45° I actually see 45° on screen. BUT this is only the case when phone is held vertically upright with zero pitch or roll, i.e. the phone is facing parallel to ground. As soon as I pitch or roll, my yaw angle starts to change, e.g. if I slouch over and face the ground, tilting the screen is not detected, rather this is shown on-screen as a roll angle.

    I think my problem is that I am using real-world orientation. But I need to define a local z-axis that always goes through the screen, no matter which direction it is facing. I then need to yaw about that local z-axis. Please can someone help me with this? I am completely confused as to how to achieve this.

    Interestingly, this is how the
    Code (CSharp):
    1. gyro.rotationRateUnbiased
    function works. If I tilt quickly in any orientation, it detects the speed consistently about a local z-axis, no matter what the orientation is! I don't understand why Unity does not give us an equivalent for attitude?! Any help would be greatly appreciated.

    Or if you have another idea/better solution I am open to ideas.
     
  2. Peeling

    Peeling

    Joined:
    Nov 10, 2013
    Posts:
    401
    You need to sample the device's orientation as the level starts, and use that quaternion to generate and store an 'up' vector (ie a vector representing a line drawn from the bottom of the device to the top) and an 'in' vector (it a vector drawn through the screen from the front to the back).

    During gameplay, recalculate the current 'up' vector and then use Vector3.SignedAngle(originalUp, currentUp, originalIn).

    That will work to an extent, but fail if the user is playing in a car or train that goes around a corner.

    I'm not 100% certain, but I think you can fix that thus:
    Code (CSharp):
    1.         Quaternion q = Quaternion.FromToRotation(originalIn, currentIn);
    2.         Vector3 correctedOrignalUp = q * originalUp;
    3.         tilt = Vector3.SignedAngle(correctedOrignalUp, currentUp, currentIn)
     
  3. PanicEnsues

    PanicEnsues

    Joined:
    Jul 17, 2014
    Posts:
    185
    As Peeling said, you'll need to store the "home" orientation at startup, then calculate the difference between the current and home orientations.

    And due to the constant drift in the crappy gyros used in most devices (esp. Android phones), you'll want that "store the home orientation" as a function that the player can call with a button press at any time.
     
  4. Cato11

    Cato11

    Joined:
    Jan 5, 2021
    Posts:
    193
    Hi Peeling, PanicEnsues.. I opened up a separate thread that is very much related to the same issue. I have already done what you both describe and it is detailed in that thread. The problem seems to be more of a quaternion problem. Your advice would be really welcomed - the thread is this one. I think it makes sense if this thread is therefore closed.