Merge branch 'edge' of https://github.com/Smoothieware/Smoothieware into edge
[clinton/Smoothieware.git] / src / modules / robot / Robot.cpp
index 1592553..486fe79 100644 (file)
@@ -40,7 +40,6 @@
 #include <fastmath.h>
 #include <string>
 #include <algorithm>
-using std::string;
 
 #define  default_seek_rate_checksum          CHECKSUM("default_seek_rate")
 #define  default_feed_rate_checksum          CHECKSUM("default_feed_rate")
@@ -194,29 +193,48 @@ void Robot::load_config()
     // default s value for laser
     this->s_value             = THEKERNEL->config->value(laser_module_default_power_checksum)->by_default(0.8F)->as_number();
 
-    // Make our Primary XYZ StepperMotors
+     // Make our Primary XYZ StepperMotors, and potentially A B C
     uint16_t const checksums[][6] = {
         ACTUATOR_CHECKSUMS("alpha"), // X
         ACTUATOR_CHECKSUMS("beta"),  // Y
         ACTUATOR_CHECKSUMS("gamma"), // Z
+        #if MAX_ROBOT_ACTUATORS > 3
+        ACTUATOR_CHECKSUMS("delta"),   // A
+        #if MAX_ROBOT_ACTUATORS > 4
+        ACTUATOR_CHECKSUMS("epsilon"), // B
+        #if MAX_ROBOT_ACTUATORS > 5
+        ACTUATOR_CHECKSUMS("zeta")     // C
+        #endif
+        #endif
+        #endif
     };
 
     // default acceleration setting, can be overriden with newer per axis settings
     this->default_acceleration= THEKERNEL->config->value(acceleration_checksum)->by_default(100.0F )->as_number(); // Acceleration is in mm/s^2
 
     // make each motor
-    for (size_t a = X_AXIS; a <= Z_AXIS; a++) {
+    for (size_t a = 0; a < MAX_ROBOT_ACTUATORS; a++) {
         Pin pins[3]; //step, dir, enable
         for (size_t i = 0; i < 3; i++) {
             pins[i].from_string(THEKERNEL->config->value(checksums[a][i])->by_default("nc")->as_string())->as_output();
         }
+
+        if(!pins[0].connected() || !pins[1].connected()) { // step and dir must be defined, but enable is optional
+            if(a <= Z_AXIS) {
+                THEKERNEL->streams->printf("FATAL: motor %c is not defined in config\n", 'X'+a);
+                n_motors= a; // we only have this number of motors
+                return;
+            }
+            break; // if any pin is not defined then the axis is not defined (and axis need to be defined in contiguous order)
+        }
+
         StepperMotor *sm = new StepperMotor(pins[0], pins[1], pins[2]);
         // register this motor (NB This must be 0,1,2) of the actuators array
         uint8_t n= register_motor(sm);
         if(n != a) {
             // this is a fatal error
             THEKERNEL->streams->printf("FATAL: motor %d does not match index %d\n", n, a);
-            __debugbreak();
+            return;
         }
 
         actuators[a]->change_steps_per_mm(THEKERNEL->config->value(checksums[a][3])->by_default(a == 2 ? 2560.0F : 80.0F)->as_number());
@@ -254,6 +272,7 @@ uint8_t Robot::register_motor(StepperMotor *motor)
         __debugbreak();
     }
     actuators.push_back(motor);
+    motor->set_motor_id(n_motors);
     return n_motors++;
 }
 
@@ -351,6 +370,21 @@ int Robot::print_position(uint8_t subcode, char *buf, size_t bufsize) const
             n = snprintf(buf, bufsize, "APOS: X:%1.4f Y:%1.4f Z:%1.4f", current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]);
         }
     }
+
+    #if MAX_ROBOT_ACTUATORS > 3
+    // deal with the ABC axis
+    for (int i = A_AXIS; i < n_motors; ++i) {
+        if(actuators[i]->is_extruder()) continue; // don't show an extruder as that will be E
+        if(subcode == 4) { // M114.4 print last milestone
+            n += snprintf(&buf[n], bufsize-n, " %c:%1.4f", 'A'+i-A_AXIS, machine_position[i]);
+
+        }else if(subcode == 2 || subcode == 3) { // M114.2/M114.3 print actuator position which is the same as machine position for ABC
+            // current actuator position
+            n += snprintf(&buf[n], bufsize-n, " %c:%1.4f", 'A'+i-A_AXIS, actuators[i]->get_current_position());
+        }
+    }
+    #endif
+
     return n;
 }
 
@@ -369,6 +403,8 @@ Robot::wcs_t Robot::mcs2wcs(const Robot::wcs_t& pos) const
 void Robot::check_max_actuator_speeds()
 {
     for (size_t i = 0; i < n_motors; i++) {
+        if(actuators[i]->is_extruder()) continue; //extruders are not included in this check
+
         float step_freq = actuators[i]->get_max_rate() * actuators[i]->get_steps_per_mm();
         if (step_freq > THEKERNEL->base_stepping_frequency) {
             actuators[i]->set_max_rate(floorf(THEKERNEL->base_stepping_frequency / actuators[i]->get_steps_per_mm()));
@@ -391,10 +427,18 @@ void Robot::on_gcode_received(void *argument)
             case 1:  motion_mode = LINEAR;  break;
             case 2:  motion_mode = CW_ARC;  break;
             case 3:  motion_mode = CCW_ARC; break;
-            case 4: { // G4 pause
+            case 4: { // G4 Dwell
                 uint32_t delay_ms = 0;
                 if (gcode->has_letter('P')) {
-                    delay_ms = gcode->get_int('P');
+                    if(THEKERNEL->is_grbl_mode()) {
+                        // in grbl mode (and linuxcnc) P is decimal seconds
+                        float f= gcode->get_value('P');
+                        delay_ms= f * 1000.0F;
+
+                    }else{
+                        // in reprap P is milliseconds, they always have to be different!
+                        delay_ms = gcode->get_int('P');
+                    }
                 }
                 if (gcode->has_letter('S')) {
                     delay_ms += gcode->get_int('S') * 1000;
@@ -437,10 +481,16 @@ void Robot::on_gcode_received(void *argument)
                             }
 
                         } else {
-                            // the value is the offset from machine zero
-                            if(gcode->has_letter('X')) x = to_millimeters(gcode->get_value('X'));
-                            if(gcode->has_letter('Y')) y = to_millimeters(gcode->get_value('Y'));
-                            if(gcode->has_letter('Z')) z = to_millimeters(gcode->get_value('Z'));
+                            if(absolute_mode) {
+                                // the value is the offset from machine zero
+                                if(gcode->has_letter('X')) x = to_millimeters(gcode->get_value('X'));
+                                if(gcode->has_letter('Y')) y = to_millimeters(gcode->get_value('Y'));
+                                if(gcode->has_letter('Z')) z = to_millimeters(gcode->get_value('Z'));
+                            }else{
+                                if(gcode->has_letter('X')) x += to_millimeters(gcode->get_value('X'));
+                                if(gcode->has_letter('Y')) y += to_millimeters(gcode->get_value('Y'));
+                                if(gcode->has_letter('Z')) z += to_millimeters(gcode->get_value('Z'));
+                            }
                         }
                         wcs_offsets[n] = wcs_t(x, y, z);
                     }
@@ -502,14 +552,11 @@ void Robot::on_gcode_received(void *argument)
                 if(gcode->subcode == 0 && (gcode->has_letter('E') || gcode->get_num_args() == 0)){
                     // reset the E position, legacy for 3d Printers to be reprap compatible
                     // find the selected extruder
-                    // NOTE this will only work when E is 0 if volumetric and/or scaling is used as the actuator last milestone will be different if it was scaled
-                    for (int i = E_AXIS; i < n_motors; ++i) {
-                        if(actuators[i]->is_selected()) {
-                            float e= gcode->has_letter('E') ? gcode->get_value('E') : 0;
-                            machine_position[i]= compensated_machine_position[i]= e;
-                            actuators[i]->change_last_milestone(e);
-                            break;
-                        }
+                    int selected_extruder= get_active_extruder();
+                    if(selected_extruder > 0) {
+                        float e= gcode->has_letter('E') ? gcode->get_value('E') : 0;
+                        machine_position[selected_extruder]= compensated_machine_position[selected_extruder]= e;
+                        actuators[selected_extruder]->change_last_milestone(get_e_scale_fnc ? e*get_e_scale_fnc() : e);
                     }
                 }
                 #endif
@@ -535,7 +582,28 @@ void Robot::on_gcode_received(void *argument)
                 THEKERNEL->call_event(ON_ENABLE, (void*)1); // turn all enable pins on
                 break;
 
-            case 18: // this used to support parameters, now it ignores them
+            case 18: // this allows individual motors to be turned off, no parameters falls through to turn all off
+                if(gcode->get_num_args() > 0) {
+                    // bitmap of motors to turn off, where bit 1:X, 2:Y, 3:Z, 4:A, 5:B, 6:C
+                    uint32_t bm= 0;
+                    for (int i = 0; i < n_motors; ++i) {
+                        char axis= (i <= Z_AXIS ? 'X'+i : 'A'+(i-3));
+                        if(gcode->has_letter(axis)) bm |= (0x02<<i); // set appropriate bit
+                    }
+                    // handle E parameter as currently selected extruder ABC
+                    if(gcode->has_letter('E')) {
+                        // find first selected extruder
+                        int i= get_active_extruder();
+                        if(i > 0) {
+                            bm |= (0x02<<i); // set appropriate bit
+                        }
+                    }
+
+                    THEKERNEL->conveyor->wait_for_idle();
+                    THEKERNEL->call_event(ON_ENABLE, (void *)bm);
+                    break;
+                }
+                // fall through
             case 84:
                 THEKERNEL->conveyor->wait_for_idle();
                 THEKERNEL->call_event(ON_ENABLE, nullptr); // turn all enable pins off
@@ -545,20 +613,20 @@ void Robot::on_gcode_received(void *argument)
             case 83: e_absolute_mode= false; break;
 
             case 92: // M92 - set steps per mm
-                if (gcode->has_letter('X'))
-                    actuators[0]->change_steps_per_mm(this->to_millimeters(gcode->get_value('X')));
-                if (gcode->has_letter('Y'))
-                    actuators[1]->change_steps_per_mm(this->to_millimeters(gcode->get_value('Y')));
-                if (gcode->has_letter('Z'))
-                    actuators[2]->change_steps_per_mm(this->to_millimeters(gcode->get_value('Z')));
-
-                gcode->stream->printf("X:%f Y:%f Z:%f ", actuators[0]->get_steps_per_mm(), actuators[1]->get_steps_per_mm(), actuators[2]->get_steps_per_mm());
+                for (int i = 0; i < n_motors; ++i) {
+                    if(actuators[i]->is_extruder()) continue; //extruders handle this themselves
+                    char axis= (i <= Z_AXIS ? 'X'+i : 'A'+(i-A_AXIS));
+                    if(gcode->has_letter(axis)) {
+                        actuators[i]->change_steps_per_mm(this->to_millimeters(gcode->get_value(axis)));
+                    }
+                    gcode->stream->printf("%c:%f ", axis, actuators[i]->get_steps_per_mm());
+                }
                 gcode->add_nl = true;
                 check_max_actuator_speeds();
                 return;
 
             case 114:{
-                char buf[64];
+                char buf[128];
                 int n= print_position(gcode->subcode, buf, sizeof buf);
                 if(n > 0) gcode->txt_after_ok.append(buf, n);
                 return;
@@ -577,6 +645,13 @@ void Robot::on_gcode_received(void *argument)
                         for (size_t i = X_AXIS; i <= Z_AXIS; i++) {
                             gcode->stream->printf(" %c: %g ", 'X' + i, gcode->subcode == 0 ? this->max_speeds[i] : actuators[i]->get_max_rate());
                         }
+                        if(gcode->subcode == 1) {
+                            for (size_t i = A_AXIS; i < n_motors; i++) {
+                                if(actuators[i]->is_extruder()) continue; //extruders handle this themselves
+                                gcode->stream->printf(" %c: %g ", 'A' + i - A_AXIS, actuators[i]->get_max_rate());
+                            }
+                        }
+
                         gcode->add_nl = true;
 
                     }else{
@@ -588,6 +663,19 @@ void Robot::on_gcode_received(void *argument)
                             }
                         }
 
+                        if(gcode->subcode == 1) {
+                            // ABC axis only handle actuator max speeds
+                            for (size_t i = A_AXIS; i < n_motors; i++) {
+                                if(actuators[i]->is_extruder()) continue; //extruders handle this themselves
+                                int c= 'A' + i - A_AXIS;
+                                if(gcode->has_letter(c)) {
+                                    float v= gcode->get_value(c);
+                                    actuators[i]->set_max_rate(v);
+                                }
+                            }
+                        }
+
+
                         // this format is deprecated
                         if(gcode->subcode == 0 && (gcode->has_letter('A') || gcode->has_letter('B') || gcode->has_letter('C'))) {
                             gcode->stream->printf("NOTE this format is deprecated, Use M203.1 instead\n");
@@ -610,9 +698,11 @@ void Robot::on_gcode_received(void *argument)
                     if (acc < 1.0F) acc = 1.0F;
                     this->default_acceleration = acc;
                 }
-                for (int i = X_AXIS; i <= Z_AXIS; ++i) {
-                    if (gcode->has_letter(i+'X')) {
-                        float acc = gcode->get_value(i+'X'); // mm/s^2
+                for (int i = 0; i < n_motors; ++i) {
+                    if(actuators[i]->is_extruder()) continue; //extruders handle this themselves
+                    char axis= (i <= Z_AXIS ? 'X'+i : 'A'+(i-A_AXIS));
+                    if(gcode->has_letter(axis)) {
+                        float acc = gcode->get_value(axis); // mm/s^2
                         // enforce positive
                         if (acc <= 0.0F) acc = NAN;
                         actuators[i]->set_acceleration(acc);
@@ -666,19 +756,34 @@ void Robot::on_gcode_received(void *argument)
 
             case 500: // M500 saves some volatile settings to config override file
             case 503: { // M503 just prints the settings
-                gcode->stream->printf(";Steps per unit:\nM92 X%1.5f Y%1.5f Z%1.5f\n", actuators[0]->get_steps_per_mm(), actuators[1]->get_steps_per_mm(), actuators[2]->get_steps_per_mm());
+                gcode->stream->printf(";Steps per unit:\nM92 ");
+                for (int i = 0; i < n_motors; ++i) {
+                    if(actuators[i]->is_extruder()) continue; //extruders handle this themselves
+                    char axis= (i <= Z_AXIS ? 'X'+i : 'A'+(i-A_AXIS));
+                    gcode->stream->printf("%c%1.5f ", axis, actuators[i]->get_steps_per_mm());
+                }
+                gcode->stream->printf("\n");
 
-                // only print XYZ if not NAN
+                // only print if not NAN
                 gcode->stream->printf(";Acceleration mm/sec^2:\nM204 S%1.5f ", default_acceleration);
-                for (int i = X_AXIS; i <= Z_AXIS; ++i) {
-                    if(!isnan(actuators[i]->get_acceleration())) gcode->stream->printf("%c%1.5f ", 'X'+i, actuators[i]->get_acceleration());
+                for (int i = 0; i < n_motors; ++i) {
+                    if(actuators[i]->is_extruder()) continue; // extruders handle this themselves
+                    char axis= (i <= Z_AXIS ? 'X'+i : 'A'+(i-A_AXIS));
+                    if(!isnan(actuators[i]->get_acceleration())) gcode->stream->printf("%c%1.5f ", axis, actuators[i]->get_acceleration());
                 }
                 gcode->stream->printf("\n");
 
                 gcode->stream->printf(";X- Junction Deviation, Z- Z junction deviation, S - Minimum Planner speed mm/sec:\nM205 X%1.5f Z%1.5f S%1.5f\n", THEKERNEL->planner->junction_deviation, isnan(THEKERNEL->planner->z_junction_deviation)?-1:THEKERNEL->planner->z_junction_deviation, THEKERNEL->planner->minimum_planner_speed);
 
                 gcode->stream->printf(";Max cartesian feedrates in mm/sec:\nM203 X%1.5f Y%1.5f Z%1.5f\n", this->max_speeds[X_AXIS], this->max_speeds[Y_AXIS], this->max_speeds[Z_AXIS]);
-                 gcode->stream->printf(";Max actuator feedrates in mm/sec:\nM203.1 X%1.5f Y%1.5f Z%1.5f\n", actuators[X_AXIS]->get_max_rate(), actuators[Y_AXIS]->get_max_rate(), actuators[Z_AXIS]->get_max_rate());
+
+                gcode->stream->printf(";Max actuator feedrates in mm/sec:\nM203.1 ");
+                for (int i = 0; i < n_motors; ++i) {
+                    if(actuators[i]->is_extruder()) continue; // extruders handle this themselves
+                    char axis= (i <= Z_AXIS ? 'X'+i : 'A'+(i-A_AXIS));
+                    gcode->stream->printf("%c%1.5f ", axis, actuators[i]->get_max_rate());
+                }
+                gcode->stream->printf("\n");
 
                 // get or save any arm solution specific optional values
                 BaseSolution::arm_options_t options;
@@ -760,6 +865,15 @@ void Robot::on_gcode_received(void *argument)
     next_command_is_MCS = false; // must be on same line as G0 or G1
 }
 
+int Robot::get_active_extruder() const
+{
+    for (int i = E_AXIS; i < n_motors; ++i) {
+        // find first selected extruder
+        if(actuators[i]->is_extruder() && actuators[i]->is_selected()) return i;
+    }
+    return 0;
+}
+
 // process a G0/G1/G2/G3
 void Robot::process_move(Gcode *gcode, enum MOTION_MODE_T motion_mode)
 {
@@ -815,21 +929,17 @@ void Robot::process_move(Gcode *gcode, enum MOTION_MODE_T motion_mode)
         }
     }
 
+    float delta_e= NAN;
+
+    #if MAX_ROBOT_ACTUATORS > 3
     // process extruder parameters, for active extruder only (only one active extruder at a time)
-    selected_extruder= 0;
+    int selected_extruder= 0;
     if(gcode->has_letter('E')) {
-        for (int i = E_AXIS; i < n_motors; ++i) {
-            // find first selected extruder
-            if(actuators[i]->is_selected()) {
-                param[E_AXIS]= gcode->get_value('E');
-                selected_extruder= i;
-                break;
-            }
-        }
+        selected_extruder= get_active_extruder();
+        param[E_AXIS]= gcode->get_value('E');
     }
 
     // do E for the selected extruder
-    float delta_e= NAN;
     if(selected_extruder > 0 && !isnan(param[E_AXIS])) {
         if(this->e_absolute_mode) {
             target[selected_extruder]= param[E_AXIS];
@@ -840,6 +950,20 @@ void Robot::process_move(Gcode *gcode, enum MOTION_MODE_T motion_mode)
         }
     }
 
+    // process ABC axis, this is mutually exclusive to using E for an extruder, so if E is used and A then the results are undefined
+    for (int i = A_AXIS; i < n_motors; ++i) {
+        char letter= 'A'+i-A_AXIS;
+        if(gcode->has_letter(letter)) {
+            float p= gcode->get_value(letter);
+            if(this->absolute_mode) {
+                target[i]= p;
+            }else{
+                target[i]= p + machine_position[i];
+            }
+        }
+    }
+    #endif
+
     if( gcode->has_letter('F') ) {
         if( motion_mode == SEEK )
             this->seek_rate = this->to_millimeters( gcode->get_value('F') );
@@ -931,10 +1055,11 @@ void Robot::reset_actuator_position(const ActuatorCoordinates &ac)
 }
 
 // Use FK to find out where actuator is and reset to match
+// TODO maybe we should only reset axis that are being homed unless this is due to a ON_HALT
 void Robot::reset_position_from_current_actuator_position()
 {
     ActuatorCoordinates actuator_pos;
-    for (size_t i = X_AXIS; i <= Z_AXIS; i++) {
+    for (size_t i = X_AXIS; i < n_motors; i++) {
         // NOTE actuator::current_position is curently NOT the same as actuator::machine_position after an abrupt abort
         actuator_pos[i] = actuators[i]->get_current_position();
     }
@@ -950,8 +1075,20 @@ void Robot::reset_position_from_current_actuator_position()
     // NOTE This is required to sync the machine position with the actuator position, we do a somewhat redundant cartesian_to_actuator() call
     // to get everything in perfect sync.
     arm_solution->cartesian_to_actuator(compensated_machine_position, actuator_pos);
-    for (size_t i = X_AXIS; i <= Z_AXIS; i++)
+    for (size_t i = X_AXIS; i <= Z_AXIS; i++) {
         actuators[i]->change_last_milestone(actuator_pos[i]);
+    }
+
+    // Handle extruders and/or ABC axis
+    #if MAX_ROBOT_ACTUATORS > 3
+    for (int i = A_AXIS; i < n_motors; i++) {
+        // ABC and/or extruders just need to set machine_position and compensated_machine_position
+        float ap= actuator_pos[i];
+        if(actuators[i]->is_extruder() && get_e_scale_fnc) ap /= get_e_scale_fnc(); // inverse E scale if there is one and this is an extruder
+        machine_position[i]= compensated_machine_position[i]= ap;
+        actuators[i]->change_last_milestone(actuator_pos[i]); // this updates the last_milestone in the actuator
+    }
+    #endif
 }
 
 // Convert target (in machine coordinates) to machine_position, then convert to actuator position and append this to the planner
@@ -973,7 +1110,7 @@ bool Robot::append_milestone(const float target[], float rate_mm_s)
     }
 
     bool move= false;
-    float sos= 0; // sum of squares for just XYZ
+    float sos= 0; // sum of squares for just primary axis (XYZ usually)
 
     // find distance moved by each axis, use transformed target from the current compensated machine position
     for (size_t i = 0; i < n_motors; i++) {
@@ -981,7 +1118,7 @@ bool Robot::append_milestone(const float target[], float rate_mm_s)
         if(deltas[i] == 0) continue;
         // at least one non zero delta
         move = true;
-        if(i <= Z_AXIS) {
+        if(i < N_PRIMARY_AXIS) {
             sos += powf(deltas[i], 2);
         }
     }
@@ -990,7 +1127,13 @@ bool Robot::append_milestone(const float target[], float rate_mm_s)
     if(!move) return false;
 
     // see if this is a primary axis move or not
-    bool auxilliary_move= deltas[X_AXIS] == 0 && deltas[Y_AXIS] == 0 && deltas[Z_AXIS] == 0;
+    bool auxilliary_move= true;
+    for (int i = 0; i < N_PRIMARY_AXIS; ++i) {
+        if(deltas[i] != 0) {
+            auxilliary_move= false;
+            break;
+        }
+    }
 
     // total movement, use XYZ if a primary axis otherwise we calculate distance for E after scaling to mm
     float distance= auxilliary_move ? 0 : sqrtf(sos);
@@ -1001,7 +1144,7 @@ bool Robot::append_milestone(const float target[], float rate_mm_s)
 
 
     if(!auxilliary_move) {
-         for (size_t i = X_AXIS; i <= Z_AXIS; i++) {
+         for (size_t i = X_AXIS; i < N_PRIMARY_AXIS; i++) {
             // find distance unit vector for primary axis only
             unit_vec[i] = deltas[i] / distance;
 
@@ -1032,7 +1175,7 @@ bool Robot::append_milestone(const float target[], float rate_mm_s)
     // for the extruders just copy the position, and possibly scale it from mm³ to mm
     for (size_t i = E_AXIS; i < n_motors; i++) {
         actuator_pos[i]= transformed_target[i];
-        if(get_e_scale_fnc) {
+        if(actuators[i]->is_extruder() && get_e_scale_fnc) {
             // NOTE this relies on the fact only one extruder is active at a time
             // scale for volumetric or flow rate
             // TODO is this correct? scaling the absolute target? what if the scale changes?
@@ -1041,7 +1184,7 @@ bool Robot::append_milestone(const float target[], float rate_mm_s)
         }
         if(auxilliary_move) {
             // for E only moves we need to use the scaled E to calculate the distance
-            sos += pow(actuator_pos[i] - actuators[i]->get_last_milestone(), 2);
+            sos += powf(actuator_pos[i] - actuators[i]->get_last_milestone(), 2);
         }
     }
     if(auxilliary_move) {
@@ -1068,7 +1211,7 @@ bool Robot::append_milestone(const float target[], float rate_mm_s)
 
         // adjust acceleration to lowest found, for now just primary axis unless it is an auxiliary move
         // TODO we may need to do all of them, check E won't limit XYZ.. it does on long E moves, but not checking it could exceed the E acceleration.
-        if(auxilliary_move || actuator <= Z_AXIS) {
+        if(auxilliary_move || actuator < N_PRIMARY_AXIS) {
             float ma =  actuators[actuator]->get_acceleration(); // in mm/sec²
             if(!isnan(ma)) {  // if axis does not have acceleration set then it uses the default_acceleration
                 float ca = fabsf((d/distance) * acceleration);
@@ -1289,6 +1432,7 @@ bool Robot::append_arc(Gcode * gcode, const float target[], const float offset[]
     float cos_T = 1 - 0.5F * theta_per_segment * theta_per_segment; // Small angle approximation
     float sin_T = theta_per_segment;
 
+    // TODO we need to handle the ABC axis here by segmenting them
     float arc_target[3];
     float sin_Ti;
     float cos_Ti;