<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
    <channel>
        <title>plan_buffer_line</title>
        <description> Hi everyone,

I was looking through the Marlin firmware and came across this function (plan_buffer_line) throughout marlin_main.cpp 
It appears to be involved in the movement of the printer. I just cannot find this function anywhere in the files.
Does anyone know where this function is? I would like to figure out its inner workings and get to the bottom of this. 

Thanks!

Bryan</description>
        <link>https://reprap.org/forum/read.php?146,451615,451615#msg-451615</link>
        <lastBuildDate>Sat, 18 Jul 2026 20:40:36 -0400</lastBuildDate>
        <generator>Phorum 5.2.23</generator>
        <item>
            <guid>https://reprap.org/forum/read.php?146,451615,555480#msg-555480</guid>
            <title>Re: plan_buffer_line</title>
            <link>https://reprap.org/forum/read.php?146,451615,555480#msg-555480</link>
            <description><![CDATA[ You can find it in planner.cpp<br />
It is a long function that generates the blocks according to many considerations such as speed and acceleration.<br />
<br />
Here I copy the function for you:<br />
#ifdef ENABLE_AUTO_BED_LEVELING<br />
void plan_buffer_line(float x, float y, float z, const float &amp;e, float feed_rate, const uint8_t &amp;extruder)<br />
#else<br />
void plan_buffer_line(const float &amp;x, const float &amp;y, const float &amp;z, const float &amp;e, float feed_rate, const uint8_t &amp;extruder)<br />
#endif  //ENABLE_AUTO_BED_LEVELING<br />
{<br />
  // Calculate the buffer head after we push this byte<br />
  int next_buffer_head = next_block_index(block_buffer_head);<br />
<br />
  // If the buffer is full: good! That means we are well ahead of the robot. <br />
  // Rest here until there is room in the buffer.<br />
  while(block_buffer_tail == next_buffer_head)<br />
  {<br />
    manage_heater(); <br />
    manage_inactivity(); <br />
    lcd_update();<br />
  }<br />
<br />
#ifdef ENABLE_AUTO_BED_LEVELING<br />
  apply_rotation_xyz(plan_bed_level_matrix, x, y, z);<br />
#endif // ENABLE_AUTO_BED_LEVELING<br />
<br />
  // The target position of the tool in absolute steps<br />
  // Calculate target position in absolute steps<br />
  //this should be done after the wait, because otherwise a M92 code within the gcode disrupts this calculation somehow<br />
  long target[4];<br />
  target[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]);<br />
  target[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]);<br />
  target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]);     <br />
  target[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]);<br />
<br />
  #ifdef PREVENT_DANGEROUS_EXTRUDE<br />
  if(target[E_AXIS]!=position[E_AXIS])<br />
  {<br />
    if(degHotend(active_extruder)axis_steps_per_unit[E_AXIS]*EXTRUDE_MAXLENGTH)<br />
    {<br />
      position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part<br />
      SERIAL_ECHO_START;<br />
      SERIAL_ECHOLNPGM(MSG_ERR_LONG_EXTRUDE_STOP);<br />
    }<br />
    #endif<br />
  }<br />
  #endif<br />
<br />
  // Prepare to set up new block<br />
  block_t *block = &amp;block_buffer[block_buffer_head];<br />
<br />
  // Mark block as not busy (Not executed by the stepper interrupt)<br />
  block-&gt;busy = false;<br />
<br />
  // Number of steps for each axis<br />
#ifndef COREXY<br />
// default non-h-bot planning<br />
block-&gt;steps_x = labs(target[X_AXIS]-position[X_AXIS]);<br />
block-&gt;steps_y = labs(target[Y_AXIS]-position[Y_AXIS]);<br />
#else<br />
// corexy planning<br />
// these equations follow the form of the dA and dB equations on [<a href="http://www.corexy.com/theory.html" target="_blank"  rel="nofollow">www.corexy.com</a>]<br />
block-&gt;steps_x = labs((target[X_AXIS]-position[X_AXIS]) + (target[Y_AXIS]-position[Y_AXIS]));<br />
block-&gt;steps_y = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-position[Y_AXIS]));<br />
#endif<br />
  block-&gt;steps_z = labs(target[Z_AXIS]-position[Z_AXIS]);<br />
  block-&gt;steps_e = labs(target[E_AXIS]-position[E_AXIS]);<br />
  block-&gt;steps_e *= volumetric_multiplier[active_extruder];<br />
  block-&gt;steps_e *= extrudemultiply;<br />
  block-&gt;steps_e /= 100;<br />
  block-&gt;step_event_count = max(block-&gt;steps_x, max(block-&gt;steps_y, max(block-&gt;steps_z, block-&gt;steps_e)));<br />
<br />
  // Bail if this is a zero-length block<br />
  if (block-&gt;step_event_count &lt;= dropsegments)<br />
  { <br />
    return; <br />
  }<br />
<br />
  block-&gt;fan_speed = fanSpeed;<br />
  #ifdef BARICUDA<br />
  block-&gt;valve_pressure = ValvePressure;<br />
  block-&gt;e_to_p_pressure = EtoPPressure;<br />
  #endif<br />
<br />
  // Compute direction bits for this block <br />
  block-&gt;direction_bits = 0;<br />
#ifndef COREXY<br />
  if (target[X_AXIS] &lt; position[X_AXIS])<br />
  {<br />
    block-&gt;direction_bits |= (1&lt;direction_bits |= (1&lt;direction_bits |= (1&lt;direction_bits |= (1&lt;direction_bits |= (1&lt;direction_bits |= (1&lt;active_extruder = extruder;<br />
<br />
  //enable active axes<br />
  #ifdef COREXY<br />
  if((block-&gt;steps_x != 0) || (block-&gt;steps_y != 0))<br />
  {<br />
    enable_x();<br />
    enable_y();<br />
  }<br />
  #else<br />
  if(block-&gt;steps_x != 0) enable_x();<br />
  if(block-&gt;steps_y != 0) enable_y();<br />
  #endif<br />
#ifndef Z_LATE_ENABLE<br />
  if(block-&gt;steps_z != 0) enable_z();<br />
#endif<br />
<br />
  // Enable extruder(s)<br />
  if(block-&gt;steps_e != 0)<br />
  {<br />
    if (DISABLE_INACTIVE_EXTRUDER) //enable only selected extruder<br />
    {<br />
<br />
      if(g_uc_extruder_last_move[0] &gt; 0) g_uc_extruder_last_move[0]--;<br />
      if(g_uc_extruder_last_move[1] &gt; 0) g_uc_extruder_last_move[1]--;<br />
      if(g_uc_extruder_last_move[2] &gt; 0) g_uc_extruder_last_move[2]--;<br />
      <br />
      switch(extruder)<br />
      {<br />
        case 0: <br />
          enable_e0(); <br />
          g_uc_extruder_last_move[0] = BLOCK_BUFFER_SIZE*2;<br />
          <br />
          if(g_uc_extruder_last_move[1] == 0) disable_e1(); <br />
          if(g_uc_extruder_last_move[2] == 0) disable_e2(); <br />
        break;<br />
        case 1:<br />
          enable_e1(); <br />
          g_uc_extruder_last_move[1] = BLOCK_BUFFER_SIZE*2;<br />
          <br />
          if(g_uc_extruder_last_move[0] == 0) disable_e0(); <br />
          if(g_uc_extruder_last_move[2] == 0) disable_e2(); <br />
        break;<br />
        case 2:<br />
          enable_e2(); <br />
          g_uc_extruder_last_move[2] = BLOCK_BUFFER_SIZE*2;<br />
          <br />
          if(g_uc_extruder_last_move[0] == 0) disable_e0(); <br />
          if(g_uc_extruder_last_move[1] == 0) disable_e1(); <br />
        break;        <br />
      }<br />
    }<br />
    else //enable all<br />
    {<br />
      enable_e0();<br />
      enable_e1();<br />
      enable_e2(); <br />
    }<br />
  }<br />
<br />
  if (block-&gt;steps_e == 0)<br />
  {<br />
    if(feed_ratesteps_x &lt;=dropsegments &amp;&amp; block-&gt;steps_y &lt;=dropsegments &amp;&amp; block-&gt;steps_z &lt;=dropsegments )<br />
  {<br />
    block-&gt;millimeters = fabs(delta_mm[E_AXIS]);<br />
  } <br />
  else<br />
  {<br />
    #ifndef COREXY<br />
      block-&gt;millimeters = sqrt(square(delta_mm[X_AXIS]) + square(delta_mm[Y_AXIS]) + square(delta_mm[Z_AXIS]));<br />
	#else<br />
	  block-&gt;millimeters = sqrt(square(delta_mm[X_HEAD]) + square(delta_mm[Y_HEAD]) + square(delta_mm[Z_AXIS]));<br />
    #endif	<br />
  }<br />
  float inverse_millimeters = 1.0/block-&gt;millimeters;  // Inverse millimeters to remove multiple divides <br />
<br />
    // Calculate speed in mm/second for each axis. No divide by zero due to previous checks.<br />
  float inverse_second = feed_rate * inverse_millimeters;<br />
<br />
  int moves_queued=(block_buffer_head-block_buffer_tail + BLOCK_BUFFER_SIZE) &amp; (BLOCK_BUFFER_SIZE - 1);<br />
<br />
  // slow down when de buffer starts to empty, rather than wait at the corner for a buffer refill<br />
#ifdef OLD_SLOWDOWN<br />
  if(moves_queued &lt; (BLOCK_BUFFER_SIZE * 0.5) &amp;&amp; moves_queued &gt; 1)<br />
    feed_rate = feed_rate*moves_queued / (BLOCK_BUFFER_SIZE * 0.5); <br />
#endif<br />
<br />
#ifdef SLOWDOWN<br />
  //  segment time im micro seconds<br />
  unsigned long segment_time = lround(1000000.0/inverse_second);<br />
  if ((moves_queued &gt; 1) &amp;&amp; (moves_queued &lt; (BLOCK_BUFFER_SIZE * 0.5)))<br />
  {<br />
    if (segment_time &lt; minsegmenttime)<br />
    { // buffer is draining, add extra time.  The amount of time added increases if the buffer is still emptied more.<br />
      inverse_second=1000000.0/(segment_time+lround(2*(minsegmenttime-segment_time)/moves_queued));<br />
      #ifdef XY_FREQUENCY_LIMIT<br />
         segment_time = lround(1000000.0/inverse_second);<br />
      #endif<br />
    }<br />
  }<br />
#endif<br />
  //  END OF SLOW DOWN SECTION    <br />
<br />
<br />
  block-&gt;nominal_speed = block-&gt;millimeters * inverse_second; // (mm/sec) Always &gt; 0<br />
  block-&gt;nominal_rate = ceil(block-&gt;step_event_count * inverse_second); // (step/sec) Always &gt; 0<br />
<br />
#ifdef FILAMENT_SENSOR<br />
  //FMM update ring buffer used for delay with filament measurements<br />
  <br />
  <br />
    if((extruder==FILAMENT_SENSOR_EXTRUDER_NUM) &amp;&amp; (delay_index2 &gt; -1))  //only for extruder with filament sensor and if ring buffer is initialized<br />
  	  {<br />
    delay_dist = delay_dist + delta_mm[E_AXIS];  //increment counter with next move in e axis<br />
  <br />
    while (delay_dist &gt;= (10*(MAX_MEASUREMENT_DELAY+1)))  //check if counter is over max buffer size in mm<br />
      	  delay_dist = delay_dist - 10*(MAX_MEASUREMENT_DELAY+1);  //loop around the buffer<br />
    while (delay_dist&lt;0)<br />
    	  delay_dist = delay_dist + 10*(MAX_MEASUREMENT_DELAY+1); //loop around the buffer<br />
      <br />
    delay_index1=delay_dist/10.0;  //calculate index<br />
    <br />
    //ensure the number is within range of the array after converting from floating point<br />
    if(delay_index1&lt;0)<br />
    	delay_index1=0;<br />
    else if (delay_index1&gt;MAX_MEASUREMENT_DELAY)<br />
    	delay_index1=MAX_MEASUREMENT_DELAY;<br />
    	<br />
    if(delay_index1 != delay_index2)  //moved index<br />
  	  {<br />
    	meas_sample=widthFil_to_size_ratio()-100;  //subtract off 100 to reduce magnitude - to store in a signed char<br />
  	  }<br />
    while( delay_index1 != delay_index2)<br />
  	  {<br />
  	  delay_index2 = delay_index2 + 1;<br />
  	if(delay_index2&gt;MAX_MEASUREMENT_DELAY)<br />
  			  delay_index2=delay_index2-(MAX_MEASUREMENT_DELAY+1);  //loop around buffer when incrementing<br />
  	  if(delay_index2&lt;0)<br />
  		delay_index2=0;<br />
  	  else if (delay_index2&gt;MAX_MEASUREMENT_DELAY)<br />
  		delay_index2=MAX_MEASUREMENT_DELAY;  <br />
  	  <br />
  	  measurement_delay[delay_index2]=meas_sample;<br />
  	  }<br />
    	<br />
    <br />
  	  }<br />
#endif<br />
<br />
<br />
  // Calculate and limit speed in mm/sec for each axis<br />
  float current_speed[4];<br />
  float speed_factor = 1.0; //factor &lt;=1 do decrease speed<br />
  for(int i=0; i &lt; 4; i++)<br />
  {<br />
    current_speed<i> = delta_mm<i> * inverse_second;<br />
    if(fabs(current_speed<i>) &gt; max_feedrate<i>)<br />
      speed_factor = min(speed_factor, max_feedrate<i> / fabs(current_speed<i>));<br />
  }<br />
<br />
  // Max segement time in us.<br />
#ifdef XY_FREQUENCY_LIMIT<br />
#define MAX_FREQ_TIME (1000000.0/XY_FREQUENCY_LIMIT)<br />
  // Check and limit the xy direction change frequency<br />
  unsigned char direction_change = block-&gt;direction_bits ^ old_direction_bits;<br />
  old_direction_bits = block-&gt;direction_bits;<br />
  segment_time = lround((float)segment_time / speed_factor);<br />
  <br />
  if((direction_change &amp; (1&lt;nominal_speed *= speed_factor;<br />
    block-&gt;nominal_rate *= speed_factor;<br />
  }<br />
<br />
  // Compute and limit the acceleration rate for the trapezoid generator.  <br />
  float steps_per_mm = block-&gt;step_event_count/block-&gt;millimeters;<br />
  if(block-&gt;steps_x == 0 &amp;&amp; block-&gt;steps_y == 0 &amp;&amp; block-&gt;steps_z == 0)<br />
  {<br />
    block-&gt;acceleration_st = ceil(retract_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2<br />
  }<br />
  else<br />
  {<br />
    block-&gt;acceleration_st = ceil(acceleration * steps_per_mm); // convert to: acceleration steps/sec^2<br />
    // Limit acceleration per axis<br />
    if(((float)block-&gt;acceleration_st * (float)block-&gt;steps_x / (float)block-&gt;step_event_count) &gt; axis_steps_per_sqr_second[X_AXIS])<br />
      block-&gt;acceleration_st = axis_steps_per_sqr_second[X_AXIS];<br />
    if(((float)block-&gt;acceleration_st * (float)block-&gt;steps_y / (float)block-&gt;step_event_count) &gt; axis_steps_per_sqr_second[Y_AXIS])<br />
      block-&gt;acceleration_st = axis_steps_per_sqr_second[Y_AXIS];<br />
    if(((float)block-&gt;acceleration_st * (float)block-&gt;steps_e / (float)block-&gt;step_event_count) &gt; axis_steps_per_sqr_second[E_AXIS])<br />
      block-&gt;acceleration_st = axis_steps_per_sqr_second[E_AXIS];<br />
    if(((float)block-&gt;acceleration_st * (float)block-&gt;steps_z / (float)block-&gt;step_event_count ) &gt; axis_steps_per_sqr_second[Z_AXIS])<br />
      block-&gt;acceleration_st = axis_steps_per_sqr_second[Z_AXIS];<br />
  }<br />
  block-&gt;acceleration = block-&gt;acceleration_st / steps_per_mm;<br />
  block-&gt;acceleration_rate = (long)((float)block-&gt;acceleration_st * (16777216.0 / (F_CPU / 8.0)));<br />
<br />
#if 0  // Use old jerk for now<br />
  // Compute path unit vector<br />
  double unit_vec[3];<br />
<br />
  unit_vec[X_AXIS] = delta_mm[X_AXIS]*inverse_millimeters;<br />
  unit_vec[Y_AXIS] = delta_mm[Y_AXIS]*inverse_millimeters;<br />
  unit_vec[Z_AXIS] = delta_mm[Z_AXIS]*inverse_millimeters;<br />
<br />
  // Compute maximum allowable entry speed at junction by centripetal acceleration approximation.<br />
  // Let a circle be tangent to both previous and current path line segments, where the junction<br />
  // deviation is defined as the distance from the junction to the closest edge of the circle,<br />
  // colinear with the circle center. The circular segment joining the two paths represents the<br />
  // path of centripetal acceleration. Solve for max velocity based on max acceleration about the<br />
  // radius of the circle, defined indirectly by junction deviation. This may be also viewed as<br />
  // path width or max_jerk in the previous grbl version. This approach does not actually deviate<br />
  // from path, but used as a robust way to compute cornering speeds, as it takes into account the<br />
  // nonlinearities of both the junction angle and junction velocity.<br />
  double vmax_junction = MINIMUM_PLANNER_SPEED; // Set default max junction speed<br />
<br />
  // Skip first block or when previous_nominal_speed is used as a flag for homing and offset cycles.<br />
  if ((block_buffer_head != block_buffer_tail) &amp;&amp; (previous_nominal_speed &gt; 0.0)) {<br />
    // Compute cosine of angle between previous and current path. (prev_unit_vec is negative)<br />
    // NOTE: Max junction velocity is computed without sin() or acos() by trig half angle identity.<br />
    double cos_theta = - previous_unit_vec[X_AXIS] * unit_vec[X_AXIS]<br />
      - previous_unit_vec[Y_AXIS] * unit_vec[Y_AXIS]<br />
      - previous_unit_vec[Z_AXIS] * unit_vec[Z_AXIS] ;<br />
<br />
    // Skip and use default max junction speed for 0 degree acute junction.<br />
    if (cos_theta &lt; 0.95) {<br />
      vmax_junction = min(previous_nominal_speed,block-&gt;nominal_speed);<br />
      // Skip and avoid divide by zero for straight junctions at 180 degrees. Limit to min() of nominal speeds.<br />
      if (cos_theta &gt; -0.95) {<br />
        // Compute maximum junction velocity based on maximum acceleration and junction deviation<br />
        double sin_theta_d2 = sqrt(0.5*(1.0-cos_theta)); // Trig half angle identity. Always positive.<br />
        vmax_junction = min(vmax_junction,<br />
        sqrt(block-&gt;acceleration * junction_deviation * sin_theta_d2/(1.0-sin_theta_d2)) );<br />
      }<br />
    }<br />
  }<br />
#endif<br />
  // Start with a safe speed<br />
  float vmax_junction = max_xy_jerk/2; <br />
  float vmax_junction_factor = 1.0; <br />
  if(fabs(current_speed[Z_AXIS]) &gt; max_z_jerk/2) <br />
    vmax_junction = min(vmax_junction, max_z_jerk/2);<br />
  if(fabs(current_speed[E_AXIS]) &gt; max_e_jerk/2) <br />
    vmax_junction = min(vmax_junction, max_e_jerk/2);<br />
  vmax_junction = min(vmax_junction, block-&gt;nominal_speed);<br />
  float safe_speed = vmax_junction;<br />
<br />
  if ((moves_queued &gt; 1) &amp;&amp; (previous_nominal_speed &gt; 0.0001)) {<br />
    float jerk = sqrt(pow((current_speed[X_AXIS]-previous_speed[X_AXIS]), 2)+pow((current_speed[Y_AXIS]-previous_speed[Y_AXIS]), 2));<br />
    //    if((fabs(previous_speed[X_AXIS]) &gt; 0.0001) || (fabs(previous_speed[Y_AXIS]) &gt; 0.0001)) {<br />
    vmax_junction = block-&gt;nominal_speed;<br />
    //    }<br />
    if (jerk &gt; max_xy_jerk) {<br />
      vmax_junction_factor = (max_xy_jerk/jerk);<br />
    } <br />
    if(fabs(current_speed[Z_AXIS] - previous_speed[Z_AXIS]) &gt; max_z_jerk) {<br />
      vmax_junction_factor= min(vmax_junction_factor, (max_z_jerk/fabs(current_speed[Z_AXIS] - previous_speed[Z_AXIS])));<br />
    } <br />
    if(fabs(current_speed[E_AXIS] - previous_speed[E_AXIS]) &gt; max_e_jerk) {<br />
      vmax_junction_factor = min(vmax_junction_factor, (max_e_jerk/fabs(current_speed[E_AXIS] - previous_speed[E_AXIS])));<br />
    } <br />
    vmax_junction = min(previous_nominal_speed, vmax_junction * vmax_junction_factor); // Limit speed to max previous speed<br />
  }<br />
  block-&gt;max_entry_speed = vmax_junction;<br />
<br />
  // Initialize block entry speed. Compute based on deceleration to user-defined MINIMUM_PLANNER_SPEED.<br />
  double v_allowable = max_allowable_speed(-block-&gt;acceleration,MINIMUM_PLANNER_SPEED,block-&gt;millimeters);<br />
  block-&gt;entry_speed = min(vmax_junction, v_allowable);<br />
<br />
  // Initialize planner efficiency flags<br />
  // Set flag if block will always reach maximum junction speed regardless of entry/exit speeds.<br />
  // If a block can de/ac-celerate from nominal speed to zero within the length of the block, then<br />
  // the current block and next block junction speeds are guaranteed to always be at their maximum<br />
  // junction speeds in deceleration and acceleration, respectively. This is due to how the current<br />
  // block nominal speed limits both the current and next maximum junction speeds. Hence, in both<br />
  // the reverse and forward planners, the corresponding block junction speed will always be at the<br />
  // the maximum junction speed and may always be ignored for any speed reduction checks.<br />
  if (block-&gt;nominal_speed &lt;= v_allowable) { <br />
    block-&gt;nominal_length_flag = true; <br />
  }<br />
  else { <br />
    block-&gt;nominal_length_flag = false; <br />
  }<br />
  block-&gt;recalculate_flag = true; // Always calculate trapezoid for new block<br />
<br />
  // Update previous path unit_vector and nominal speed<br />
  memcpy(previous_speed, current_speed, sizeof(previous_speed)); // previous_speed[] = current_speed[]<br />
  previous_nominal_speed = block-&gt;nominal_speed;<br />
<br />
<br />
#ifdef ADVANCE<br />
  // Calculate advance rate<br />
  if((block-&gt;steps_e == 0) || (block-&gt;steps_x == 0 &amp;&amp; block-&gt;steps_y == 0 &amp;&amp; block-&gt;steps_z == 0)) {<br />
    block-&gt;advance_rate = 0;<br />
    block-&gt;advance = 0;<br />
  }<br />
  else {<br />
    long acc_dist = estimate_acceleration_distance(0, block-&gt;nominal_rate, block-&gt;acceleration_st);<br />
    float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * <br />
      (current_speed[E_AXIS] * current_speed[E_AXIS] * EXTRUSION_AREA * EXTRUSION_AREA)*256;<br />
    block-&gt;advance = advance;<br />
    if(acc_dist == 0) {<br />
      block-&gt;advance_rate = 0;<br />
    } <br />
    else {<br />
      block-&gt;advance_rate = advance / (float)acc_dist;<br />
    }<br />
  }<br />
  /*<br />
    SERIAL_ECHO_START;<br />
   SERIAL_ECHOPGM("advance :");<br />
   SERIAL_ECHO(block-&gt;advance/256.0);<br />
   SERIAL_ECHOPGM("advance rate :");<br />
   SERIAL_ECHOLN(block-&gt;advance_rate/256.0);<br />
   */<br />
#endif // ADVANCE<br />
<br />
  calculate_trapezoid_for_block(block, block-&gt;entry_speed/block-&gt;nominal_speed,<br />
  safe_speed/block-&gt;nominal_speed);<br />
<br />
  // Move buffer head<br />
  block_buffer_head = next_buffer_head;<br />
<br />
  // Update position<br />
  memcpy(position, target, sizeof(target)); // position[] = target[]<br />
<br />
  planner_recalculate();<br />
<br />
  st_wake_up();<br />
}<br />
<br />
#ifdef ENABLE_AUTO_BED_LEVELING<br />
vector_3 plan_get_position() {<br />
	vector_3 position = vector_3(st_get_position_mm(X_AXIS), st_get_position_mm(Y_AXIS), st_get_position_mm(Z_AXIS));<br />
<br />
	//position.debug("in plan_get position");<br />
	//plan_bed_level_matrix.debug("in plan_get bed_level");<br />
	matrix_3x3 inverse = matrix_3x3::transpose(plan_bed_level_matrix);<br />
	//inverse.debug("in plan_get inverse");<br />
	position.apply_rotation(inverse);<br />
	//position.debug("after rotation");<br />
<br />
	return position;<br />
}</i></i></i></i></i></i>]]></description>
            <dc:creator>Vahid</dc:creator>
            <category>Firmware - mainstream and related support</category>
            <pubDate>Tue, 08 Sep 2015 06:58:10 -0400</pubDate>
        </item>
        <item>
            <guid>https://reprap.org/forum/read.php?146,451615,542114#msg-542114</guid>
            <title>Re: plan_buffer_line</title>
            <link>https://reprap.org/forum/read.php?146,451615,542114#msg-542114</link>
            <description><![CDATA[ This might be helpful:<br />
[<a href="http://3digitalcooks.com/2014/10/marlin-movement-101/" target="_blank"  rel="nofollow">3digitalcooks.com</a>]]]></description>
            <dc:creator>jessicabrenner</dc:creator>
            <category>Firmware - mainstream and related support</category>
            <pubDate>Tue, 04 Aug 2015 23:23:36 -0400</pubDate>
        </item>
        <item>
            <guid>https://reprap.org/forum/read.php?146,451615,451615#msg-451615</guid>
            <title>plan_buffer_line</title>
            <link>https://reprap.org/forum/read.php?146,451615,451615#msg-451615</link>
            <description><![CDATA[ Hi everyone,<br />
<br />
I was looking through the Marlin firmware and came across this function (plan_buffer_line) throughout marlin_main.cpp <br />
It appears to be involved in the movement of the printer. I just cannot find this function anywhere in the files.<br />
Does anyone know where this function is? I would like to figure out its inner workings and get to the bottom of this. <br />
<br />
Thanks!<br />
<br />
Bryan]]></description>
            <dc:creator>AMINKERR</dc:creator>
            <category>Firmware - mainstream and related support</category>
            <pubDate>Tue, 06 Jan 2015 11:09:27 -0500</pubDate>
        </item>
    </channel>
</rss>
