Hello Tello Pilot!
Join our DJI Tello community & remove this banner.
Sign up

IR Height Data

VR_Dev

Well-known member
Joined
Aug 19, 2018
Messages
48
Reaction score
46
I am trying to get the height sensor data from the downward facing IR sensor.

I am currently getting the height via TelloLib, which I believe is getting the accurate height data from the SDK. I expected this to be the raw IR data, meaning the distance to the object directly below the craft.

It seems however that this is the height from the takeoff point. I know this because the height does not change as I fly from above my lawn to above my roof. I would expect the value to drop greatly as the ground has essentially moved up below the tello.

The fact this value doesn't indicates height is really the barometer reading, or some kind of IR value that takes these elevation changes into account.

Im curious if anyone knows how to get the raw sensor data, meaning the distance between the tello, and whatever it is flying directly over.

Any help would be appreciated, thanks.
 
Last edited:
What was the height above your roof?

I guess that you get height readings as distance readings from the IR sensor only as long as that sensor delivers usable values - may be up to 3 meters distance from a surface or so (also depending on the texture and angle)

When the IR sensor gets out of range, you propably only get readings from the baro sensor as heigt above starting point.
 
Addendum:
I looked into the SDK. In the "Tello State" (a long string contaninig several key:value pairs), you get seperate values for tof (ToF distance if IR), h (height relative to take-off) and baro (height detected by barometer).

So I guess, that height is something calculated by sensor fusion, whereas tof and baro may be the raw readings.
 
The altitude above ground available through the proprietary protocol is fairly accurate and reliable up to 10m. I use it for the "follow terrain" mode in TelloFpv where Tello automatically keeps it's altitude above ground.

I am not 100% sure this is strictly raw IR sensor output as this could also include some sensor fusion.
 
So I am use Krag's TelloLib, which uses the low level protocol to communicate with the drone. This works really well but I'm 100% sure the height value is wrong.

Thanks to Hacky I saw in the SDK protocol there is height, baro, and tof. I would assume tof is Time of Flight but the documentation says it is measured in cm.

Anyway, spent the last few days writing my own sdk communicator and I got it working. The tof is greater than height which is confusing to me, but it does seem to change with altitude change as well as when I place something under the quad. The value decreases, which is what I want.

Non of this matters anyway, because as I am hooking up my new SDK I see that the supported SDK doesn't show posx, posy, from takeoff? That's the most powerful part! I didnt even bother looking from them in SDK documentation before I started the switch else I never would have bothered.

Does anyone know a low level protocall c# or c++ library that has an accurate height, and exposes tof?

Now I am going to attempt to fix TelloLib's height, but not too familiar with byte parsing. I know height here is wrong. It returns integers which are closer to 1 = 100cm

C#:
public void set(byte[] data)
            {
                var index = 0;
                height = (Int16)(data[index] | (data[index + 1] << 8)); index += 2;
                northSpeed = (Int16)(data[index] | (data[index + 1] << 8)); index += 2;
                eastSpeed = (Int16)(data[index] | (data[index + 1] << 8)); index += 2;
                flySpeed = ((int)Math.Sqrt(Math.Pow(northSpeed, 2.0D) + Math.Pow(eastSpeed, 2.0D)));
                verticalSpeed = (Int16)(data[index] | (data[index + 1] << 8)); index += 2;// ah.a(paramArrayOfByte[6], paramArrayOfByte[7]);
                flyTime = data[index] | (data[index + 1] << 8); index += 2;// ah.a(paramArrayOfByte[8], paramArrayOfByte[9]);


                imuState = (data[index] >> 0 & 0x1) == 1 ? true : false;
                pressureState = (data[index] >> 1 & 0x1) == 1 ? true : false;
                downVisualState = (data[index] >> 2 & 0x1) == 1 ? true : false;
                powerState = (data[index] >> 3 & 0x1) == 1 ? true : false;
                batteryState = (data[index] >> 4 & 0x1) == 1 ? true : false;
                gravityState = (data[index] >> 5 & 0x1) == 1 ? true : false;
                windState = (data[index] >> 7 & 0x1) == 1 ? true : false;
                index += 1;


                //if (paramArrayOfByte.length < 19) { }
                imuCalibrationState = data[index]; index += 1;
                batteryPercentage = data[index]; index += 1;
                droneFlyTimeLeft = data[index] | (data[index + 1] << 8); index += 2;
                droneBatteryLeft = data[index] | (data[index + 1] << 8); index += 2;


                //index 17
                flying = (data[index] >> 0 & 0x1) == 1 ? true : false;
                onGround = (data[index] >> 1 & 0x1) == 1 ? true : false;
                eMOpen = (data[index] >> 2 & 0x1) == 1 ? true : false;
                droneHover = (data[index] >> 3 & 0x1) == 1 ? true : false;
                outageRecording = (data[index] >> 4 & 0x1) == 1 ? true : false;
                batteryLow = (data[index] >> 5 & 0x1) == 1 ? true : false;
                batteryLower = (data[index] >> 6 & 0x1) == 1 ? true : false;
                factoryMode = (data[index] >> 7 & 0x1) == 1 ? true : false;
                index += 1;


                flyMode = data[index]; index += 1;
                throwFlyTimer = data[index]; index += 1;
                cameraState = data[index]; index += 1;


                //if (paramArrayOfByte.length >= 22)
                electricalMachineryState = data[index]; index += 1; //(paramArrayOfByte[21] & 0xFF);


                //if (paramArrayOfByte.length >= 23)
                frontIn = (data[index] >> 0 & 0x1) == 1 ? true : false;//22
                frontOut = (data[index] >> 1 & 0x1) == 1 ? true : false;
                frontLSC = (data[index] >> 2 & 0x1) == 1 ? true : false;
                index += 1;
                temperatureHeight = (data[index] >> 0 & 0x1);//23


                wifiStrength = Tello.wifiStrength;//Wifi str comes in a cmd.
            }
 
Last edited:
I haven't looked at Tellolib for years but I remember it has all you need. The interesting data is not in flight status message but hidden in Tello's log messages.
 
This is the conversion I have to do to get the height value from TelloLib to get anywhere close to the correct height of the craft.

(height * .1f) + .2f

And the height value only changes every 10cm or so.

My guess is its supposed to be a float but its getting parsed into an int? That would explain the rounding

height = (Int16)(data[index] | (data[index + 1] << 8)); index += 2;

And I dont see anything about baro or tof anwhere in tellolib. A bunch of these just dont work too.
https://github.com/Kragrathea/TelloLib/blob/master/TelloLib/Tello.cs
TelloLib/Tello.cs at master · Kragrathea/TelloLib

Code:
            public int flyMode;
            public int height;
            public int verticalSpeed;
            public int flySpeed;
            public int eastSpeed;
            public int northSpeed;
            public int flyTime;

            public bool flying;//

            public bool downVisualState;
            public bool droneHover;
            public bool eMOpen;
            public bool onGround;
            public bool pressureState;

            public int batteryPercentage;//
            public bool batteryLow;
            public bool batteryLower;
            public bool batteryState;
            public bool powerState;
            public int droneBatteryLeft;
            public int droneFlyTimeLeft;


            public int cameraState;//
            public int electricalMachineryState;
            public bool factoryMode;
            public bool frontIn;
            public bool frontLSC;
            public bool frontOut;
            public bool gravityState;
            public int imuCalibrationState;
            public bool imuState;
            public int lightStrength;//
            public bool outageRecording;
            public int smartVideoExitMode;
            public int temperatureHeight;
            public int throwFlyTimer;
            public int wifiDisturb;//
            public int wifiStrength;// = 100;//
            public bool windState;//

            //From log
            public float velX;
            public float velY;
            public float velZ;

            public float posX;
            public float posY;
            public float posZ;
            public float posUncertainty;

            public float velN;
            public float velE;
            public float velD;

            public float quatX;
            public float quatY;
            public float quatZ;
            public float quatW;
 
Last edited:
Altitude in the simple flight data message comes in decimeters, and always has some error.

You need full telemetry data from the log messages for higher precision
 
Then I guess TelloLib just doesnt extract everything from the log, here is what it gets from log.


C#:
   //Parse some of the interesting info from the tello log stream
            public void parseLog(byte[] data)
            {
                int pos = 0;

                //A packet can contain more than one record.
                while (pos < data.Length-2)//-2 for CRC bytes at end of packet.
                {
                    if (data[pos] != 'U')//Check magic byte
                    {
                        //Console.WriteLine("PARSE ERROR!!!");
                        break;
                    }
                    var len = data[pos + 1];
                    if (data[pos + 2] != 0)//Should always be zero (so far)
                    {
                        //Console.WriteLine("SIZE OVERFLOW!!!");
                        break;
                    }
                    var crc = data[pos + 3];
                    var id = BitConverter.ToUInt16(data, pos + 4);
                    var xorBuf = new byte[256];
                    byte xorValue = data[pos + 6];
                    switch (id)
                    {
                        case 0x1d://29 new_mvo
                            for (var i = 0; i < len; i++)//Decrypt payload.
                                xorBuf[i] = (byte)(data[pos + i] ^ xorValue);
                            var index = 10;//start of the velocity and pos data.
                            var observationCount = BitConverter.ToUInt16(xorBuf, index); index += 2;
                            velX = BitConverter.ToInt16(xorBuf, index); index += 2;
                            velY = BitConverter.ToInt16(xorBuf, index); index += 2;
                            velZ = BitConverter.ToInt16(xorBuf, index); index += 2;
                            posX = BitConverter.ToSingle(xorBuf, index); index += 4;
                            posY = BitConverter.ToSingle(xorBuf, index); index += 4;
                            posZ = BitConverter.ToSingle(xorBuf, index); index += 4;
                            posUncertainty = BitConverter.ToSingle(xorBuf, index)*10000.0f; index += 4;
                            //Console.WriteLine(observationCount + " " + posX + " " + posY + " " + posZ);
                            break;
                        case 0x0800://2048 imu
                            for (var i = 0; i < len; i++)//Decrypt payload.
                                xorBuf[i] = (byte)(data[pos + i] ^ xorValue);
                            var index2 = 10 + 48;//44 is the start of the quat data.
                            quatW = BitConverter.ToSingle(xorBuf, index2); index2 += 4;
                            quatX = BitConverter.ToSingle(xorBuf, index2); index2 += 4;
                            quatY = BitConverter.ToSingle(xorBuf, index2); index2 += 4;
                            quatZ = BitConverter.ToSingle(xorBuf, index2); index2 += 4;
                            //Console.WriteLine("qx:" + qX + " qy:" + qY+ "qz:" + qZ);

                            //var eular = toEuler(quatX, quatY, quatZ, quatW);
                            //Console.WriteLine(" Pitch:"+eular[0] * (180 / 3.141592) + " Roll:" + eular[1] * (180 / 3.141592) + " Yaw:" + eular[2] * (180 / 3.141592));

                            index2 = 10 + 76;//Start of relative velocity
                            velN = BitConverter.ToSingle(xorBuf, index2); index2 += 4;
                            velE = BitConverter.ToSingle(xorBuf, index2); index2 += 4;
                            velD = BitConverter.ToSingle(xorBuf, index2); index2 += 4;
                            //Console.WriteLine(vN + " " + vE + " " + vD);

                            break;

                    }
                    pos += len;
                }
            }
 
The Altitude above ground that I use is in the MVO record: Float starting at position 75 of the record content (excluding the record header up to the tick). I think this translates to index 85 for your code.
 
  • Like
Reactions: VR_Dev
The Altitude above ground that I use is in the MVO record: Float starting at position 75 of the record content (excluding the record header up to the tick). I think this translates to index 85 for your code.
This is super helpful thanks. I do see there are 95 bytes in that mvo log, but TelloLib is only parsing 34 of them. Are the values/contents of that mvo log public anywhere? I looked around but doesn't seem there is a definitive list. I assume I have to use packet sniffer or something which I would have to learn.

Also I have tried parsing index 75 and 85 into singles and int16s, but i just get random numbers. I have not attempted flying yet though so maybe thats when the values become valid
 
Last edited:
I haven't seen documentation beyond the comments in tellolib and the thread on this forum.

I don't think you will get far without being familiar with Wireshark.
 
I haven’t dealt with packet sniffers since Novell Netware, but my understanding is that Wireshark has a pretty steep learning curve. Great program, though.
 
@BigL like the rapper?

I downloaded wireshark and yeah I'm totally lost, so then I just tried parsing the rest of that log after posUncertainty to singles then trying to guess what they were by flying the tello around. Thats pretty pointless as I don't even know the type I should be parsing to begin with.

I got some pretty cool stuff cooking, I just need to get the correct values from the Tello to keep moving forward. The height I'm getting here is the TelloLib.Height value which you can see jumps in decimeters. I also apply a .2m offset just by eyeballing.

To view this content we will need your consent to set third party cookies.
For more detailed information, see our cookies page.

To view this content we will need your consent to set third party cookies.
For more detailed information, see our cookies page.
 
Last edited:
  • Like
Reactions: BigL
@BigL like the rapper?

I downloaded wireshark and yeah I'm totally lost, so then I just tried parsing the rest of that log after posUncertainty to singles then trying to guess what they were by flying the tello around. Thats pretty pointless as I don't even know the type I should be parsing to begin with.

I got some pretty cool stuff cooking, I just need to get the correct values from the Tello to keep moving forward. The height I'm getting here is the TelloLib.Height value which you can see jumps in decimeters. I also apply a .2m offset just by eyeballing.

To view this content we will need your consent to set third party cookies.
For more detailed information, see our cookies page.

To view this content we will need your consent to set third party cookies.
For more detailed information, see our cookies page.



The simple flight state data is useless for your task at it just holds crippled altitude data. You have to parse the MVO record for altitude. The single "posZ" in Tellolib parseLog() code is what Tello considers it's true altitude.

I just debuged my code to find what you need:
For Altitude above Ground you need to parse the single starting at the position 52 bytes after start of "posZ".

In the code above "posZ" seems to start at index=26 so I think this should work
aag=BitConverter.ToSingle(xorBuf, 78)


For Baro you need to parse the IMU record instead:
baro_raw = BitConverter.ToSingle(xorBuf, 26);

I haven't tested this code as I don't use tellolib.

Keep in mind: The log parsing in TelloLib isn't really robust and will miss log records from time to time.
 
Last edited:
  • Like
Reactions: VR_Dev
Friendly bump on this. Been a good while but I am still interested if anyone has exposed the raw IR sensor data. Never figure it out myself
 

New Posts

Members online

No members online now.

Forum statistics

Threads
5,746
Messages
40,215
Members
17,331
Latest member
silver_codigoactivo

New Posts