Machine Week

Files: temp_control.sch temp_control.brd temp_control_cutout.png temp_control_routes.png (both images are 1000 dpi; ignore the embedded metadata) code

It’s here: machine week. Even with some helpful structure, it’s a lot. Let’s see how far we get!

My group’s collective documentation lives here. This page describes my individual contributions.

Mechanical Design

Having the most Fusion 360 experience in the group, I did most of the modeling work. This was largely an exercise in arranging Jake’s parametric axes. However we did have to fix a few sketches in the axes after modifying parameters (since they would rebuild with errors). I also changed Jake’s parametric angle bracket into a box bracket. The original purpose of this part was to lift the X axis above the Y axes (to gain additional Z travel), but we ended up leaving it out in order to increase stiffness. Design files are linked on the group page. The video below is from our late-night design session.

The main flaw in our design is that the end effector is much more massive than our axes can reasonably support. This was mostly due to our aggressive design timeline: we wanted to finish our design in the first day, so the end effector and gantry system were designed completely in parallel. So by the time we combined them, there wasn’t time to go back and stiffen up our axes. Though clearly we would have benefited from some additional communication between Filippos and I during the design process.

Chocolate Temperature Control

We want to keep the chocolate in our machine’s reservoir as close to its melting point as possible without letting it solidify, since this helps it harden faster when printed. So I worked on a temperature control system with Filippos and Ravi.


The circuit consists of two essential parts: a thermistor to measure the chocolate’s temperature, and a heating pad to increase it. We decided to mount our electronics on a daughter board for Jake’s breadboard board. This makes it possible for the temperature control system to be another node on the RNDMC network controlling the machine’s motion.

To use a thermistor, one generally wires it in series with a fixed resistor. One end of the two resistors should be connected to power, and the other to ground. This creates a voltage divider, where the intermediate voltage depends on the resistance – and thus temperature – of the thermistor. I initially chose a fixed resistor value around the middle of the temperature range we hoped to measure (43K), though we had to change this later (see software).

The heating pad is essentially a giant resistor: push current through it and it gets hot. But it requires more current than the Xmega can source from it’s pins (and at a higher voltage to boot), so I used a MOSFET to switch current from a dedicated 12V 5A power supply. Filippos and Ravi ordered this one.

Here’s the board and thermistor, before attaching the heating pad. Also visible are the RNDMC router and the dedicated power supply.

Here’s the chocolate syringe, wrapped in a heating blanket. You can also see the leads of the thermistor, which is tucked inside.

Thermistor Software

Jake’s breadboard board programmed fine on the first try, and its test function worked fine.

My first priority was getting some samples from the Xmega’s ADC. So I was happy to find a command called DELIM_KEY_ADCGET in the existing packet handler. Unfortunately when I ran it the board became unresponsive – not even the test commands would get through afterward unless I did a hard reset. After much datasheet diving, and getting some additional example code from Jake, I figured out that it was getting stuck in get_adc() because the bit that should indicate a sample is ready was never getting set. Fixing it should just be a matter of modifying the appropriate ADC registers.

While looking into this, it became clear that Xmega’s ADC can’t read values between 0 and 3.3V (i.e. logic level) – the highest available reference voltage is about 2V. This had hardware repercussions, since the existing thermistor voltage divider circuit would exceed 2V within our expected temperature range. Luckily it could be fixed by increasing the value of the fixed resistor. So Filippos and I removed the existing one and soldered in a bigger one.

Back in register land, the following initialization procedure fixed the issue with adc conversions never completing.

void init_adc(void){

	// Using highest available reference voltage: 3.3/1.6 = 2.0625V.
	// For our thermistor setup, we use a fixed resistor of 75K.
	// So the lowest temp we can read should be about 20C (i.e. 125K).
	// start it up 

But the values I got sent back in my terminal were obviously wrong. I should see a 12 bit number that correlates with temperature, but instead got an 8 bit number that moved around seemingly at random. This ended up being due to some bit shifting errors in the breadboard board code. After fixing them, the voltage readings were just what I expected given our thermistor circuit.

In the image below we get the response 142, 13, 244. The first byte (142) is just echoing the command for an ADC conversion. The second two bytes encode the 12 bit reading from the ADC (right packed). So 13, 244 is 0b1101, 0b11110100 in binary, meaning the ADC read the value 0b110111110100 or 3,572. This represents 3572 / 4095 * 2.0625V = 1.8V.

To convert this value to a temperature, we first need to convert it to a resistance. From Ohm’s law and Kirchhoff’s laws I derived R = 75 * v / (3.3 - v) where v is the voltage measured by the ADC. (75 is the value of the fixed resistor in kilo-ohms; 3.3V is our logic level; the resulting resistance is also in kilo-ohms.) Online I found an informal datasheet for our thermistor, which includes a table of temperature and resistance values. Ravi fit an exponential model to the data that converts from resistance to temperature. So our final temperature reading code is as follows.

float temperature_from_adc(uint16_t adc_reading) {
	float voltage = (float)adc_reading / 4095.0 * 2.065;
	// in kilo ohms
	float resistance = 75.0 * voltage / (3.3 - voltage);
	// To get from a voltage to a temperature we use an exponential model a + b * e^(c * resistance).
	const float a = 15.860977372457437;
	const float b = 79.1567233970091;
	const float c = -0.022498404090181136;
	return a + b * exp(c * resistance);

Heat Pad Software

After getting reasonable temperature values, controlling the heating pad turned out to be pretty quick. It just requires using a pin as an output, and setting it high when the pad should be on. Still, when I first tried it I couldn’t get the pin to change it’s state. This was because there was some additional servo control code in the project that coincidentally used the same pin and changed its configuration registers. Once I deleted that code everything worked fine.

Since the temperature of the chocolate changes extremely slowly relative to the timescale of the microcontroller, I went with the simplest possible control logic. If the thermistor reading indicates the chocolate is below a set temperature, we turn the pad on. If it’s above that temperature, we turn it off. I also co-opted the orange error LED on the breadboard board to serve as an indicator for the heating pad. This makes it easy to tell visually when the chocolate is at the right temperature: the light flickers, as opposed to being all the way on (as it is when the chocolate is too cold) or all the way off (when the chocolate is too hot). I used a digital thermometer to verify that we were keeping the syringe at the right temperature. Our system was able to hold the temperature to within a half degree Celsius.

Here’s the final system: syringe, temp control board, and all.