The Forceplate Team
Figure 1. Forceplate Team

The Olin Forceplate project was started by Zachary Borden, Mark Cavolowsky, and Jonathan Tse under the sponsorship of Professors Yevgenia Zastavker and Gill Pratt.

The content from this page was adapted from here. I prepared most of it, save the mechanical engineering and software portions, which were prepared by Mark and Zac, respectively.

What is a force plate?

Our Forceplate
Figure 2. Bare Forceplate

A force plate is an instrument for measuring force. Typically they are used in biophysics and athletics applications to study the forces involved in human or animal locomotion.

Usually this is done by observing the ground reaction forces (GRFs) at the center of pressure (CoP). The most simplistic force plates are essentially bathroom scales, and only calculate the normal component of the GRF at the geometric center of the plate. Somewhat more advanced forceplates can calculate the normal component of the GRF at the CoP.

Center of Pressure

The CoP arises from the idea that if you place a mass on a surface, the point at which the net force from the interaction between the mass and the surface is the CoP. This net force is essentially the GRF.

The most advanced force plates can calculate all three components (not just the normal) of the GRF at the CoP, as well as a number of torques about either the CoP or the geometric center of the plate.

How do they work?

Force plates use load cells to read forces. Load cells use what are called strain gauges, which essentially are variable resistors that change their resistance relative to their strain (basically how much they stretch). By measuring the resistance, and calibrating each load cell so that the resistance is meaningful in proportion to force, you can use linear algebra and some knowledge of statics to figure out what the torques, CoP, and GRF are.

So why did you do this anyway?

The Forceplate Team
Figure 3. Forceplate Team

Our force plate was created to address a need of Olin College. During a first semester freshman mechanics class we (Zachary Borden, Mark Cavolowsky, and Jonathan Tse) saw that the current method of measuring force, a bathroom spring scale, was woefully inadequate for a lab assignment on the GRFs generated by a human jumping.

Essentially the issue was that the bathroom scale not only didn’t have the force range required (jumping multiplies the GRF generated by just your mass by a factor of about 10), but that the bathroom scale’s needle was impossible to read during a jump with a timescale on the order of a second.

When approached about this problem, Professor Yevgeniya Zastavker suggested that a team of undergraduate students could construct a force plate for about $5000. With that in mind, and the support of Professor Zastavker and Professor Gill Pratt, we designed and built a force plate for approximately $2300 in the second semester of freshmen year.

During our sophomore year, we further refined and improved the force plate. Although there was no intent to write a technical paper, there is work currently progressing on an educational paper detailing our experiences during the project.

Why is your force plate so special?

The base design of our force plate is an exciting departure from the ordinary. Typically, force plates are constructed with load cells, all with their axes vertical, supporting a plate. This standard design is adequate for applications where you need the center of pressure and the normal force, but is a poor choice for applications with shear forces.

In such applications, shear forces will apply off-axis loads on the load cells. Off-axis loads can result in bad data from the load cells, which are usually designed only to read forces along their axes. Off-axis loads can also result in damage to load cells.

To solve this problem, Professor Gill Pratt suggested we investigate building a force plate based on a Stewart platform design. Stewart platforms have 6 support struts between the ground or some other immobile object, and a top plate or platform.

Instead of terminating in six different points, the support struts terminate on the ground and plate in sets of two, resulting in three termination points on both the ground and the top plate.

Stewart Platforms

A typical application for Stewart platforms involves replacing the support members with linear actuators. Since the force plate has six degrees of freedom, this is an ideal solution for positioning objects in a wide range of applications, from the microscopic for biology, to the macroscopic for amusement park rides.

Our design replaces the support members with six load cells, allowing us to gather data in six degrees of freedom. It also has the added benefit of keeping all of the loads axial along the load cells. While we do sacrifice some stiffness in the system because the support members/load cells are not completely vertical, the effects are essentially negligible.

Mechanical Design

CAD Model
Figure 4. CAD Model

The force plate is based off of the standard Stewart Platform hexapod design, with the six legs attached, in pairs, to three points on each plate. This provides a perfectly constrained system, fixing plates in relation to each other in all three translational axes and all three rotational axes. With the load cells mounted in the center of each of the legs, we are able to read the forces and the torques in all directions through axial loads on the load cells.

Each of the plates is actually a series of plates attached together to provide additional stiffness. If the top and bottom plates were deforming as load is applied to the force plate, energy would be absorbed into deforming the force plate rather than the load cells. Since the load cell readings are directly based on the deformation of the load cell frame, this will lead to inaccuracies in our force readings.

We were especially worried about top and bottom plates bending from outward forces applied to the brackets. To help remedy this, we added a reinforcing plate and brackets in between the plates to rigidly fix the two plated together. That way when a large, outward force is applied to the brackets, it would try to bend the top/bottom plate, but the reinforcing plate would be placed in tension. Aluminum is much stronger in tension than in bending, so this would lead to a much stiffer system.

Our original design had a ball and socket joint attaching each of the legs to mounting brackets mounted in a triangle on each plate. These joints allowed the legs of the force plate to align themselves at the appropriate angle. Since the ball and socket joints had the ability to rotate in all three axes, the angle of the legs would be able to change as the plate deformed.

This ensured that the loads would all be along the axis of the load cells, thus eliminating off-axis noise, but it also allowed the angle of the forces to change to change, potentially invalidating our model. Although we felt that the effects of either of these factors would be minimal at best, we decided that minimizing the off-axis loading of the load cells was more important, and that sold us on this design.

Ball and Socket Design
Figure 5. Ball and Socket Design

Unfortunately, the socket joints that we bought had a lot of "slop" in them. This could cause the readings on the force plate to be inaccurate, so we had to redesign the force plate to incorporate a "slopless" mounting system. Professor Gill Pratt suggested that we look into flexure joints to adjust the angle rather than ball and socket joints. Flexure joints rely on the natural flexibility in the metal to adjust the angles of each of the legs.

However, flexture joints are not nearly as flexible as the ball and socket joints, only being able to move a couple of degrees (without excessive forces being applied, which would cause off-axis loading problems on the load cells).

That means that we needed to create a mounting block with the holes for the flexure joints aligned perfectly with the load cells. Because of the complex angles involved, this block would have to be made with the 4th axis on a CNC mill.

Designing the flexure joints was a tricky matter. They needed to be flexible enough to reduce the off-axis loading to insignificant levels, yet still strong enough not to break as a person jumped on the force plate.

To actually design the flexure joints properly, we used CosmosWorks (a FEM software package) to model the physical response to differing loads. Using this data, we settled on a design that was above the endurance limit of our material as well as flexible enough and strong enough for our needs.

However, in addition to complications with the analysis, we had trouble machining the titanium stock for the flexture joints. Titanium is a very difficult metal to machine due to its hardness. By the time the steel stock arrived on campus, the end-of-semester crunch had rolled around and we were unable to machine the flexture joints.

Note Why did we choose titanium? Well, say the following out loud: "Titanium Flexture Joints." Cool, huh? We thought so too.

Unfortunately, in the long run, we did not finish building the flexure joints as the project fell by the wayside in the latter half of our undergraduate careers. However, Mark, our mechanical engineering lead, had this to say:

Although it has been a while, I’m also not quite sure that the flexure joints would have been a complete improvement to the system. The main reason why we were looking into the flexure joints was to eliminate the sloppiness introduced by the ball joints, but I fear that the flexure joints may have removed the slop at the cost of off-axis loading on the load cells. This could alter the results of the force readings in unpredictable ways.
— Mark Cavolowsky

A collection of our Solidworks CAD drawings is available here.

Electrical and Software Design

Original (Spring 2005) Circuit

Amplifier Circuitry
Figure 6. Amplifier Circuitry

The original circuit (Spring 2005) was no more complicated than an AD624 instrumentation amplifier in line with each load cell. The resulting amplified signal was fed through a 9-conductor serial cable to a breakout box, and finally to a PCMCIA data acquisition card which fed data to a laptop computer for manipulation in MATLAB.

For ease of prototyping and time constraints, the Spring 2005 circuitry was implemented on a pair of solderless breadboards. Since solderless breadboards are designed for easy insertion and removal of components, impacts to the projects boxes containing the breadboards could cause components to come loose.

Additionally, the the 50-pin data acquisition card connection was attached using 30 AWG wire, and we had to solder 22 AWG solid core wire to the end of it in order for it to actually stay in the breadboard. Unsurprisingly, we kept losing connection between the 50-pin data acquisition card connector and the breadboard.

Unfortunately, the PCMCIA data acquisition card we were using was woefully inadequate for its intended purpose. Due to age and repeated use, the data output from the data acquisition card has become very noisy and unreliable.

Updated (Fall 2005) Circuit

PCB for Amplifiers
Figure 7. Amplifier PCB

Because of the problems with the data acquisition card and the breadboards, it was decided that we should move to a PIC microcontroller as a ADC, and a PCB to replace the breadboards.

Because the PIC runs on a 0-5V range, and the output of the AD624s (as configured) ranged from -7.2V to 7.2V, we needed to recenter the output of the AD624s around 2.5V with a maximum of 5V and a minimum of 0V. We were able to accomplish this using a resistor tree, as suggested by Professor Gill Pratt.

By connecting a 20k resistor to 5V, a 65k to GND, a 28.8k to the signal from the AD624s and tying the other ends of the resistors to the input pin on the PIC, we were able to recenter the output signal around 2.5V. These resistor values were chosen very carefully to have an apparent resistance of 10k between the signal and the input to the PIC.

This 10k resistance was used with a 0.022uF capacitor in a RC filter circuit to attenuate signals with a greater than 1kHz frequency, as to filter out any EMI or RFI from outside sources.


The firmware for the forceplate is very simple. Essentially all it does is enumerate the PIC as a USB device, and sets up the PIC to do analog to digital conversion for all six load cells. As part of the USB interface, the firmware has several vendor specific requests which do nothing more than request the 10-bit value for each load cell, which correspond to each load cell’s voltage.

The PIC we used is a PIC18F2455. Credit for the original USB code goes to Professor Brad Minch of BMinch fame on Microchip’s forums.

Assembly Main Loop Code

This code goes through the setup of the PIC and runs the program’s main loop. Essentially the main loop calls ADC subroutines and checks to see if there are any waiting vendor requests from the USB host, which is in this case, a computer.

        banksel         COUNTER
        for COUNTER, 0x01, 0x1E         ; do nothing for a little while
        next COUNTER

        ; We need to set up PORTA and PORTB
        ; to have analog inputs for the loadcells.
        ; In order to do that, we'll need to turn
        ; on AN0, AN1, AN2, AN3, AN4, and AN8
        ; We set the corresponding bits of TRISA
        ; and TRISB high to indicate that they are inputs
        ; and we use ADCON1 to specify which of the
        ; analog inputs are active.
        ; We have also right-justified the A/D output
        ; for easy parsing in the host-side c code
        clrf    PORTA, ACCESS
        clrf    PORTB, ACCESS
        clrf    TRISA, ACCESS
        clrf    TRISB, ACCESS
        clrf    ADCON0, ACCESS
        clrf    ADCON1, ACCESS
        clrf    ADCON2, ACCESS

        movlw   0x2F
        movwf   TRISA, ACCESS           ; Make RA0, RA1, RA1, RA2, RA3, and RA5
                                        ; inputs
        movlw   0x04
        movwf   TRISB, ACCESS           ; Make RB1, RB2, and RB3 inputs
        movlw   0x01
        movwf   ADCON0, ACCESS          ; select AN0, enable A/D module
        movlw   0x0A                    ; AN0 to AN8
        movwf   ADCON1, ACCESS          ; Turn on 8 A/D inputs.
                                        ; bits 0-3 are 0110
        movlw   0xAE
        movwf   ADCON2, ACCESS          ; configure A/D module result to right
                                        ; justified, acquisition time to 32 us,
                                        ; and clock period to 2.67 us

        call            InitUSB         ; initialize the USB registers and
                                        ; serial interface engine
                call    ServiceUSB      ; service USB requests...
                banksel USB_USWSTAT
        until USB_USWSTAT, ==, CONFIG_STATE     ; ...until the host configures
                                                ; the peripheral

        ; Fix Fencepost by grabbing all the values before we start looping
        call    GetLC1Value
        call    GetLC2Value
        call    GetLC3Value
        call    GetLC4Value
        call    GetLC5Value
        call    GetLC6Value

                call    GetLC1Value
                call    GetLC2Value
                call    GetLC3Value
                call    GetLC4Value
                call    GetLC5Value
                call    GetLC6Value
                call    ServiceUSB

ADC Subroutine Detail

This is one of six ADC subroutines. It starts the ADC conversion on a particular pin, and waits until a status flag changes to stop. Once the flag changes, it moves the ADC result into the appropiate buffer.

; Run the A/D on AN0 and store the result in LC_1
        banksel LC_1
        movlw   0x03
        movwf   ADCON0, ACCESS                  ; Select AN0 and set the
                                                ; GO_DONE bit
                                                ; to start the A/D Conversion
        untilclr ADCON0, GO_DONE, ACCESS        ; Wait till A/D Conversion done
        movf    ADRESH, W, ACCESS               ; Move the 8 most
                                                ; significant bits into
        movwf   LC_1, BANKED                    ; LC_1's most significant 8 bits
        movf    ADRESL, W, ACCESS               ; Move the 8 least significant
                                                ; bits into
        movwf   LC_1+1, BANKED                  ; LC_1's least significant bits

Vendor Request Detail

This is one of six vendor requests. This particular one is a detail of the vendor request for the first load cell. Basically it sets up the buffer for USB transfers, loads the pointer to the actual load cell data into the buffer, and sends the data.

; Vendor Requests Subroutine
        movf            USB_buffer_data+bRequest, W, BANKED
                ; Vendor Request to get the current value for LC_1
                case GET_LC_1
                        banksel BD0IAH
                        movf    BD0IAH, W, BANKED       ; put EP0 IN buffer
                                                        ; pointer...
                        movwf   FSR0H, ACCESS
                        movf    BD0IAL, W, BANKED
                        movwf   FSR0L, ACCESS           ; ...into FSR0
                        banksel LC_1
                        movf    LC_1, W, BANKED         ; put POT_VALUE...
                        movwf   POSTINC0
                        movf    LC_1+1, W, BANKED
                        movwf   POSTINC0
                        banksel BD0IBC
                        movlw   0x02
                        movwf   BD0IBC, BANKED          ; set byte count to 2
                        movlw   0xC8
                        movwf   BD0IST, BANKED          ; send packet as DATA1,
                                                        ; set UOWN bit
                ;; Note: Vendor Requests for other Load Cells
                ;; follow and are semantically the same


The point of having software on the computer for this project is to do all of the complicated (for a PIC anyway) linear algebra manipulations on a platform that actually has a FPU, and of course the whole GUI thing.

Original (Spring 2005) Software

The original software was written using MATLAB. It served its purpose admirably, the problem was with the data acquisition card, so we had to scrap it and move to another solution.

Updated (Fall 2005) Software

Software Interface
Figure 8. Screenshot

Since one of the major goals of the semester was to port the force plate over to USB, a different platform for the host code had to be found. The most logical choice was Python due to its large number of freely available modules and its ease of use in designing and implementing GUIs.

The first hurdle to the software development was the desire to implement real time data collection. This problem offers two main challenges. First, it is very difficult to calculate the exact time that a computer calculation will take since it is dependent on what else the computer is doing at the time.

If this problem could not be solved, we would still be able to collect data in real time, but we would not be able to match each data point with the time that it occurred. Fortunately, Python offers a solution to this problem. Python contains a module called time which, when called, returns the time at which the function call was issued. This enabled us to implement real time data collection.

The second challenge offered by real time data acquisition is the problem of frame rate. Most plotting packages offered by Python have relatively low refresh rates, on the order of 10 FPS. This is not nearly high enough to produce the desired resolution in our data. We went through three different plotting utilities before we found one that was able to more reasonably meet our resolution requirements by offering 18 FPS resolution.

After some optimization of the GUI code by reducing the amount of data that needed to be refreshed each cycle, the resolution was again increased to 24 FPS. If plotting in real time is not necessary, it can be turned off and frame rates of around 40 FPS can be reached.