Worklog: Affordable Bench Autopilot

Having some major GCS dev burnout—time to dig back into my first love: hardware. This thread will serve as a journal as I work on this niche side-project: a low-cost, feature-complete bench autopilot using a Nucleo board.

Motivation

We have a huge selection of flight controllers to choose from, each designed for different use cases, but all generally for flight. None (that I know of) are built with the bench as the primary focus.

I want something

  1. Less than $100 USD
  2. Debugger-friendly (no dinky DCD-S connector)
  3. Big (by autopilot standards), and easy to probe
  4. Capable of supporting nearly every feature available in ArduPilot on a single piece of hardware
  5. Every single pin of the MCU broken out to a pad

This will serve as a learning platform for me. I am by no means an expert in any of this, but hopefully someone else will find it educational to follow along with me.

Scope

For this, I am planning to design a custom expansion board for a NUCLEO-H755ZI-Q. The Nucleo board itself checks a lot of boxes:

  1. Cheap: $30
  2. STLink-V3 built into it
  3. Ethernet
  4. USB OTG
  5. Every pin is broken out to a pad

The expansion board will contain as many things as I can think of that are typically found on an autopilot:

  • IMU + heater
  • Mag
  • Baro
  • MicroSD Slot
  • CAN Transceivers + switchable terminators
  • A few common JST-GH connectors (CAN, GPS, Telem1, etc)
    • Just for convenience. I’m not going to go too overboard with these. Every pin is available somewhere on a header, and I’ll plan to do that for everything but the most common connections.
  • Space to solder in a nano-RX, like an RP1 or RX4
    • Yeah, this is outside my stated scope, but whatever.
  • IOMCU (F103)
  • QSPI Flash Expansion
    • Since this is going on an expander board, there’s a really good chance this simply won’t work due to the length and the connector. But that won’t stop me from trying.
  • FRAM
  • Power1 connector (maybe Power2 as well)

Some of these additions might seem unnecessary, but remember, this autopilot isn’t designed to be “useful” in the traditional sense. For example, I have tons of I/O, so I really don’t need an IOMCU. But if I want to learn, develop, or test something with an IOMCU, I want it on this board. That was my guiding philosophy with each of these inclusions.

If anyone reading this thinks that I’ve left something out, please let me know.

What’s not included

This is meant to be an autopilot, not a mockup aircraft. As such, I’m leaving out most devices you typically plug into the autopilot, like servos, ESCs, GPS, other periph nodes, etc.

I also am not including an OSD chip, because I don’t know enough about reliably sourcing whatever MAX7456 clone all the FC manufacturers are using.

Next Steps

I’ll document my progress as I go—covering design, PCB layouts, and firmware integration. If it proves useful, great. If not, at least I’ll have learned something along the way.

My next post will cover component selection, and maybe a little bit of schematic work.

2 Likes

First Steps

The Nucleo-144 has a stackable header system, called “ST Zio”, extended from the Arduino Uno’s:

A subset of these pins is directly compatible with Arduino shields, which could probably be useful. The other set of pins, which aren’t populated with any headers, are called the “ST Morpho”. Every pin on the MCU can be accessed on the Morpho connector, so you can easily solder something up if the expander board is missing something.

This also gives me the name I’ll be using for my board: ZioPilot.

Peripheral Mapping

The first step is to map out the peripherals we need. We need to confirm that the desired features are available on the Zio connector, and I will try to minimize the pins I consume on the Arduino subset of the headers (so that they are available to be used with stock shields). Here’s a snippet from ST’s published schematic for the Nucleo-H755

This is great, most of the peripherals we wanted are already broken out in nicely-grouped sections. If we stick to pins with named functions as much as possible, our routing will be dead simple and our expander board should compatible with other Nucleo-144 boards. Not just the H755, but the F7 series and even something like the U5 (if someone ever wanted to design a controller around that for some reason).

Quick clarification, ST makes a naming distinction between groups of pins on the Zio (e.g., SPIA, SPIB) and functions in the STM32 (e.g. SPI1, SPI2). This is because different Nucleo boards may have different SPI pins/driver numbers routed to those sections. The H755 may have USART2 routed to USARTB, but another board might have USART6. I too will use this terminology in this entry.

Now, on the downside, there’s only one CAN port, and only two UARTs, but we can route plenty of stuff from the many other pins. All the bare minimum things at least can be routed in a universal fashion, then I’ll add a few optional things defaulted to the H755, but make it so those parts can be disconnected and hand-rerouted if needed.

Pin Conflicts

Unfortunately, there are some clashes between pin functions. A lot of this is bad luck with the specific pins ST chose to route to the existing connectors (not just the Zio, but also Ethernet). None of this is a terribly big deal; every pin is still accessible, but this impacts how many features I can use at once and how universal I can make things between boards past/present/future.

SPIA/SPIB MOSI Conflict

I really wanted two SPI busses routed to the Zio; one for my internal sensors, and the Arduino SPI bus left empty for maximum flexibility, but SPIA/SPIB share their MOSI pin (PB5)! WHY!? Two pins literally right next to each other route to the same pin on the MCU. It looks like they originally intended PA7 to be SPIA MOSI, but that interferes with Ethernet, so they use PB5 as the alternate, not noticing, or not caring, that it clashes. Looking across other Nucleo-144 boards, it looks like this is a problem across the board. You have to choose two of the following three: SPIA, SPIB, Ethernet.

I could configure another SPI bus elsewhere (there are 6 available, half of which have 2+ alternate pin assignments), but other Nucleo boards aren’t guaranteed to have SPI that can route to those same pins (I checked). The only SPI bus that is guaranteed to work on all Nucleo-144 boards is SPIA.

So, what I’ll do is route SPIA to my internal sensor bus, but I will put them through normally-closed solder bridges on my expander board, so you can bodge any pins on the Zio to there. This default arrangement will work in the vast majority of cases.

SPIB/SWO Conflict

Additionally, SPIB’s SCK conflicts with the Serial Wire Output (SWO) pin, which is useful for tracing with the debugger. I doubt that will ever be needed/useful, but it’s still a shame. I like that pin. Well, SPIB is already unusable for us, so all I need to do is not wire anything to D23 on the Zio and we’re good.

RMII_TXD1/FDCAN2_TX and USART1_TX/FDCAN2_TX

This one is the worst. For some reason, they picked PB13 for the ethernet TXD1 pin. This pin is all the way on the other side of the chip from the rest of the ethernet TX pins. It’s like ST went out of their way to create this conflict. PG12 or PG14 would have made WAY WAY WAY more sense. It’s also really strange that this is the only ethernet pin that uses an actual shunt jumper (JP6) instead of a solder bridge.

I could remove the shunt from JP6 and bodge a wire from PG14, and maybe I will for rev 2, but I’m guessing that will screw with the signal lengths too much.

So, thanks to this, I need to make USARTA, mutually exclusive with CAN2—damn.

This one almost makes me want to scrap this whole damn project and just design a brand new board from the ground up, but I will control myself and carry on with. Barely anybody needs dual (or triple) CAN, but I will install 3 transceivers so that they can be optionally connected (the F767 supports 3, but the H755 only has 2).

UARTS Are in Short Supply on Zio

I have one guaranteed UART, and that’s it (edit: to clarify, I mean guaranteed to be on specific pins on the expander board; there are many more UARTs, but they will be on different pins for each Nucleo model). The Arduino UART might be taken up by CAN2, or by a shield. There’s also D41/D42 (PE7/PE8), which are not intended to be UARTs, but I will assert, without proof, that most Nucleo-144 boards can put a UART there.

  • Since the guaranteed UART (USARTB), has flow control, I’d like to wire it up to a 6-pin JST-GH, to be used with whatever you want to plug in there. It would really be wasted on the IOMCU, which doesn’t need flow control and is one of the least important things really.
  • The IOMCU can take D41/D42.
  • The Arduino TX/RX will be reserved for one of three mutually exclusive options: CAN2, GPS, or shield.
  • I’m scrapping the RC receiver. I admitted last time that it was out of scope anyway.

Anything else will just have to be soldered to the Morpho pads (or Zio if they route there). This is fine. This is largely what I intended originally anyway. We have plenty of UARTs if you don’t care about a little easy soldering.

Final Block Diagram

Apologies for using KiCAD as a block diagram generator. It was the easiest way to scratch this out quickly. I’m doing a weird mix of using wire lines as bundles of wires. I also didn’t align the connectors correctly, nor did I show the pin names or the Zio names for each pin. For that, you’ll have to check out the spreadsheet.

Google sheet of all pin assignments

  • MicroSD Slot
  • Internal Sensors
    • Connected to SPIA, I2CB, and a couple chip select pins.
    • The SPI and CS pins are connected through NC solder bridges in case someone has a reason to reassign those pins.
  • CAN1
    • Connected to the Zio CAN.
    • GPIO Controlled terminator (default).
    • Solder bridges can be reconfigured to make it permanently on or off and free up that GPIO
  • LEDs
    • Red, Green, and Yellow
  • USARTB
    • Connected straight to a JST-GH connector
    • No need for any jumpers or solder bridges
  • Power1 Connector
    • Can optionally power the board.
    • Analog sense pins for current and voltage
  • GPS Connector
    • UARTA and I2CA
    • Solder bridges to disconnect and reroute if needed.
    • Conflicts with CAN2
  • CAN2
    • Can be used if UARTA is unused.
    • GPIO wired to the “standby” pin on the transciever. This means I can use the BRD_ALT_CONFIG parameter to switch between these two.
    • Solder bridges everywhere to disconnect and reroute at will. I put them at both ends to minimize stubs when reconfiguring.
    • Terminator is manually configured with a jumper. I was originally going with software control for everything, but it’s too much of a pain. I really only need one reference circuit for that.
  • CAN3
    • Populated, but not connected to anything.
    • Wire it up manually to boards that support a 3rd driver.
    • Terminator is manually configured with a jumper.
  • IOMCU to UARTC*
    • This isn’t actually a named group of pins on the Zio, but I checked three different Nucleo boards and they all have an available UART to route to these pins.
    • Solder bridges to disconnect and reroute if needed. I forgot to draw these, but I’m not fixing it now.
  • IMU Heater
    • I also forgot this one in the diagram!
    • I will make this one solder configurable to be controlled by either the IOMCU or a GPIO pin from the FMU

Next Steps

I’ve done the preliminary component selection, but this post is already way too long, so I’ll kick that to the next update. The good news is that I think I can get this all assembled at JLCPCB with parts they have in stock, which is huge.

1 Like

I am sorry to tell you, but this project is a lame duck from the outset. UARTs are the most important thing for APs, and if this processor has like 2 UARTS, with one being semi-occupied, that is a dead end. Most probably you would end up adding some additional processors, maybe even Pi Picos which would work like extra UARTs, but it will be a very very pain in the a… programming and hardware design.

I strongly suggest you look for something which has at leat 4 hardware UARTs. In previous, older, projects I have been using Mega 2560 pro, which has 4 Uarts, and it always came short, it was always a fight to get everything in. Then you will start using I2Cs instead of UARTs whereever possible, then you will run into wiring distance problems with I2C, then … you will come back to something where it works straight out of the box with UARTs

I am sorry to tell you, but this project is a lame duck from the outset. UARTs are the most important thing for APs, and if this processor has like 2 UARTS, with one being semi-occupied, that is a dead end.

Two things:

  1. No, there are much more than 2 UARTs on the processor.
    • On the H755, there are 6 in total I can actually use on this autopilot (8 if I’m willing to disable Ethernet), but only 3 can be routed to the expander board in a way that is consistent across the Nucleo-144 line.
    • The rest of them can all still be used, but you’ll have to access them from the Zio header or solder to the Morpho header pads.
    • For 2 of the 6, you have to pick and choose between them and CAN2 or IOMCU, which can both be disconnected.
  2. I absolutely agree with the importance of UARTs for practical autopilots. This isn’t one of those.
    • This thing will be heavy, bulky, terribly packaged, and held together with stacked 0.1" headers and many exposed conductors.
    • Needing to solder a wire to a pad is absolutely not be a dealbreaker for this thing’s intended purpose.
2 Likes

Oh sorry, I did not get that. It does not matter if you have a pad or connector, in fact I always prefer pads. In any case, you should do everything possible to have the maximum number of Uarts, even it involves redesigning the board.

You seem to be missing the point of a bench test focused board.

1 Like

I love them.



In fact, I have been (hand-) making them along time ago…

1 Like

Love this. I miss those days a bit. Drilling those things was the worst though.

But you get the protype in a day. Where I live it would take about 2 weeks to get the PCB from china

Part Selection and WIP Schematics

I’ve got all of the critical parts picked out, and I have parts of the schematic done.

Part Number LCSC
IMU ICM-42688-P C1850418
Compass QMC5883L C976032
Baro BMP388 C779278
Flash W25Q256JVE C97522
FRAM MB85RS256B C8742

Part selection was a tricky process, because JLC’s search functionality sucks is extremely limited. It’s definitely no DigiKey. You can’t easily select a range of values to filter, and many of its data fields for its parts are incomplete, which makes filtering useless. For example, they have a field to filter out accels from accel+gyro, but most of the things labeled accel-only are really accel+gyro.

I tried a few different approaches, but in the end, I found that the best way to search was to find the category I was looking for, sort by stock count (descending), and look for the first part that fits my needs. This ended up working really well, and was not as time consuming as you might expect; I highly recommend this flow. This is very different from my DigiKey approach, where I filter strictly by specs, then, if I have many pages of parts, sort the remaining parts by unit cost at 1-piece quantity.

For getting the library parts for KiCAD, I used this great python script that extracts them directly from LCSC part number and includes footprints and 3d models. I hate that the parts had the pins arranged in physical order on the schematic though, so I remade the schematic symbols myself to make them match KiCAD’s design guide.

Sensors Schematic

Big shoutout to CUAV for open sourcing many of their schematics. The IMU heater design part was particularly helpful. The CUAVv5 used series resistors in a big loop around the IMU board, but I had concerns about that current loop’s potential impact on the compass, so I went with the approach the X7 uses: parallel resistors. I think it will be easy to keep the mag interference tolerable (the loop geometry is way smaller, and the current through each loop 1/4 the size). You’ll notice my heater is barely any different than the X7, right down to the same choice of MOSFET (because I guess we both chose the most common SMT N-Channel MOSFET in China).

I noticed a lot of boards have sensor VDD enable signals in their hwdefs. I’m not sure what advantage there is to disabling them, but having a dedicated LDO for the sensors makes sense to ensure they get really clean power.

For the IMU, I’m going with the ICM-42688-P. I wanted to make sure I could also drop in an ICM-42670-P, just in case, which looks like it is possible as long as you aren’t intending to use FSYNC, which I’m not. Designing for both with give me a little supply-chain flexibility (this actually turned out to be prescient, because stock availability on JLC went from thousands to a mere 16 at the time of writing).

Other than that, nothing particularly interesting about these, just a lot of digging through datasheets to make sure I’m not missing anything about what the pins do, and make sure there’s nothing special to watch out for.

Memory Schematic

Nothing terribly interesting here, just copying reference designs from datasheets mostly. I had to read up quite a bit to make sure I understood what was necessary in the MicroSD and what wasn’t.

I’m not bothering with ESD protection diodes like you’ll find in many reference designs for MicroSD. This whole board is an unprotected ESD nightmare; my SD slot isn’t going to make it worse.

Zio Pinout and Heirarchy (WIP)


Changes

  • I need to have two SPI busses. It crossed my mind that IMU and FRAM probably should not share a bus. I don’t think any autopilot out there shares SPI between the IMU and FRAM. SD and baro often share with FRAM, but the IMU never does, and that’s probably for the best.
    • PF7, PF8 and PF9, which are used for SAI_B, do actually seem to always be routed to the same Zio pins across the line and do seem to always support SPI. I will route the FRAM bus there (since it won’t be the end of the world if I have to disable it; can always do flash storage)
    • I will use the SPI_A for internal sensors, again because those are the most important parts of this expander (if literally nothing else is on it, that’s still usable).
    • Since I2C_A is also right there, I’ll use it for the internal baro and compass. I2C_B can go to the GPS connector.
  • I messed up CAN2 RX in my previous post. Mistook it for a different pin. Fixed in the spreadsheet.