Automating the Versalab M3

Grinders are one of the keys to exceptional espresso. Discuss them here.
User avatar
AssafL
Posts: 2588
Joined: 14 years ago

#1: Post by AssafL »

What is it: "This hack (for the Versalab M3 fitted with the hopper) will start the grinder automatically when the slide drops beans into the chute, and stop the grinder automatically when the beans have been completely ground. It detects that the beans are in the process of being ground by measuring the current consumption of the motor and waiting until it goes down".

Note: this is major overkill and will not improve your espresso. But - if you like to tinker - this does make a nice weekend project that serves a useful purpose. I've had my grinder for about 4 years so it was time due for an upgrade. I didn't want a new grinder so it had to be hacked.

Important Note: This hack is outright dangerous and can indeed kill you (especially if you live in a 220V country). The DC motor runs at 90/130VDC and is connected directly to mains. Touching live wires will shock you and may kill you. Shorting live wires may start a fire and kill you. Mistakes may kill the driver board (I think about USD100) or the motor (over USD200) or/and also be dangerous to you. Insulate everything well and secure loose wires. If you do not know and fully understand why "LIVE" is both meaningful and dangerous - then this weekend project isn't for you: play with some other project (go flash an LED or something).

So after regulating flow on my GS/3, and after finally working up the guts to realign the burrs on my Versalab (which is now complete without wobble and a feeler gauge fitting snugly all around) it was time for a weekend of figuring out how to assign a junkpile of Arduino leftovers to the Versalab.

Specifically, these leftovers consisted of:
  • 5V Trinket controller board (a tiny ATtiny85 nearly Arduino compatible board from Adafruit)
  • ACS712 Hall effect based 20A current sensor (DC with PWM must use Hall effect to sense current)
  • Relay output board
  • Tiny 5V power supply dug out of a cell phone charger and shrink wrapped (NO LONGER UL listed after that treatment)
  • Microswitches, LEDs and cabling
So the idea was this:
  • 1. Using the slider will start the grinder automatically using a micro switch.
    2. Monitor the grinding process by measuring the RMS current drawn by the motor using an Adafuit Trinket controller board and an ACS712 Hall effect sensor module (the current is chopped rectified AC so we have to calculate RMS); have a single LED display the current to the motor for diagnostics.
    3. Delays to account for the time between the slider triggering the switch and the beans entering the grinder itself; and a power off delay to ensure every last bean has been mercilessly crushed and ground
    4. Egg drop control: pulse the motor twice at the end to eject any leftover eggs and clear the distibution funnel
I originally wanted this powered from the "dimmer" like speed controller circuitry, but:
  • 1. It is not an isolated supply (which would make the low voltage wiring between the module LIVE)
    2. The OPAMP (TL074) based controller rectifies the AC and drops it to 26V which is too high for the Trinket's Bat input (which up to 16V)
The current as measured by the Fluke meter is as follows for "no-load" ("no load" means no coffee; consumption due to losses in belt and wheels and bearings is still there and substantial!):

Note the RMS on the top left. Zero A is where the "A-" mark is on the left of the screen (so while it looks AC current actually flows in one direction).

And for full grinder load (note that the mA/div has changed):


Since the no-load consumption was ~336mA RMS and full load was over 1A RMS I chose a threshold of 400mA RMS. With a power down timer this threshold ensures that every last bean is ground before the motor is stopped.

Trinket Pin Assignments:
  • 5V or USB+ - +5VDC from Power Supply
    GND - Ground from Power Supply
    #3, RST, Bat+ - N/C
    #4 - ACS712 Output (Analog A2 input)
    #2 - Switch to trigger power (used for INT0)
    #0 - Relay module to motor driver - inverse logic
    5V - Power to ACS712 Module and Relay output module
The schematic:

Note: Pick a value for R where the brightness of the LED will be to your liking - but not so high as to fry the LED with excess current.

Implemented in the grinder this is what it looks like (warning: these are modules so rats nest wiring below):


In keeping with the "fully reversible hack" philosophy, the Cherry lever switch is mounted using a sturdy plastic version of Velcro. It does the job well.


The LED serves a useful diagnostic purpose: the brightness is proportional to the motor current. It is mounted on an LED raiser block affixed with double sided adhesive (reversible - Yay!):



AVR code for the project (updated 2/4/2015):
/*
Versalab M3 Grinder Controller (based on ATtiny85)
Ver 1.1

For use with optional hopper (required).

Operation:
1. Hopper slide activates grind (using microswitch)
2. Motor current is monitored to sense when grinding is complete
3. Optional eggdrop function clears the grinder funnel by pulsing the motor
4. System sleeps waiting for the next trigger

See [url=/grinders/automating-versalab-m3-t34196.html]Automating the Versalab M3[/url] for more information, wiring diagrams and important safety notices.
*/

// We need these for sleep and power management
#include <avr/power.h>
#include <avr/sleep.h>

  /*
  Trinket Pin Assignments:
  USB+ - +5VDC from Power Supply
  GND  - Ground from Power Supply
  #3, RST, Bat+ - N/C
  #4 - ACS712 Output (Analog A2 input)
  #2 - Switch to trigger power
  #0 - Relay module to motor driver - inverse logic
  5V   - Power to ACS712 Module and Relay output module 
  */

// Settings  
#define LED 01 // Onboard LED PWM Control (LED shows current through motor)
#define MOTOR 00 // Pin #0 for Relay Output Module
#define SW 02 // Pin #2 for interrupt trigger input
#define THRESHOLD 400 // Versalab Grinder motor takes about 330mA without beans. So 400mA will be our threshold - Assumption: Grinding current is in the 500-1300mA
#define DELAY_ON 3 // delay in seconds before motor stops
#define DELAY_OFF 2 // delay in seconds before motor stops
#define EGG_DROPS 2 // # of times eggs are dropped after a grind (set to 0 to disable)
#define EGG_DROP_TIME 750 // Off time for an egg to drop in mSec

// ACS712x20A current sensor module input on the pin labelled #4 which is actually A/D input pin #2 (confusing a bit but refer to ATTiny85 datasheet) 
const int CurrentAnalogPin = 2;         // associated analog pin number to use with analogRead()
const int adc_zero = 509;// relative digital zero of the arudino input from ACS712 (could make this a variable and auto-adjust it)
const int current_factor = 50000 / 1023 ; // ACS712 EC20A: 50,000 mA to 5V ratio for 1023 count ADC

// RMS calculation timing from http://forum.arduino.cc/index.php?topic=179541.15
const unsigned long sampleTime = 100000UL;                           // sample over 100ms, it is an exact number of cycles for both 50Hz and 60Hz mains
const unsigned long numSamples = 250UL;                               // choose the number of samples to divide sampleTime exactly, but low enough for the ADC to keep up
const unsigned long sampleInterval = sampleTime/numSamples;  // the sampling interval, must be longer than then ADC conversion time

// Various counters
int egg_counter = 0;
volatile int delayLeft = 0;       // initialize state to 'off' (when delayLeft=0 motor is off) (Volatile for interrupt)
unsigned long last_second; // Used for timer delay

void setup() {
  pinMode(LED, OUTPUT);
  pinMode(SW, INPUT);
  digitalWrite(SW, HIGH); // Pullup resistor
  pinMode(MOTOR, OUTPUT);
  digitalWrite(MOTOR, HIGH );   // Inverted control (HIGH = OFF)
 };

//Measure the current, display on LED and calculate and return the RMS value of the current over 100mSec
int SampleRMS(){
  unsigned long currentAcc = 0;
  unsigned int count = 0;
  unsigned long prevMicros = micros() - sampleInterval ;
  while (count < numSamples){
    if (micros() - prevMicros >= sampleInterval){
      int adc_raw = abs(analogRead(CurrentAnalogPin) - adc_zero);  // Since zero amp is at ~ half voltage 2.5V output of the ACS712 
      analogWrite(LED, adc_raw/4);                                 // Analog ammeter using the LED
      currentAcc += (unsigned long)(adc_raw * adc_raw);            // RMS calculation
      ++count;
      prevMicros += sampleInterval;}}
  float SampleRMS = sqrt((float)currentAcc/(float)numSamples);
return SampleRMS;}

//Now grinding
void grind(){
last_second = millis();
egg_counter = 0;
while (delayLeft > 0){ // If delayLeft > 0 means motor should be on
    digitalWrite(MOTOR, LOW); //Power motor on
    while(SampleRMS() * current_factor > THRESHOLD){// Factor output to read in mA      
      ++egg_counter;
      delayLeft = DELAY_OFF; 
      last_second = millis();}
    if (millis() - last_second >= 1000){ 
    last_second = millis();
     --delayLeft;}}
digitalWrite(MOTOR, HIGH);
analogWrite(LED, 0);}

//Drop eggs
void eggdrop(){
egg_counter = EGG_DROPS;
for(int i = 0; i < egg_counter; i++){
  delay(EGG_DROP_TIME);
  digitalWrite(MOTOR, LOW); //Power motor on
  while (SampleRMS() * current_factor > THRESHOLD) digitalWrite(MOTOR, LOW);
  analogWrite(LED, 0);
  digitalWrite(MOTOR, HIGH);}}         

// Interrupt Service Handler
void pin2_isr_grind(){delayLeft = DELAY_ON;}

void loop(){
// Main function here is sleep while waiting for switch... See  http://playground.arduino.cc/Learning/ArduinoSleepCode
noInterrupts();
sleep_enable();
power_all_disable ();   
set_sleep_mode(SLEEP_MODE_IDLE); 
attachInterrupt(0, pin2_isr_grind, FALLING);
interrupts();
sleep_cpu();
//Now sleeping...
sleep_disable();
power_all_enable ();   
grind();
if((egg_counter > 4) && (EGG_DROPS > 0)) eggdrop();} //drop Versalab eggs (leftover coffee)
Enjoy.
Scraping away (slowly) at the tyranny of biases and dogma.

User avatar
AssafL (original poster)
Posts: 2588
Joined: 14 years ago

#2: Post by AssafL (original poster) »

Please note: This project "hack" was performed on a 230V grinder. The motor is the same so theoretically the it should work for 110V. However, it is likely to require some threshold changes (in software) to compensate for different voltage/current readings.
Scraping away (slowly) at the tyranny of biases and dogma.

cebseb
Posts: 567
Joined: 9 years ago

#3: Post by cebseb »

This is incredible. I like to tinker as much as the next guy, but this is beyond me. I would just like to applaud your efforts.

Slow clap

Sebastian

User avatar
AssafL (original poster)
Posts: 2588
Joined: 14 years ago

#4: Post by AssafL (original poster) »

Thank you for the kind words. This isn't a difficult project but since we are dealing with high DC and AC voltages - it is mainly for tinkerers comfortable and experienced around mains wiring and non-isolated power supplies.

For example (and this is critical): be extraordinarily cautious if you use a scope to probe around the circuit since the PCB is ground referenced. If unsure see this: http://www.eevblog.com/2012/05/18/eevbl ... illoscope/

To measure current I used a sensitive Fluke i80-110s current clamp (which does DC/AC low current very well and accurately). By virtue of being a clamp, it is isolated from mains. The scope I use is a Fluke Scopemeter which is isolated as well. So I have to exercise care probing around but no-where as much as if I has a grounded scope.

A word of caution and encouragement for owners of other grinders:
The circuit is isolated. The ACS712 is a hall effect device isolated to 1000V or so. The output relay is isolated. So there should be no problem doing something similar for other grinders.

That is if it makes logical sense - e.g. if you always measure the bean weight before throwing them in the hopper it might make sense... Otherwise it will grind everything in the hopper (BTW - you may add a timer to the software but will have to add a way to control it).

A caution: All the constants in the software are set up for the Bodine motor used in the Versalab which is DC pulse regulated for speed. You will need other constants if you -
1. Use a different motor (AC motor, different DC motors, 3~ AC motors, etc.)
2. Different version of ACS712 (there is a 5A and 30A versions as well as the 20A)

I annotated the software so it should be clear which part does what and modify it for any sort of device you may have.
Scraping away (slowly) at the tyranny of biases and dogma.

User avatar
AssafL (original poster)
Posts: 2588
Joined: 14 years ago

#5: Post by AssafL (original poster) »

Updated source code for better interrupt handling and better annotation.
Scraping away (slowly) at the tyranny of biases and dogma.