Hello!
I'm new here, so let me introduce myself :
First, please excuse any offense to your beautiful language: I learned English in computer books, is tell you!
I have in my mind since a while a Bipod CNC, whose spindle is directly actuated by two rods in the XY plan, forming a rigid deformable triangle (Bipod configuration). The Z axis remains cartesian.
I built this way a small CNC, as a proof of concept, with full success. The driving software was LinuxCNC, whose direct and inverse kinematics modules are very suitable.
It turned out that this architecture was very relevant to making a 3D printer : very light moving parts, rigidity, precision, simplicity. As movements in Z has very different requirements from those of XY movements in a 3D Printer, I think that the Bipod architecture is well suited.
With adding some others ideas, I have now designed and built a pretty inedite 3D printer, which does almost nothing like the others, except, I hope, to put some molted plastic in some shape. The simplicity translates in very few mechanical parts, really.
More information will follow, as soon as I will be able to pass the last obstacle : The firmware.
I know I could use LinuxCNC, which runs now on BeagleBone Black thanks to the 'Machine Kit'. But all my current design, which began before the BBB, does includes a proven and cheap RAMPS / Arduino set. I thought that since many delta printers are using it, I could use it too. I hope to achieve my project this way, but LinuxCNC / BBB remains an option.
I am not as fluent in software than in hardware, so I need some guidance.
Here is a sketch of the kinematics (the Z axis is not represented) :
[attachment 20879 Bipod_1.GIF]
I intend to re-use the same strategy as the delta robots : trick the motion control algorithm by exchanging many small segments, recalculated using kinematics, instead of a single cartesian movement.
I choose Repetier (0.83), which seems to me better structured.
Hoping to make a change as surgical as possible , I set Bipod, in CONFIGURATION.h as a new drive system :
# define DRIVE_SYSTEM 4
but then reused all the delta code, amending the directives :
#if DRIVE_SYSTEM >= 3 in place of #if DRIVE_SYSTEM==3
#if DRIVE_SYSTEM < 3 in place of #if DRIVE_SYSTEM != 3, etc...
I created only the alternative 'calculate_delta' function, this way :
#if DRIVE_SYSTEM == 4
/** Set Delta rods positions
@param xaxis X arm length.
@param yaxis Y arm length.
@param zaxis no change cartesian position.
*/
inline void set_delta_position(long xaxis, long yaxis, long zaxis) {
printer_state.currentDeltaPositionSteps[0] = xaxis;
printer_state.currentDeltaPositionSteps[1] = yaxis;
printer_state.currentDeltaPositionSteps[2] = zaxis;
}
/**
Calculate the Delta arm position from a cartesian position
@param cartesianPosSteps Array containing cartesian coordinates.
@param DeltaPosSteps Result array with arm coordinates.
@returns 1 if cartesian coordinates have a valid Delta arm position 0 if not.
Conventions : Origine du systeme cartesien au centre du plateau
Origine pendant les calculs sur la charniere A (A_X_COORDINATE, A_Y_COORDINATE)
#define AB_STEPS_PER_MM 242.5218 // 4 mm shaft, 0.2 mm cable, 200 steps, 16 microsteps
#define XAXIS_STEPS_PER_MM 242.5218 // 4 mm shaft, 0.2 mm cable, 200 steps, 16 microsteps
#define YAXIS_STEPS_PER_MM 242.5218 // 4 mm shaft, 0.2 mm cable, 200 steps, 16 microsteps
#define ZAXIS_STEPS_PER_MM 377.2561 // 5 mm shaft, 0.4 mm cable, 400 steps, 16 microsteps
#define AB_MAX_LENGTH 340 // Arm's length at rear endstop
#define AB_MIN_LENGTH 110
#define A_B_HINGES_DISTANCE 235
#define A_X_COORDINATE -150 //
#define A_Y_COORDINATE -117.5 //-( A_B_HINGES_DISTANCE / 2)
#define Z_MAX 300 // Max height of prints
#define MAX_Delta_SEGMENTS_PER_LINE 30
*/
byte calculate_delta(long cartesianPosSteps[], long DeltaPosSteps[]) {
DeltaPosSteps[Z_AXIS] = cartesianPosSteps[Z_AXIS]; // Z does not change
// Changement d'origine XY pour faciliter les calculs
// L'origine est ramenee sur la charniere A
long local_X = cartesianPosSteps[X_AXIS] + A_X_COORDINATE;
long local_Y = cartesianPosSteps[Y_AXIS] + A_Y_COORDINATE;
long local_X_SQUARED = sq(local_X);
DeltaPosSteps[X_AXIS] = sqrt(local_X_SQUARED + sq(local_Y));
DeltaPosSteps[Y_AXIS] = sqrt(local_X_SQUARED + sq(A_B_HINGES_DISTANCE - local_Y));
// if ( (DeltaPosSteps[X_AXIS] >= AB_MIN_LENGTH) &&
// (DeltaPosSteps[X_AXIS] <= AB_MAX_LENGTH) &&
// (DeltaPosSteps[Y_AXIS] >= AB_MIN_LENGTH) &&
// (DeltaPosSteps[Y_AXIS] <= AB_MAX_LENGTH) )
// return 1;
// else return 0;
// DEBUG
// out.println_long_P(PSTR("* Cartesian X:"), cartesianPosSteps[X_AXIS]);
// out.println_long_P(PSTR("* Cartesian Y:"), cartesianPosSteps[Y_AXIS]);
// out.println_long_P(PSTR("* Delta X:"), DeltaPosSteps[X_AXIS]);
// out.println_long_P(PSTR("* Delta Y:"), DeltaPosSteps[Y_AXIS]);
//DEBUG
return 1;
}
#endif // DRIVE_SYSTEM == 4
For now, this compiles without error, and do move the machine, but badly. Z homing find the endstop, but A and B rods, not. Then XY movements are incoherent, albeit non-linear as expected.
If I try to send some G-code, I got 2 segments with some move, then the following message :
"ERROR: No move in delta segment with > 1 segment. This should never happen and may cause a problem!". Well said !
I therefore ask you, and especially Repetier, for the following questions :
1 - Is my approach OK, or is it to much kinematic-specific code in the Delta sections to avoid duplication in corresponding Bipod sections? (Pretty horrible!)
2 - Do you think that homing sequence should be Bipod-specific to? Where are the critical sections?
3 - Where are the others pitfalls?
As you can imagine, it's quite difficult to understand and clean modify such a big code as Repetier, being not software fluent at all.
The ubiquitous "Delta" designation , with different meanings of "Parallel-robot-with-many-segments-strategy", then "Three-towers-delta-drive-system", then even also "difference", is especially disturbing.
So, many thanks for any help! And many thanks for the work already made!
I'm new here, so let me introduce myself :
First, please excuse any offense to your beautiful language: I learned English in computer books, is tell you!
I have in my mind since a while a Bipod CNC, whose spindle is directly actuated by two rods in the XY plan, forming a rigid deformable triangle (Bipod configuration). The Z axis remains cartesian.
I built this way a small CNC, as a proof of concept, with full success. The driving software was LinuxCNC, whose direct and inverse kinematics modules are very suitable.
It turned out that this architecture was very relevant to making a 3D printer : very light moving parts, rigidity, precision, simplicity. As movements in Z has very different requirements from those of XY movements in a 3D Printer, I think that the Bipod architecture is well suited.
With adding some others ideas, I have now designed and built a pretty inedite 3D printer, which does almost nothing like the others, except, I hope, to put some molted plastic in some shape. The simplicity translates in very few mechanical parts, really.
More information will follow, as soon as I will be able to pass the last obstacle : The firmware.
I know I could use LinuxCNC, which runs now on BeagleBone Black thanks to the 'Machine Kit'. But all my current design, which began before the BBB, does includes a proven and cheap RAMPS / Arduino set. I thought that since many delta printers are using it, I could use it too. I hope to achieve my project this way, but LinuxCNC / BBB remains an option.
I am not as fluent in software than in hardware, so I need some guidance.
Here is a sketch of the kinematics (the Z axis is not represented) :
[attachment 20879 Bipod_1.GIF]
I intend to re-use the same strategy as the delta robots : trick the motion control algorithm by exchanging many small segments, recalculated using kinematics, instead of a single cartesian movement.
I choose Repetier (0.83), which seems to me better structured.
Hoping to make a change as surgical as possible , I set Bipod, in CONFIGURATION.h as a new drive system :
# define DRIVE_SYSTEM 4
but then reused all the delta code, amending the directives :
#if DRIVE_SYSTEM >= 3 in place of #if DRIVE_SYSTEM==3
#if DRIVE_SYSTEM < 3 in place of #if DRIVE_SYSTEM != 3, etc...
I created only the alternative 'calculate_delta' function, this way :
#if DRIVE_SYSTEM == 4
/** Set Delta rods positions
@param xaxis X arm length.
@param yaxis Y arm length.
@param zaxis no change cartesian position.
*/
inline void set_delta_position(long xaxis, long yaxis, long zaxis) {
printer_state.currentDeltaPositionSteps[0] = xaxis;
printer_state.currentDeltaPositionSteps[1] = yaxis;
printer_state.currentDeltaPositionSteps[2] = zaxis;
}
/**
Calculate the Delta arm position from a cartesian position
@param cartesianPosSteps Array containing cartesian coordinates.
@param DeltaPosSteps Result array with arm coordinates.
@returns 1 if cartesian coordinates have a valid Delta arm position 0 if not.
Conventions : Origine du systeme cartesien au centre du plateau
Origine pendant les calculs sur la charniere A (A_X_COORDINATE, A_Y_COORDINATE)
#define AB_STEPS_PER_MM 242.5218 // 4 mm shaft, 0.2 mm cable, 200 steps, 16 microsteps
#define XAXIS_STEPS_PER_MM 242.5218 // 4 mm shaft, 0.2 mm cable, 200 steps, 16 microsteps
#define YAXIS_STEPS_PER_MM 242.5218 // 4 mm shaft, 0.2 mm cable, 200 steps, 16 microsteps
#define ZAXIS_STEPS_PER_MM 377.2561 // 5 mm shaft, 0.4 mm cable, 400 steps, 16 microsteps
#define AB_MAX_LENGTH 340 // Arm's length at rear endstop
#define AB_MIN_LENGTH 110
#define A_B_HINGES_DISTANCE 235
#define A_X_COORDINATE -150 //
#define A_Y_COORDINATE -117.5 //-( A_B_HINGES_DISTANCE / 2)
#define Z_MAX 300 // Max height of prints
#define MAX_Delta_SEGMENTS_PER_LINE 30
*/
byte calculate_delta(long cartesianPosSteps[], long DeltaPosSteps[]) {
DeltaPosSteps[Z_AXIS] = cartesianPosSteps[Z_AXIS]; // Z does not change
// Changement d'origine XY pour faciliter les calculs
// L'origine est ramenee sur la charniere A
long local_X = cartesianPosSteps[X_AXIS] + A_X_COORDINATE;
long local_Y = cartesianPosSteps[Y_AXIS] + A_Y_COORDINATE;
long local_X_SQUARED = sq(local_X);
DeltaPosSteps[X_AXIS] = sqrt(local_X_SQUARED + sq(local_Y));
DeltaPosSteps[Y_AXIS] = sqrt(local_X_SQUARED + sq(A_B_HINGES_DISTANCE - local_Y));
// if ( (DeltaPosSteps[X_AXIS] >= AB_MIN_LENGTH) &&
// (DeltaPosSteps[X_AXIS] <= AB_MAX_LENGTH) &&
// (DeltaPosSteps[Y_AXIS] >= AB_MIN_LENGTH) &&
// (DeltaPosSteps[Y_AXIS] <= AB_MAX_LENGTH) )
// return 1;
// else return 0;
// DEBUG
// out.println_long_P(PSTR("* Cartesian X:"), cartesianPosSteps[X_AXIS]);
// out.println_long_P(PSTR("* Cartesian Y:"), cartesianPosSteps[Y_AXIS]);
// out.println_long_P(PSTR("* Delta X:"), DeltaPosSteps[X_AXIS]);
// out.println_long_P(PSTR("* Delta Y:"), DeltaPosSteps[Y_AXIS]);
//DEBUG
return 1;
}
#endif // DRIVE_SYSTEM == 4
For now, this compiles without error, and do move the machine, but badly. Z homing find the endstop, but A and B rods, not. Then XY movements are incoherent, albeit non-linear as expected.
If I try to send some G-code, I got 2 segments with some move, then the following message :
"ERROR: No move in delta segment with > 1 segment. This should never happen and may cause a problem!". Well said !
I therefore ask you, and especially Repetier, for the following questions :
1 - Is my approach OK, or is it to much kinematic-specific code in the Delta sections to avoid duplication in corresponding Bipod sections? (Pretty horrible!)
2 - Do you think that homing sequence should be Bipod-specific to? Where are the critical sections?
3 - Where are the others pitfalls?
As you can imagine, it's quite difficult to understand and clean modify such a big code as Repetier, being not software fluent at all.
The ubiquitous "Delta" designation , with different meanings of "Parallel-robot-with-many-segments-strategy", then "Three-towers-delta-drive-system", then even also "difference", is especially disturbing.
So, many thanks for any help! And many thanks for the work already made!