-
-
Notifications
You must be signed in to change notification settings - Fork 19.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[FR] Polar kinematics for vertical CNC or plotter #5275
Comments
I have based the code off McConny's work. Configuration.h: // Uncomment the following line to enable POLARGRAPH_CNC kinematics
#define POLARGRAPH_CNC Marlin.h: #ifdef POLARGRAPH_CNC
extern float polarGRAPH_CNC_HomeY;
extern float polarGRAPH_CNC_HomeZ;
extern float polarGRAPH_CNC_PageWidth;
extern float polarGRAPH_CNC_LastA;
extern float polarGRAPH_CNC_LastB;
extern float polarGRAPH_CNC_LastC;
#endif Planner.cpp: #ifdef POLARGRAPH_CNC
float aPos = sqrt(x*x + y*y);
float bPos = sqrt(sq(POLARGRAPH_CNC_PageWidth - x) + y*y);
float cPos = z
/*
SERIAL_PROTOCOLPGM("X:");
SERIAL_PROTOCOL(x);
SERIAL_PROTOCOLPGM(" Y:");
SERIAL_PROTOCOL(y);
SERIAL_PROTOCOLPGM(" Z:");
SERIAL_PROTOCOL(z);
SERIAL_PROTOCOLPGM(" A:");
SERIAL_PROTOCOL(aPos);
SERIAL_PROTOCOLPGM(" B:");
SERIAL_PROTOCOL(bPos);
SERIAL_PROTOCOLPGM(" C:");
SERIAL_PROTOCOL(cPos);
SERIAL_PROTOCOLPGM(" LA:");
SERIAL_PROTOCOL(POLARGRAPH_CNC_LastA);
SERIAL_PROTOCOLPGM(" LB:");
SERIAL_PROTOCOL(POLARGRAPH_CNC_LastB);
SERIAL_PROTOCOLPGM(" LC:");
SERIAL_PROTOCOL(POLARGRAPH_CNC_LastC);
*/
target[X_AXIS] = lround((aPos - POLARGRAPH_CNC_LastA)*axis_steps_per_unit[X_AXIS]);
target[Y_AXIS] = lround((bPos - POLARGRAPH_CNC_LastB)*axis_steps_per_unit[Y_AXIS]);
target[Z_AXIS] = lround((cPos - POLARGRAPH_CNC_LastC)*axis_steps_per_unit[Z_AXIS]);
position[X_AXIS] = 0;
position[Y_AXIS] = 0;
position[Z_AXIS] = 0;
POLARGRAPH_CNC_LastA = aPos;
POLARGRAPH_CNC_LastB = bPos;
POLARGRAPH_CNC_LastC = cPos;
/*
SERIAL_PROTOCOLPGM(" TX:");
SERIAL_PROTOCOL(target[X_AXIS]);
SERIAL_PROTOCOLPGM(" TY:");
SERIAL_PROTOCOL(target[Y_AXIS]);
SERIAL_PROTOCOLPGM(" TZ:");
SERIAL_PROTOCOL(target[Z_AXIS]);
SERIAL_PROTOCOL("\n");
*/
#endif Marlin_main.cpp: #ifdef POLARGRAPH_CNC
float POLARGRAPH_CNC_HomeY = 250;
float POLARGRAPH_CNC_HomeZ = 0;
float POLARGRAPH_CNC_PageWidth = 840;
float POLARGRAPH_CNC_LastA;
float POLARGRAPH_CNC_LastB;
float POLARGRAPH_CNC_LastC;
void POLARGRAPH_CNC_Home(float homeY, float homeZ) {
POLARGRAPH_CNC_HomeY = homeY;
POLARGRAPH_CNC_HomeZ = homeZ;
float x = POLARGRAPH_CNC_PageWidth / 2;
float y = POLARGRAPH_CNC_HomeY;
float z = POLARGRAPH_CNC_HomeZ;
current_position[X_AXIS] = x;
current_position[Y_AXIS] = y;
current_position[Z_AXIS] = z;
float aPos = sqrt(x*x + y*y);
float bPos = sqrt(sq(POLARGRAPH_CNC_PageWidth - x) + y*y);
float cPos = z
long a = lround(aPos*axis_steps_per_unit[X_AXIS]);
long b = lround(bPos*axis_steps_per_unit[Y_AXIS]);
long c = lround(cPos*axis_steps_per_unit[Z_AXIS]);
st_set_position(a, b, c, 0);
POLARGRAPH_CNC_LastA = aPos;
POLARGRAPH_CNC_LastB = bPos;
POLARGRAPH_CNC_LastC = cPos;
}
void POLARGRAPH_CNC_Width(float value) {
POLARGRAPH_CNC_PageWidth = value;
POLARGRAPH_CNC_Home(POLARGRAPH_CNC_HomeY);
POLARGRAPH_CNC_Home(POLARGRAPH_CNC_HomeZ);
}
void POLARGRAPH_CNC_SegmentLine(float x2, float y2, float z2) {
float x1 = current_position[X_AXIS];
float y1 = current_position[Y_AXIS];
float z1 = current_position[Z_AXIS];
float dx = x2 - x1;
float dy = y2 - y1;
float dz = z2 - z1;
float x = x1;
float y = y1;
float z = z1;
float steps = fabs(dx);
if (fabs(dy) > steps)
steps = fabs(dy);
dx = dx / steps;
dy = dy / steps;
dz = dz / steps;
// Com::print("seg line ");
// Com::print((int)steps);
// Com::print("\n ");
for (int s = 0; s<steps - 1; s++) {
x += dx;
y += dy;
z += dz;
destination[X_AXIS] = x;
destination[Y_AXIS] = y;
destination[Z_AXIS] = z;
prepare_move();
}
destination[X_AXIS] = x2;
destination[Y_AXIS] = y2;
destination[Z_AXIS] = z2;
prepare_move();
}
#endif
#ifdef POLARGRAPH_CNC
polarGRAPH_CNC_Home(250);
#endif
#ifdef POLARGRAPH_CNC
polarGRAPH_CNC_SegmentLine(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS]);
#else
prepare_move();
#endif
#ifdef POLARGRAPH_CNC
case 1: {
if (code_seen('Y')) {
POLARGRAPH_CNC_Home(code_value());
}
}
case 4: {
if (code_seen('X')) {
POLARGRAPH_CNC_Width(code_value());
}
}
#endif
#ifdef POLARGRAPH_CNC
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply / 60 / 100.0, active_extruder);
#endif
#if ! (defined DELTA || defined SCARA || defined POLAR || defined POLARGRAPH_CNC)
// Do not use feedmultiply for E or Z only moves
if( (current_position[X_AXIS] == destination [X_AXIS]) && (current_position[Y_AXIS] == destination [Y_AXIS])) {
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
}
else {
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60/100.0, active_extruder);
}
#endif // !(DELTA || SCARA || POLARGRAPH_CNC) |
@tilkor Some context seems to be missing in the last set of code for Also, is the |
Here is the code as it would need to be updated, style-wise, for the latest Marlin codebase: Configuration.h: // Uncomment the following line to enable POLARGRAPH_CNC kinematics
#define POLARGRAPH_CNC Conditionals_post.h: #define IS_KINEMATIC (ENABLED(DELTA) || IS_SCARA || ENABLED(POLAR) || ENABLED(POLARGRAPH_CNC)) Marlin.h: #if ENABLED(POLARGRAPH_CNC)
extern float polarGRAPH_CNC_PageWidth,
polarGRAPH_CNC_LastA,
polarGRAPH_CNC_LastB,
polarGRAPH_CNC_LastC;
#endif Planner.cpp: #if ENABLED(POLARGRAPH_CNC)
const float aPos = HYPOT(x, y),
bPos = HYPOT(POLARGRAPH_CNC_PageWidth - x, y),
cPos = z;
/*
SERIAL_PROTOCOLPGM("X:");
SERIAL_PROTOCOL(x);
SERIAL_PROTOCOLPGM(" Y:");
SERIAL_PROTOCOL(y);
SERIAL_PROTOCOLPGM(" Z:");
SERIAL_PROTOCOL(z);
SERIAL_PROTOCOLPGM(" A:");
SERIAL_PROTOCOL(aPos);
SERIAL_PROTOCOLPGM(" B:");
SERIAL_PROTOCOL(bPos);
SERIAL_PROTOCOLPGM(" C:");
SERIAL_PROTOCOL(cPos);
SERIAL_PROTOCOLPGM(" LA:");
SERIAL_PROTOCOL(POLARGRAPH_CNC_LastA);
SERIAL_PROTOCOLPGM(" LB:");
SERIAL_PROTOCOL(POLARGRAPH_CNC_LastB);
SERIAL_PROTOCOLPGM(" LC:");
SERIAL_PROTOCOL(POLARGRAPH_CNC_LastC);
*/
target[X_AXIS] = lround((aPos - POLARGRAPH_CNC_LastA) * axis_steps_per_unit[X_AXIS]);
target[Y_AXIS] = lround((bPos - POLARGRAPH_CNC_LastB) * axis_steps_per_unit[Y_AXIS]);
target[Z_AXIS] = lround((cPos - POLARGRAPH_CNC_LastC) * axis_steps_per_unit[Z_AXIS]);
position[X_AXIS] = position[Y_AXIS] = position[Z_AXIS] = 0;
POLARGRAPH_CNC_LastA = aPos;
POLARGRAPH_CNC_LastB = bPos;
POLARGRAPH_CNC_LastC = cPos;
/*
SERIAL_PROTOCOLPGM(" TX:");
SERIAL_PROTOCOL(target[X_AXIS]);
SERIAL_PROTOCOLPGM(" TY:");
SERIAL_PROTOCOL(target[Y_AXIS]);
SERIAL_PROTOCOLPGM(" TZ:");
SERIAL_PROTOCOL(target[Z_AXIS]);
SERIAL_PROTOCOL("\n");
*/
#endif Marlin_main.cpp: #if ENABLED(POLARGRAPH_CNC)
float POLARGRAPH_CNC_HomeY = 250,
POLARGRAPH_CNC_HomeZ = 0,
POLARGRAPH_CNC_PageWidth = 840,
POLARGRAPH_CNC_LastA,
POLARGRAPH_CNC_LastB,
POLARGRAPH_CNC_LastC;
void POLARGRAPH_CNC_Home(const float &homeY, const float &homeZ) {
POLARGRAPH_CNC_HomeY = homeY;
POLARGRAPH_CNC_HomeZ = homeZ;
const float x = POLARGRAPH_CNC_PageWidth * 0.5,
y = POLARGRAPH_CNC_HomeY,
z = POLARGRAPH_CNC_HomeZ;
current_position[X_AXIS] = x;
current_position[Y_AXIS] = y;
current_position[Z_AXIS] = z;
float aPos = HYPOT(x, y),
bPos = HYPOT(POLARGRAPH_CNC_PageWidth - x, y),
cPos = z;
long a = lround(aPos * axis_steps_per_unit[X_AXIS]),
b = lround(bPos * axis_steps_per_unit[Y_AXIS]),
c = lround(cPos * axis_steps_per_unit[Z_AXIS]);
stepper.set_position(a, b, c, 0);
POLARGRAPH_CNC_LastA = aPos;
POLARGRAPH_CNC_LastB = bPos;
POLARGRAPH_CNC_LastC = cPos;
}
void POLARGRAPH_CNC_Width(const float &value) {
POLARGRAPH_CNC_PageWidth = value;
POLARGRAPH_CNC_Home(POLARGRAPH_CNC_HomeY);
POLARGRAPH_CNC_Home(POLARGRAPH_CNC_HomeZ);
}
void POLARGRAPH_CNC_SegmentLine(const float &x2, const float &y2, const float &z2) {
const float x1 = current_position[X_AXIS],
y1 = current_position[Y_AXIS],
z1 = current_position[Z_AXIS];
float dx = x2 - x1, dy = y2 - y1, dz = z2 - z1, x = x1, y = y1, z = z1;
const float steps = fabs(dx);
NOLESS(steps, fabs(dy));
dx /= steps;
dy /= steps;
dz /= steps;
// Com::print("seg line ");
// Com::print((int)steps);
// Com::print("\n ");
for (int s = 0; s < steps - 1; s++) {
x += dx;
y += dy;
z += dz;
destination[X_AXIS] = x;
destination[Y_AXIS] = y;
destination[Z_AXIS] = z;
prepare_move_to_destination();
}
destination[X_AXIS] = x2;
destination[Y_AXIS] = y2;
destination[Z_AXIS] = z2;
prepare_move_to_destination();
}
#endif // POLARGRAPH_CNC
#if ENABLED(POLARGRAPH_CNC)
polarGRAPH_CNC_Home(250);
#endif
#if ENABLED(POLARGRAPH_CNC)
polarGRAPH_CNC_SegmentLine(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS]);
#else
prepare_move_to_destination();
#endif
#if ENABLED(POLARGRAPH_CNC)
case 1: { if (code_seen('Y')) POLARGRAPH_CNC_Home(code_value()); }
case 4: { if (code_seen('X')) POLARGRAPH_CNC_Width(code_value()); }
#endif
#if ENABLED(POLARGRAPH_CNC)
planner.buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], MMS_SCALED(feedrate), active_extruder);
#endif
#if !IS_KINEMATIC
// Do not use feedmultiply for E or Z only moves
if (current_position[X_AXIS] == destination[X_AXIS] && current_position[Y_AXIS] == destination[Y_AXIS])
planner.buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], MMM_TO_MMS(feedrate), active_extruder);
else
planner.buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], MMS_SCALED(feedrate), active_extruder);
#endif // !(DELTA || SCARA || POLARGRAPH_CNC) |
I hope this helps. Planner.cpp code goes under, Marlin_main.cpp code Routines, starting at line 440 #ifdef POLARGRAPH_CNC
float POLARGRAPH_CNC_HomeY = 250;
float POLARGRAPH_CNC_HomeZ = 0;
float POLARGRAPH_CNC_PageWidth = 840;
float POLARGRAPH_CNC_LastA;
float POLARGRAPH_CNC_LastB;
float POLARGRAPH_CNC_LastC;
.............
destination[Z_AXIS] = z2;
prepare_move();
}
#endif Under void process_commands() void process_commands()
{
unsigned long codenum; //throw away variable
char *starpos = NULL;
#ifdef ENABLE_AUTO_BED_LEVELING
float x_tmp, y_tmp, z_tmp, real_z;
#endif
if(code_seen('G'))
{
switch((int)code_value())
{
case 0: // G0
if(Stopped == false) {
get_coordinates(); // For X Y Z E F
#ifdef FWRETRACT
if(autoretract_enabled)
if( !(code_seen('X') || code_seen('Y') || code_seen('Z')) && code_seen('E')) {
float echange=destination[E_AXIS]-current_position[E_AXIS];
if((echange<-MIN_RETRACT && !retracted) || (echange>MIN_RETRACT && retracted)) { //move appears to be an attempt to retract or recover
current_position[E_AXIS] = destination[E_AXIS]; //hide the slicer-generated retract/recover from calculations
plan_set_e_position(current_position[E_AXIS]); //AND from the planner
retract(!retracted);
return;
}
}
#endif //FWRETRACT
prepare_move();
//ClearToSend();
}
break;
case 1: // G1
if(Stopped == false) {
get_coordinates(); // For X Y Z E F
#ifdef FWRETRACT
if(autoretract_enabled)
if( !(code_seen('X') || code_seen('Y') || code_seen('Z')) && code_seen('E')) {
float echange=destination[E_AXIS]-current_position[E_AXIS];
if((echange<-MIN_RETRACT && !retracted) || (echange>MIN_RETRACT && retracted)) { //move appears to be an attempt to retract or recover
current_position[E_AXIS] = destination[E_AXIS]; //hide the slicer-generated retract/recover from calculations
plan_set_e_position(current_position[E_AXIS]); //AND from the planner
retract(!retracted);
return;
}
}
#endif //FWRETRACT
#ifdef POLARGRAPH_CNC
polarGRAPH_CNC_SegmentLine(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS]);
#else
prepare_move();
#endif
//ClearToSend();
}
break;
#ifndef SCARA //disable arc support |
@tilkor Thanks. I hope some will find this useful. It would be interesting to see polar kinematics integrated into the latest code-base, but obviously that is more involved than merely the handful of changes laid out here. I've recently been working on a SCARA robot for a client, and a myriad of changes were required to support those specific kinematics throughout the code-base. I would be interested to see a video and other details about the specific machine that you are trying to support. |
I greatly appreciate your help in cleaning up the code, I am still working out all the details but this is kind of the design i had in mind. The main goal is to make it compact so when not in use it would folds up neatly against a wall with hinges along the top and a folding standoff at the bottom. The idea is to be able to cut out CAD designs from a sheet of plywood/steel using a router/plasma cutter attached to bike chains with counter weights through a step motors attached to the red squares. I want run it all a arduino/ramps setup (super cheap) with 3 nema-17 (two mounted on the back side of the red plates). I would use the Z-axis 3rd nema to control the router's cut depth as it takes passes over the design. |
There is some interest in using polar with a linear actuator to be used as a portable plasma cutter. On youtube with user AvE. https://www.youtube.com/watch?v=IllVwt6CRJQ |
I like the idea, I have not had time to work on this project recently. I have based this mostly on a pen plotter and knowing the distance between the two motors (page width). |
I was looking for info on MaslowCNC and a google search brought me here - lol Basically same idea as PenPlotter here, but a 4x8 plywood CNC router. https://www.youtube.com/watch?v=CIQC5ZyzfDM Looks like it runs it's own home-rolled FW: https://github.com/MaslowCNC/Firmware Unfortunately, because it uses DC motors with ~8k steps/rotation rotory encoders, it doesn't look like it would be a slam-dunk for porting to Marlin, even if polar kinematics were implemented unless you slap an Arduino running Misan's stepper->servo closed-loop converter software between: https://github.com/misan/dcservo Come to think of it, once 32-bit Marlin becomes commonplace, I could see Marlin actually handling the closed-loop DC servo translation directly. This would be so awesome for CNC. One can dream... :) |
Please post your question either on discord: https://discord.gg/n5NJ59y or on facebook: https://www.facebook.com/groups/2080308602206119/ |
@thinkyhead i think we can close this one again its labeled as a question and there is no activity from the OP |
yep we should be able to close this one, no activity for months |
This was a feature request for implementing the polar kinematics. Whoever put the question tag on it probably just skimmed it quickly. |
In my search for an hanging all in one V-Plotter. I wanted to make it wireless (Battery or Power-line only, or get its power from the two cables it hangs from), much easier to set up and calibrate no matter of the size of the surface. ESP3D continues figuring out the wireless part and can be added as library in Marlin. Luc is maintaining a version of Marlin 2.0 with ESP3D integrated. There is a project which has all steps needed to change in Marlin (old version) for an V-Plotter https://github.com/RickMcConney/PenPlotter Hardware: |
I've been preferring Makelangelo for hanging plotter firmware. Marlin won't be integrating plotter or additional CNC or Laser support before version 2.1, but we definitely encourage others to adapt Marlin to special hardware. |
Added in #22790 |
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Hello,
I came across an open source palorgraph/Vertical plotter style CNC mill/router (http://www.maslowcnc.com/home/) that I thought would be a nice feature to add to marlin. This style of CNC looks like it would be very easy to DIY build using a Ramps 1.4 board.
I found Rick McConny's Pen Plotter based off Marlin (https://github.com/RickMcConney/PenPlotter/tree/master/Marlin) that is the same concept just with the Z axis limited.
I am not a coder by any means so I really do not have a clue how hard it would be to add this feature in but I would greatly appreciate it if it was taken into consideration.
Thanks,
-Maslowcnc souce code (https://github.com/MaslowCNC/Firmware/tree/master/cnc_ctrl_v1)
The text was updated successfully, but these errors were encountered: