Sunday, June 21, 2020

The Falcon DS1 - BeagleBone Blue Drone (Part 3)

Construction


The hardest part of the build is coming up with a bracket to mount the BeagleBone on the Martian II air frame. In part 1 of these tutorials, I mentioned that there was an existing bracket design available. This doesn't fit for a number of reasons, including clashes with the XT60 socket, the propellers and the top deck of the air frame. But we will come to that...

Start off by putting the frame together. There is a very thorough video of how to do this on YouTube. They are using some different components (including the flight controller), but it does a great job of showing what goes where.

As shown in Figure 20, I labelled the front of the drone and motor number locations using electrical tape. This helps keep you oriented.

Figure 20. Martian II Frame Construction.

Once you have the arms attached to the bottom frame and the Power Distribution Board (PDB) mounted, you can add the quad 20A Electronic Speed Controller (ESC). The RaceStar ESC that I bought has mounting holes which line up nicely with the PDB. I assume that this isn't a coincidence but I admit that I fluked it. Figure 21, provides an overview of what the bottom layer of the drone will look like when we are finished.

Figure 21. Bottom layer Component layout

Figure 22, illustrates the Quad ESC in place above the PDB. Now comes the tricky part (for me, you will find it easy since I supply the bracket design), mounting the BeagleBone. Referring to Figure 21, you can see that there is only 10 mm clearance between the PDB and the propellers, so our bracket can't overhang much. In addition the XT60 socket and associated cables must remain accessible with the BeagleBone in place. If we are going to stick with a stock Martian II frame, the available distance between the top and bottom layers is 30 mm and with the ESC in place we have already used 20 mm of that. Finally, we want to keep the weight centred as much as possible.

Figure 22. Bottom layer components in place.

In the end, I wasn't able to satisfy all of these constraints. The BeagleBone is just too big, it requires 17mm even if you didn't have to make connections to the pin headers (which you do). In addition, to provide access to the XT-60 the BeagleBone needs to be offest from the centre line of the drone.

Typically with the Martian II build, the LiPo battery is attached to the top frame. Instead, I have placed it between the ESC and BeagleBone. As illustrated in Figure 23, it took 5 attempts but I eventually came up with a design that met most of the constraints.

Figure 23. BeagleBone mounting plate with LiPo.

The STL file for the mounting plate is available for download from Thingiverse.

Figure 24. BeagleBone Blue 3D Printed Mounting Plate.

Wire up the power and control cabling as per the schematics in Parts 1 and 2. As our build is a bit different to the standard Martian II, I will provide a few supplementary notes and guidelines based on my experience.

Mounting the Motors

We need to mount the four brushless motors to work out the correct wire length to the ESC. My RacerStar motors came with two sets of M3 screws, 8mm and 6mm. The thickness of the frame arms is 4mm, so use the 6mm screws to ensure they don't short out the motor coils. For now you can just do them up finger tight but eventually you will want to apply loctite to ensure that the motors don't fall off mid flight (bad).

The RacerStar ESC can be programmed using the BLHeliSuite software on PC. With that we can reverse the motor direction but you need compatible Flight Controller software. For our purposes, it is probably simpler to just swap two wires if the motor is going in the wrong direction.

My motors indicate their default rotational direction (clockwise or anticlockwise) by arrows on the top of the motor and different coloured propeller  nuts. The black nuts rotate clockwise and the red nuts anticlockwise. To minimise the amount of work, you should mount the motors in the configuration shown in Figure 25.


Figure 25. Required Motor Directions (X Configuration)

Once you have mounted the motors you can then wire them to the Quad ESC. While you are doing this, also solder the ESC battery connection to the appropriate pads (+ and -) on the Power Distribution Board and a connector to allow you to plug power into the flight controller.



The Falcon DS1 - BeagleBone Blue Drone (Part 2)

Control Wiring


The BeagleBone uses mostly JST connectors. We need the following:
  • Four (4) of the 2-pin 1.5 JST ZH female connectors, with attached 150mm 28AWG wires, for the motors,
  • Eight (8) of the 4-pin 1.0 JST SH female connectors, with attached 150mm 28AWG wires, for the encoders as well as the UART, I2C, CAN, and PWR busses, and
  • Four (4) of the 6-pin 1.0 JST SH female connectors, with attached 150mm 28AWG wires, for the SPI, GPS, GPIO, and ADC busses.
These connectors are small but they are also fiddly to crimp and a bit delicate. Nevertheless this is what we are stuck with. Despite a LOT of searching, I was unable to find a complete diagram which indicated all of the correct connections for using the BeagleBone Blue as a flight controller for ArduCopter. The best I was able to find was the Imfatant version, which he provides as part of his description regarding how to get ArduCopter onto the BeagleBone. I have reproduced his image below in Figure 12.

Figure 12. BeagleBone Blue Connections (ref: https://github.com/imfatant/test)


I ended up doing my own drawing, to ensure I knew what connected to what. I needed this in order to work out the best layout on the airframe and what cables and connectors are required.

Figure 13. BeagleBone Blue Control Wiring.

Note that the front of the drone is towards the top of the diagram in Figure 13. The motor numbers match up with the nearest motor outputs on the QUAD ESC. The control wires for each motor (S1, S2, S3 and S4) then go to the corresponding servo/ESC connections on the BeagleBone Blue.

Now that we have the connections worked out we can load up some software and start testing our rig.

Loading ArduCopter on the BeagleBone Blue


The most comprehensive guide to loading the ArduCopter software onto the BeagleBone Blue is found at the Imfatant Github repository. There is also a summarised version of these instructions on the Mirkix Github repository (Mirko Denecke's port of ArduPilot).

Figure 14. Checking the BBB Connection to the Mac.


I don't intend to reproduce what has already been written in these guides but I will point out areas where things have changed or if I had difficulties.

PART 1 - Preparation

  1. The first issue I found in the Imfatant Guide is that the recommended console image is no longer available at  https://rcn-ee.net/rootfs/bb.org/testing/. I used the latest version that I could find: https://rcn-ee.net/rootfs/bb.org/testing/2019-06-30/stretch-console/bone-debian-9.9-console-armhf-2019-06-30-1gb.img.xz Download this and flash it to a microSD card using Etcher (or equivalent). I used a Toshiba 16GB class 10 card so that I would have plenty of room and speed.
  2. I inserted the SD card (it only goes in one way) and booted up the BeagleBone Blue (BBB from here on), by connecting it to my Mac via the micro USB connection. As suggested in the instructions I tried "ssh debian@192.168.7.2" but the operation timed out. It appears that there are two drivers that you have to download and install for this to work on the Mac. 
  3. Download the two drivers: Network: https://beagleboard.org/static/Drivers/MacOSX/RNDIS/HoRNDIS.pkg and Serial: https://beagleboard.org/static/Drivers/MacOSX/FTDI/EnergiaFTDIDrivers2.2.18.pkg and then install them. The Serial driver may ask you to reboot your computer (it did for me).  The Beaglebone Blue creates a network connection and emulates an Ethernet adapter. Your computer will receive IP addresses 192.168.7.1 and 192.168.6.1. The Beaglebone Blue has IP addresses 192.168.7.2 and 192.168.6.2. You can check whether this has worked by looking at Networks in system preferences (ref: Figure 14).
  4. You should now be able to ssh in ("ssh debian@192.168.7.2") without difficulty. Password is "temppwd" (see Figure 15 to view a successful first log in).  If you receive a “REMOTE HOST IDENTIFICATION HAS CHANGED” error, you have probably previously connected to a different computer on 192.168.7.2 (like another BBB). Remove the old ECDSA key with: "ssh-keygen -R 192.168.7.2".
  5. Next thing you need to do is get WiFi up on the BBB. Follow the Imfatant instructions for this but I found that I had to power the device down and reboot before the changes would take effect. Make sure you "sudo shutdown -h now" before powering down. While you have the power off, CAREFULLY turn the antennas around so that they face off the board. They swivel so don't just try and bend them up and over. You can unplug and replug the antennas if you prefer. Once you power back up, you should have the central green LED lit to indicate a WiFi network connection (ref: Figure 16). 
  6. To get the WiFi IP address of your BBB, I usually use "hostname -I" or "ip addr show wlan0". Alternatively, you can just have a look on your router. Terminate your usb connection and ssh back in using the WiFi IP address. The password is the same. Verify that you have an internet connection using "ping -c 3 google.com".
  7. The remainder of the Imfatant Part 1 Preparation instructions went smoothly for me.
Figure 15. Logged into the BBB via USB.



Figure 16. Green WiFi LED on indicating a connection.


Part 2 - Installing ArduPilot


Follow the Imfatant instructions for setting up the ArduPilot environment configuration file, /etc/default/ardupilot.

The switch -A in the ardupilot config file maps ArduPilot's "Console" serial port (SERIAL0, default 115200) to a target IP address and port number of one's choosing. For example, this allows MAVLink data to be transmitted over WiFi for test purposes. This data stream is auto-sensed by ground control station software like Mission Planner (Windows) and QGroundControl (Windows, OS X, Linux, iOS and Android).

To get the IP address of your Mac, from the Apple menu pull down “System Preferences” and click on the “Network” preference pane. The IP address for your WiFi connection will be shown on the right (see Figure 17).

Figure 17. Getting your Mac IP address for WiFi.


For Windows, press the Windows Start key to open the Start screen. Type cmd and press Enter to launch the command prompt. Type ipconfig at the command prompt to check the network card settings. See Figure 18, you want the IPv4 address.


Figure 18. Getting IP address for Windows


The next tricky bit is getting the latest ArduCopter executable, built specifically for the BBBlue's Arm architecture, onto the BBB. The Mirko Denecke link no longer works but the Imfatant one will allow you to download arducopter v3.6.

Once you have the file downloaded, there are a few different ways you can copy it to the BeagleBone. You can use SCP, just copy it onto a USB drive and then plug that into the BBB, or you can use something like FileZilla. I took the last approach. Depending on permissions, this may be as easy as dragging the file across (Figure 19).

To check the current permissions on the file type, "ls -ld /usr/bin/ardupilot". My initial result was:

drwxr-xr-x 2 root root 4096 Aug  6 08:29 /usr/bin/ardupilot

Which is a problem because the directory's owner and group is root and we have FTP'ed in as debian. In the string displayed above, the first character indicates if we are looking at a directory (d), file (-) or link (l). After that, the folder and file access rights are divided into three categories:

xxxyyyzzz
xxx are access rights for the owner
yyy are access rights for the owner's group
zzz are the access rights for everyone else
The access rights symbols will indicate whether you can read (r), write (w), execute (x) or are missing a right(-). Based on our results, the only person who can write a file into this directory is the owner (i.e. root). We can use chmod to fix this. In terminal type: "sudo chmod o+rwx /usr/bin/ardupilot" The "o" switch applies this change to all users and we are adding (+rwx) read, write and execute rights for this directory. Check with "ls -ld /usr/bin/ardupilot". You should get something like:

drwxr-xrwx 2 root root 4096 Aug  6 08:29 /usr/bin/ardupilot

You should now be able to drag across the arducopter executable into the /usr/bin/ardupilot directory as shown in figure 19. Username and password is the same as for ssh. Use port 22.

Figure 19. Copying the arducopter executable to the BBB using FileZilla.


After this we "sudo systemctl enable arducopter.service" and rebooted the BBB. Job done! You can check that arducopter is enabled with "systemctl is-enabled arducopter".

In Part 3 we will start putting everything together.

The Falcon DS1 - BeagleBone Blue Drone (Part 1)

Flight Controller


Figure 1. BeagleBone Blue Flight Controller


This project will document the construction of a self built drone using the BeagleBone Blue as a flight controller.

An objective of the build was that the drone should be modular, open sourced hardware and software and include an API to allow mission control.

My preference would be to use a board that I already have experience with (e.g. Arduino or Raspberry Pi) as a flight controller.

Unfortunately even though ArduCopter firmware was originally designed for the Arduino, the consensus seems to be that it doesn’t have enough grunt these days (ref: https://dojofordrones.com/drone-flight-controller/).

I like the Navio2 & Raspberry Pi, as the hardware platform for the flight controller. The only problem is that it is expensive ($299 for the HAT alone). Also the Navio2 is not open source hardware.

The PXFmini is a pHAT designed for the Raspberry Pi Zero/Raspberry Pi Zero W but is also compatible with other models from the Raspberry Pi family. It was more affordable (approx. $74) but is now discontinued. The good news is that it is open source hardware and the schematics are available. You could develop your own HAT or pHAT based on this design. It would be great to get hold of one but I haven’t been able to track it down. An issue with this design is that all the soldering is surface mount, which is a pain without the right gear (and great eye sight).

I haven’t used the BeagleBone, but the BeagleBone Blue looks like a pretty good option. It is relatively cheap at $130 delivered and includes most of the sensors you need on the board. The exception is a GPS (the recommended module is the u-blox M8N GPS - $60 from Hobby King). There is an ArduCopter build available for the BeagleBone.

Based on the above I am going to try out the BeagleBone for my initial prototype. The build documentation is very sketchy, so there is going to be a bit of trial and error.

Air Frame


Figure 2. Power Distribution Board on frame.


For my prototype I propose using a Martian II 220mm frame, because that is what BeagleBone suggest in their half documented project. Half documented is probably generous, apparently they never actually got this design flying, nevertheless there is nothing like a challenge to get the juices flowing!

There is a 3D printable case, designed for the BeagleBone for use on a drone, available from Thingiverse (Figure 3).

Figure 3. BeagleBone drone mounting case.


There are plenty of videos documenting how to build the Martian II air frame and its various clones so I wont go into that in detail, except where you need to do something different to utilise the BeagleBone. This happens pretty early in the build.

Figure 4. Airframe with front and motor numbers.


The first thing that you will notice is that the yellow XT60 socket mounted on the power distribution board (Figure 2) prevents you from using the 3D printed case in Figure 3. So we need to do some modifications.

It is a good idea to mark your air frame with the forward direction and motor numbers (Figure 4). This will assist with layout and help ensure that you mount boards in the correct locations.

Technology Stack


The proposed technology stack is shown in Figure 5. We now need to work out the specifics, there wont be a camera in the initial build, in fact my first objective is just to get things working on the bench. I will then be in a better position to work out where the various modules can fit on the airframe. 

Figure 5. Falcon Drone Technology Stack.


Power Distribution


Figure 6. Turnigy 1300mAh 2S 20C Lipo Pack


All of the drones power comes from our 2S 1300 mAh Lithium Polymer battery (Figure 6). The specifications for our battery are:

Minimum Capacity: 1300mAh
Configuration: 2S1P / 7.4v / 2Cell
Constant Discharge: 20C
Peak Discharge (10sec): 30C
Pack Weight: 81g
Pack Size: 73 x 35 x 17mm
Charge Plug: JST-XH
Discharge plug: XT60

At 3.7V per cell our 2S battery will deliver a nominal 7.4V from the contacts on the power distribution board. The 2S indicates that we have two cells in series so the sum of the two cells voltage is the output voltage. As an aside, cells in parallel add to the batteries capacity (i.e. mAh) not voltage.

Figure 7. BeagleBone connected to LiPo

The BeagleBone Blue includes a 2-cell LiPo battery charger with balancing, and an LED state-of-charge monitor. The state of charge LED's are shown in Figure 7. They are just above the 3-pin JST XH battery charging connector.

One of our considerations when mounting the BeagleBone is that we will need access to the JST XH connector in order to get power off the micro-controller. We will also need access to the XT60 in order to power down the distribution board. Ideally the battery needs to be less than 50mm from the BeagleBone or we will need to extend the charging cables.

Figure 8. Racerstar Quad 20A ESC.

The other modules we will need to power are:

  • The Racerstar BLHeli_S 20A Quad Electronic Speed Control - shown in Figure 8 (connects to the battery, receiver and the four motors). It doesn't have a BEC (Battery Elimination Circuit) to provide a regulated supply but the BeagleBone does.
  • The UBLOX Micro M8N GPS Compass Module - shown in Figure 9. This module expects a regulated 5V on VCC but control voltages are 3.3V (see Figure 10). The BeagleBone supplies 3.3VDC and 5VDC power output via 4 pin JST connector.
  • The FrSKY X8R 2.4Ghz SBUS Receiver. The receiver will also need to be connected to the regulated 5VDC bus.

Figure 9. The UBLOX Micro M8N GPS Compass Module.


The overall power distribution block diagram is shown in Figure 11. The 3 wire LiPo charging cable will connect directly to the BeagleBone as mentioned above. We will then have two power buses, 7.4VDC which powers the ESC and 5VDC to power the GPS and Receiver modules.

Figure 10. GPS Compass Module connections.


When building robots I have had problems when there is a common supply for the motors and the micro-controller. The current surge when starting the motor can bring down the voltage to the micro-controller and cause it to reboot. It may not be an issue with the drone since the motors are always on. The bench test will demonstrate whether this is going to be a problem.

In part 2 we will cover the control wiring required for our drone.



Figure 11. Falcon DS1 Power Distribution.

Tuesday, May 26, 2020

Arduino ESC Tester - Adding DShot

The Arduino Servo/ESC Tester Series (Part 4)


Figure 1. Arduino & Tester Shield.


In our first article in this series, we built a prototype ESC/Servo Tester using the Altronics MegaBox as our hardware platform. We followed this up with an article using a custom Arduino shield to make construction cheaper and easier. In Part 3 we added the Fast PWM and OneShot protocols.

In this final article we will add the DShot protocol and show the tester in action. By protocol, we are referring to the agreed communication method between the Flight Controller and the ESC. One of the issues we found was that there doesn't appear to be a single document which clearly defines what the Dshot protocol is. We have tried to pull all the available information together here, and explain how Dshot operates.


Synchronous vs Asynchronous Serial Protocols


Before leaping into DShot, it is useful to review other serial protocols to see how it compares.

Most serial digital communication protocols (e.g. RS232, OneWire, RS485, SPI, and I2C) require fairly precise timing in order to determine which bit is being read. We can further break down serial protocols into synchronous and asynchronous. Synchronous protocols require a separate wire for the clock signal (Figure 2) in addition to the data lines. Examples of synchronous serial communication are I2C and SPI. On the ATMega328P, SPI is the fastest synchronous communication interface allowing data transfer speeds up to half of the core clock (i.e. 8 MHz on an UNO).

Figure 2. Synchronous Serial Data (credit)

With an asynchronous Serial Interface, the external clock signal is absent (Figure 3). This is useful when we need to transmit over longer distances. With asynchronous communication you need to know when a packet starts and stops (start bit and stop bit) and the baud rate (i.e. when to expect the next bit). Common examples of asynchronous serial protocols are RS-232, RS-422 and RS-485. Spoiler alert - DShot is an asynchronous serial protocol.

Figure 3. Asynchronous Serial Data (credit)

A Review of DShot



In case you haven't read the previous articles in our series (*gasp*), here is a quick review of the DShot ESC protocol. DShot stands for Digital Shot and is the proposed replacement for previous analogue protocols like PWM, OneShot and MultiShot. DShot was developed by Flyduino in collaboration with Betaflight.

Compared to the protocols already considered, DShot is the only one which is truly digital. You could argue that PWM and OneShot are also digital since they use pulses with encoded data but the point is moot. PWM protocols, such as Multishot, Oneshot42, and Oneshot125 rely on the width of the pulse to indicate throttle position. This can introduce issues like jitter where timing variations cause errors in the desired throttle speed. The shorter the protocol pulse width the higher the likelihood and impact of jitter.

A comparison of the theoretical data rates for OneShot and DShot are shown in Figure 4. DShot is almost as fast as Multishot v1. The advantage of DShot over OneShot is not so much about speed but reliability and flexibility. Moving to a fully digital protocol allows the introduction of error correction and bi-directional data flow. In addition, with DShot no ESC calibration is required. Calibration is about tweaking the PWM pulse width which isn't required with a digital protocol. The final advantage of DShot is higher throttle value resolution (2000 steps), which should lead to smoother control.

Figure 4. DShot vs OneShot (credit)

A DShot digital message (Figure 5) consists of 16 bits (called a frame) in three parts, throttle value (11 bits), telemetry request (1 bit) and the CRC checksum (4 bits).

Figure 5. DShot Message Format (credit)

Figure 6 shows a DShot message captured on an oscilloscope. Details on the three components of the DShot packet are as follows:

  1. The throttle contains 11-bit data sent from the flight controller to the ESC. It gives a resolution of 2000 throttle values. The values 0-47 are reserved for special commands (see enum code listing below), 48-2047 are for throttle control, and 0 is for disarming. In the throttle portion of the frame the most significant bits are first, consequently the bit sequence 11111111111 represents full throttle, and 10000000000 represents half throttle. In standard mode, code 48 (0b110000) is the lowest throttle setting and code 2047 (0b11111111111) is the highest throttle setting, for a full range of 2000 throttle settings.
  2. The telemetry bit is set if the flight controller signals a telemetry update to the ESC. The telemetry update uses a separate return wire. 
  3. The checksum comprises a 4-bit CRC value. The checksum is calculated using CRC12, and is calculated over the throttle and telemetry request bit. The exact methodology is explained below.


Figure 6. DShot message on oscilloscope (credit)

The 47 special reserved commands in the throttle value can be seen in the source code of betaflight:

//this typedef taken from src\main\drivers\pwm_output.h in the betaflight github page
typedef enum {
    DSHOT_CMD_MOTOR_STOP = 0,
    DSHOT_CMD_BEACON1,
    DSHOT_CMD_BEACON2,
    DSHOT_CMD_BEACON3,
    DSHOT_CMD_BEACON4,
    DSHOT_CMD_BEACON5,
    DSHOT_CMD_ESC_INFO, // V2 includes settings
    DSHOT_CMD_SPIN_DIRECTION_1,
    DSHOT_CMD_SPIN_DIRECTION_2,
    DSHOT_CMD_3D_MODE_OFF,
    DSHOT_CMD_3D_MODE_ON,
    DSHOT_CMD_SETTINGS_REQUEST, // Currently not implemented
    DSHOT_CMD_SAVE_SETTINGS,
    DSHOT_CMD_SPIN_DIRECTION_NORMAL = 20,
    DSHOT_CMD_SPIN_DIRECTION_REVERSED = 21,
    DSHOT_CMD_LED0_ON, // BLHeli32 only
    DSHOT_CMD_LED1_ON, // BLHeli32 only
    DSHOT_CMD_LED2_ON, // BLHeli32 only
    DSHOT_CMD_LED3_ON, // BLHeli32 only
    DSHOT_CMD_LED0_OFF, // BLHeli32 only
    DSHOT_CMD_LED1_OFF, // BLHeli32 only
    DSHOT_CMD_LED2_OFF, // BLHeli32 only
    DSHOT_CMD_LED3_OFF, // BLHeli32 only
    DSHOT_CMD_AUDIO_STREAM_MODE_ON_OFF = 30, // KISS audio Stream mode on/Off
    DSHOT_CMD_SILENT_MODE_ON_OFF = 31, // KISS silent Mode on/Off
    DSHOT_CMD_SIGNAL_LINE_TELEMETRY_DISABLE = 32,
    DSHOT_CMD_SIGNAL_LINE_CONTINUOUS_ERPM_TELEMETRY = 33,
    DSHOT_CMD_MAX = 47
} dshotCommands_e;

Notes on the Special Commands (credit):
  1. If you change any settings with DShot commands, you have to issue the save settings command for them to take effect;
  2. To change the spin direction, set 3D mode, or save settings you must enable the telemetry bit in the associated command packet, and you must issue the command 10 times in a row for the command to take effect.
  3. If you issue command 0 and the ESC is not armed, it arms the ESCs with the throttle ranges set. If the ESC is armed it stops the motors. This command should be used if you want the motor to be stopped. If you try to use a throttle setting to stop the motor, it still spins slowly.
  4. If you stop sending commands, the ESC disarms. I haven’t timed the required update rate, but it’s pretty fast (10ms or less). 

There are four types (or protocol modes) of DShot, differentiated by their speed of connection:
  • DShot150 – 150 kbits per second or 9375 Hz update frequency
  • DShot300 – 300 kbits per second or 18.75 kHz update frequency
  • DShot600 – 600 kbits per second or 37.5 kHz update frequency
  • DShot1200 – 1,200 kbits per second or 75 kHz update frequency

The maximum practical ESC update frequencies (i.e. Flight Controller loop frequencies) are substantially slower than the theoretical update rates above:
  • DShot150: 4.05 kHz max
  • DShot300: 8.09 - 10.6 kHz max (10.6 kHz is only available on 32 kHz gyro boards)
  • DShot600: 16.0 kHz max
  • DShot1200: >32.0 kHz max (Currently only KISS24 supports DSHOT1200)


Figure 7. DShot Pulse Width according to mode (credit)

In our discussion about asynchronous serial protocols, we noted that the baud rate was critical in determining bit values. This is not as important for DShot because the bit value (1 or 0) is determined by the pulse width as a proportion of the total period. In other words, the duty cycle. Bits 1 and 0 are represented by a 74.850% and 37.425% duty cycle respectively.

As detailed in Figures 7 and 8, the signals for 0 and 1 are distinguished by their different high times, and the bit period is constant for each protocol mode. For example, with DShot600

  • Bit length (Period Time) is 1.67 microseconds = (T0H + T0L or T1H + T1L).
  • For a bit to be 0, the pulse width is 625 nanoseconds (T0H – time the pulse is high for a bit value of ZERO)
  • For a bit to be 1, the pulse width is 1250 nanoseconds (T1H – time the pulse is high for a bit value of ONE)

Figure 8. DShot Sequence Chart (credit)

The reason for the difference in pulse length for 0 and 1 is that it allows for some tolerance when determining the value. So these timings can be off slightly and the result will still be the same.

Unlike a number of other asynchronous serial protocols, DShot has no start or stop bit. Instead, there is normally a pause between frames of at least 2 microseconds (recommended reset time is 21 bits) to indicate a frame reset. A reset simply indicates the end of one frame and thus any future bits are the start of a new frame. With DShot occurring at the end of a Flight Controller PID loop this pause is actually considerably longer. If DShot were to be made to continuously output a signal then this delay would be required.

DShot Compatible Flight Controllers & ESC's


Any ESC that comes with BLHeli_S or KISS 24A (v1.02 or higher) firmware should support DShot.

A list of flight controllers tested to support DShot on Betaflight 3.1 is provided on the Betaflight Github repository.

Generating DShot on an Arduino UNO


Our first issue is that most flight controllers use Direct Memory Access (DMA) to generate the DShot frames. DMA allows hardware subsystems to access main system memory without using the MPU.  You can think of DMA as a co-processor that is used to transfer data between main memory and peripherals without the intervention of the MPU. The advantage of this is that MPU cycles are not wasted on DShot communication and can focus on the flight controlling PID loop. A lot of the ESC's use DMA as well.

The problem is that the ATMega328P MPU does not have DMA - so neither does the Arduino UNO. The Arduino DUE has DMA but we are not using that board. There are three approaches to generating DShot on the UNO that we could find:

1. Use The UNO Hardware SPI (Serial Peripheral Interface)
Remember how the duration of the ON and OFF states in DShot are different. This is not generally how serial protocols work but you can use four SPI bytes to construct one DShot bit. This is a bit of a hack and there are a few problems with this:
  • We didn't break out the SPI pins on our custom shield (doh!);
  • It uses up your SPI port which may be used for something else (in theory you can have multiple devices on the SPI bus but that is probably not practical - if this is an issue then approach 2 may be the answer);
  • You can only connect one ESC (not a problem for our tester but it would be if you were using the code for a quadcopter);
  • Timing is a problem. As mentioned, DShot has some tolerance on pulse timing but there is at least a 250 nS pause (two clock pulses - 16 MHz clock divided by 2 for each pulse) between bytes in a SPI transmission. In practise, we measured a 0.5 μs delay between bytes (Figure 11).
Nevertheless, I thought it was worth attempting this approach to see if it would work. If necessary we could modify the shield and I wanted to make some other changes to the layout anyway. Let me explain the theory behind the code. Figure 8 illustrates the bit pattern that we are attempting to replicate. We will start with DShot150 since being the slowest mode it should give us the best chance of success. The required bit timings for DShot150 (Figure 7) are:

  • T1H = 5 μs
  • T0H = 2.5 μs
  • T (Period) = T1H / 74.850% = 6.68 μs

So the period of each SPI bit needs to be 6.68 / 3 = 2.23 μs (i.e a frequency 0.45 MHz). The default frequency setting for SPI is to use the system clock speed (16 MHz) divided by four, that is, one SPI clock pulse every 250 ns. You can change the SPI frequency by setting the divider to one of the following options:

  • SPI_CLOCK_DIV2
  • SPI_CLOCK_DIV4
  • SPI_CLOCK_DIV8
  • SPI_CLOCK_DIV16
  • SPI_CLOCK_DIV32
  • SPI_CLOCK_DIV64
  • SPI_CLOCK_DIV128

The fastest rate is "divide by 2" or one SPI clock pulse every 125 ns. We need:

divider = 16 (clock speed in MHz) / 0.45 = 35.6

This doesn't really work as the closest available divider is 32. We are better of using a divider of 4 (i.e. a SPI frequency of 4 MHz) which gives us a SPI bit period of 0.25 μs. This period divides evenly into T1H and T0H. It also happens to be the default.

  • T1H = 5 μs = 20 ON SPI bits
  • T1L = T - T1H = 7 OFF SPI bits
  • T0H = 2.5 μs = 10 ON SPI bits
  • T0L = T - TOH = 17 OFF SPI bits
  • T = 6.68 μs ≅ 27 SPI bits (actually 26.7, we may need to tweak this. We will need 4 SPI bytes for every DShot bit)

The other important thing for us to set is the bit data order. The DShot protocol expects MSB first. Our SPI initalisation code is thus:

SPI.beginTransaction (SPISettings (4000000, MSBFIRST, SPI_MODE0));

The final parameter in the SPI initialisation is the clock mode. We are not using the clock signal or expecting a response, so it doesn't matter what you set here but for completeness, the options are:

  • Mode 0 (the default) - clock is normally low (CPOL = 0), and the data is sampled on the transition from low to high (leading edge) (CPHA = 0)
  • Mode 1 - clock is normally low (CPOL = 0), and the data is sampled on the transition from high to low (trailing edge) (CPHA = 1)
  • Mode 2 - clock is normally high (CPOL = 1), and the data is sampled on the transition from high to low (leading edge) (CPHA = 0)
  • Mode 3 - clock is normally high (CPOL = 1), and the data is sampled on the transition from low to high (trailing edge) (CPHA = 1)

To test  our code and allow us to measure the results, we will repeatedly send the same DShot frame with a delay between frames. The test frame will consist of:

Throttle = 10101010101
Telemetry = 0
Checksum = 1010 (See Calculating the DShot Checksum below)

There is normally a pause between frames of at least 2 microseconds and the recommended reset time is 21 bits. We will delay for 200 μs (i.e. plenty of space between frames).

In the test sketch we are calculating the check sum every time we loop. Since the frame isn't changing we could just do this once in setup() or even hard code the check sum value, but for the ESC tester this frame will be changing and we will need to update the check sum each time that it does. By including it here we will be able to see if it creates a timing issue.

As described in the DShot SPI Test Sketch and explained above, for the Arduino UNO (16MHz CPU):

  • DShot LOW (0)  = 10 SPI bits ON, 17 SPI bits OFF = 0x07FE 0000
  • DShot HIGH (1) = 20 SPI bits ON, 7 SPI bits OFF   = 0x07FF FF80

Thus there is a total of 27 SPI bits for every DShot bit. In practise we are using 32 SPI bits (4 bytes) sent 16 bits at a time.

Figure 9. A DShot ON bit = 20 SPI bits ON & 7 SPI bits OFF  = 0x07FF FF80

Looking at the protocol analyser (Figure 9) we can see that this sort of works. Channel 0 on the analyser is SS (SPI Enable). This goes low at the start of transmission as expected.

Figure 10. DShot ON (First 16 SPI Bits = 0x07FF)

It is hard to see the details in Figure 9, so we have split it up and zoomed in (Figures 10 and 11). Notice that even using the SPI.transfer16() command, there is a 0.5 μs delay between bytes as illustrated by the gap in the clock signal (channel 2 in Figure 11). Between every 16 bits there is another 1.3 μs delay. The length of a DShot "bit" is 8.7 μs. We were aiming for 6.7 μs. Most of this difference we can attribute to the delays between sending bytes.

Figure 11. DShot ON (Second 16 SPI Bits = 0xFF80)

The important thing with DShot is the duty cycle. Bits 1 and 0 should be represented by a 74.850% and 37.425% duty cycles respectively. We measured the relevant high and low bit components (Figure 12) and found:

  • T1H = 7 μs (should be 5 μs)
  • T1L = 1.7 μs (correct)


The second LOW bit is messed up because we are seeing voltage spikes on the SS line.

Figure 12. DShot T1H

At this point we gave up on the SPI approach. As we will see in Approach 3, the bit banging methodology gives a much better frame pattern, runs at DShot600 and we can use it on any digital pin, so there is no need to adjust the ESC tester hardware.

2. Additional SPI Port using USART
This is similar to Approach 1. For most Arduino devices, using the USART (Universal Serial Asynchronous Receiver Transmitter) in SPI mode is a way of generating a hardware-timed stream of bits out of one pin. This gives the UNO an additional SPI port. Unfortunately the UNO only has one serial port and it is used for programming and debugging. This option is better on the Arduino variants with more than one serial port (e.g. the Mega2560 which has four). Example code for using the USART in “Master SPI Mode” (MSPIM) is available here.

3. Bit Banging
Bit banging is slang for any method of data transmission that employs software as a substitute for dedicated hardware. In our case we are managing all the details of DShot communication, unlike SPI or USART for example which as shown in Figures 13 and 14, have dedicated hardware in the MPU to facilitate communication.

Figure 13. ATMega328P Block Diagram (credit)

Andy Tsui has written a DShot library for the Arduino, so lets compare the output of this bit banging with our SPI test.

Figure 14. SPI Hardware Block Diagram in the ATMega328P (credit)

The DShot packet produced by Andy's DShot library is shown in Figure 15. The results are so consistent that you can read the packet bits just by looking at it (1010101010101010). When using the DShot library you only pass the throttle value, the telemetry bit is fixed at 0 and the checksum is calculated within the library. This does mean that you can't use the telemetry request feature of DShot but it wouldn't be hard to tweak the library if you needed it.

Figure 15. Dshot frame produced by library

Comparing the timing of the library bits against theory we find:

  • T1H = 1.3μs (Figure 16 - theoretically 1.25 μs)
  • T1L = 0.3 μs (Figure 16 - theoretically 0.42 μs)
  • T0H = 0.7 μs (Figure 17 - theoretically 0.625 μs)
  • T0L = 1.0 μs (Figure 17 - theoretically 1.045 μs)

The results are good and there are no unwanted delays between bytes as with SPI.

Figure 16. DShot HIGH bit (T1H = W, T1L = 𝜏 - W).

If you want to produce DShot on the UNO then this library is definitely the way to go. This is the approach that we have used for our Tester.

Figure 17. DShot LOW bit (T0H = W, T0L = 𝜏 - W).


Calculating the DShot Checksum


There are LOTS of different ways that a CRC checksum can be calculated. Like just about everything else with the DShot protocol this needs to be reverse engineered. The algorithm in Figure 18 is taken from the cleanflight/betaflight source code.

This code starts with 0 and XOR's the 12 bits of our packet (11 throttle bits + 1 telemetry request bit) with that (which wont change anything since, 0 XOR 0 = 0 and 1 XOR 0 = 1). The code then right-shifts the data by four bits and XOR's the result with the value obtained in the previous step. It does this for each nibble (4 bits) in our packet (i.e. three times).

// compute checksum
int csum = 0;
int csum_data = packet;
for (int i = 0; i < 3; i++) {
 csum ^= csum_data; // xor data by nibbles
 csum_data >>= 4;
}
csum &= 0xf;
// append checksum
packet = (packet << 4) | csum;
Figure 18. Calculating the DShot (4 bit) Checksum.

The Tester Code


You can download the updated Servo/ESC Tester sketch with DShot functionality from the Reefwing Gist.

One thing to check is that the pin you want to use is on PORTD (D0-D7) for the UNO or PORTB (D8-D11) for the Leonardo. These are the default port allocations for the library. If you are connecting more than one ESC, these need to be all attached to pins on the same port.

For our tester, we are using D9 for the PWM output and this is the only pin with a header on our arduino shield. PORTB maps to Arduino UNO digital pins 8 to 13 The two high bits (6 & 7) map to the crystal pins and are not usable.

Thus in our sketch we have to define the DShot port as PORTB. We found that defining this in the sketch didn't work, so we modified the library to use Port B.

#define DSHOT_PORT PORTB

The other issue is that our PWM code is using Timer1 in a different manner to the DShot library. In other words there is a conflict. The ATMega328P has a couple of other timers. Timer 0 is used by the Arduino millis() and delay() functions, so we won't use that since we are using delay().

To address this issue we will modify the DShot library to use Timer 2. This is an 8 bit timer, whereas Timer 1 is a 16 bit timer. The DShot library is using the timer to send out packets with a frequency of 1 kHz. They used the Arduino Timer Interrupts Calculator to generate ISR code which fires 1,000 times a second (1 kHz). We can use this same site to generate code which uses Timer 2.

static void initISR(){
    // TIMER 2 for interrupt frequency 1000 Hz:
    cli(); // stop interrupts
    TCCR2A = 0; // set entire TCCR2A register to 0
    TCCR2B = 0; // same for TCCR2B
    TCNT2  = 0; // initialize counter value to 0
    // set compare match register for 1000 Hz increments
    OCR2A = 249; // = 16000000 / (64 * 1000) - 1 (must be <256)
    // turn on CTC mode
    TCCR2B |= (1 << WGM21);
    // Set CS22, CS21 and CS20 bits for 64 prescaler
    TCCR2B |= (1 << CS22) | (0 << CS21) | (0 << CS20);
    // enable timer compare interrupt
    TIMSK2 |= (1 << OCIE2A);
    sei(); // allow interrupts
}

In addition to changing the ISR initialisation code we also need to change the ISR to refer to the appropriate Timer 2 vector.

ISR(TIMER2_COMPA_vect){
   sendData();
}

To test our modifications to the DShot library we used the following sketch. The DShot data stream is on Pin D9. The output was identical to Figure 15.

#include <DShotTimer2.h>

DShot esc;

uint16_t throttle = 0b10101010101; // 0x555 or 1365 Decimal (68% throttle)

void setup() {
  esc.attach(9);  
  esc.setThrottle(0);
}

void loop() {
  esc.setThrottle(throttle);
  delay(10);
}

Because we are using a common pin for DShot and PWM, we need to be able to disable DShot once we return to the home menu of the ESC Tester. To do this we detach interrupts from pin D9 and set timerActive to false. To be able to do this, we added a new public function to the DShot library called setTimerActive(bool active).

void DShot::setTimerActive(bool active){
    timerActive = active;
}

You can download a copy of the modified DShot library using Timer 2 from the Reefwing Gist. You will need 2 files:
Make a copy of the original DShot Library in your Arduino libraries folder. Name the new library DShotTimer2. Replace the two files in the src directory with those you have downloaded.

Tuesday, May 5, 2020

Arduino ESC Tester - Adding Fast PWM and OneShot125

The Arduino Servo/ESC Tester Series (Part 3)


Figure 1. Arduino and Tester Shield mounted in 3D printed enclosure.


In our first article in this series, we built a prototype Servo Tester using the Altronics MegaBox as our hardware platform. We followed this up with an article using a custom Arduino shield to make construction cheaper and easier.

As shown in Figure 1, we have created a 3D printed case for the shield version of our tester. You can download the STL files for the base, lid and LCD mount from Thingiverse. The LCD mounting bracket and hinges are connected using M3 bolts and nuts.

If we do another version of this shield, I would do a few things differently. These include:

  • Moving the group of 15 tester pin headers away from the left hand hinge, towards the centre of the PCB.
  • Moving the LCD connector towards the top of the PCB (or use a 90 degree connector) to allow the LCD mount to close like a lid.
  • Move the potentiometer a bit further towards the front of the PCB.
  • Break out the D13 LED onto the shield.
  • Adding four mounting holes to the PCB and use this as the lid to the box.

Our previous prototypes only provided PWM output at varying frequencies (50 Hz, 125 Hz and 250 Hz). In this article we will add PWM 490 Hz and the OneShot125 protocol to our tester. This will be used for testing ESC's which utilise this protocol.

PWM 490 Hz (Fast PWM)


In standard PWM the maximum pulse width is 2 ms, so the highest theoretical frequency using this control strategy is 500 Hz. To get pulse separation, the practical upper limit is 490 Hz.

Adding this protocol is very easy. In part 1 of our series we found that the simplest way to output PWM is to use the analogWrite(pin, dutyCycle) command. The ATmega328P PWM default frequency is 490 Hz for all PWM capable pins (3, 9, 10 and 11), with the exception of pins 5 and 6, whose default frequency is 980 Hz.

We tested this using our protocol analyser and found that a 50% duty cycle [analogWrite(9, 127)] provides PWM with a 1.016 ms pulse width and a frequency of 490 Hz.

For our existing shield sketch we may as well continue to use the register method of setting PWM frequency. The formula that we derived in Part 1 gives us the value for ICR1 at a particular PWM frequency:

ICR1 = 1MHz / fPWM = 1MHz / 490 = 2040

Setting the ICR1 register to this value should give us PWM at 490 Hz. Updating the sketch accordingly, we measured the output on our protocol analyser (Figure 2). We ended up with a PWM frequency very close to 490 Hz. The updated code will be provided at the end of the article.

Figure 2. Output for PWM 490 Hz

We also tried connecting the 9G Servo to see if it would work at this frequency. It did to a certain extent but there was a LOT of jitter. The servo is expecting a nominal frequency of 50 Hz so these results are not surprising.

What is an ESC?


Figure 3. An example of an ESC.

An Electronic Speed Control or ESC is an electronic circuit that controls and regulates the speed of an electric motor. ESC's come in many different packages, one version is shown in Figure 2.

ESC's contain a microcontroller which take an input (e.g. direction or speed from a flight controller) and convert this to the appropriate motor control output. The flight controller (or ESC tester in our case), communicates with the ESC using an ESC protocol. The available protocols depend on the ESC firmware being used. Some examples of ESC firmware are:

  • BLHeli ESC.
  • BLHeli_S ESC.
  • SimonK ESC.
  • Kiss.
  • BLHeli_32.

The ESC in Figure 3 is encapsulated in yellow heatshrink. The 3 x blue leads with bullet connectors, go to the brushless motor that is being controlled. With brushless motors, the speed of the motor is varied by adjusting the timing of pulses of current delivered to the windings of the motor. The ESC effectively creates three-phase AC power to deliver these pulses.

Figure 4. Example ESC control wiring.

In Figure 3, the thick red and black wires (ending in a male Deans T-plug) connect to the LiPo batteries and the 3 smaller wires (white, black and red) are for the ESC control (white) and to provide a regulated 5 VDC (red and black). Not all ESC's provide this regulated 5 VDC (also called a Battery Eliminator Circuit or BEC).

An example of how an ESC is used in a quadcopter design is shown in Figure 4. This design uses a quad ESC (i.e. four ESC's mounted on one PCB), controlled by a Beaglebone Blue flight controller.

The idea is that our ESC tester can be used in place of the flight controller, to allow us to test each part of the system separately.

What is OneShot?


The OneShot125 protocol consists of:
  • A single pulse (hence the name OneShot) with the new response required (this is different to PWM which is a stream of pulses);
  • Pulse width is between 125 µs (stop) and 250 µs (full power). This is where the 125 in the name comes from.
Oneshot comes in three varieties:
  • Oneshot125 (pulse width 125-250 μs, maximum frequency 4 kHz); 
  • Oneshot42 (pulse width 42-84 μs, maximum frequency 11.9 kHz); and 
  • Multishot (pulse width 5-25 μs, maximum frequency 40 kHz). 

OneShot125 was created by Flyduino and is supported by flight controllers which use Cleanflight, Betaflight, Raceflight and Kiss. From an ESC perspective you will need SimonK, BLHeli rev13, or KISS firmware.

OneShot42 was also developed by Flyduino as part of their KISS FC and ESC program. It is not widely supported at the moment.

Out of the three varities in the OneShot stable, Multishot is the fastest ESC protocol. To take advantage of this it requires a fast flight controller and ESC processor. It was developed by RaceFlight and again is not widely supported.

The Raceflight firmware and Multishot protocol were introduced by RS2K (RCGroups user). Raceflight is a fork (or branch) of Betaflight, meaning it used the original Betaflight code and was modified for the purpose of F4 flight controller targets.

How about DShot?


Compared to the protocols already considered, DShot is the only one which is truly digital. You could argue that PWM and OneShot are also digital since they use pulses with encoded data but the point is moot. A comparison of the theoretical data rates for OneShot and Dshot are shown in Figure 5. The advantage of DShot over OneShot is not so much about speed but reliability and flexibility. Moving to a fully digital protocol allows the introduction of error correction and bi-directional data flow.

Figure 5. DShot vs OneShot


A DShot digital message consists of 16 bits in three parts, throttle value (11 bits), telemetry request (1 bit) and the CRC checksum (4 bits). The telemetry request asks for data back from the ESC on models that support it. Transmission of telemetry data is done on a different wire. Any ESC that comes with BLHeli_S firmware should support DShot.

There are four types of DShot, differentiated by their speed of connection:

  • DShot150 – 150 kbits per second or 9375 Hz update frequency
  • DShot300 – 300 kbits per second or 18.75 kHz update frequency
  • DShot600 – 600 kbits per second or 37.5 kHz update frequency
  • DShot1200 – 1,200 kbits per second or 75 kHz update frequency

We will look at developing DShot capability for our ESC Tester in a subsequent article.

Is OneShot125 better than standard PWM?


In our original article in this series, we talked about how PWM is used to control a servo. TLDR - a 1 ms pulse width equates to stop and a 2 ms pulse width = full power. As mentioned above, the theoretical fastest refresh rate is 1 / 2ms = 500 Hz. In practice it is more like 490 Hz as you need some gap between the pulses. A consequence of this is that there is no point your flight controller running faster than 490 Hz since we can only update the motor control at this rate.

By reducing the pulse width band to 125 - 250 µs, OneShot125 is theoretically eight times faster than PWM 490 Hz. A consequence of this faster update speed is no jitter in your controls. Jitter is caused when your flight model updates quicker than your ESC can respond. With OneShot125, your flight controllers PID loop can update eight times faster than Fast PWM.

A comparison of Fast PWM and OneShot is shown in Figure 6.

Figure 6. Fast PWM vs OneShot


Programming OneShot125 for the Arduino UNO


Using our approach to date we would send continuous OneShot125 pulses in the 125 - 250 µs range (see Figure 6) as we have done for the previous PWM solutions, but that is not how OneShot operates. OneShot sends one pulse when the throttle information changes.

However, we are not writing flight controller software but an ESC tester. The ESC wont care if it gets repeated pulses with the same value. So for simplicity we will produce a stream of pulse at a frequency of about 1 kHz. The pulse width will be between 125 - 250 µs, based on the potentiometer position (simulating the throttle input).

Taking this approach allows us to reuse a lot of our exisiting code. If you need a more purist solution then you can use the OneShot125 code written for the Arduino Mega which is available on the Arduino forum.

Once again, the formula that we derived in Part 1 gives us the value for ICR1 at a particular PWM frequency:

ICR1 = 1MHz / fPWM = 1MHz / 1kHz = 1000

Setting the ICR1 register to this value should give us PWM at 1 kHz. The only other changes we need to make are to the minimum and maximum pulse widths. Register OCR1A can then be set to the required pulse width between 125 and 250.

Figure 7. OneShot125 with pulse width set to 193 µs


Connecting the output of our Servo/ESC tester to our protocol analyser provides the output shown in Figures 7 and 8. As expected we get a pulse width of 193 µs at a frequency of 1kHz.

Figure 8. Output on Protocol Analyser.

Adding OneShot42 or Multishot to our ESC Tester is trivial. You just need to change the minimum and maximum pulse width values and use the same approach as that used for OneShot125. I'm not going to add it to our code because I have no need for it.

You can download a copy of the updated sketch from the Reefwing Gist.