SparkFun Forums 

Where electronics enthusiasts find answers.

Have questions about a SparkFun product or board? This is the place to be.
User avatar
By unexpectedly
I'm setting out on my most ambitious project yet. Version 2.0, an epic improvement of my TPS test bench. A TPS is a throttle position sensor. I have them made for me and I sell them. Only I'm ADD and OCD so I want them perfect. Since the main impetus for setting out on this is SparkFun's fault, I thought I'd write about it in this forum. My most recent completed project's write up is here. Or with more verbose explanation here.
What you don't see are two Adafruit shields: 1) 1.8" TFT+Joystick that I consider mandatory for anything and 2) their proto shield, which is among the best for features.

What started the madness was SparkFun's Thermal Printer. And then came the stepper motor Easy Driver and their awesome dual voltage power supply, both of which are represented above. The stepper motor is a NEMA15 or something I bought from somewhere... probably Adafruit or Poulo.

I got the stepper motor working with some other people's code, but it kinda annoyed me having to handle each wire's HI LO and I wasn't able to easily repeat my successes with various motor driver boards. I see the SF easy driver and read everything I can about it and YESH, I'm gonna get it.

The build:
This is the proto shield with the SF easy driver mounted to it. This shield has +5V and GND kinda everywhere and I like how it has the proto holes tied together under the SF Easy Driver (that you can't see). I used simple headers to attach the Easy Driver to the proto shield. In from the right are the +12 yellow, +5V red, and GND from the power supply. +12 only goes to the Easy Driver's motor input. The +5 and GND go to the main rails of the Proto board. Normally, +5 is distributed from the Arduino as normal, but you can almost see how I cut the trace at the bottom of the picture. Out the left is +5/GND from the main rail to feed the Seeduino Mega running all this mess. I'm using a Mega because my code to test the TPSs pushed the limits of the uno's RAM, and Seeduino's Mega is super tiny, so I like it.
The two connectors on the right are for the thermal printer. Top one is a 3 pin I robbed from a sensor shield and the white power connector I somehow had in my parts. Yellow and Green wires match the printer's RX TX wires. White connector fits the thermal printer's 2 pin power plug perfectly.

On the top is the 4 pin connector I robbed from a sensor shield for the motor (attached to the SF Easy Driver board) and on the bottom, two more 3 pin connectors from poor cannibalized sensor shield to connect to the two kinds of TPSs I need, reading in on Analog pins 1 and 2. A3 is the joystick for the TFT, fed through the stacking header pins (these properly routed connections are in brown on the Fritzing diagram above).

Put together:
I cut the pins on the TFT shield for it's ICSP and soldered in wires to go to the header I soldered onto pins 50-53 on the Mega (they moved `em from where they were on the UNO, hence the wires). That's the CD Audio cable running to the Mega with the Red-Black-Black-White wires in it. Running the TFT via hardware ICSP is much much faster than just declaring all the pins and using software to run the display. And you can see the two printer connectors right there. To the right are the raw pins to the stepper. I wanted to make sure they worked in that order before committing to the connector housing. White piece of paper is insulation between the left two pins that wanted to touch.

OK, I did a Hello World in this stack and the TFT works. I ran an AccelStepper test from here and it worked. My current hangup is trying to implement the ENABLE line on the SF Easy Driver so the stepper isn't running current ALL the time. It gets stupid hot pretty quickly. It might like to have 5V instead of 12... hmmmmm :P

I haven't done anything about the printer yet, but once I can make the stepper sleep, I'll do a hello world there next. My plan is to plot out the graph of each TPS's response curve and then print that out to include with each TPS we sell. So next steps are to port over my TPS testing code from legacy and then figure out how to PLOT my graph into a bitmap so I can display it on the TFT and also print it out on the printer. If I run out of RAM, I'll get to hook up D4 and figure out how to make the microSD card on the TFT shield work...

:D Chris
You do not have the required permissions to view the files attached to this post.
Last edited by unexpectedly on Wed Jul 31, 2013 10:07 am, edited 1 time in total.
User avatar
By unexpectedly
I can definitely confirm that the Easy Driver board will chop the current to the stepper with HIGH on the ENABLE input. I researched quite a bit and no one on the internet said they've done it. I did it. I'm happy about that, as the stepper gets seriously hot if I leave it on and I made no accommodations for that.
User avatar
By unexpectedly
I thought that the stepper being so hot wasn't right, so I set up a current test. Sure enough the potentiometer doesn't match the silk screen. Aw man, this has got to be driving the SF guys batty. I know how aggro I am about attention to detail things like this. Maybe they should change the silk screen to "Dot indicates MIN" and then test it in QA, turn the pot to MIN and dot the board? :P

Pics or it didn't happen:
As delivered with the POT full clockwise, set to MIN. Measured current is 0.44 (occasionally 0.45) amps. In this position, I was worried about the temperature of the stepper; almost too hot to touch.
I turn the POT full CCW, to MAX, and the current is 0.22A. I've had the stepper locked in position with current flowing through it and when feeling it, you can barely tell that it's warm.
You do not have the required permissions to view the files attached to this post.
User avatar
By Ross Robotics
Then you must have gotten the older version. On v4.4 they supposedly fixed the silkscreen error.

Sparkfun only sells the Driver, Brian Schmalz at actually develops this.
User avatar
By unexpectedly
Check out bottom right corner of the picture... "v44"
User avatar
By Ross Robotics
I said supposedly.. Contact Sparkfun customer support or the original designer.
User avatar
By unexpectedly
Yup I did, before I added the FYI to my build thread. Also submitted an idea for a solution. :)
User avatar
By unexpectedly
Great progress!! Turns out the sticker on the printer describing its wires' input is backwards. I found that out reviewing this guy's code! This other guy's code and Thermal.h lib is what I ended up using to get the printer going.

My first real use of the thermal printer was to print out the results of various "speed" settings for the stepper motor. With the Easy Driver's potentiometer adjusted for minimum current, I wanted to see how speed affected the stepper's performance. Three of the TPSs I sell have a return spring loaded on the input shaft and I know from my 1st test bench that this force needs to be overcome by the stepper motor. Speed is a value from 0.1 to 1. This (of my 4 TPSs) stutters with speed set to 0.75, but can complete the sweep with speed set to 0.6. The below printouts are a listing of 1 degree measurements of the ADC input for speed values of 1, 0.5, and 0.1.
With speed set to 1.0, it couldn't even complete the sweep!! The next test, I ran "speed" values of 0.9, 0.75, and 0.6. I could hear 0.9 and 0.75 stutter, but 0.6 was OK, so I set that as the speed factor setting for this particular TPS.

Next up, to start the process of plotting the voltage to angle response curve of the TPS. My initial goal was to display this curve to the operator of the test bench to help decide if they believe the Arduino when it decides if the TPS is good or bad. Test bench 1.0 only tests 35 points and uses a character LCD display to SAY good or bad based on the program's observation of point-to-point analysis. This is certainly better than the industry-standard test of 4 points: off, on, and 2 points in the middle. YES, this 4 point test is what you normally pay $100+ to buy a TPS for! OEM parts sometimes fail my v1.0 bench with its measly 35 test points...

I found out that with this proper stepper motor and the Easy Driver board coupled with my 18:54 (1:3) gearing that 13 and 1/3 microsteps (u-steps) is 1 degree. With 14 u-steps per measurement, I got 90+ points of data! So I need to decide if I want to depict degree data at all through this, and if it should have accuracy. 3 degrees = 40 u-steps. I'll either do 10 u-steps per measurement or 14. Twenty u-steps is too similar to the current test bench and therefore, "not good enough".

Now that I have a power_test() function sorted out, I started on the test() function. It's really about the same as the power_test(), only we're only iterating once at a speed factor known to have enough power to complete the test. test() sweeps through the known range of TPS valid values and records each step to an array. Then the stepper returns the input shaft to initial position and my rest() function drives ENABLE input to Easy Driver high, turning off the current through the stepper, prolonging its life, saving energy, and keeping the stepper motor at a cooler temperature.

With the sweep of the TPS's range done, I iterate through the array and figured out how to plot the values from bottom left to top right. I used the map() function and known beginning and end points of the TFT to map() the idx (as x) and test[idx] ADC values to to x and y for each step. I then "looked ahead" and instead of drawing points, I drew lines from this x,y to the "next x,y". And ended the for() loop one entry too soon since my look ahead induced a one-off error.

And here's the plot:
Non-casual observers will notice that the plot is non-linear. The theory behind non-linear TPS is great: the most important time a person is using the throttle is from closed to half open. This is when you are mid-corner or entering into a parking lot, etc. Very crucial moments! With a steep 1st half of the plot, there is great resolution between inputs. This helps the fuel injection computer (referred to an an ECU) more precisely understand what your input is at during these crucial moments.

And then past what I call the "knee", the slope of the curve is gentle. From half throttle, there isn't much point in differentiating the operator's input; most people go to wide open throttle (WOT) from half throttle very quickly anyway.

There we are today. 1 of 4 TPSs pretty well handled. Next up, convert that array of idx to ADC values into a bitmap so I can print it out on the printer. Of the four TPSs I sell, two are non-linear and two are linear. The linear ones are pretty easy to programatically determine good or bad, but the non-linear ones quickly become miserable before-and-after rules and exceptions.

Anyhow, I am very very :D for today and honestly :o that I'm able to graphically show the display. From the first time I plotted idx vs ADC values in a spreadsheet, I knew that showing the response curve was the best way for the operator running the test bench to decide if this particular TPS is good or bad.

:mrgreen: Chris
You do not have the required permissions to view the files attached to this post.
User avatar
By unexpectedly
I can confirm that the U-Line ( box of 50 rolls for around 20 bucks part number S-18644 fits and works great in the printer. I got them in today and tested right away.

Still trying to make a bitmap print... :cry:
By Mee_n_Mac
In the end, other than the knowledge you get from having the data (and being a datadog myself, I can grok that), what's the end purpose of the tester ? The ECU assumes some ideal model of the TPS to do it's job. The closer the real-life TPS comes to that (?unknown?) model, the "better" it will be, at least in achieving the designed performance. What you can do is find that certain TPS's from certain vendors have a wide variance and so will offer variable performance, hopefully noticable differences, and so discount them. Other vendors may have tighter tolerances and come closer to the "truth" and so be recommended ?
User avatar
By unexpectedly
We've got a couple pallets of them and I don't want to sell any that give sketchy data. If a dealerships "fires" us because we wasted their time with a couple of faulty parts, we lose big time. With this, I'll be able to include evidence of the test. It'll have date / time of test and I'm currently "printing" the console that will hold all this stuff in a nice package.
User avatar
By unexpectedly
I finally got my setup to print a plot!

I spent a lot of time screwing around with all sorts of peoples' code when the AdaFruit sample was the easiest to implement. I got it to print their logo on the first try. Then I started messing around with supplying my own bitmap. Took me a while to realize they are using PROGMEM, and then to realize that we don't get to write to it, only read from it. Good thing I'm doing all this with a Mega, as an Uno wouldn't be able to do anything...

As it was, I was testing with a 128 x 128 sample bitmap I created. I used it to sort out my algorithm for translating an array's index to X and array[index] values to Y and then getting that to work in the byte array in SRAM and THEN also getting it to print!!! Not trivial.

Here's the algorithm in case anyone googles their way here trying to plot an array to a bitmap...
Code: Select all
//  Serial Thermal Printer setup
//  code based on
#include <SoftwareSerial.h> // core lib
#include <Adafruit_Thermal.h>
#include <avr/pgmspace.h>
//  From Crazy web project
// this is the green wire
#define PTR_RX_PIN 3
// this is the yellow wire
#define PTR_TX_PIN 2
// Thermal1 printer(PTR_RX_PIN, PTR_TX_PIN, 19200);
Adafruit_Thermal printer(PTR_RX_PIN, PTR_TX_PIN);
static const unsigned int IMGSIZE = 192;
static const unsigned int IMGROWBYTES = IMGSIZE/8;
byte bitmap_data[IMGSIZE*IMGROWBYTES] = {0};

void graph2thermal( unsigned int size, int test[], int idxmax ){
	static const unsigned int w=size, h=size, Bpr=w/8;    // Bytes per row, 128/8 = 16
	sprintf( text, "%d data points:", idxmax );
	for(unsigned int idx=0; idx < idxmax-1; idx++  ){
		unsigned int y = map(test[idx], TPS_floor[_tps], TPS_max[_tps], 1, w);
		unsigned int x = map(idx, 0, idxmax, 0, h-1);
		//  what's our Y offset? 128-45 = 83 : 83*16=1328
		unsigned int yoffset =(h-y)*Bpr;   // how many bytes away from start of our array
		// which x byte : 44/8 = 5 whole bytes
		unsigned int xoffset = x/8;
		unsigned int offset = yoffset+xoffset;
		// now which bit
		//  44%8=4 : 0x80 >> 4 = 0x08
		unsigned int shifty = x%8;
		unsigned int _pixel = 0x80 >> shifty;
		bitmap_data[offset] = bitmap_data[offset] | _pixel;
	printer.printBitmap(w, h, bitmap_data, 0 );

Credit to AdaFruit for their Thermal.h library and also including the separate sketch to convert bitmaps into a PROGMEM static array include file. I was able to reverse engineer that into a bottom-left is (x,y)=0,0 plot.

I next learned why EVERYONE is throwing a micro SD card onto shields: the SRAM sucks!! Now I'm stupidly excitedly waiting for the Goldilocks UNO-compatible with its ATmega1284p MCU and 16k of SRAM! The Mega is at it's limit running a sketch AND displaying a 192x192 pixel monochrome bitmap, and a 256x256 BMP equals the Mega's 8K of SRAM :( Admittedly, even the Goldilocks and it's 16k couldn't hold a 384x384 mono bitmap as a byte array either, as that guy is 18432 bytes.

So I went to Radio Shack and bought their smallest micro SD card (8 GB!!) for an astonishing $9. I soldered on the header for digital pins 0-7 so I could get the SD Card's D4 chip select. Reminder: I already clipped the pins for the normal UNO's hardware SPI pins and ran a 4 pin connector to the proper pins on the Seeduino mega.

While I had the soldering iron out, I also hooked up SparkFun's Real Time Clock Module to the Seeed Mega's nicely separated out I2C pins. They put them on the edge at a corner of the board, so I slapped on an angle 4 pin header and soldered a 4 pin wire connector onto the RTC board. This was the stupidestly easiest "thing" I have ever made work on an Arduino. :)

So sweeet, I've got the RTC working and the SD Card working... next up to get the 384x384 bitmaps setup on the SD Card so I can print my plot full width! :D
You do not have the required permissions to view the files attached to this post.
User avatar
By unexpectedly
Updated Fritzing drawing to reflect SD Card's required digital pin 4 connection and the newly added RTC module. :mrgreen:

Oh, and I found that the Mega wanted more than 5V; I started getting whacky ADC readings when the USB wasn't connected, but stable when USB connected. So I tried sending the Mega 12V from the power supply instead of 5 and it likes that much better. 8)
You do not have the required permissions to view the files attached to this post.
User avatar
By unexpectedly
I've been busy 3D printing the test bench itself:
I've got everything working but am hung up on the concept of printing out the response curve to paper in a larger than 192 px bitmap. I came up with a way to translate the byte array into a binary file that can be printed directly from the SD Card. But it, too, has some kind of size limitation and is losing its mind as well. I asked about this on the Adafruit forums as well.

As you can see in the picture in this post, I can print from the SD Card no problem. That image is 100x68 and stored as bytes on the SD Card, printed in my setup() via this code:
Code: Select all
   //  SD Card
   if (!SD.begin(SD_CS)) {
      printer.println("SD Card initialization failed!");
   } else {
        File myFile;
        myFile ="cw100x68.bin");
        if( myFile ){  // this totally works!
         printer.printBitmap(100, 68, dynamic_cast<Stream*>(&myFile) );
        } else {
         printer.println("Opening file cw100x68.bin failed!");
I've got another version of my logo where the black bar goes all the way across the 384 pixels and that pretty much locks everything up. :(

It feels like there's something simple I'm missing... I'll keep going over the SD card and thermal printer code to try and find a solution...
You do not have the required permissions to view the files attached to this post.
User avatar
By unexpectedly
Here is the inside of the base of the housing:
You'll notice the black ABS plastic from this picture in bottom of the previous picture showing the whole bench. I'll share the CAD files once I'm done and happy with them (or earlier upon specific request). I have iterated through how to hold the Arduino "stack" a few times. There isn't really any great way for that, but having the top shield bolted to the outside is pretty awesome. I did that on my timing belt measuring bench previously. On THIS project, I can't bolt the subsequent shields to the top one due to the spaghetti of wires I have coming off the proto shield, so I've got some support designed to push up on the bottom of the stack. We'll see how that works. Most of my designs require a couple tries to get perfect.

Yaay, maybe it'll be done soon... I hope so, as I'm neglecting the rest of life and work until then! :mrgreen:
You do not have the required permissions to view the files attached to this post.