Hello All,
I'll try to explain what I'm wanting to do, and what I'll be using.
I have built my own 3D Printer's and used RAMPS/RAMBO boards to upload and tweak Marlin software using the Arduino IDE.
I want to drive a laser to cut from point-A to point-B. over and over again from same point-A to same point-B.
The steps, as I see it are:
Get signal from micro-switch - move laser from home (XY) to Point-A (XY)
Set stepper motor speed - turn ON laser
Move laser to point-b (XY) @ stepper motor speed - turn OFF laser
Return laser to home (XY) and wait for signal from micro-switch.
I plan on using an EleksMaker Mana SE V3.2 2-axis Stepper Motor Controller Driver Board and the GRBL-Master software.
So, my question (finally) is, does this seem like an OK plan? Is there a simpler way to go about this? Can anyone point in a direction (YouTube, blog post, forum post, instructable) that will get me started?
Either Marlin or GRBL should be able to accept the GCODE commands to do what you want. Moving is the 'G0' command where you optionally specify X, Y, Z, and F (feedrate). Drawing is done with the 'G1' command which has the same arguments. If you have limit switches you can auto-home.
After much research, and a few questions on some other forums, I have decided to program my Arduino using no installed CNC software, just a stepper motor library. So, to that end can someone point me to some code that moves the X motor and Y motor in plus directions then in negative directions until the two limit switches are hit; essentially "homing" the laser? I assumed it was in the Marlin software somewhere, but I couldn't find it.
// Move until you hit the switch
while (digitalRead(LimitSwitchPin) != LOW)
{
StepTowardsTheLimitSwitch();
delay(10); // About 100 steps per second
}
// back off 100 steps
for (int i=0; i < 100; i++)
{
StepAwayFromTheLimitSwitch();
delay(10); // About 100 steps per second
}
// Approach the switch slowly until it closes
while (digitalRead(LimitSwitchPin) != LOW)
{
StepTowardsTheLimitSwitch();
delay(200); // About 5 steps per second
}
// Step away until it opens
while (digitalRead(LimitSwitchPin) == LOW)
{
StepAwayFromTheLimitSwitch();
delay(500); // About 2 steps per second
}
John,
Thank you very much, I really appreciate it.
Ok, one more round of questions before I put some actual code together for you all to critique.
Thanks to John, I have my homing code. What I would like help with now is when programming any of my 3D printers I using the Marlin software so something like:
MoveTo(X135 Y300) made sense, but using the Stepper.h library I obviously don’t have those types of options, so, has anyone come up with something like:
const int stepPin_X = 3; // Step
const int dirPin_X = 2; // Direction
const int stepPin_Y = 5; // Step
const int dirPin_Y = 4; // Direction
const int STEPS_PER_REV = 3200;
const int STEPS_PER_MM = 3200/654; Or whatever the actual division works out to be.
Stepper myStepper_X(STEPS_PER_MM * 135, 3, 2);
Stepper myStepper_Y(STEPS_PER_MM * 300, 5, 4);
Sorry for the Non-Code here I’m just trying to understand how to go about this and move forward.
After reading Robin2’s great post on stepper motors; Ideally I would want to just use the Stepper library and a board using two A4988 drivers.
The Stepper library does not work with step/dir type drivers (ie. A4988). Use the AccelStepper library or use Robin2's simple stepper code tutorial to write your own code.
I would use grbl controller and gcode. There is a version of grbl for lasers.
If you want (for example) to cut a diagonal then your code will need to ensure that the two stepper motors start and stop at the same time even though they meed to move different numbers of steps.
I have written a short Arduino program for my Mega and RAMPS shield to control a small CNC mill. I interpret the GCode with a Python program on my PC. That was much easier than trying to write very tight Arduino code to interpret GCode and still give the desired step performance.
The stepper-libaries are made for single axis-movement.
For moving in an area = X and Y-ccordinate the pulses of the two stepper-motors have to be timely coordinated to each other.
Of course you can write code for this from scratch using the bresenham-algorithm.
As you described your goal as move from point A (X , Y) to point B (X , Y) back and forth
using GRBL the G-code looks as simple as that
For such a simple objective, you could certainly use GRBL, or your own home-brew functions or library based code, but if I was doing it, I’d just use three instances of a simple stepper object (for 3 axes), and maintain two variables for each motor...
CurrentPosition, and TargetPosition.
In the main loop, you can manage the button(s), laser, limits, homing and other runtime capabilities... speed, ramping and interpolation of angles, arcs etc.
Not so hard with the right hardware, and a great learning project.
As you get to understand what you’re doing, you can add extra features like stored paths etc... eventually your own GRBL !
I'll be working on one motor (X) at a time and then work on the other.
Working on the limit switch now (Thanks John).
The way I see it is that I can connect a digital pin, through a NO micro-switch, to Gnd OR to 5v. would there be any advantage to using one way rather than the other?
normally closed could be used to detect a broken wire. Because the only situation where signal changes would be switch is "pressed" because of referencing.
While you’re there thinking about one or multiple motors, look into array[]s, then once you’ve got object[0], working it’s almost trivial to expand for ‘n’ motors.
N/C switches, with pull-up - has advantages, because you can use that to help identify broken switches or wiring, then fall safe (stop) — StefanL38 beat me !
Ok, I've made a lot of progress and this code works:
#include <Stepper.h>
/*
Muggs
*/
// Define Constants
const int X_Home = 6; // Set X-Home limit switch to pin 6
const int Y_Home = 7; // Set Y-Home limit switch to pin 7
const int Trg_1 = 8; // Set/initiate switch to pin 8
const int Trg_2 = 9; // Set/initiate switch to pin 9
const int Home_Speed = 3000;// Set speed at which motor moves to the Home position
const int Move_Speed = 1500;// Set speed at which motor moves to position
const int Cut_Speed = 200;// Set speed at which LASER makes cut
// Connections to A4988
const int X_stepPin = 3; // X Step
const int X_dirPin = 2; // X Direction
const int Y_stepPin = 5; // Y Step
const int Y_dirPin = 4; // Y Direction
// Motor steps per rotation
const int STEPS_PER_REV = 200;
const int MM = STEPS_PER_REV / 40;
// Define Variables
boolean hasRun = false;
int sensorValue_X = digitalRead(X_Home);
int sensorValue_Y = digitalRead(Y_Home);
void setup() {
Serial.begin(9600);
pinMode(X_stepPin, OUTPUT);
pinMode(X_dirPin, OUTPUT);
pinMode(Y_stepPin, OUTPUT);
pinMode(Y_dirPin, OUTPUT);
pinMode(X_Home, INPUT_PULLUP);
pinMode(Y_Home, INPUT_PULLUP);
pinMode(Trg_1, INPUT_PULLUP);
pinMode(Trg_2, INPUT_PULLUP);
hasRun = false;
Home();
}
void loop() {
Serial.println(sensorValue_X);
Serial.println(sensorValue_Y);
if (digitalRead(Trg_1) == LOW) {
Move_X(13);// Move to position X13mm from 0
Move_Y(2); // Move to position Y2mm from 0
// Turn on LASER
Move_Y(22);// Move to position Y24mm from 0
}
if (digitalRead(Trg_2) == LOW) {
Move_X(13);// Move to position X13mm from 0
Move_Y(141);// Move to position Y141mm from 0
// Turn on LASER
Move_Y(22);// Move to position Y163mm from 0
}
}
void Home() {
// Move until you hit the switch
while (digitalRead(X_Home) != LOW)
{
StepTowards_X_Switch();
}
// back off 20 steps
for (int xi = 0; xi < 20; xi++)
{
StepAwayFrom_X_Switch();
}
// Approach the switch slowly until it closes
while (digitalRead(X_Home) != LOW)
{
StepTowards_X_Switch();
delay(10);
}
while (digitalRead(Y_Home) != LOW)
{
StepTowards_Y_Switch();
}
// back off 20 steps
for (int yi = 0; yi < 20; yi++)
{
StepAwayFrom_Y_Switch();
}
// Approach the switch slowly until it closes
while (digitalRead(Y_Home) != LOW)
{
StepTowards_Y_Switch();
delay(10);
}
hasRun = true;
}
void StepTowards_X_Switch() {
digitalWrite(X_dirPin, LOW);
digitalWrite(X_stepPin, HIGH);
delayMicroseconds(Home_Speed);
digitalWrite(X_stepPin, LOW);
delayMicroseconds(Home_Speed);
}
void StepTowards_Y_Switch() {
digitalWrite(Y_dirPin, HIGH);
digitalWrite(Y_stepPin, HIGH);
delayMicroseconds(Home_Speed);
digitalWrite(Y_stepPin, LOW);
delayMicroseconds(Home_Speed);
}
void StepAwayFrom_X_Switch() {
digitalWrite(X_dirPin, HIGH);
digitalWrite(X_stepPin, HIGH);
delayMicroseconds(Home_Speed);
digitalWrite(X_stepPin, LOW);
delayMicroseconds(Home_Speed);
}
void StepAwayFrom_Y_Switch() {
digitalWrite(Y_dirPin, LOW);
digitalWrite(Y_stepPin, HIGH);
delayMicroseconds(Home_Speed);
digitalWrite(Y_stepPin, LOW);
delayMicroseconds(Home_Speed);
}
void Move_X(int x) {
int t = 0;
while (t < x) {
for (int i = 0; i < MM; i++) {
digitalWrite(X_dirPin, HIGH);
digitalWrite(X_stepPin, HIGH);
delayMicroseconds(Move_Speed);
digitalWrite(X_stepPin, LOW);
delayMicroseconds(Move_Speed);
}
t++;
}
}
void Move_Y(int x) {
int t = 0;
while (t < x) {
for (int i = 0; i < MM; i++) {
digitalWrite(Y_dirPin, LOW);
digitalWrite(Y_stepPin, HIGH);
delayMicroseconds(Move_Speed);
digitalWrite(Y_stepPin, LOW);
delayMicroseconds(Move_Speed);
}
t++;
}
}
BUT, things seem a little weird. If I home the machine and press either Trg_1 or Trg_2, the machine moves as expected, however after a second or two the Y motor "jumps"; like it was stuck in between steps! Also, sometimes Y motor will get pulses but not move and a little "push" gets things going.
I've adjusted the A4988 voltage and I'll be swapping out the Y's A4988 for another one just as another check. I'm pretty sure the issues are on the hardware side of things, but I thought I would have you more experienced peeps look over my code to be sure there's not some glaring problem.
Thanks again,
Muggs
Muggs:
the machine moves as expected, however after a second or two the Y motor "jumps"; like it was stuck in between steps! Also, sometimes Y motor will get pulses but not move and a little "push" gets things going.
Sounds like your Y motor doesn't have enough power to overcome friction.
Thanks John. So this is weird! While trying the tried and true "sounds good" method of setting the A4988 driver voltage, I made a simple (HAH!) program to get the motor to run one direction for a time then move the other direction for a time; essentially repeating back and forth.
However this code randomly makes the X_dirPin High OR Low and then keeps it that way. I'm sorry, but I don't understand why it's not "flip-flopping".
#include <Stepper.h>
/*
Muggs
*/
// Define Constants
const int X_Home = 6; // Set X-Home limit switch to pin 6
const int Y_Home = 7; // Set Y-Home limit switch to pin 7
const int Trg_1 = 8; // Set/initiate switch to pin 8
const int Trg_2 = 9; // Set/initiate switch to pin 9
const int Home_Speed = 2000;// Set speed at which motor moves to the Home position
const int Move_Speed = 1500;// Set speed at which motor moves to position
const int Cut_Speed = 200;// Set speed at which LASER makes cut
// Connections to A4988
const int X_stepPin = 3; // X Step
const int X_dirPin = 2; // X Direction
const int Y_stepPin = 5; // Y Step
const int Y_dirPin = 4; // Y Direction
// Motor steps per rotation
const int STEPS_PER_REV = 200;
const int MM = STEPS_PER_REV / 40;
// Define Variables
int sensorValue_X = digitalRead(X_dirPin);
int sensorValue_Y = digitalRead(Y_Home);
void setup() {
Serial.begin(9600);
pinMode(X_Home, INPUT_PULLUP);
pinMode(Y_Home, INPUT_PULLUP);
}
void loop() {
// for (int i = 0; i < 20; i++) {
digitalWrite(X_dirPin, LOW);
// digitalWrite(X_stepPin, HIGH);
// delayMicroseconds(Move_Speed);
// digitalWrite(X_stepPin, LOW);
// delayMicroseconds(Move_Speed);
// }
Serial.print("LOW?");
Serial.println(sensorValue_X);
delay(1000);
// for (int i = 0; i < 20; i++) {
digitalWrite(X_dirPin, HIGH);
// digitalWrite(X_stepPin, HIGH);
// delayMicroseconds(Move_Speed);
// digitalWrite(X_stepPin, LOW);
// delayMicroseconds(Move_Speed);
// }
Serial.print("HIGH?");
Serial.println(sensorValue_X);
delay(1000);
// digitalWrite(Y_dirPin, LOW);
// digitalWrite(Y_stepPin, HIGH);
// delayMicroseconds(Move_Speed);
// digitalWrite(Y_stepPin, LOW);
// delayMicroseconds(Move_Speed);
//
// digitalWrite(Y_dirPin, HIGH);
// digitalWrite(Y_stepPin, HIGH);
// delayMicroseconds(Move_Speed);
// digitalWrite(Y_stepPin, LOW);
// delayMicroseconds(Move_Speed);
}
One time through I'll get all 1's the next all 0's, but not consistently back and forth.