Sunday 25 November 2012

More accurate thermistor tables

A couple of weeks ago I wanted to create some thermistor tables for Marlin. At that time it had a copy of createTemperatureLookup.py, which I think was written by Zach Smith based on my article "Measuring temperature the easy Way". It uses the simple two constant thermistor equation based on the resistance at 25°C and beta.

The two constant formula was adequate for my own software because I have separate constants for each thermistor that I use and I calibrate them against a thermocouple at the working temperature and room temperature. Marlin however has a thermistor table for each type of thermistor, so if you use the same thermistor for the bed and the hot end they share a table. The problem with the simple equation is that beta is not very constant and depends on temperature. There are several values given on the datasheet for different temperature ranges
, none of them very applicable to our application. If you have beta correct for the hot end at say 250°C it is about 7°C out at the bed temperature, say 130°C.

I decided to make a new script which uses the three constant Steinhart–Hart equation. The graph shows the difference between the two equations over a large temperature range: -
The two constant equation is only accurate around the two temperatures the constants are calculated at (in this case 25°C and 256°C). When these are at opposite ends of the thermistors range the error in the middle is quite large.

The script I made is MakeTempTable.py. Its parameters are resistances at three temperatures. The tables is makes look like this: -

    {     344,       300     }, // r=   101 adc=  21.47
    {     369,       295     }, // r=   108 adc=  23.08
    {     397,       290     }, // r=   117 adc=  24.83
    {     428,       285     }, // r=   126 adc=  26.75
    {     461,       280     }, // r=   136 adc=  28.84
    {     498,       275     }, // r=   147 adc=  31.12
    {     538,       270     }, // r=   160 adc=  33.63
    {     582,       265     }, // r=   173 adc=  36.37
    {     630,       260     }, // r=   188 adc=  39.38
    {     683,       255     }, // r=   205 adc=  42.69
    {     741,       250     }, // r=   223 adc=  46.32
    {     805,       245     }, // r=   243 adc=  50.31
    {     875,       240     }, // r=   266 adc=  54.71
    {     953,       235     }, // r=   290 adc=  59.55
    {    1038,       230     }, // r=   318 adc=  64.88
    {    1132,       225     }, // r=   349 adc=  70.77
    {    1236,       220     }, // r=   384 adc=  77.26
    {    1351,       215     }, // r=   423 adc=  84.42
    {    1477,       210     }, // r=   466 adc=  92.32
    {    1617,       205     }, // r=   515 adc= 101.05
    {    1771,       200     }, // r=   570 adc= 110.68
    {    1941,       195     }, // r=   632 adc= 121.30
    {    2128,       190     }, // r=   702 adc= 133.01
    {    2335,       185     }, // r=   782 adc= 145.91
    {    2562,       180     }, // r=   872 adc= 160.11
    {    2811,       175     }, // r=   975 adc= 175.70
    {    3085,       170     }, // r=  1092 adc= 192.81
    {    3384,       165     }, // r=  1225 adc= 211.53
    {    3711,       160     }, // r=  1378 adc= 231.95
    {    4066,       155     }, // r=  1554 adc= 254.15
    {    4451,       150     }, // r=  1756 adc= 278.21
    {    4866,       145     }, // r=  1989 adc= 304.15
    {    5312,       140     }, // r=  2258 adc= 331.99
    {    5787,       135     }, // r=  2570 adc= 361.68
    {    6290,       130     }, // r=  2934 adc= 393.15
    {    6820,       125     }, // r=  3357 adc= 426.25
    {    7373,       120     }, // r=  3852 adc= 460.80
    {    7945,       115     }, // r=  4433 adc= 496.54
    {    8531,       110     }, // r=  5116 adc= 533.16
    {    9125,       105     }, // r=  5921 adc= 570.31
    {    9722,       100     }, // r=  6875 adc= 607.60
    {   10314,        95     }, // r=  8007 adc= 644.61
    {   10895,        90     }, // r=  9356 adc= 680.92
    {   11458,        85     }, // r= 10968 adc= 716.13
    {   11998,        80     }, // r= 12903 adc= 749.86
    {   12509,        75     }, // r= 15234 adc= 781.80
    {   12987,        70     }, // r= 18051 adc= 811.66
    {   13428,        65     }, // r= 21469 adc= 839.27
    {   13832,        60     }, // r= 25635 adc= 864.50
    {   14197,        55     }, // r= 30732 adc= 887.30
    {   14523,        50     }, // r= 36995 adc= 907.68
    {   14811,        45     }, // r= 44725 adc= 925.72
    {   15064,        40     }, // r= 54309 adc= 941.52
    {   15284,        35     }, // r= 66249 adc= 955.23
    {   15472,        30     }, // r= 81195 adc= 967.02
    {   15633,        25     }, // r=100000 adc= 977.08
    {   15769,        20     }, // r=123783 adc= 985.58
    {   15883,        15     }, // r=154025 adc= 992.71
    {   15978,        10     }, // r=192694 adc= 998.64
    {   16057,         5     }, // r=242427 adc=1003.54
    {   16121,         0     }, // r=306773 adc=1007.56


The ADC values in the table are multiplied by 16 because Marlin uses oversampling to give four more bits of precision. The old tables just multiplied the integer ADC value by 16 but I multiply it before rounding it to an integer so the table has the same precision as the oversampled ADC reading.

The script can also take ADC values as parameters instead of resistances. This allows you to calibrate a thermistor in situ. If you set the temperature to a value in an existing table and let it settle and then measure it with a thermocouple you know that the ADC value for the measured temperature is the value in the table for the set temperature. You can then produce a new more accurate table.

Two days after I put it on Github ErikZalm added a new script to the official version of Marlin to do exactly the same thing: createTemperatureLookupMarlin.py, amazing coincidence! It is different code but I think it uses exactly the same maths to find the three coefficients using simultaneous equations that I lifted from here

Wednesday 15 August 2012

Peel-able support?

One of the few advantages commercial FFF machines have over Reprap at the moment is that breakaway support works much better. In particular the UP printer from PP3DP is reputed to have easily removable support using only the same material it builds with, i.e. ABS.

Today I was redesigning the Mendel90 ribbon clamps to have nut traps to make assembly easier and came up with this design: -


I thought I could print it using the bridging ability to span the slot in the base but it failed abysmally. I think it is because it is so close to the heated bed the bridge sags a lot more that it would normally do.

I tried the support option in Skeinforge but I have never got it to work well. It puts a sparse zigzag under the bridge and the flow rate can be reduced to make it weak. The problem is then that when it is removed the top layer of the support bonds more strongly to the part above than that it does to the support below, so it gets left behind. Worse still the bottom layer of the object is more strongly attached to the top of the support than it is to the layer above, so it is very hard to remove just the support.

I think the reason for this is that when the support is sparse the layer above drapes down in between the gaps. That reduces its contact to the layer above and increases its contact to the layer below. This sketch illustrates my theory: -


When I watch videos of the UP printer it looks like the top of the support is solid and flat. This reminds me of the way I used to do rafts. I made the top layer of the raft almost solid and raised the bottom layer of the object a little to make it peel-able. Indeed support is just the same as a raft, it is just that it is elevated.

To test the theory I hacked my host software to load a separate file for the support so that it could be sliced as a normal object and so have a solid top. It also has a solid base of course, which is another advantage over Skeinforge's sparse support as that can easily become detached from the bed.


When extruding I did the support for each layer before the object's layer and did it a bit lower. I also missed off the outline to give a gap of one filament width at the ends. I worked out the diameter that the object's infill would be if it was not squashed into an oval. I offset the support downwards by the difference between that diameter and the normal layer height. That means that when extruding the underside of the object that is being supported the filament is not being squashed, so has minimum contact with the support. It doesn't droop though and the next object layer is squashed against it making the bond above stronger.

The bottom layer of the support is thinner than the rest because of the downwards offset, so I had to reduce the flow rate accordingly. 


It wasn't peel-able by hand but I could separate it cleanly with a penknife, something I have not been able to do before.


The bottom layer of the bridge has round filaments that do not touch (as they are not as wide as they should be) but that is always the case with bridges. The difference is they do not droop and are well bonded to the layer above.


They are of course a little lower than they should be. A better scheme might be to have the support at normal height and raise the head as it passes over it. That would give even better bonding to the layer above which would tend to fill in the gaps. It would need rapid Z movements though.

I would be interested to see what the bottom of a supported surface of an object from an UP printer looks like.

To test the idea further I tried making a sphere. I made the support in OpenScad by subtracting it from a cylinder. To get some lateral clearance I did a Minkowski sum of the sphere with a thin disk.
$fa = 10;

R = 20;
clearance = 0.5;
h = R - R * cos(60);

module sp()
    translate([0, 0, R])
        sphere(R);
 
if(0)
    sp();
else
    difference() {
        translate([0, 0, h / 2])
            cylinder(r = (R * sin(60) + 2), h = h, center = true);
        minkowski() {
            sp();
           cylinder(r = clearance, h = 0.01, center = true);
        }
    }
 
color("red") sp(); 




The support was pretty difficult to remove because it ended up quite dense as Skeinforge makes solid layers when there are shallow sloping sides. Also the sparse infill ends join up to make a complete outline. It is more a proof of concept rather than a practical way to make support.


This is the underside of the sphere where it met the support. It looks quite good but above it there is some distortion to the spherical shape that I cannot explain.

So I think having a solid top surface on top of sparse support is the way to go and a dense bottom layer to anchor it to the bed. In between it can be very sparse but it would then need several solid layers to become flat.

It still takes some effort to remove, so I don't know if it is as good as the UP support yet. The difference may be the plastic.

Tuesday 31 July 2012

Melzi mod

In my previous post: StepStuck I described how Pololu stepper drivers (and the open source equivalent StepSticks) are not configured optimally for the typical motors used for RepRap. Not surprisingly Melzi suffers from the same problem as it just has the same circuit on board the single PCB.

This video is a good demonstration of the effect of enabling the A4988's "low current micro step mode". The Z axis is stepping slowly and you can hear a buzz with pauses in it. When I short out R20 it sounds a lot smoother, but still not perfect.



So I replaced all the ROSC resistors with 0R links.