// DLP Sidewinder
// Simple dlp 3d printer interface to Creation Workshop software for step/direction step motor drivers
// Written by Henry Locke January 2014
// Use this software at your own risk //
///////////////////////////////////////////////////////
// press arduinos reset button:
// before a print run
// before homing the build platform up or down
///////////////////////////////////////////////////////
// uses Creation Workshop rc 3: http://www.buildyourownsla.com/forum/viewtopic.php?f=5&t=118
// uses AccelStepper library (http://www.airspayce.com/mikem/arduino/AccelStepper/)
// use creation workshop Default SLA machine config profile and testprof slicing profile (modified with custom commands)
// the servo code is for a shutter (for the projector) on a hobby type servo
// the accelstepper stuff is for a step/direction step motor controller
// the uvled stuff is for turning a light source such as a uv led on and off through a relay or ssr
// adjust "PlatenStepsPerLayer" to adjust the layer thickness. for example, for a 0.1mm layer thickness using a 10 mm pitch lead screw driven
// by a 200 step per revolution step motor running at 16 micosteps per step (3200 steps per revolution) you need to set PlatenStepsPerLayer to 32.
// required libraries:
// AccelStepper
// Servo (built in)
#include
Servo servo;
int servoPin = 9; // for projector shutter, connect to a hobby servo. do not power the servo from the arduino unless the arduino uses a separate power supply (do not use usb power).
#include
int motorSpeed = 1800; //maximum steps per second, z axis
int motorAccel = 1800; //steps/second/second to accelerate, z axis
int TiltDownSpeed = 400; // vat tilt down speed
int TiltDownAccel = 200; // vat tilt down acceleration
int TiltUpSpeed = 1600; // vat tilt up speed
int TiltUpAccel = 1600; // vat tilt up acceleration
int TiltMotorDirPin = 2; //digital pin 2
int TiltMotorStepPin = 3; //digital pin 3
int TiltMotorEnablePin = 4; //enable, can be ignored if no enable input on driver
//set up the accelStepper intance, the "1" tells it we are using a driver
AccelStepper TiltStepper(1, TiltMotorStepPin, TiltMotorDirPin);
int LiftMotorDirPin = 5; //digital pin 5
int LiftMotorStepPin = 6; //digital pin 6
int LiftMotorEnablePin = 7; //enable, can be ignored if no enable input on driver
//set up the accelStepper intance, the "1" tells it we are using a driver
AccelStepper LiftStepper(1, LiftMotorStepPin, LiftMotorDirPin);
#define SDATABUFFERSIZE 200
char sdataBuffer[SDATABUFFERSIZE+1]; //Add 1 for NULL terminator
byte sdataBufferIndex = 0;
boolean sstoreString = false; // flag to put the data in our buffer
#define xtop_limit 14 //A0, top limit switch pin
#define xbot_limit 15 //A1, bottom limit switch pin
#define signal_led 13 // general purpose signal, blinks on board led
#define UVLED 12 // used for projector modification light sources like uv leds
int shutterclosed = 45; // projector shutter closed angle
int shutteropen = 0; // projector shutter open angle
int SIGNALLED_OFF = LOW; // off
int SIGNALLED_ON = HIGH; // on
int UVLED_OFF = LOW; // off
int UVLED_ON = HIGH; // on
boolean printing3d = false;
boolean HomingBuildPlateTop = false;
boolean HomingBuildPlateBottom = false;
boolean RaiseBuildPlate =false;
boolean CycleLayer = false;
boolean tiltingDown = false;
boolean on_top_limit = false;
boolean on_bottom_limit = false;
unsigned long LayerCycleTimer = 0; // do not change
String LayerCycle_TIME_STRING; //do not change
// the following value is obtained from Creation Workshop in the "LIFT-SEQUENCE-TIME" message.
// This is the "Lift and Sequence Time (ms)" in Creation workshop "Slice Profile Config > Options". do not change
int LayerCycle_TIME = 0;
/////// This thickness must match the "Slice Profile Config > Options > Slice Thickness (mm)" setting in Creation Workshop /////////////////////////////////////////////////
int PlatenStepsPerLayer = 64; // steps needed for layer thickness (0.1mm at 6400 steps per revolution - using a 10mm pitch leadscrew)
//int PlatenStepsPerLayer = 32; // steps needed for layer thickness (0.1mm at 3200 steps per revolution - using a 10mm pitch leadscrew)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int StepsToRaiseLowerBuildPlate = 1200; // steps to raise/lower the build plate between exposures. I use 400 step per revolution motors microstepped times 16 for 6400 steps per revolution.
int StepsToRaiseLowerVat = 400; // steps to lower/raise the vat. I use 400 step per revolution motors microstepped times 16 for 6400 steps per revolution.
char buf[10];
char startChar = '<'; // char endChar = '\r'; char gcodeStartChar = 'G'; void setup() { // init pc serial Serial.begin(115200); Serial.flush(); // step/dir controller *************************************************** TiltStepper.setCurrentPosition(0); TiltStepper.setMaxSpeed(motorSpeed); TiltStepper.setAcceleration(motorAccel); TiltStepper.setPinsInverted(true, false, false); // adjust the direction of the tilt step motor here (dir,step,enable) pinMode(TiltMotorDirPin, OUTPUT); pinMode(TiltMotorStepPin, OUTPUT); pinMode(TiltMotorEnablePin, OUTPUT); digitalWrite(TiltMotorEnablePin, LOW); // enable controller (if controller has enable connect it to pin), set low or high or ignore depending on controller LiftStepper.setCurrentPosition(0); LiftStepper.setMaxSpeed(motorSpeed); LiftStepper.setAcceleration(motorAccel); // LiftStepper.setPinsInverted(true, false, false); // adjust the direction of the z axis step motor here(dir,step,enable) pinMode(LiftMotorDirPin, OUTPUT); pinMode(LiftMotorStepPin, OUTPUT); pinMode(LiftMotorEnablePin, OUTPUT); digitalWrite(LiftMotorEnablePin, LOW); // enable controller (if controller has enable connect it to pin), set low or high or ignore depending on controller //************************************************************************ // projector shutter (controls a hobby servo) servo.attach(servoPin); servo.write(shutterclosed); // close shutter // init the uv led to off pinMode(UVLED, OUTPUT); digitalWrite(UVLED, UVLED_OFF); // signal led pinMode(signal_led,OUTPUT); digitalWrite(signal_led,SIGNALLED_OFF); // limit switches. use pin pullup resistors pinMode(xtop_limit,INPUT); digitalWrite(xtop_limit,HIGH); pinMode(xbot_limit,INPUT); digitalWrite(xbot_limit,HIGH); } void loop() { TiltStepper.run(); // for step/dir controllers LiftStepper.run(); // for step/dir controllers while(Serial.available()>0) // get commands from Creation Workshop
{
char sincomingbyte = Serial.read();
if(sincomingbyte==startChar || sincomingbyte == gcodeStartChar)
{
sdataBufferIndex = 0; //initialize the dataBufferIndex
sstoreString = true;
}
if(sstoreString)
{
//check the serial buffer, bail if buffer overrun
if(sdataBufferIndex==SDATABUFFERSIZE){
// index is pointing to an array element outside our buffer. re init the buffer and bail
sdataBufferIndex = 0;
break;
}
if(sincomingbyte==endChar) // got a command line, parse it
{
Serial.println("ok"); //acknowlege the command
if (String(sdataBuffer).substring(1,21) == "LAYER-ON############") // only needed if using uv led or other projector mod light source
{
digitalWrite(UVLED, UVLED_ON);
}
else if (String(sdataBuffer).substring(1,21) == "LAYER-OFF-TILT-VAT##") //
{
digitalWrite(signal_led, SIGNALLED_ON);
LayerCycleTimer = millis(); // start timer for layer cycle
CycleLayer = true; // begin cycling vat and platen
servo.write(shutterclosed); // close shutter
digitalWrite(UVLED, UVLED_OFF); // only needed if using uv led
TiltStepper.setAcceleration(TiltDownAccel);
TiltStepper.moveTo(StepsToRaiseLowerVat * -1); //tilt the vat
RaiseBuildPlate = true;
}
else if (String(sdataBuffer).substring(1,19) == "LIFT-SEQUENCE-TIME") // this is how long to give the vat tilt/build plate lift sequence.
// This number is set in creation workshop > slice profile config > Options > Lift and Sequence Time (ms)
{
LayerCycle_TIME_STRING = String(sdataBuffer).substring(21,26);
LayerCycle_TIME = LayerCycle_TIME_STRING.toInt();
}
else if (String(sdataBuffer).substring(1,21) == "INIT################") // reset position, open shutter
{
printing3d = true;
TiltStepper.setCurrentPosition(0);
TiltStepper.setMaxSpeed(motorSpeed);
TiltStepper.setAcceleration(motorAccel);
LiftStepper.setCurrentPosition(0);
LiftStepper.setMaxSpeed(motorSpeed);
LiftStepper.setAcceleration(motorAccel);
servo.write(shutteropen); // open shutter
}
else if (String(sdataBuffer).substring(1,21) == "END#################") // reset position, open shutter
{
printing3d = false;
TiltStepper.setCurrentPosition(0);
LiftStepper.setCurrentPosition(0);
servo.write(shutterclosed); // close shutter
}
else if (String(sdataBuffer).substring(0,7) == "G1 Z-10") // bottom limit (vat floor)
{
if (on_bottom_limit == false) // not already on bottom limit
{
HomingBuildPlateBottom = true;
LiftStepper.setMaxSpeed(2000);
LiftStepper.setAcceleration(12000);
LiftStepper.move(-100000); // move towards bottom limit
}
}
else if (String(sdataBuffer).substring(0,6) == "G1 Z10") // top limit
{
if (on_top_limit == false) // not already on top limit
{
HomingBuildPlateTop = true;
LiftStepper.setMaxSpeed(2000);
LiftStepper.setAcceleration(12000);
LiftStepper.move(100000); // move towards top limit
}
}
sstoreString = false;
}
else
{
sdataBuffer[sdataBufferIndex++] = sincomingbyte;
sdataBuffer[sdataBufferIndex] = 0; //null terminate the C string
}
}
}
if (digitalRead(xtop_limit) == LOW and on_top_limit == false) // hit limit
{
if (printing3d == false)
{
on_top_limit = true;
LiftStepper.stop();
delay(250);
LiftStepper.moveTo(10000);
LiftStepper.setCurrentPosition(10000);
LiftStepper.setMaxSpeed(motorSpeed);
LiftStepper.setAcceleration(motorAccel);
}
}
if (digitalRead(xtop_limit) == HIGH and on_top_limit == true) // off limit
{
on_top_limit = false;
digitalWrite(signal_led,LOW);
}
if (digitalRead(xbot_limit) == LOW and on_bottom_limit == false) // hit limit
{
if (printing3d == false)
{
on_bottom_limit = true;
LiftStepper.stop();
delay(250);
LiftStepper.moveTo(0);
LiftStepper.setCurrentPosition(0);
LiftStepper.setMaxSpeed(motorSpeed);
LiftStepper.setAcceleration(motorAccel);
}
}
if (digitalRead(xbot_limit) == HIGH and on_bottom_limit == true) // off limit
{
on_bottom_limit = false;
digitalWrite(signal_led,LOW);
}
if (RaiseBuildPlate == true)
{
if (LayerCycleTimer + 2500 < millis()) //time to raise build plate (2.5 seconds after vat tilt)
{
LiftStepper.setCurrentPosition(LiftStepper.currentPosition() - PlatenStepsPerLayer);
LiftStepper.moveTo(StepsToRaiseLowerBuildPlate); // lift build
RaiseBuildPlate = false;
}
}
if (CycleLayer == true)
{
// if (TiltStepper.currentPosition() == StepsToRaiseLowerVat * -10 && tiltingDown == true)
// {
// TiltStepper.setAcceleration(TiltUpAccel);
// TiltStepper.moveTo(0); // un-tilt the vat
// tiltingDown = false;
// }
if (LayerCycleTimer + 4500 < millis()) // 4500 ms into the cycle time, time to raise vat and lower platen
{
LiftStepper.moveTo(0);
TiltStepper.setAcceleration(TiltUpAccel);
TiltStepper.moveTo(0); // un-tilt the vat
}
if (LayerCycleTimer + LayerCycle_TIME < millis()) // through the cycle time, open the shutter
{
servo.write(shutteropen); // open shutter
digitalWrite(signal_led, SIGNALLED_OFF);
CycleLayer = false; // done cycling layer
}
}
}