Homebrew USB controller for Tello




What, why and how? 


Writing programs for Tello is fun - at least for me. I do the programming on the PC. So I have to control Tello with the PC. With the keyboard. Not very comfortable.

I'd like to have a controller, like the one I use with the mobile. It connects to the phone via Bluetooth. But this one (Gamesir T1 d) is only compatible with the Tello apps and cannot be connected via the normal pairing procedure. If you find out, please let me know. There is one which is compatible to the rest of the world (Gamesir T1 s),but this one cannot be used with the Tello apps.

So, the conclusion is: I don't have a controller which can be used with the PC, I don't want to buy one, and if I had one, I wouldn't know how to connect to the PC.

How about building a controller? I would need two joysticks (like this one, just as an example), a few buttons and a micro-controller. Let's say, an Arduino.

An old RC-transmitter, or an old controller? Salvage the joysticks and build some mechanics? Or use the mechanics and just add the electronics? Well, I have one of those tiny quadrocopters which are sold for little money, are hard to fly (they are definitely not drones even though everybody calls them so), get clogged wit dust and hairs, bang against the furniture and after a few days they don't fly any more. Who doesn't have at least one?

If you have a (still working) RC transmitter with a trainer/student jack, there might be a solution without having to dismantle the transmitter. See for example "Reading PPM Receiver Signal with Arduino using Interrupts" on Youtube.
I'll cover this later (when I get it working), now we dismantle a device which we would otherwise throw away. 

The following instructions are for beginners. If you are experienced, just have a glance on it, you probably have lots of ideas. 

The controller has everything I need. It has two joysticks, six buttons one switch and one LED. I remove the electronic components, there are not many. It has a battery case, but I do not need it because the micro-controller is powered via the USB. And it fits into the space where the batteries (two AAA's) have been.

Arduino Nano in the battery case of the controller

How to connect the micro-controller to the PC via USB? There are two possibilities:
  • Use the tty interface
  • Emulate a keyboard 
For using the tty, the program on the PC must be able to communicate via tty. I can write this part of software into my programs. There is a python library called pyserial.

Emulating a keyboard or mouse, you can use the Arduino to control any existing software. I have seen a paragliding simulator where you sit in a real harness and real brake lines control a flight simulator.

For emulating a (mouse or) keyboard you need an Arduino which has a 32U4 processor such as the Leonardo or the Micro. You cannot use the keyboard library with an Uno, Nano, Mega, etc.


Examine whatever material you have

Okay, enough said about planning, let's go on the job. Open the case of the transmitter or controller and have a voltmeter and a soldering iron at hand. Clamp the minus of the voltmeter to the minus power line of the controller (whether you use the battery or not). 

Electronic components

On a controller board, there are a few electronic components and probably a battery case and an on-off-switch. You can leave all this in place, or remove the electronic components and the battery case. If it is still working, you can leave everything in place for the first tests, just solder additional wires as I describe further down. Later, I recommend to remove them and power the board from the Arduino which is powered by the PC via the USB.

Small controllers are powered with 3V, and (most) Arduinos supply 5V. So you will grill the existing electronics or the Arduino. Remove them, even if it is still working, as they may cause a short circuit when they die. And you might get some electromagnetic dusturbance. But, as I wrote, you can leave it in place for now and use the controller's battery pack.




Joysticks

The joysticks use potentiometers, and you have to find out which pin is the one that changes voltage when moved. Each axis has three pins. One is connected to "plus", one is connected to "minus" and one gives a voltage that varies when you move the joystick. On my board it is the middle pin.

Green cables connect to the processor,
the red cable is +5V

Solder a wire to this pin and connect it to one of the analog pins of the Arduino. Connect "minus" (the negative pole of the battery, this one will be the same for all inputs) to "GND" of the Arduino. If the PCB of the controller still has a battery compartment and batteries, turn the power on. If not, connect "5V" of the Arduino to the plus cable of the controller.

Write a little test program or search for it on the web. You know: "Good programmers write good code, great programmers borrow good code". Here is one, and there are lots of others. Copy the code into the editor window of the Arduino IDE, connect the Arduino to the PC via USB, select the serial port (Tools - Port) and the correct device (Tools - Board), load the program to the device and open the monitor (Tools - Serial Monitor). Be sure to set the monitor to the same baudrate which you use in the program (probably 9600). You should see values that change when you move the joystick. The range of the values will be roughly between 0 and 700 when you power the controller with 3V batteries or between 0 and 1000 (1023, to be exact) when you power the controller with 5V.

It works? Great!
If not, get it working before going on. Wrong port? Wrong baudrate? Wrong pin? Loose cable?

Connect the remaining three axes to the Arduino and note which axis is connected to which input.

Buttons

Probably the board you are using has a number of buttons. Buttons are great for sending additional commands. Let's say, a button for "land". A panic button which will send "stop" to avoid crashing into an obstacle, one for flip if you are playful (why are you here????), and so on.

A word of caution about buttons: You might think that pressing the button once will send "takeoff", pressing it again will send "land", then "takeoff" again and so on. Any mechanical switch may bounce, it means that it opens and closes a few times before it remains in a stable condition. We humans don't see it, but the processor will read erratic values and seem to get crazy. "Deboucing" is an art in itself, the simplest possibility is adding a delay before reading the value again.

A button usually has four pins. When a button is still connected to the rest of the PCB, find out which pin changes voltage when you press it. Solder a wire to the pin and connect it to a digital pin of the Arduino. If you are using a button on your own board, wire it so that it connects the digital pin to ground "GND" of the Arduino when pressed (you can connect it to "plus" as well, but then you need an additional resistor - connecting it to GND is easier). When you press the button, the input goes to 0, when you release it it will go to 1.

My setup now looked like this:


Again, there's lots of examples on the web to test your setup. Search for "digitalRead".

It works? Great! If not, get it working before going on. Everyday life for a developer.

You can connect the remaining buttons to the Arduino and note which button is connected to which input. Put the Arduino inside the case or somehow attach it to the case. If you are eager to see if it flies, like I was,  you can do that later and continue with this makeshift setup.

Writing software

So far, we have seen that the Arduino can send information from the controller to the PC. but we have only observed it on the monitor of the Arduino IDE and do not yet have access to the data in our own program. There's two things to do:
  • Bring the data to a format that makes sense to Tello. We'll do this on the Arduino.  
  • Write a program on the PC that receives the data from the USB and sends it to Tello. 
We will write a program for the Arduino, this is written in (a dialect of) C.
We will write a program for the PC, and we do this in Python (although we could write this in any language).
Writing in two different languages can be confusing. Semicolon at the end of the line in one language (C), and no Semicolon at the end of the line in the other language (Python). 

Arduino program (also called "sketch")

We will send three different commands to Tello:
  1. command
  2. rc a b c d 
  3. land
If you miss "takeoff" you can add it, but we can takeoff using the joysticks. I think it is safer, at least for the beginning. And we can save a button for other things.

1) The string "command" sets Tello to SDK (system design kit) mode so it can receive the following data. You can send "command" any time, even if Tello is already in SDK mode.

2) The "rc" command contains the joystick data to control the quadrocopter. We need to convert the readings of the potentiometers to a range of -100 to 100.
And we have to write an ASCII string containing these values in the right order.

This is done in a loop which runs roughly 10 times per second. A delay command at the end of the loop is responsible for this.

3) When the user presses the button we have wired before, Arduino stops sending rc commands and sends "land".

You can find the program ArduinoTello.ino in the folder example001 on github ArduinoTello project.
(Sorry, I forgot that the .ino file must be in a directory with the same name. You must do this after downloading. Sorry, again.)

Note that the baud-rate is set to 115200 instead of 9600, it means that the bits are transferred faster. On the serial monitor you need to set the baud-rate accordingly.  

On the Serial Monitor you should see these commands. They are sent only when the values change, so move the joysticks to see commands. Maybe the values jitter a bit and commands are sent even without moving the joysticks. That's fine.

Check if the correct value changes when you move a joystick in one direction, the order is left/right - forward/back - up/down - yaw. Check if the range is correct, from -100 to 100 (if it's only 99 that's fine, too), and around 0 when you center the joysticks. Positive values when you go right, forward, up and clockwise.

Press the "land button", you see the command "land" and no more rc commands. Press the button again, another "command"-command is sent and the rc-commands begin.

When there is no activity for 10 seconds, another "command"-command is sent so Tello won't feel lonely (and start blinking red and eventually shuts off).


The PC program

The Tello SDK communicates with the PC via ASCII strings (byte-arrays, to be exact) which are sent over UDP (user datagram protocol). This can be done in any programming language.

Python is a language which is fun to use (at least I have fun) and it is popular with robotics. Ryze provides an example Tello3.py in Python. I used this example and added the serial (tty) communication. 

The todo list:
  1. install and test python, 
  2. install and test pyserial
  3. test Tello3.py 
  4. put it all together 
Again, you can find the program ArduinoTello.py in the folder example001 on github ArduinoTello project.

1) install and test python

There's lots of instructions on how to install python on the web. There are IDE's (Integrated Development Environments) like idle, pycharm and jupyter, I stick to the normal console view.

There is Python 2 and Python 3. Python 3 is not downward-compatible to Python3, so Python 3 programs do not necessarily run on Python 2 and vice versa.

Open a console window ("cmd" on Windows) and type python.

You should get something like

Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>

Don't care if you are on 3.5 instead of 3.7, that's fine. Or a more advanced version of Python if you erad this text in teh future. Basically you can write in Python2 as well, if you are already using Python2. You will have to make some changes in the code.

Type
print ("hello world")
and Python does exactly that.

type
import pyserial
and you will get an error message. That's fine, too. We will take care of that in the next step.

type exit() to close Python (the brackets are necessary).

2) install and test pyserial

Still on the console, type
pip install --user pyserial
or, if Windows doesn't find pip, type
python -m pip  install --user pyserial

You will be asked if aou really want to install and then you see a progress bar. Try again to import serial as before, this time you don't get an error message.

Now, let's write a little test program.

Copy and paste the following into an editor window and save it, let's say as minimalSerialTest.py

''' a little test program for the serial communication '''
import serial

ser = ''
try:
    ser = serial.Serial('COM13', 115200 ) # Establish the connection on a specific port
except Exception as e:
    print (str(e))

if (ser):
    while True:
        Text = ser.readline()
        Text = Text.decode(encoding="utf-8")
        Text = Text.replace("\r",'')
        Text = Text.replace("\n",'')
        print (Text)
else:
    print ("unable to open the serial port")

Note the line "ser = serial.Serial('COM13', 115200)":

I have written "COM13" because my serial port is emulated on port COM13. This varies. On the next day you might get a different port. In the Arduino IDE you had to set the port, we use the same name here.

Note the baud-rate of 115200, this must match the value in the Arduino program.

How does it work? 
If the serial port can be connected, it means that ser  is changed to something meaningful, commands are read from the serial port. We need to do some conversions to be able to print the command.

Close the Serial Monitor in the Arduino IDE and start the Python program while the Arduino is running. Type
python  minimalSerialTest.py

It looks like this:


To stop the program, type Ctrl-C (hold the Ctrl-key (Strg on German keyboards) and type the letter "C"). This works only when the Arduino is running and sends commands. otherwise readLine() waits forever and ignores your Ctrl-C. Close the console window if this happens.

3) test Tello3.py

Download Tello3.py.

Press the power button on Tello and connect the PC to the WiFi provided by Tello.
Open a command window on the PC. To see if the connection works, you can enter "ping 192.168.10.1". When you don't get an error message, the connection is OK.

Start the program by typing
python Tello3.py
in a console window.

When you miss a module, you know how to install it with pip.

Type "command" and get an "ok".
Try "battery?", "wifi?", and so on.
Note that Tello tends to overheat and turn itself off when parked on the ground.

Send "rc -100 -100 -100 100" and Tello will start its motors without taking off. This will be our first test of the controller and Tello will not overheat. "land" stops the motors.

When you know what you are doing, you can send "takeoff" and commands like "up 100", "forward 50", and so on, and "land".    

4) put it all together

A program to combine all these features can be found on Github, it is called ArduinoTello.py.
Again, you need to put the name of your serial interface where I wrote "COM13".

You're all set for....

The maiden flight!

The controller is still wired via a breadboard and the whole thing looks like Daniel Düsentrieb's newest invention? Good. Be careful not to pull out a wire or let metallic parts touch.

Connect the PC to Tello as before. Now, plug in the USB.

Then enter "python ArduinoTello.py". Press the button you have wired for "land".  Arduino sends "command" and you should see an "ok" before it scrolls away when you move the joysticks and the "rc" commands run like crazy.

Move the joysticks simultaneously to forward, left, down and clockwise (down and middle if you wired it for mode2 = "throttle on the left hand"). The rc command should be something like "rc -100 -100 -100 100" and Tello should start its motors without taking off. Press the land button and the motors stop. Press the button again, see "command" and rc-commands. 

We are ready for takeoff. Are you in a safe environment with good light? 

Start the motors again. Slowly move the joystick "up". Tello will takeoff, center the joysticks and Tello should hover. Carefully test the other directions. If all works well, enjoy the flight!

Press the "land" button. Congratulations!


What to do next

I have postponed the wiring of the remaining buttons and the final assembly. Do it and have fun flying around.


Here you see my final assembly with an Arduino Pro Micro in the battery compartment. The most bulky component is the USB plug. To make room I cut away the side walls of the battery compartment. Be careful when putting the Arduino into the controller. On the first try I broke the USB jack off when I tried to bend the USB cable and the Arduino was ruined. Luckily I had bought a spare part in advance.

Attach the Arduino on the outside of the controller if you think that putting it inside is not possible, too complicated or too risky.

The programs are just simple examples which leave much room for improvement.

What can be done:
  •  on the Arduino
    • Add commands to the remaining buttons, if there is a LED, use it. 
    • Do not re-send rc commands when there only a small change in values 
    • expo (small changes around zero and big changes towards the ends) 
    • trim (ensure that Arduino actually sends 0 when sticks are centered) 
    • As the stick for up/down on my controller doesn't have a spring to center it, I will use the original on/off switch to maintain elevation (send 0 for up/down and ignore the stick) 
  • on the PC
    • Wait for connection on the WiFi (using pyping) 
    • search for serial port 
    • receive state string and video stream
    • add a fancy user interface 
  • Establish  a two-way-communication, feed the answers from Tello back to the Arduino
  • Use an Arduino with a WiFi and skip the PC
  • your ideas?
I will put the serial interface into tellTello.

Links











Keine Kommentare: