Nash Ali
Published © MIT

Accessories for a DIY 3018 PRO hobby CNC

Here are some of the things that you thought might be nice to have to spruce up that mill.

IntermediateShowcase (no instructions)6 hours1,189
Accessories for a DIY 3018 PRO hobby CNC

Things used in this project

Hardware components

3018 CNC Hobby Mill
×1
mini micro switch (20 pack)
Limit Micro Switch Long Hinge Lever for Arduino (Pack of 25)
×1
KeeYee's ESP32S WROOM-32
×1
OLED Display
×1
DS3231M - ±5ppm, I2C Real-Time Clock
Maxim Integrated DS3231M - ±5ppm, I2C Real-Time Clock
×1
ULN2803A
×1

Software apps and online services

Arduino IDE
Arduino IDE
Candle 1.1.7
GRBL controller software
FlatCam
PCB milling software

Hand tools and fabrication machines

Plier, Diagonal
Plier, Diagonal
Soldering Station, 110 V
Soldering Station, 110 V
Solder Wire, Lead Free
Solder Wire, Lead Free
Cable Cutter, 143mm
Cable Cutter, 143mm
Wire Stripper & Cutter, 30-10 AWG Solid & Stranded Wires
Wire Stripper & Cutter, 30-10 AWG Solid & Stranded Wires
Multitool, Screwdriver
Multitool, Screwdriver
prototype pcb

Story

Read more

Code

ESP32CNC

C/C++
This code runs on the esp32
#include <Adafruit_MLX90614.h>
#include <DS3231.h>
#include <WiFi.h>
#include <Adafruit_SSD1306.h>
#include <Wire.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

/*
   This applicatioon is an accessory to the 3018 PRO CNC (DIY Version)
   Using an esp32 WROOM-32 38 pin dev module in a side car configuration
   it provides real time spindle RPM information as well as control for
   the work table illumination and safety lighting. Also a running timer
   keeps track of job times by monitoring spindle status.(to follow).
*/

//***********************************************************************
//  DEFINES
//***********************************************************************
#define OFF 0
#define ON 1
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET    -1// Reset pin # (or -1 if sharing Arduino reset pin)
#define OLED_ADDR   0x3C
#define IR_ADDR 0x5B  //  Normally this would be 0x5A, this MLX has been fixed to 0x5B.
const char *ssid     = "******";  //  add your network SSID here
const char *password = "***********"; //  add your network password here
const long utcOffsetInSeconds = -14400;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
char months[12][4] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
bool Century = false, h12, pm;
// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);


//  GPIO Pin definitions
const int Touch8 = 33;
const int Touch9 = 32;
const int TACH_IN = 1;
const int WORK_LED = 12;
const int SPINDLE_ACTIVE_LED = 14;
const int FAN_MOTOR = 13;
const int DEMO_LED1 = 15;
const int DEMO_LED2 = 3;
const int I2C_FAST = 400000;
const int I2C_SLOW = 100000;
const int analogInPin = A0;  // ESP32 Analog Pin ADC0 = A0
bool LAMP = false;
volatile byte REV;       //  VOLATILE DATA TYPE TO STORE REVOLUTIONS
int TouchValue8, TouchValue9, RPM, UP_TIME;
int TouchThreshold = 30;
double MOTOR_VOLTAGE;
double MOTOR_TEMP;
DS3231 Clock;
Adafruit_SSD1306 display1(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_MLX90614 mlx = Adafruit_MLX90614(IR_ADDR);

byte Year;
byte Month;
byte Date;
byte DoW;
byte Hour;
byte Minute;
byte Second;

//***********************************************************************
//  FUNCTIONS
//***********************************************************************

void InitPins() {
  pinMode(TACH_IN, INPUT);
  pinMode(WORK_LED, OUTPUT);
  pinMode(DEMO_LED1, OUTPUT);
  pinMode(DEMO_LED2, OUTPUT);
  pinMode(SPINDLE_ACTIVE_LED, OUTPUT);
  digitalWrite(WORK_LED, OFF);
  digitalWrite(DEMO_LED1, OFF);
  digitalWrite(DEMO_LED2, OFF);
}

void InitDisplay() {
  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if (!display1.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) { // Address 0x3C for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for (;;); // Don't proceed, loop forever
  }
  display1.clearDisplay();
  display1.display();
  Serial.println();
  Serial.println("SSD1306 display OK and ready");
}

void InitIRSensor() {
  Wire.setClock(I2C_SLOW);
  mlx.begin();
  delay(100);
  Serial.println("IR Sensor ready");
  Wire.setClock(I2C_FAST);
}
void ReadIRSensor() {
  Wire.setClock(I2C_SLOW);
  MOTOR_TEMP = mlx.readObjectTempC();
  delay(50);
  Wire.setClock(I2C_FAST);
}
void ReadTachometer() {
  // init quarter sec timer loop - non blocking
  int CM = millis();
  int FM = millis() + 250;
  REV = 0;
  while (millis() < FM) {}
  // .5 second is up
  int COUNT = REV;
  //count ticks
  // RPM = ticks/2*240;
  RPM = (COUNT / 2) * 240;
}
void ReadVoltage() {
  double av = analogRead(analogInPin);
  MOTOR_VOLTAGE = av * .0322256;
}
void JoinNetwork() {
  WiFi.begin(ssid, password);
  while ( WiFi.status() != WL_CONNECTED ) {
    delay ( 500 );
    display1.clearDisplay();
    display1.setCursor(4, 4);
    display1.print("ETMS");
    display1.setCursor(64, 30);
    display1.print("Connecting......");
    display1.display();
  }
  timeClient.begin();
  delay(50);
  timeClient.update();
  String current_time = timeClient.getFormattedTime();
  display1.clearDisplay();
  display1.display();
  ShowWifi();
}
void InitTime() {
  Clock.setClockMode(false);  // set to 24h
  Clock.setYear(Year);
  Clock.setMonth(Month);
  Clock.setDate(Date);
  Clock.setDoW(DoW);
  Clock.setHour(Hour);
  Clock.setMinute(Minute);
  Clock.setSecond(Second);
  // Test of alarm functions
  // set A1 to one minute past the time we just set the clock
  // on current day of week.
  //Clock.setA1Time(DoW, Hour, Minute+1, Second, 0x0, true, false, false);
  // set A2 to two minutes past, on current day of month.
  //Clock.setA2Time(Date, Hour, Minute+2, 0x0, false, false, false);
  // Turn on both alarms, with external interrupt
  //Clock.turnOnAlarm(1);
  //Clock.turnOnAlarm(2);
}
void ShowTime() {
  display1.fillRect(74, 0, display1.width(), 16, WHITE);
  display1.setCursor(78, 4);
  display1.setTextColor(BLACK); // Draw black text
  display1.print(Clock.getHour(h12, pm));
  display1.print(":");
  if (Clock.getMinute() < 10) {
    display1.print("0");
  }
  display1.print(Clock.getMinute());
  display1.print(":");
  if (Clock.getSecond() < 10) {
    display1.print("0");
  }
  display1.print(Clock.getSecond());
  display1.display();
}
void ShowRibbon() {
  display1.setTextSize(1);      // Large 1:1 pixel scale
  display1.fillRect(0, 0, 74, 16, WHITE);
  display1.setTextColor(BLACK); // Draw black text
  display1.setCursor(4, 4);
  display1.print("Spindle775");
  display1.display();
}
void ShowWifi() {
  String ip = WiFi.localIP().toString();
  display1.setCursor(32, 16);
  display1.print("Wifi connected...");
  display1.setCursor(32, 32);
  display1.print("IP Address:");
  display1.setCursor(32, 48);
  display1.print(ip);
  display1.display();
  delay(2000);
  display1.clearDisplay();
  display1.display();
}
void ShowPage1() {
  Serial.print("show rpm -->");
  Serial.println(RPM);
  //send RPM to display
  display1.setTextSize(1);      // Large 1:1 pixel scale
  display1.setTextColor(WHITE); // Draw white text
  display1.setCursor(15, 20);
  display1.print("RPM:");
  display1.setCursor(60, 20);
  display1.setTextSize(2);      // Large 2:1 pixel scale for RPM value
  display1.print(RPM);
  display1.setCursor(20, 45);
  display1.setTextSize(1);      // Normal 1:1 pixel scale
  Serial.println("show motor voltage->");
  display1.print("Voltage:");
  display1.fillRect(80, 45, 127, 60, BLACK);
  display1.setCursor(80, 45);
  display1.print(MOTOR_VOLTAGE);
  display1.print(" V");
  Serial.println("show motor temperature->");
  display1.setCursor(20, 55);
  display1.print("Temp:");
  display1.fillRect(80, 55, 127, 60, BLACK);
  display1.setCursor(80, 55);
  display1.print(MOTOR_TEMP);
  display1.display();
}
void FlashLED() {
  digitalWrite(WORK_LED, ON);
  delay(750);
  digitalWrite(WORK_LED, OFF);
}
void SetWorkLight(int val) {
  if (val = 0) digitalWrite(WORK_LED, OFF);
  else digitalWrite(WORK_LED, ON);
}
void RPMCount()       // EVERYTIME WHEN THE SENSOR GOES FROM LOW TO HIGH , THIS FUNCTION WILL BE INVOKED
{
  REV++;             // INCREASE REVOLUTIONS
}
void ToggleWorkLamp() {
  Serial.print("set lamp->");
  int touch_sensor_value = touchRead(T8);
  Serial.print("Touch8 value is = ");
  Serial.println( touch_sensor_value);
  LAMP = !LAMP;
  digitalWrite(WORK_LED, LAMP);
  delay(100);
}
void setup() {
  Serial.begin(19200);
  InitPins();
  InitDisplay();
  FlashLED();
  InitIRSensor();
  JoinNetwork(); // goes online and gets Time from ntp
  //attachInterrupt(digitalPinToInterrupt(TACH_IN), RPMCount, RISING);     //  ADD A HIGH PRIORITY ACTION ( AN INTERRUPT)  WHEN THE SENSOR GOES FROM LOW TO HIGH
  touchAttachInterrupt(T8, ToggleWorkLamp, TouchThreshold);
}

void loop() {
  // put your main code here, to run repeatedly:
  ShowTime();
  ShowRibbon();
  ReadVoltage();
  //ReadTachometer();
  ReadIRSensor();
  ShowPage1();
  if (RPM > 0) FlashLED();
  delay(1000);
}

Credits

Nash Ali

Nash Ali

13 projects • 13 followers
Put together a transistor radio by "Heathkit" when I was around 10, fell in love with electronics and has been a hobby ever since.

Comments