Portland State Aerospace Society meeting notes for 2008-05-07

I have become the official blogger for the Portland State Aerospace Society (PSAS). If you haven’t heard about PSAS, watch my five minute Ignite Portland 2 talk and follow along with the sides.

In this PSAS weekly episode, I talk about the rocket airframe and the software for the avionics sensor nodes.

Airframe

Tim showed off pictures of his setup for creating the light-weight fiberglass shell that goes around our rocket:

I asked Tim why we make a shell for the airframe, since there’s a 5.5 inch metal shell inside of the fiberglass tube. The fiberglass really isn’t smoother than metal, so it’s mostly for looks. All the other rocket groups are doing it, so we should too, I guess?

This is what our old rocket airframe looked like:

It’s pretty. Unfortunately, it’s in little pieces after it crashed into the desert:

Which is why we need to build a new one.

USBFS2 and Rocket sensor nodes

Our rocket has a bunch of sensors that we need to pull data from. The data flows into the Linux flight computer; based on the sensor readings, the computer decides when to deploy the parachute.

Rocket avionics:

The flight computer has about a five second window to correctly deploy the parachute. If it deploys it too early, the rocket drifts on the parachute for a long time. The rocket will drift further from our launch site, and the recovery teams have to travel father. If the parachute is deployed too late, the rocket is moving too fast, and the parachute rips off.

My job is to figure out how to get the flight computer software to talk to the USB sensor nodes. The flight computer software runs in userspace (vs. running in the Linux kernel). The “traditional” way of talking to USB devices from userspace is to use libusb. libusb is a convenience wrapper around the kernel interface to the USB core, usbfs. Previous versions of libusb have some serious issues, like not supporting certain USB endpoint transfer types, and not supporting asynchronous transfers.

Most of you are probably asking, “What is asynchronous transfers and why do you care?” With synchronous transfers, you submit a transfer, wait for it to complete, and submit another. This is really slow because the kernel can block, and you won’t get a periodic stream of data. What you really want is to submit all your transaction requests at once, and get notified via a callback when they complete. This is called an asynchronous transfer. The PSAS avionics team really care about this because we need to sample our sensors at a known periodic rate, and thus we need asynchronous transfers.

However, libusb doesn’t do asynchronous transfers. libusb also doesn’t deal with isochronous endpoints. Isochronous endpoints are found in USB devices that send data periodically, like webcams. We want our USB sensor nodes to have isochronous endpoints because they have guaranteed bandwidth, and the host computer won’t retry the transaction if there’s an error. We want the most current data from our nodes, so we don’t want retries. Therefore, we want either interrupt or isochronous endpoints on our USB sensor nodes, and we can’t use libusb.

All that boils down to one fact: We can’t use libusb, and we need to redesign usbfs to get asynchronous transfers. Here’s a picture of the current usbfs stack vs. my proposed usbfs2 stack:

(Technically, Greg Kroah-Hartman proposed this idea, but he passed the project onto me.)

usbfs is on the left and usbfs2 is on the right. usbfs represents a USB device as one file, which means you use tons of ioctls to talk to a device. ioctl is the ugly stepchild of system calls. We want to replace usbfs with a better interface. usbfs2 represents a USB device as a bunch of files, one for each endpoint. That means you can do reads or writes to a physical USB endpoint. (Except for control endpoints, which still need an ioctl.)

Sounds great! I had the basic prototype for usbfs2 endpoint communication done within a couple months of starting this project. The hard part is making usbfs2 support asynchronous transfers. The USB core for devices, gadgetfs, uses the in-kernel aio core to get asynchronous behavior. However, in-kernel aio has some serious race conditions, the code is a mess, and no one wants to work on it.

Zach Brown is working on a set of patches to replace the in-kernel aio core with something that uses kernel threads and is much simpler. The idea is that system calls (like read, write, ioctl) work like normal, until the call blocks in the kernel. When the call blocks, the aio core will spawn off a new kernel thread, and return to the userspace caller in the old thread. The userspace code will get a callback when the system call completes. This way, the code can fire off a bunch of transactions and get the asynchronous behavior it wants.

This has issues if the userspace code is trying to do a bunch of read transactions from a USB endpoint. If one transaction blocks before it submits to the USB core, and other read transaction submits, we get out of order data. That would be very confusing for our flight computer software. So the new in-kernel aio core needs to deal with this. The implementation is still fuzzy (like this picture). I told Zach I’d look at his code and think about how to do this, but I’m still trying to understand his code. 🙁

We could avoid the whole libusb/usbfs/usbfs2 problem by writing a kernel driver to pull data from the sensor nodes:

At that point, we still need some sort of interface for the userspace flight computer code. Our kernel driver would be so simple that it would basically be doing the same thing as usbfs/usbfs2. So it makes sense to use usbfs2. Whenever that gets done. *sigh*

You may be asking, why USB for your rocket sensor nodes? That’s a can of worms I don’t want to rehash. You can read about that discussion here.

Whew! Now you know everything you ever wanted to about USB sensor nodes.