PIC32MX: Interfacing with Force Sensors from a Scale
Original Assignment
Do not erase this section!
Your assignment is to use four analog inputs to continuously read four force sensors taken from a bathroom scale, and to display them on a PC screen as bars whose length corresponds to the force at the sensors. You will use Processing for the PC data acquisition and graphics.
Overview
A BME Senior Design project group is developing a device to measure the weight shifting ability of a child with Cerebral Palsy. The end goal is develop an interface that will allow the child to visually see on a screen how they are shifting their weight.
Our portion of the project involves designing the hardware to read the signals from 4 load cells and writing code to read in the load values to a PIC 32 microcontroller which is then sent to a PC via RS232. Additionally we developed an interface for the PC that visually represents the collected data in a useful and intuitive format.
Circuit
Each load sensor acts as a half bridge rectifier. When a potential difference is applied across the bridge, changes in load can be measured by sensing the voltage change at the middle of the bridge. This voltage change will be on the order of a few microvolts for most load cells.
In order to read this very small change in voltage you need to use an [Instrumentation Amplifier]. Instrumentation amplifiers read in two voltages and multiply the difference by a value specified by an external gain resistor.
To complete the second half of the Wheatstone bridge a potentiometer is used. This potentiometer can be tuned to match the voltage produced by the load cell when no weight is applied. Therefore as more weight is applied the voltage out of the amplifier will increase until saturation of the amp is reached. This tunning is very important and can be time consuming because an initial offset of a few millivolts can force the amplifier to saturation.
The signal that leaves the amp is fairly noisy so a low pass filter is used to smooth out the signal that is sent to the ADC.
PIC Code
The purpose of this code is to take the input signals (amplified voltage differences) from the 4 individual force sensors on the scale and output a string of 4 floats separated by spaces ending with a new line. This string will be sent out using RS232 and deciphered by Processing.
ADC: In order to use the Analog-to-Digital converter embedded in PIC, we used Nick’s example, PIC32MX: Analog Input. Copy all the lines in this link except for the infinite while loop. However, you want to have four analog inputs for this project therefore you will need to change the number of analog inputs since this example only uses two analog inputs. Do the following modifications in order to have four analog inputs.
- define PARAM2, you need four samples, so change ADC_SAMPLES_PER_INT_2 --> ADC_SAMPLES_PER_INT_4.
- define PARAM4, you also need to enable AN3 and AN4 as well with AN1 and AN2,
- define PARAM5, you don’t want to skip AN3 and AN4, so remove these two inputs from this parameter.
Interrupt Handler: This function will affect our code only if the PIC receives a data from the processing via RS232 cable. If the interrupt occurs, it will first check whether the receive input interrupt flag was generated or transmit output interrupt flag was generated. And if it was the receive input interrupt, then it will save the value it received to the volatile unsigned char data, which we declared as a global variable. Then, the next line of code is a switch statement. If it reads the character 'p' from volatile unsigned char data, which is sent from Processing when the 'zero out sensors' button is pressed, then it will record the initial values of the four sensors.
The full code can be found here.
"main.c"
Main Function
int main(void) { int pbClk; // Sets the B port to Analog Input AD1PCFG = 0xFFFF; // Configure the proper PB frequency and the number of wait states pbClk = SYSTEMConfigPerformance(SYS_FREQ); // Allow vector interrupts INTEnableSystemMultiVectoredInt(); mInitAllLEDs(); initUART2(pbClk); initADC(); while(1) { // read each sensor, subtract zero state value, top_left= ReadADC10(0)-top_left_initial; top_right= ReadADC10(1)-top_right_initial; bottom_left= ReadADC10(2)-bottom_left_initial; bottom_right= ReadADC10(3)-bottom_right_initial; //Send to PC via RS232 sendDataRS232(); } } //end main
Processing Code
The Processing portion of our lab involves 4 main sections:
1. Colorbars, colorbars();
continuously displaying the force applied onto each force sensor by using 4 bars that will grow or shrink depending on the amplitude of mass (force). The bars will also show the amplitude of the mass by changing colors. When 0 or little force is applied, then corresponding bar is black colored, at the max force, the bar is orchid (pink) colored.
2. XY-Plot, xyplot();
continuously displays the x- and y- position of the center of balance calculated between all 4 sensors with a dot on a xy-coordinate plane. So, if the person shifts his weight to the right side of scale, then the dot will move to the right in the x direction. If the person shifts his weight to the front of the sensor, then the dot will move up in the y direction.
3. X-position vs. Time (not a separate function)
continuously plots a dot for the x-position along a time axis. This plot will be useful to see how much the person shifts his/her weight to the left or right (sagittal plane) over time. Due to the window size and the speed of processing, the points will be plotted over a time period of about 20 seconds.
4. Y-position vs. time (not a separate function)
continuously plots a dot for the y-position along a time axis. This plot will be useful to see how much the person shifts his/her weight forward or backwards (coronal or frontal plane) over time. The code for this section is essentially the same as the x-position but edited to show y-position.
Screenshots: exerting force on the sensors in a circular pattern (left) and exerting force on one sensor at a time (right).
Other Important Functions:
1. Communication between the PC (Processing) and the PIC via RS232, void initSerial();
The purpose of InitSerial(); is to open a serial port on the PC and communicate with the PIC32. The code found here is essentially a modification of the ME333 Lab 4: Motor Control Processing code written by Nick Marchuk.
2. X-position, float xposition();
Calculates the x-position based on the contribution of each force sensor output and returns the resulting float value.
3. Y-position, float yposition();
Calculates the y-position based on the contribution of each force sensor output and returns the resulting float value.
4. Button to zero out force sensors
Adds a button to zero out the force sensors. Noise displaces our dot in the xy-plot from the center when we first turn on our circuit. There is an interrupt function in the main.c file that will do the "zeroing out" and output altered values once this button is pressed. The code for this button was taken from ME333: Motor Control Processing code written by Nick Marchuk.
General Notes:
Our code was written with the assumption that the inputs from the PIC (that initially comes from the 4 force sensors) will come in the form of a 4x1 array. It does not actually arrive in that form from the PIC, it actually arrives as a string of floats separated by spaces ending with a new line. The new line is deleted and the floats are extracted out, normalized between 0-255, and put into the "mass" array. All of the normalization, window dimension parameters, rectangle dimensions, etc. were set up with the 0-255 range and 1000x700 window size in mind. So if the values are not between 0-255 or the window size is altered, almost all of following code will be messed up. The x-position vs. time and y-position vs. time plots are not implemented as independent functions. The code for these plots are found at the very end of colorbars();.
The full Processing code can be found here.
A full zip file containing the PIC code, Processing code, images, screenshots can be found here.
A link to the demonstration video of the force sensing scale can be found [link here].