The objective of the project was to execute and film a demonstration of the feasibility of remotely controlling a rover on the surface of a planet, such as Mars. Once the demo could be reliably executed, a cameraman was brought in to record the demo for presentation to JPL executives and other authorities; they then could use it as a proof-of-concept to pursue funding for more realistic planetary roving projects.
The demo scenario consisted of the following steps:
- The rover scans the area around it.
- Mission Control identifies a target rock on the monitors, using the crosshair thumbwheels.
- Using the thumbwheel values, the computer calculates the commands to move the rover to the target.
- The rover propels itself to the designated rock.
- The operator refines the position of the target rock on the monitors, again using the crosshair thumbwheels.
- The rover positions one of its grippers above the rock.
- The operator confirms that the gripper’s position was suitable.
- The rover lowers the gripper, closes on the rock, and lifts a few inches.
- The operator confirms that the rock is in the gripper.
- The rover lifts the rock near to the cameras, and presents it for examination.
- The rover drops the rock and returns the arm to a ready position.
I don’t recall any deadline or time pressure to complete the programming, and I didn’t submit progress reports. Occasionally, someone would come by to see how things were going, but it was all very informal as far as I was concerned. For the two or three months of the project, I worked exclusively in the project area, and never saw my colleagues from the bullpen. I don’t even know if they were aware of what I was working on.
Although the work wasn’t planned in detail or documented in this way, it was done in the following stages.
Stage 1 – Learning the PDP-1
The development of the software was solely my responsibility. No one advised me or gave me detailed requirements. I was told what was generally desired and asked if I could do it. At one point, I had a problem programming the tape drives, which John Strand helped me with. Progress was steady and evidently fast enough for the sponsor.
The first step was to learn how to operate the PDP-1. There were some manuals and the previously-mentioned basket of paper tapes. Many of the tapes were fan-fold, not rolls, and some were rather worn, in danger of tearing at the folds. The paper tape hardware could take an input tape and punch a copy onto a new tape. This primitive backup procedure was occasionally necessary to ensure needed programs were always available.
When the PDP-1 was first powered up each morning, the operator could not assume anything about its state. Its memory was based on magnetic cores, which don’t require power to maintain their bit patterns. However, it was not practical to try to resume work from the point at which the system had been shut down the night before.
The worst-case way to start the PDP-1 was to enter an address (usually starting with all 0’s) into the console ADDRESS switches, and an instruction into the TEST WORD switches, and press the DEPOSIT switch. This caused the instruction to be deposited into the addressed word in memory. The operator would then set the ADDRESS switches to the next address, enter the next instruction, and repeat the process until a short program had been entered. This was quite error-prone and extremely tedious. Once the program was in memory, the operator set the ADDRESS to the first instruction and pressed the START switch, which executed the program starting at that address.
Fortunately, the PDP-1 has a special-purpose mode to load a program from paper tape. Pressing the READ-IN switch activated this mode, in which the computer automatically read a series of lines of punch holes from the paper tape, depositing a program into memory. In some cases, this mode was used to pre-load utility programs, such as FLINT, for use by other programs. Once all required parts of the program were in memory, it could be executed.
One utility allowed the operator to punch a new tape from a range of addresses in memory. Other utilities printed the contents of memory or of a paper tape onto the typewriter, which was fed from a box of fan-fold paper. (I also had to change the typewriter ribbon when its ink dried out.)
After some time learning how to use the PDP-1 and its utilities, I realized that the task of keeping everything on paper tape would prove very inefficient. I adapted the magnetic tape utility into a boot-loader. This would allow me to first load the boot-loader paper tape, which would then allow me to load further programs from magnetic tape. This was an innovation of my own. Though others had certainly had similar ideas before me, no such program came with the PDP-1. Essentially, I created a tiny operating system to manage the programs, and minimize the reliance on slow and fragile paper tapes.
I encountered my first obstacle when I tried to implement this idea. The way magnetic tape works is that a series of “characters” (pieces of words, six bits each in the PDP-1, so three characters per word) are written one after another from a block of sequential memory locations. When the last character of the block is written, a special End-Of-Record (EOR) character is written along with a short blank stretch of tape. When a tape is read, the drive starts reading from the current position of the tape, assembles words from characters and deposits them in sequential memory locations. When the drive reads the EOR character it stops the tape in the blank space. My first approach was to take each of the utility paper tapes, and write them as records to the magnetic tape. However, this required that I keep track of the order of the utilities. To help with this, I created a directory of the records and wrote it to the start of the tape, followed by each record in the order they were identified in the directory. The directory was fixed in size, and large enough to hold plenty of record descriptions. Then when I mounted a tape on the drive in the morning, I could read the directory block and know what was on the rest of the tape.
When I developed a new program, or a revision of an earlier one, I wrote it at the end of the tape, then rewound the tape and wrote the modified directory over the old one. I soon learned that this didn’t work, but I didn’t understand why. Once I had written the new directory, I could no longer read anything else on the tape. John explained to me that once a block was written, in addition to the EOR character and the blank space, the tape drive also wrote another special End-Of-Tape (EOT) character, and then backed up so that it’s read/write head was between the EOR and EOT characters. The drive would never read past the EOT character, because everything on the tape following the EOT would be interpreted as random noise, not as triplets of characters making up words.
Once I understood this, I changed my approach to maintain the directory in memory, until I had all the programs written on tape, and then append the directory record as the last record on the tape. When I mounted a tape, my “operating system” would read records into memory, discarding them until it found the directory record, which it saved in memory, then rewind the tape to be ready to seek specific records for further work.
The PDP-1 had three IBM model 729 tape drives, and usually two were in working order. Joe repaired them more than once during the project. I usually needed only one at a time for my work (except for making backup tapes).
Stage 2 – Sensing Joint Positions
The PDP-1 was designed so that a wide variety of devices could provide input information. For the rover project, each position sensor on the arms and pan-tilt head was represented as a location in memory that could be read by the program. Each word could hold 18 bits of data, but the actual data was quite a bit less. Rotation positions of the joints were encoded as 10 bits (representing 1,024 values) for 360 degrees. (Due to mechanical constraints, most of the joints could not move through a full 360 degrees.)
A block of memory, six words per arm plus two for the pan/tilt head, was designated to hold these input values, which were updated continuously by Joe’s control circuits and could be read at any time by the program.
Stage 3 – Commanding Joint Positions
To command the rover, a number encoded in the same way as the position sensors was written to a specific location in memory. The circuits designed by Joe then caused the motors to drive the joints to the corresponding position. A block of these memory locations was designated for these commands, the same as for reading positions plus two for controlling the speed of the left and right tracks, and could be written at any time by the program.
Stage 4 – Stopping
When we began to integrate the rover with the computer, we soon discovered an unforeseen problem. With the manual control manual, when the rover was turned on it did nothing unless one of the knobs was out of its neutral position. But when the rover’s new control electronics were first powered up, the registers holding the commanded positions all had random bit patterns in them, not matching their actual positions. As a result, all of the rover’s joints, and the drive treads, would start moving at once, and we had no idea where it was trying to go. There was some danger of an arm hitting a camera, or otherwise damaging something. We quickly turned everything off.
Joe had not anticipated this, and was thinking about revising the circuits to automatically zero out the registers when powered on, which would drive the rover to a safe position. However, it occurred to me that the computer could handle this situation, even before the system was calibrated. By simply reading the position sensors and writing those values into the command registers, the electronics would cut off the drive signals to the motors and the rover would be effectively commanded to STOP! This was the first command I implemented, triggered by pressing the ‘S’ key on the typewriter. From then on, it was simply a matter of waiting for the program to be loaded and running before powering up the rover, then pressing the S key. As I recall, Joe was impressed at the utility of having a computer in the system.
Stage 5 – Calibration
The circuits that provided the position of the rover’s joints to the computer needed to be calibrated before they could be used to position the gripper at a precise point and attitude in space. For this purpose, Joe used the manual control panel to drive the rover into the computer room. With convenient access to both the computer console and the rover, it was a straightforward matter to measure (using meter stick, spirit level and protractor) the angles of the joints corresponding to several positions, and to relate them to the position values read by the computer. The encoding turned out to be very linear, and the conversion of a position value to an angle simply required one addition and one multiplication operation; calibration required recording just two numbers for each joint.
The conversion of thumbwheel settings to angles in the video reference frame also had to be calibrated. For this purpose, a paper target was taped to the window and the rover was positioned so that the cameras were horizontal and perpendicular to the target. By measuring the actual coordinates of points on the target and the corresponding thumbwheel settings that placed the crosshairs on those points, it was straightforward to calibrate the conversion of thumbwheel settings to angles in each camera’s own reference frame. The combination of thumbwheels, crosshairs and vidicon cameras was quite linear, so that conversion of thumbwheel settings to angles again required only two arithmetic operations, using just two numbers for each thumbwheel/camera combination.
Stage 6 – Kinematics
Once calibration was complete, it was possible to begin development of code to drive a gripper to a desired position within the rover’s frame of reference. I defined this frame to be centered at the point midway between the shoulders’ centers, with the X-axis pointing forward, the Y-axis to the left, and the Z-axis upward.
There are two ways of looking at the relationship between a rover’s joint angles and the position of its gripper. The first, known as forward position kinematics, uses a given set of joint angles to calculate the position and attitude of the gripper. The second, known as inverse position kinematics, calculates a set of joint angles that will position a gripper at a desired target position and attitude. I had not heard of these phrases when I started the project.
The forward problem is straightforward: Starting from the origin of the frame of reference, working through the chain of joints one at a time, a position for each joint is calculated based on the length of the arm segment and its angle relative to the segment before it. The inverse problem is more complex, because there can be multiple (even an infinite number of) solutions, or sometimes no solution at all. If the target point is beyond the reach of the rover, no combination of joint angles will place the gripper there. If the target is nearby, there can be many combinations of shoulder, elbow and wrist angles that will place the gripper at the target.
To come to a single solution for the inverse problem, certain constraints can be applied. One that I adopted was to have the gripper vertical with its tip down when it was going to pick up something; this conveniently kept the wrist above the ground! For examination of a gripped rock, I chose the opposite convention of pointing the gripper upward; this kept the wrist joints from blocking the view from the rover’s cameras.
The wrist angle convention still left a choice for the elbow. Unlike our arms, the elbow could be either above or below a line from the shoulder to the wrist. I chose a similar convention as for the wrist: When the target was near the ground, the elbow was in the high position, and when the gripper was high, the elbow was low. The first choice avoided the lower arm hitting the edge of the rover’s base; the second kept the elbow away from the cameras.
The angle of the plane of the gripper’s jaws was also arbitrary. I chose this to be perpendicular to the arm’s axis, so that the operator could clearly see that the target rock was within the gripper’s jaws.
A final choice was to select an arm to grip a particular target; for many target positions near the rover’s midline, either gripper could have been used. The selection was made depending on whether the target was to the right or left of the center line; using the arm on the same side as the target kept the elbow higher than the opposite choice, so the arm was less likely to hit the base.
Stage 7 – Sequencing
Once all of the preceding stages had been accomplished, the rest of the programming was straightforward. A set of routines were written to perform the following actions:
- Convert the thumbwheel settings and pan-tilt positions into target coordinates in the rover’s frame of reference.
- Convert a target position on the floor to a set of tread-drive commands to turn the rover to a heading for the target, and move to a position that placed the target near the rover midline and within reach of a gripper.
- Convert a target position to a set of joint angles that would position a selected gripper six inches over the target.
- Issue a sequence of commands to lower the gripper five inches, close the gripper on the target rock, and lift up five inches.
- Raise the gripper to a position near to and in view of both cameras, and rotate the gripper to allow viewing all sides of the rock.
- Move the gripper to a collection box on the rover’s base, and release the rock into the box. (In fact, no box was actually installed on the rover.)
- Move the gripper to a safe position above the platform and not blocking the video cameras.
Because the rover lacked its own visual perception and could not sense the presence of an object in its grasp, this could not be made one long automatic sequence. The operator initiated each step of the scenario. Aside from typing the thumbwheel settings, all commands were invoked with a single key on the typewriter, such as “G” for Go or “P” for Pick.
Certain aspects of the sequence could be safely performed concurrently. For instance, while the rover turned on its tracks and traversed the floor toward the target, the pan-tilt system was commanded to keep the cameras pointed at the target position, simultaneously panning in the opposite direction of the turn and tilting downward as the target was approached. Similarly, the conventions for elbow and wrist joints allowed for a safe trajectory of the gripper so that the shoulder joints, the elbow and the wrist joints could be commanded all at once. This gave the entire motion a fluid character that was almost magical to watch. It was much nicer than the one-joint-at-a-time manual control panel.