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:
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:
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:
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.
We could avoid the whole libusb/usbfs/usbfs2 problem by writing a kernel driver to pull data from the sensor nodes:
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.