launchcontrol: a rocket-launching java app.
Up: | Software |
---|---|
Xref: | FlightComputerStateFlowSep2003,LaunchSequenceLv2 |
LaunchControl's official motto: "This worked pretty well last year. Let's not do that again."
Introduction
For the 2009 launches, since the CAN-based rocket avionics and telemetry is no more, we trimmed launch control back to basics. There is now again a separate LaunchControl app containing nothing but the RocketViewLaunchPanel. This panel now only contains toggles for the shore power/strobe/siren, an indicator for the timer, a big Launch button and a big Abort button. You can invoke it via ant with ant run-launchcontrol
or directly with java -jar dist/launchcontrol.jar
.
LaunchControl and all the other Java bits are available from a new git repository: http://git.psas.pdx.edu/?p=launch-control.git;a=summary After cloning the repository, copy the launch configuration files main.conf
and sched.conf
from src/launchcontrol up into the main directory.
2005 Introduction
launchcontrol talks to the rocket and to the launch tower. It can control the rocket by sending it messages to change state. It can control the launch tower by sending messages to the launch tower relay board to turn on and off relays which power the igniter, siren, etc. But most of all, it sequences all of these events into one, coherent, safe, abortable launch sequence.
For 2005 summer launches
The separate Launch Control java app has been merged into a single optional RocketViewLaunchPanel. You can invoke it by giving RocketView a parameter on the command line or through ant with ant run-launchview
.
Requirements for Black Rock 2004
Per the new launch sequence, launch control now sends a handful of commands to the rocket.
- Start Preflight Check: this is probably a timed event, but could have a manual override
- Arm for Countdown: only enabled after Preflight Check
- Abort: always enabled, it should be a big red button far away from other UI.
- Deploy Drogue: send to fire the drogue chute
- Deploy Main: send to fire the main chute. These both assume we can get a lock on the rocket while in flight, so we shouldn't rely on this.
- Power Down: Sent when we lug the rocket back to camp.
Each command will send a flood of messages until a corresponding ACK is received from the rocket. This could be implemented using buttons in the Java app, but it may be more expedient to define a number of shell scripts wrapping ?TestNetSend for each of these messages.
Status as of 2003-09-21
The Java app was abandoned late in the schedule, and Jamey was too ill to pick it back up in time for the launch. The night the LTC hardware was bolted into the enclosure, I pulled an all-nighter and hacked together a command-line app, launch.c
, to arm the board and trigger the four relays in the new Launch Tower Relay CAN node: siren, strobe, shore power, and ignition. Launch
was capable of reading back relay and armed status, but bugs in the CAN driver prevented these requests from getting through.
There was half-assed support for piping a launch script into stdin (gotta have a countdown!), but I don't think it was good enough to be used.
-- IanOsgood
Also see: Launch Tower Electronics page
(The following is heavily edited from an instant messaging chat log.)
I wrote a program which runs a launch countdown and triggers events at the launch tower. I wrote it for Linux, in C, using the GTK widget toolkit. Once a second, it checks whether it needs to do something. That something may include playing sounds (audio countdown is important to me :) or sending commands to the launch tower. When messages come from the tower, it checks to see if there's any important information in them. And it updates a clock on the screen. And all that's left is the "Start Countdown" and "Abort Countdown" buttons. Communication with the tower is by TCP/IP over wireless ethernet.
Events in the countdown sequence were hardcoded into an array in the C implementation, necessitating recompiling when the sequence of events should change. There were three kinds of events. One executed an external command on the Launch Control Computer; I used this only for playing sounds. The second sent a command across the network. The third was a special case of the second, testing for the rocket being ready to launch, and if it was ready, then sending the launch command.
There are no particular clock synchronization issues; the countdown need not be timed precisely. Therefore we make timing relative to the time the countdown begins and accept non-deterministic scheduling.
We have a microcontroller board at the tower, which controls power to electrical devices at the tower, and reads a "rocket ready (to launch)" signal from the rocket's on-board flight computer. The launch sequencer talks to the microcontroller with a specialized protocol modeled after the AT command set for modems. There's an umbilical allowing it to communicate with the flight computer a little bit, and there's a set of relays. Everything has an on/off state. Small voltages come out of the microcontroller, which turn on or off (relatively) big voltages which control things like the ignition charge, the siren, the strobe light... The launch sequencer regulates when these devices are turned on and off.
Here's the current protocol for communication with the microcontroller: the tower sends the client a prompt, "LTC>". The client responds with "at", then zero or more spaces, then the request (which happens to always be exactly three characters). Commands are case-insensitive.
Note that if a newline is sent, the microcontroller processes the command correctly but reports an error afterwards. The microcontroller doesn't, of course, know or care whether the client has recieved the prompt before sending a command, and will accept a command any time after being turned on. However, there must be enough delay between any two commands for the first command to have been completely processed before the second one is sent. There's only a one-byte buffer on the serial port in the microcontroller, and that's easily overrun.
Once the microcontroller has processed the command, it sends an appropriate response. The three characters of the request either identify a relay and specify a new state for that relay, or they are "sta", which requests the current status of all the relays.
To set the state of a relay, a '0' or '1' digit followed by a two-character relay ID (see table below) is used. The response indicates in English which relay was set and what its state is.
When the command is "atsta", the response contains "STATUS " followed by several zeros and ones indicating whether each of the following relays is on:
RR | RO | ST | SI | T5 | IG | A1 | A2 | A3 | A4 |
rocket ready | rolleron | strobe | siren | t-5 seconds | ignite | aux 1 | aux 2 | aux 3 | aux 4 |
(It's interesting that the second character of each relay ID is enough to uniquely identify a relay. I don't think Matt did that on purpose, because he didn't take advantage of it in his implementation of the protocol.)
"Rocket Ready" is special in several ways. Its state can't be set, for one: the launch sequencer reads its state to decide whether it's OK to send the "ignite" signal. Also, rocket ready is wired to a relay in the ignition circuit, so the rocket really can't launch unless its flight computer is giving permission for it to do so. (Another element in this circuit is a switch at the tower; so we have a three-component safety system in the launch sequence, two of which are human-controlled.)
Requirements for Launch Sequencing
Needs to communicate via TCP/IP to a remote system. I'd like the hostname and port to be configurable at runtime, ideally through the GUI. A config file would be nice.
Needs to be able to schedule events for particular times in the countdown sequence. I'd like the event list to be read from a file.
The on-screen clock must stay synchronized with the event clock. Also, I want the time to start at a negative value (the exact value should be configurable) and increment past 0 until a stop time is hit. Certain things turned on before launch have to be turned off afterwards.
It would be really helpful if we could get sub-second precision when scheduling events.
Old system involves a relay sending a T-2 seconds signal to the rocket via the umbilical. New system has 802.11b standard wireless ethernet between the rocket and the ground. So we want that signal, and only that signal, sent to a different IP address, by way of a protocol not yet decided.
We need to be able to turn on the VCR during the countdown. Sadly the VCR sits next to the computer running the launch sequencer, not next to the microcontroller with the relays, so a different piece of hardware is needed.
One thing I want is separate applications which can simulate all remote services, for testing the main program.
Notes on the New Sequencer Implementation
As of Monday, August 13th, I have a new sequencer implementation which behaves exactly as I expect it to (which is to say, it doesn't necessarily behave correctly) and which has a superset of the features found in the old sequencer. This implementation is written in Java and tested on JDK 1.3; it requires some classes like java.util.Timer which were not present in JDK 1.1 or earlier. The graphical interface is written with Swing. Sounds are played using the javax.sound.sampled package, which has the twin advantages of being included in JDK 1.3 and of being able to mix sounds so we don't have to be so careful about keeping sounds from overlapping as we did in the old implementation. No packages are required except those included in JDK 1.3, so we should be able to run the countdown from non-Linux machines now if desired.
The object-oriented design is practical and useful, if I do say so myself. :) To implement new types of events, you need only write a class which implements the SchedulableAction interface:
public interface SchedulableAction
{
public void dispatch(String cmd) throws Exception;
}
You then can code the construction of your class directly into the static initializer of the Scheduler class, like so:
...
private static Hashtable types = new Hashtable();
static {
/* built-in event types */
types.put("sound", new SoundAction());
types.put("msg", new MessageAction());
}
...
or, if your class requires more complex initialization or you need a reference to it besides the one in the Scheduler class, you can instantiate it in the main class, LaunchControl, and pass it to the static method Scheduler.addSchedulableAction(String, SchedulableAction)
:
...
TowerAction tower = new TowerAction(
conf.getProperty("towerHost"),
Integer.parseInt(conf.getProperty("towerPort"))
);
...
Scheduler.addSchedulableAction("tower", (SchedulableAction)tower);
...
In both cases, the string identifies the allowed value of the second field of the schedule file (whose filename is given by the "schedule" value in main.conf); the schedule file can contain these elements:
# comments in this style
startTime = <float>
endTime = <float>
<float>: <name>, <command>
For example:
startTime = -15
-15: tower, siren 1
-15: tower, strobe 1
-10: sound, sounds/10.wav
-9: sound, sounds/9.wav
...
-1: sound, sounds/1.wav
-0.2: tower, status
0: tower, launch
10: tower, igniter 0
10: tower, strobe 0
10: tower, siren 0
The "tower" action
Most commands supported by TowerAction have a relay name followed by a '0' or '1'. Currently supported relay names are "strobe", "siren", and "igniter"; new names are added by adding them to the static initializer for the TowerAction class. Upon dispatching a tower command, the two-character relay ID is looked up.
Two special commands are implemented, namely "launch" and "status". "status" updates TowerAction's sense of the current state of all relays at the tower; this is not strictly necessary except when you want to know the state of the rocket ready signal. "launch" checks the last known state of rocket ready, and if the relay was on, it behaves identically to the command "igniter 1".
TowerAction provides a getControls() method which returns a java.awt.Component containing manual controls for the tower relays. When getControls() is called, the new component registers itself as the listener for status messages from the tower. Note that in the current implementation, at most one object may be registered as a TowerListener.
Commands are queued as they're delivered from either the Scheduler thread or the GUI event thread, and the TowerAction.WriterThread is notify()d of the new data. The writer thread coordinates with TowerAction.ReaderThread to wait for acknowledgement of each command before sending another command. (This coordination may still not provide enough delay - this is an area requiring much further testing.) Once a set of commands has been delivered and acknowledged and the queue is again empty, a status request is automatically delivered, which causes the GUI to be updated with the new state of all relays. A deliberate side-effect of the particular implementation of the status requests is that a status request is delivered on start-up.
The "vcr" action (not yet implemented)
It's looking likely that control of the VCR will be by way of a parallel port. Since I'm hoping to keep the sequencer cross-platform, I checked to see whether there's a cross-platform parallel port API for Java, and, in fact, there is. Yay!
Sun's Java Communications API (known as CommAPI) is available at http://java.sun.com/products/javacomm/index.html
Implementations of CommAPI for platforms other than Windows and Solaris are not provided by Sun, but the RXTX project has ports to other Unix platforms at http://www.rxtx.org/
The "rocket" action (not yet implemented)
At one point in the countdown sequence, the launch control computer needs to communicate with the FlightComputerSoftware to give it warning that launch is approaching; we keep referring to this as the "T-5 seconds" signal, but the actual time it occurs is fairly arbitrary and was, in fact, T-2 seconds for the launch of LV1b.
I think that the protocol for delivering this signal should look much like that for the CanMuxer.
Things I do know
- What's a microcontroller anyway?
- A microcontroller is probably defined as a integrated circuit which runs programs. That definition would include any Pentium chip, for example. More common usage is a simple, cheap chip that'll run one program, often stored on EEPROM, and will be embedded in a single-purpose device. ?AndrewGreenberg adds: That's not a bad definition. I usually say something like: A very small - and unfortunately usually slow - microprocessor which has onboard RAM, ROM and a host of peripherals like digital I/O, UARTs, Analog to Digital Converters (ADCs), etc. In otherwords, it's a System On a Chip (SOC) solution meant to be - like Jamey said - embedded in an application.
?JameySharp: But I'm sure we'll be launching something in September, because it's not up to us avionics guys. :)
Justin Myers: "us avionics guys"?
?JameySharp: Yeah, us avionics guys. "Avionics" being the fancy word we use when we don't want to say something boring like "electronics". :)
Justin Myers: oh okay, so basicly you mean pit crew
?JameySharp: Well... I dunno about "pit crew". I mean, the airframe guys build the part that flies... the avionics guys, so far, build the part that says, "hey! I'm flying! wooo... duh, now what?"
-- ?JameySharp - 01 Aug 2001
-- ?JameySharp - last modified 14 Aug 2001
Attachments: