DIY Coffee Roaster

I was spinning my wheels trying to get the motor & controller to work Friday that I ordered from Amazon. It would just run intermittently. I finally tried the motor by itself hooked up to 12v and it worked perfectly. The controller must be defective, so I sent it back. I did get a chance to test the speed difference between the 3 different ratios of planetary gears I had printed & made a video of them.

The ratios appear to be:

9.27:1
6:1
3.64:1

I pulled the pancake nema17 off my bamboo pen laser engraver & will work on getting that to run with this.

1 Like

I did some temperature testing today. Before doing so, I did change the plastic V-slot brackets to metal & left the flour sifter plastic clamps off for testing. Looks like those plastic clamps may not get too hot. I was measuring around 40c on the face of the outside of the sifter and I could easily touch it with my hand. It was about 50c near the top on the outside face. I initially set the heatgun to about 600c, but didn’t get hot enough, so I set the temperature all the way up. I wasn’t getting high enough reading with the flour sifter in place & probe at the bottom of the sifter, but temperature probe was showing 250c & spiking to 290c occasionally at the same height as the bottom of the sifter. It was 53f (11.6c) outside temperature.

Doing the electrical always slows me down, but the directions seem straight forward. After I get this motor working, I’ll actually try roasting some coffee if outside temperature is warm enough. I’m getting ChatGPT to give me the wiring and Arduino code. What I have checked so far seems pretty accurate. I’m initially going to breadboard an Arduino nano, 1602a display, DRV8825 with a potentiometer (show motor RPM speed for now). I also have an Arduino UNO, but nano takes up less space. Which step rate would be best for this DRV8825 driver?

1 Like

I wouldn’t pay too much attention without a load of beans in there, I suspect they’ll slow the airflow significantly and, as I’ve mentioned before, temperature is a combination of power and airflow. The tradeoff with the poppers is that too little airflow and you don’t get stirring, too much and the heat doesn’t get there. In this case you’ve got stirring so you can slow the airflow down if needed by partially blocking the inlet with some tap, perhaps.

Be careful with electrical stuff and ChatGPT… From what I’ve seen in other electrical groups it has a habit of making stuff that ‘looks’ right, but often with critical flaws. Remember, it’s not doing anything more than mashing tons of crap together that it has seen before and coming out with an average weighted for your situation. Works great for qualitative text, less great for things that are a little less open to interpretation! Feel free to post up what you’ve got if you’d like a sanity check.

For step rate do you mean how much microstepping? I’d work backwards from your desired RPM. If you want the stirrer to turn at 20rpm (about the speed of the drum in the Behmor) from a 10:1 reduction then that’s 200rpm or ~3 rev/s. In a 1.8 degree stepper motor that’s 200 steps per revolution so 600 steps/s. With 1/8 microstepping that’s ~6kHz output frequency which gives you tons of headroom while also being enough microsteps to be a little smoother in terms of torque otuput which might prevent some rattling/shaking.

1 Like

Thanks for all your comments. They have been very helpful. I will definitely double check anything ChatGPT tells me with electronics. It is obviously bad at creating a breadboard layout. Even when I tell it the mistakes it made, it still doesn’t fix them the next time.

2 Likes

I plan to use an Arduino Nano with a DRV8825, a 1602a LCD display, 10k potentiometer to adjust speed and 1602a lcd display to show the current motor speed or RPM, a 100 µF capacitor across VMOT and GND near the driver.

ChatGPT gave me this so far. The motor I have is a Zyltech pancake nema17 which is actually a 0.9 degree motor. I had ChatGPT adjust the code to use 1/8 steps per your recommendation & use a 0.9 degree motor.

High Accuracy 0.9 Step Angle Nema 17 “Pancake” Stepper Motor - 1.5 A, .12 N.m, 17 oz.in - ZYLtech Engineering, LLC

➤ DRV8825 → Arduino Nano

DRV8825 Pin Arduino Nano Pin Description
STEP D8 Step pulse output
DIR D9 Direction
ENABLE D10 Active LOW to enable driver
RESET & SLEEP Tie together → 5V (VCC) Keeps driver awake
MS1, MS2, MS3 GND or VCC Select microstepping (suggest 1/16)
VMOT External 12–24 V + Motor power supply
GND (VMOT side) Motor power ground
GND (logic side) Common ground with Arduino
A1, A2, B1, B2 Stepper motor coils As per motor datasheet

Add a 100 µF–470 µF capacitor across VMOT and GND near the driver.
Never change wiring with power on.

➤ 1602A LCD (direct 16-pin, no I²C backpack)

LCD Pin Arduino Nano Pin Note
VSS GND Ground
VDD 5V Power
VO Middle of 10 k pot Contrast control
RS D12 Register select
RW GND Write only
E D11 Enable
D4 D5 Data 4
D5 D4 Data 5
D6 D3 Data 6
D7 D2 Data 7
A (LED +) 5V (through 220 Ω resistor if needed) Backlight
K (LED –) GND Backlight return

➤ Potentiometer (Speed control)

Pot Pin Arduino Nano Pin
Left 5V
Middle A0
Right GND

➤ Power

  • Nano powered by USB (for testing) or 5 V pin (regulated).

  • DRV8825 powered separately by 12–24 V (depending on stepper motor).

  • Common ground between Nano and DRV8825 logic GND.

:gear: 2. DRV8825 setup notes (quick recap)

  • Set current limit:
    Turn the small trim pot with power off.
    Formula (approx):

    Vref=Imax×5×RsV_{ref} = I_{max} \times 5 \times R_sVref​=Imax​×5×Rs​

    Most DRV8825s use Rs=0.1ΩR_s = 0.1 \OmegaRs​=0.1Ω.
    For 1 A current: Vref≈0.5VV_{ref} ≈ 0.5 VVref​≈0.5V.
    Measure with a multimeter (Vref to GND) while powered.

  • Microstepping:
    Example for 1/16 step: MS1=HIGH, MS2=HIGH, MS3=LOW (check your carrier board silkscreen).

:floppy_disk: 3. Arduino Nano Code (ready to upload)

#include <LiquidCrystal.h>

// LCD pin connections (RS, E, D4, D5, D6, D7)
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

#define STEP_PIN 3
#define DIR_PIN 4
#define ENABLE_PIN 5
#define MS1 6
#define MS2 A1
#define MS3 A2
#define POT_PIN A0

// Stepper parameters
const int stepsPerRev = 3200; // 400 full steps × 8 microsteps
int stepDelay; // microseconds between steps

void setup() {
// Motor driver pins
pinMode(STEP_PIN, OUTPUT);
pinMode(DIR_PIN, OUTPUT);
pinMode(ENABLE_PIN, OUTPUT);
pinMode(MS1, OUTPUT);
pinMode(MS2, OUTPUT);
pinMode(MS3, OUTPUT);

// LCD setup
lcd.begin(16, 2);
lcd.print(“Stepper Ready”);

// Enable driver (LOW = enabled)
digitalWrite(ENABLE_PIN, LOW);

// Set DRV8825 to 1/8 microstep mode
// MS1 = HIGH, MS2 = HIGH, MS3 = LOW
digitalWrite(MS1, HIGH);
digitalWrite(MS2, HIGH);
digitalWrite(MS3, LOW);

delay(1000);
lcd.clear();
}

void loop() {
int potValue = analogRead(POT_PIN);
// Map pot to step delay (adjust for desired RPM range)
stepDelay = map(potValue, 0, 1023, 1500, 100); // slower to faster

// Calculate approximate RPM
// RPM = 60 * 1e6 / (stepsPerRev * 2 * stepDelay)
float rpm = (60.0 * 1000000.0) / (stepsPerRev * 2.0 * stepDelay);

lcd.setCursor(0, 0);
lcd.print("Speed: “);
lcd.print(rpm, 1);
lcd.print(” RPM ");

lcd.setCursor(0, 1);
lcd.print("Delay: “);
lcd.print(stepDelay);
lcd.print(” us ");

// Rotate motor
digitalWrite(DIR_PIN, HIGH); // one direction
digitalWrite(STEP_PIN, HIGH);
delayMicroseconds(stepDelay);
digitalWrite(STEP_PIN, LOW);
delayMicroseconds(stepDelay);
}

That all looks reasonable to me.

You will definitely need a resistor on that LED line, 220R should be fine, that’s ~15mA.

The 10K pot for contrast is likely a little overkill, although fine to start with. I’d probably just adjust it til it looks good then set it with a resistor divider.

I’d usually recommend putting something like a 10nF or 100nF capacitor on the wiper of that pot for adjusting the speed control. Not strictly necessary but it’s always a good idea to have a capacitor or buffer driving analog inputs, otherwise the sampling process can disrupt the voltage that’s being sampled. Not an issue here where it’s just controlling the speed, but it’ll save you scratching your head and wondering why you’re not getting to 100% or 0%, for instance.

DRV8825 setup - There’s technically no issue turning the trim-pot while the board is on, but it pays to be careful and use a plastic tipped screwdriver, as well as being careful while probing. 1A seems like a decent starting point, but I would check to see if the motor heats up while it’s on. If it’s too hot to keep your hand on long term, I’d consider lowering the current. It’ll heat up while on and not turning due to the current still flowing to hold it in place.

I’m not sure about the MS1/2/3 designation for the microstepping. That doesn’t match the DRV8825 datasheet which calls them MODE0/1/2 which the few boards I looked at shorten to M0/1/2. For 1/16th microstepping that’d be M0 = low, M1 = low, M2 = high. For 1/8th microstepping it’d be M0 = high, M1 = high, M2 = low. You can control those with the micro if you want, but given they’re unlikely to be adjusted on the fly I’d just set it to 1/8 or 1/16 by linking them to Vcc or GND, respectively. Either 1/8 or 1/16 will work just fine and I doubt you’d see a difference in usage, it just means that at 1/16 you’d need to be outputting pulses faster from the arduino, which isn’t likely to be an issue at your RPM range.

Arduino code:
The #include is correct.
The comment about the LCD pin connections are correct
The line below that doesn’t look right, to me.

// LCD pin connections (RS, E, D4, D5, D6, D7)
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

For a start, I’d always do this using #defines for clarity, or better yet a const int. Just using numbers like this makes it harder to self-check.
So:
#define LCD_RS 7
#define LCD_E 8
etc.
Except that I don’t think these pin numbers are correct relative to what’s listed above. I can’t remember how Arduino do their pin numbering, but you’ve got RS on D12 and E on D11. Based on how that is above, I’d say it should be more like:

#define LCD_RS 12
#define LCD_E 11
#define LCD_D4 5
#define LCD_D5 4
#define LCD_D6 3
#define LCD_D7 2
// LCD pin connections (RS, E, D4, D5, D6, D7)
LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7);

Then there’s the stepper setup. Pins 3 4 and 5 seem reasonable but it’s then using A1 and A2 which isn’t. Those should be called out as digital pins, not analog ones. It has also split the connections up all over the place while not needing to based on hardware.

That step code is also kinda awful, honestly. It’s probably ‘ok’ enough to work, but I would strongly recommend not using floating point maths, I definitely wouldn’t be setting the LCD every step and I wouldn’t want to be generating the step pulses using delays. There’s also no way to turn the stepper off without just cutting power. I had a look and it apparently takes around 10ms to write a full refresh to the display, so you’d never get above a 100Hz pulse rate or ~2rpm.

It’s also kinda weird to have the pot setting the step timing and then back calculating the RPM rather than the opposite, even though the math being used is full heavyweight floating point. Also linearly scaling the step timing leads to a 1/x relationship to your pot, so rpm will increase slower at first and then faster later.

Personally, I’d be looking to do something more like:

const int maxRPM = 200;
const int minRPM = 20;
const int minPOT = 100;  // pot position that corresponds to minRPM, below that means off
rpm = map(potValue, 100, 1023, minRPM, maxRPM); // slower to faster
if (rpm < minRPM) rpm = 0;

That’ll take the pot value and give you a target RPM of 0 for the first 10% of the pots range then linearly between min and max RPM for the rest.

From there, I’d be looking at using the Arduino timers and using a timer interrupt to do the stepping or perhaps even the tone() function.

Perhaps try:

int StepHz = 0;
const int stepsPerRev = 3200;  // 0.9degrees per step so 400 full steps/rev, 1/8 microstepping.
const int RPMtoStepHz = stepsPerRev/60;  // Just gives a single simplified calc and forces this step to be compiled to a constant.

Then in your main loop:

if (rpm == 0)
{
    noTone(STEP_PIN);
{
else
{
    StepHz = rpm * RPMtoStepHz;
    tone(STEP_PIN, StepHz);
}

Which should generate a 50% duty cycle square wave on that pin at StepHz frequency with non-blocking code so you can happily run whatever else in the main loop, like the LCD update.

Tone can’t generate anything below 31Hz, so the minimum rpm in this case would be 0.6rpm. It also looks like the max input is ~32kHz, so 600rpm, which seems reasonable.

Using tone() is a bit of a hack, but the alternative would be PWM or the timer hardware directly, which I’ll leave as a further exercise.

Just a note: I really, really hate dealing with AI produced garbage like this, so hopefully this helps but I won’t be engaging with anything technical and AI produced again. It just wastes too much time vs providing suggestions on how to do it properly straight up.

1 Like

I appreciate all the time you must have spent putting this together. I’m using several sources to verify my connections and hopefully it will come together ok. I am adding 1 or 2 MAX6675 thermocouples to the design & the layout & code does have to change slightly for those. The display will show the motor RPM on 1 line & temperature(s) on the bottom. At least that is the goal.

I did find a beta version of the breadboard designing from Welcome to Fritzing and spent a couple of hours drawing up my 1st version. I will have to double check it all before actually wiring it up.

I decided to order one of these boards to make wiring the DRV8825 easier. Actually, I ordered 3 of them for free shipping. They were only $1.13 each.

https://www.aliexpress.us/item/3256806583829856.html

1 Like

I didn’t even read it. You’re a gentleman and a scholar.

I have used the AccelStepper library in the past and it works very well. I was using steppers for position, not speed, but IIRC it has both:

https://docs.arduino.cc/libraries/accelstepper/

The Tone will probably work for a constant speed. The only advantages to the library are clearer function names and smooth accelerations.

This code isn’t doing much. So I wouldn’t worry about using floats a few times. Using them at the same rate as updating the display is totally fine. Using floats for each step is going to be a slowdown.

2 Likes

I finally had to modify the flour sifter a little with a big hammer and chisel. The handle is just in the way to put the top stainless-steel mesh on. It only took a couple of big taps with the hammer on each dimple. Not sure if I will do anything with those dimples.

I realized yesterday that I have a couple of B&D Model 9078 Type 1 3.6v (180rpm) pivot drivers and one of them has a dead battery. I took the bad one apart and hooked it up to 3.6v and seems to run the gears good. I am printing a bracket for the good one first, but the one that uses the portable PS might be a better long-term solution than the other one since that battery could stop working in the middle of a roast, but will try the one I did not disassemble first as I am not sure how I want to connect the wiring to the gutted one. I was testing how strong the motor was by trying to stop a gear with a finger and almost hurt my finger. That was the motor torture test.

You can also see the stainless-steel mesh in this photo. It extends 10” above the sifter and overlapped 2” on the sifter held on with a stainless-steel band clamp. I am using some 22-gauge copper wire to thread in the overlap for a smoother mesh surface.

1 Like

Okay I love this. It has a steam punk type of thing going on but…3d printed. Maybe we are in a new era PrinterPunk.

2 Likes

I had not really thought about it being steam punk.

I tested my new setup today and looks like I need a better clamping system. Those plastic clamps just don’t keep it from rotating around. I looked at clamping some aluminum plates down over the lip on 4 corners of the V-slot but looks a little kludgy. Think I really need to drill 3 holes in the flour sifter below the sifter mesh and the right height to use 3 aluminum 90-degree corner brackets to pull it down against the v-slot. I just have to figure out the best position and way to drill these. I will definitely create a 3d printed drill template for it. Maybe I will make a 3d printed mockup of the bottom of the sifter before attempting the drilling.

Here is a video of the latest test.

I had several ideas of how to clamp this flour sifter down securely and this is what I am going to try next. This seems like it will work if the plastic does not get too hot. I added some inside knurling all the way around the inside to vent any heat better. The holes along the circumference of the band I initially had because of an earlier thought to drill M5 holes in 4 spots and secure it with a 90-degree metal bracket to the V-Slot.

Just use ABS/ASA. :smiley:

I had seen where someone had wrapped the top of their roaster in cork as a shim to put a glass chimney on, so I looked up how much heat cork panels can withstand, and it is 248F (120c). It should not get anywhere near that hot at that location. That will make a nice gasket to tighten the brackets against also.

Using that new clamping system with the cork keeps the sifter quite secure, but now my old problem of the inside wire cage scraping and sometimes catching the bottom of the sifter is the main problem now. I was thinking about how I could bend them just a little bit, so they no longer touch the bottom mesh. Initially I was thinking of using my 16” channel locks and then realized this stainless-steel band clamp might be perfect for that. Alas the 5”-7” clamp I have is right at 5” limits of what I need. I might could have wrapped something in there to get the extra length I need, but I will just go get at 4”-6” clamp tomorrow which should work. Just 1-2mm of movement is probably all I really need.

1 Like

I 3d printed some spacers to give me another 10mm of circumference to compress this agitator. After looking at the inside more carefully while manually turning some beans, it seems like the real problem with the beans getting caught is around the lip of where the bottom mesh is attached to side. It is really only happening on the seam side of the flour sifter which now makes sense why it worked better when rotating the beans counterclockwise. Since it might be warm enough this afternoon and I have enough confidence in trying a roast, I will probably try a test roast today with manually turning the crank.

Here is a video of me trying to compress the agitator.

I did my first roast with the flour sifter in manual crank mode. I learned a few things, like @jono035 said that flour sifter will get hotter with the beans in there and it did get really hot. I measured 95c-103c at the bottom outside inside the cork. I had the heat gun set to the highest setting. I measured about 85c at the plastic clamp that was an 1/8” away from the sifter & had no cork in front of it but doesn’t look deformed yet. I continue with long term, I will use ABS for those clamps as I can easily print that. I am sure glad I protected that plastic with the cork. I didn’t smell anything burning, so the cork didn’t get too hot. Google search says it should be good to 120c which it might get that hot there. The popcorn popper is still a lot simpler than this method so far. it was simpler to cool the beans with the sifter. I just substituted my fan for the heat gun when I stopped the roast. If I end up scrapping this project, I could use the flour sifter as a good way to cool the beans with the popcorn popper.

I did not put the 10” extra height of mesh at the top & did not have any beans go flying. I tried different methods of turning at first, just going back and forth and different speeds, but probably around 20rpm would be a good speed and only CCW. I didn’t hit 1st crack until probably 15 minutes. It is usually around 4-5 minutes with the popcorn popper. I let it run to 35 minutes before stopping it. It did not seem to look much different between 30-35 minutes. In the beginning the beans started changing color they varied in color quite a bit and think that was because I was not rotating a slow consistent movement. In the final roast they also look like they vary from a brown to a dark brown. I was hoping for 2nd crack but did not get that hot. I think the longer roast time is partly due to me moving the beans too much early on. I used 113.5 grams of beans which comes out to 4oz. I only use 76 grams (about 6 batches per pound) with the popcorn popper which is around the max people recommend using with that.

I am going to do another roast tomorrow with the heat gun 2” from the bottom of the flour sifter screen and not have the flared nozzle attached. For this roast the top of the flare was about 1.75” from the bottom of the screen. I believe @jono035 mentioned it might work better without that flare. I might keep the fire extinguisher close by this time as the outside surface of that sifter got hotter than I expected. Since I did not really have any problems with beans jumping out of the sifter today, I am going to hook up the B&D pivot driver running CCW using gear set that is about 9.3:1 ratio which when I just test it turns about 17.5RPM which seems like a good speed for the next test. I will use the same amount of beans to at least keep the variable the same. I will test it rotating for about a minute without the heat to make sure it is working reasonably well.

1 Like

That’s super strange that it took that long to get up to temperature. You should be seeing 10-15 minutes to 2nd crack, ideally. It takes about 25 minutes for a 1lb batch in the Behmor and people rag on that for being too slow.

Is the hot air gun a temperature controlled one? If so, that may also be part of the issue, behaving similarly to the over-temp cutout in the popcorn popper.

It may also be that the exhaust plume is pulling some extra cool air in. I would try to get a thermocouple in there and see what’s going on, both in terms of outlet temperature from the gun and air temperature around the bean mass. Perhaps trying to put a temporary extension on the top might help, even if it’s just made of cardboard.

Those beans also look like there’s a lot of variability in the colour… Some look very light and others quite dark… Do you think the stirring is enough to keep them moving completely evenly or are some potentially staying ‘underneath’ the stir bar for a while before being picked up?