Chesster Junior Project Report

91.548 Robotics I
David J. Meppelink
April 22, 2003

Table of Contents:

  1. Introduction
  2. Current State
  3. Technical Description
    1. Hardware Overview
    2. Software Overview
    3. GNU Chess, WinBoard, WinBoard Monitor
    4. Servo Slider
    5. Chesster Engine
    6. Arm Position Commands
    7. Arm Driver
  4. The Journey
    1. Developing the WinBoard Monitor
    2. Prototyping the Robotic Arm
    3. Final Integration
    4. Schedule Results
  5. Futher Work

Introduction

Chesster Junior was designed to be a partial implementation of a chess playing robot. It can play chess and move pieces on a physical chess board, but it lacks the ability to see its opponent's physical moves. They must move pieces on the computer screen, much as they would when playing against a computer chess program or via an Internet Chess Server. The system mimics those moves (as well as its own moves) on the physical board.

My goal is to build an active chess board that uses magnetic sensors to "see" moves on the physical board. That additional capability will complete Chesster the chess-playing robot.

I chose this project because it involves many key aspects of robotics: monitoring the physical environment, communicating with a PC, and changing the physical environment. It moves human/computer interaction off the screen and into the physical world. Also, the "chess playing robot" is a classic problem that dates back to the famous "The Turk" chess automaton created in 1769. Finally, my 10-year-old son is interested in chess and robotics and I wanted to engage him in my course work.

Current State

I presented an incomplete version of Chesster Junior at the UML Botfest on March 29. The arm hardware was complete and functional (with a couple of caveats described below):

Much of the software was complete, including the PC to arm communication, but I did not have time to program all of the 128 arm positions (2 positions for each of the 64 board squares) required to play the game. As a result, I demonstrated the arm controller software with two pre-recorded chess moves.

I wrote the arm controller software in Java using AWT. It was plain by modern UI standards, but functional.

Two sliders and buttons along the left side of the window controlled the grip position: either opened or closed. The center area of the window had a slider to control each of the four arm joints and a move button to download to the arm. The right side of the window provided slots for storing arm positions. This allowed the user to store up to 8 different arm positions and recall them quickly.

The macro buttons across the bottom of the window were the most useful during Botfest. I placed three pieces on the board: the white king, both king-side rooks. "Kingside Castle" moved the white king and its king-side rook. "Rook Capture" first discarded the white rook and then advanced the black rook to take its square. People enjoyed the capture because the arm dropped the rook into a the container with enough force that it appeared to them that Chesster was enjoying himself or showing off.

I chose these two moves because each of them demonstrated the ability of the software to recognize complex moves beyond just a simple pick-up/put-down sequence. The user interface simply called a function to record a chess move such as "e1g1" or "h8h1". The function determined that it had to move two pieces, either because it was a castle or because the destination square was occupied. This was a nice separation of functionality, and shows how close Chesster was to doing much more than I was able to demonstration. I did not have the opportunity to explain this nuance during Botfest.

Technical Description

This section describes all of Chesster Junior, both the components that I demonstrated at Botfest and the internal components that were not.

Hardware Overview

Chesster Junior has four major hardware components:

  1. A Windows-based PC runs the chess engine and the monitor program. The PC sends arm position commands to a Handy Cricket via the cricket infrared interface.

  2. A Handy Cricket converts the arm position commands into a series of intermediate servo position values. It sends those values to the servo controller via the cricket bus.

  3. A 8-Servo Controller (described in the project plan) translates the position values into servo control signals.

  4. A Lynx5 Robotic Arm (made by Lynxmotion) uses the servo control signals to drive its 5 degrees of freedom: base, shoulder, elbow, wrist, and grip.

Software Overview

Chesster Junior has these major software components:

  1. GNU Chess is an open source chess engine from GNU.

  2. WinBoard is an open source chess board that interfaces with GNU Chess, other chess engines, internet chess servers, and people (of course).

  3. The WinBoard Monitor interposes itself between WinBoard and GNU Chess so that it can view their communication. It extracts moves in coordinate algebraic notation (such as "e2e4") and passes them to the Chesster Engine.

  4. Servo Slider is a development and demonstration tool that provides a simple GUI for controlling the arm. It uses the Chesster Engine to make chess moves and to send arm position commands.

  5. The Chesster Engine maintains the chess game state and converts moves in coordinate algebraic notation into a series of arm position commands. It sends those commands to the Arm Driver.

  6. The Arm Driver moves the arm in a coordinated fashion. It runs on the Handy Cricket and accepts arm position commands from the Chesster Engine.

GNU Chess, WinBoard, WinBoard Monitor

GNU Chess has a simple console interface. So, typing "d2d4" at the beginning of a match moves the white queen's pawn forward two spaces; GNU Chess responds with "My move is: d7d5". This is just the beginning of a defacto standard Chess Engine Communication Protocol.

WinBoard runs GNU Chess as a separate child process and uses anonymous pipes to communicate with the GNU Chess console. This loose coupling makes it easy to insert the WinBoard Monitor between them.

The WinBoard Monitor is actually two Java programs:

  1. Monitor.java is interposed between WinBoard and GNU Chess. It sends chess moves to a network socket.

  2. Server.java reads chess moves from a network socket and passes them to the Chesster Engine.

This arrangement is necessary because WinBoard starts its child processes in a way that prevents them from using the serial port directly.

Servo Slider

The Servo Slider user interface is described in a previous section.

Slider.java uses the AWT package to build its user interface window and calls the Chesster Engine to interact with the robotic arm.

Chesster Engine

The Chesster Engine performs three functions: (1) it maintains the chess game state, (2) it converts moves in coordinate algebraic notation into a series of arm position commands and (3) it sends arm position commands to a Handy Cricket running the Arm Driver program.

The engine is written in Java:

  1. Move.java represents a single chess move. The program creates an instance each time it moves a chess piece. The instance uses Game, RobotArm and Square instances to perform the move. It is also responsible for the capture and castling sequences.

  2. Game.java contains all positions of the chess board: a1 through h8, plus the rest position, where to drop captured pieces and a place to temporarily set pieces aside.

  3. Square.java represents one square of the chess board. It stores (1) the coordinate position (range from "a1" to "h8"), (2) the arm positions for directly above and at the square on the board and (3) if the square is occupied. It also provides methods to pick up and put down a chess piece at that square.

  4. Position.java is a container for robotic arm position values. It stores the base, shoulder, elbow and wrist positions as a single data object.

  5. RobotArm.java is an object that represents the robotic arm. It provides simple methods for manipulating the arm: (1) move the arm to a given Position, (2) set the grip to a given value, (3) turn off the arm servos. It is also responsible for producing arm position commands.

  6. CricketComm.java wraps the Java Communications API to communicate with the Cricket. It provides low-level methods: (1) send to the cricket, (2) receive from the cricket, (3) close the serial port. It manages the serial port objects, maps IOExceptions to Problems, and handles the built-in character echo from the Cricket's Serial-to-IR interface.

  7. Problem.java is an exception that is thrown to indicate a fatal problem.

Arm Position Commands

The Chesster Engine sends these arm position commands to the Arm Driver:

  1. CMD_OFF turns off all of the servos. (command value $20)

  2. CMD_MOVE base_value shoulder_value elbow_value wrist_value moves the four servos to the specified positions. (command value $40)

  3. CMD_GRIP grip_value moves the grip servo to the specified position. (command value $60)

The command value and arguments are each one byte. However, the 8-servo controller has a range of 0 to 318. (Each servo has a "neutral" value between 0 and 63 and a "data" value between 0 and 255, for a total range of 0 to 318.) Since 318 can be represented in 9 bits, the protocol stores the extra bit for each of each arguments in the command byte, like this:

7 6 5 4 3 2 1 0
command value arg 5 bit arg 4 bit arg 3 bit arg 2 bit arg 1 bit

For example, the byte stream for the command "CMD_MOVE $123 $45 $167 $89" is "$45 $23 $45 $67 $89". Note the first and third arguments add 1 and 4 to the command byte.

Arm Driver

The arm driver program arm.logo is written in Cricket Logo with M4 macros. (arm.lgo is the same program with the macros expanded to yield plain Cricket Logo.) For each arm position command it receives over the infrared port, it coordinates the movement of each servo so that the robotic arm moves along a fairly linear path. It performs linear interpolation as follows:

  1. Let the number of steps be equal to the largest servo position change divided by 2.

  2. For each servo, its step size is its total position change divided by the number of steps.

  3. Repeat "steps" times: For each servo, increment its position by the its step size.

  4. For each servo, move it to the requested position. (This takes care of any rounding errors.)

To ameliorate integer truncation, the code scales the values by a factor of 100 during calculations. It sends the resulting position value divided by 100 to the servo controller. The scaling factor of 100 is nearly maximal since the maximum for Cricket Logo integers is 32767 and the maximum for servo positions is 318.

Note that the code uses the M4 macro processor. This allowed me to use symbolic constants and to create foreach loops over the servo-specific state variables. For example, this M4 code fragment:

; Update STEP to contain the step size, rather than total offset.
FOREACH_ARM(`
  SET(STEP) STEP / count
')
expands to:
; Update STEP to contain the step size, rather than total offset.
setstepbase stepbase / count
setstepshoulder stepshoulder / count
setstepelbow stepelbow / count
setstepwrist stepwrist / count
This seemed useful during development because it eliminated repetitive coding. But the M4 syntax is so arcane, I would think hard before using this extensively in future projects.

The Journey

This section is a brief overview of the process I went through to build Chesster Junior. It all started when Fred Martin gave the ok for the project on March 7, just 3 weeks before Botfest...

After a class presentation about robotic arm path planning, I was concerned by the complexity of the problem: coordinate system translations, matrix operations, trajectory functions, etc. I suspected it could not be done in the short time I had; Fred assured me the problem was tractable. But I took a simple approach using basic trigonometry. It quickly became apparent that my problem was considerably less complex than the general case presented in class. I could calculate the four angles (base rotation, shoulder, elbow and wrist) for any square on the chess board using a small set of equations. It may be possible to map those angles to servo position values, but I did not pursue that idea because I was not sure it would yield useful results before the deadline.

One of the challenges of this project was to do as much development as possible without the Lynx5 robotic arm, since I received it one week before Botfest. I also wanted to avoid the trap of "finishing the software" before I had the hardware -- I knew the interactions between hardware and software would require an iterative approach. So, I divided preliminary development into two paths: (1) build my software starting from the WinBoard and working toward the arm and (2) prototype a 2-DOF arm using servos and paint sticks. Each path presented unexpected challenges, described in the next two sections. Once I received the arm, I planned to build the low-level arm driver software based on what I learned from the prototype and integrate it into the WinBoard interface software.

Developing the WinBoard Monitor

This was probably the easiest part of the project. The interface between WinBoard and GNU Chess was well documented and I have extensive experience with multithreaded streams software in Java. Before the arm arrived, the monitor program could extract moves entering and leaving GNU Chess and had an overall structure for translating chess moves into arm movements.

I wanted to be able to observe the communication between WinBoard and GNU Chess, but since my monitor program's console was connected to WinBoard, I could not simply print to the console. I decided to implement the monitor as a Java AWT application and print messages to a text area. Although that approach worked, it was time consuming. It would have been easier to write to a text file, especially given the conflict I encountered during the integration (more on that below).

Prototyping the Robotic Arm

Although I scrapped the prototype arm rather quickly, the time I spent on it was a tremendous help in learning about servos, the 8-servo controller and arm mechanics.

I spent some time reverse engineering the 8-servo controller from its source code. It was able to drive the Futaba servos I was using through 150 degrees of rotation, which was sufficient for my needs. And since it had a Cricket Bus interface (unlike other third-party servo controllers), I did not spend much time on circuitry for Chesster Junior.

I built the prototype arm using a 2x4 block, metal angle bracket and paint stirring stick (1/8 thick by 1 inch wide). I mounted the angle bracket to the 2x4 to form a base and taped a servo to the bracket. Then I attached one end of a 5-inch length of paint stick to that servo horn and taped the second servo to the other end. A second 3-inch stick attached to the second servo horn completed the arm. (Sorry, no pictures.)

The first thing I learned is that a servo is not strong enough to lift the weight of a second servo at the end of a 5-inch lever. I solved that by reducing the first arm segment to 2 inches.

Secondly, I learned servos rotate to their assigned position fairly quickly and at a constant rotational speed. So, the Cricket would have to direct the servos to intermediate positions to get coordinated movement. I experimented with interpolating through the intermediate positions and found that small steps caused the servos to stutter more than large steps. But if the step size became too large, the movement became uncoordinated. Since the prototype arm was mechanically sloppy, I did not pursue the issue at that point.

Final Integration

Assembling the arm was quick and easy. It was interesting to see that its designers overcame the weight problem I encountered with my 2-DOF prototype by using two servos for the shoulder joint.

The grip assembly posed the biggest mechanical challenge. To improve reliability, I attached the ring terminals to the sheath using epoxy rather than crimping them as the directions suggested. The grip was driven by servo connected to the grip by a sheathed cable. With the small diameter of the servo horn, the cable had a maximum travel of 1/2 inch. And the amount of travel varied with the overall position of the arm.

The grip had a complicated parallel beam linkage with very loose tolerances. As a result, the grip could not be used open-loop; servo positions could not be mapped to predictable finger positions. In addition, the round fingers could not grip the chess pieces.

To make the grip usable, I discarded the grip fingers and kept the servo, cable and geared beams. I also added 1-1/4 inch extensions with foam grips. The grip still suffered from unreliable positioning, but I found that toggling between two fixed positions was fairly reliable, at least for most of Botfest. Near the end of the two hours, the grip was unable to spread far enough to pick up the pieces. Mechanical wear was already taking its toll.

My second problem with the arm was that the reach of the arm was shorter than I expected. The documentation correctly said the arm had an 11-inch reach. I interpreted that to mean that I would be able to use a chess board with 1-inch squares because the distance from its edge to the furthest corner is 9 inches. Once I assembled the arm, I realized my mistake: I had not taken into account the length of the grip assembly. The arm had to be able to reach each square on the board with its grip pointed straight down so that it would not interfere with adjoining squares. Since the distance from the wrist joint to the shoulder joint was only 7.5 inches, I had to use a chess board with 3/4 inch squares. That made the board look small (a bit disappointing for demonstration appearances) and also limited the size of the chess pieces I could use. Even with the small 6-inch board, the arm just barely reaches the furthest corner:

There was a secondary effect from having to use the smaller board. I purchased a magnetic chess set in anticipation of building the chess board with magnetic sensors under each square. However, the magnets in the pieces interfered with other. When the arm attempted to place a piece, the ajoining piece would either jump up and stick to it or would be repelled away from it. I exchanged those chess pieces for non-magnetic ones and will revisit this issue later.

With the basic mechanical issues resolved, I built a prototyping environment. I used Java AWT to build a simple GUI that allowed me to position the arm servos and used my serial communication code from lab assignment 2 to communicate with the Cricket. The Cricket simply forwarded data it received from IR to the 8-servo controller bus device. These tools proved to be valuable because they allowed me to quickly experiment with position values.

Once I had determined a couple of waypoints, I attempted to have the arm move between them. The first move, from enclosing a chess piece to being directly above it, was successful. But my second move, from one side of the board to the other side, was a disaster. The constant speed of the servos combined with disproportionate position changes caused the arm to drag its grip across the board. If it had done that during a match, Chesster would have looked like a child scattering the pieces in frustration!

I certainly had to implement interpolation, but I wanted to finish the integration with the WinBoard Monitor first. That was when I hit my first major problem with the monitor program. Apparently, something about how WinBoard launched the Monitor caused the JavaComm package to fail initialization. (Remember that the Monitor interposes itself between WinBoard and GNU Chess so that it can view their communication.) My solution was to split the monitor into two programs: the Monitor to extract moves from the WinBoard/GNU Chess communication and a server to receive the moves from a socket. In the end, this was an improvement because it eliminated the AWT portion of the monitor program and simplified the programs' structure. (At the time, I considered it more of an obstacle because it happened only 3 days before Botfest.)

I implemented interpolation in Java the first time, but the communication overhead of transmitting each incremental move to the Cricket made the arm move too slowly. I reverted back to having the PC transmit only the final arm position and implemented linear interpolation in Cricket Logo.

I ran into two problems with Logo during that implementation. First, I learned that there was a limit to amount of code that could be placed in the code block of an "if" statement. Unfortunately, the compiler did not report this problem. The Cricket reported it at runtime by beeping once and stopping execution. At first, I did not realize what was happening because I was using "beep" statements to debug my own code. I finally narrowed the problem down and moved the code into its own subroutine to fix the problem. Second, when I declared 16 globals, the compiler reported "Too many globals! Only 16 are allowed." I eliminated one global variable (for a total of 15 to solve this. (I am not sure which is a Cricket Logo bug: disallowing the 16th global or the message that claims 16 are allowed.)

Schedule Results

The schedule I proposed in the project plan helped me focus on the task at hand rather than getting distracted by superfluous tasks or overwhelmed by the overall project. Here is how I did against that plan:

Task Description Plan Actual
Prototype a Java process interposed between WinBoard and GNU Chess. --- 3/12
Order the Lynx5 (Fred). --- 3/14
Install development software on a laptop that I can bring to the UML Botfest. 3/17 3/17
Breadboard the 8-Servo Controller. 3/17 3/17
Interface the 8-Servo Controller to the PC through a Handy Cricket. 3/17 3/17
Build a prototype 2-DOF arm using Futaba servos and
experiment with sending commands from the PC.
3/20 3/20
Purchase chess board. 3/20 3/19
Pickup Lynx5 from UML (assuming it arrives on time). 3/21 3/22
Build the Lynx5. 3/22 3/23
Mount Lynx5, chess board, servo controller and Cricket
on plywood base.
3/23 3/26
Experiment with Lynx5 position commands to get familiar with its capabilities.
The greatest risk is that this is the first chance I will have to see if the arm is
physically capable.
3/24 3/28
Implement arm paths in Java. 3/27 3/28
Test and debug. 3/28 3/28

I stayed on plan until I started working with the Lynx5. I put off mounting the arm until I was ready to start moving chess pieces and it became evident that I needed to fix the location of the board relative to the arm. The largest slip involved arm path planning that I have already described.

Futher Work

From the beginning, I intended Chesster Junior to be just the first part of Chesster the chess-playing robot. However, I was not able to complete everything I had planned for Junior. So, my goal for the rest of the semester is to finish Chesster Junior and then complete Chesster.

To finish Chesster Junior, I need to:

  1. Improve the reliability of the Lynxmotion robotic arm. Over the course of the two hours at Botfest, the arm became increasingly unreliable. I plan to:

    1. Provide a consistent power source (with sufficient voltage and current) for the servos. (I used the four AA batteries of the cricket to drive the servos during Botfest.)

    2. Investigate if mechanical wear is playing a factor in the degraded performance. (Although I changed the batteries frequently during Botfest, the arm still degraded overall.)

    3. Replace the current gripper (which uses a servo and a cable sleeve) with something more reliable.

  2. Finish recording the waypoints for all board positions. I simply ran out of time to do this before Botfest. I currently have waypoints for 5 squares. I need to find them for the remaining 59 squares.

  3. Debug the rest of the Winboard-to-arm code path.

To complete Chesster, I need to add support for an "active chess board":

  1. Get some magnetic sensors and experiment with them.

  2. Design and build a LogoChip circuit to read an 8-by-8 matrix of sensors. Make it a Cricket Bus device: cricket requests state, LogoChip responds with 64 bits (each representing an occupied or unoccupied square).

  3. Build the chess board with 64 embedded sensors.

  4. Extend the current HandyCricket code to support the active chess board device. The PC will interact with the HandyCricket to both move the arm and to read the board. This will require more design since the current interpolation code uses all 15 of the cricket's global variables.