Browse Source

Fix planner block optimization

- Fixed the planner incorrectly avoiding optimization of the block following the active one.
- Added extra conditions to terminate planner early and avoid redundant computations.
etagle 7 years ago
parent
commit
a4af975873
2 changed files with 182 additions and 78 deletions
  1. 160
    63
      Marlin/src/module/planner.cpp
  2. 22
    15
      Marlin/src/module/planner.h

+ 160
- 63
Marlin/src/module/planner.cpp View File

107
 volatile uint8_t Planner::block_buffer_head,  // Index of the next block to be pushed
107
 volatile uint8_t Planner::block_buffer_head,  // Index of the next block to be pushed
108
                  Planner::block_buffer_tail;  // Index of the busy block, if any
108
                  Planner::block_buffer_tail;  // Index of the busy block, if any
109
 uint16_t Planner::cleaning_buffer_counter;    // A counter to disable queuing of blocks
109
 uint16_t Planner::cleaning_buffer_counter;    // A counter to disable queuing of blocks
110
-uint8_t Planner::delay_before_delivering;     // This counter delays delivery of blocks when queue becomes empty to allow the opportunity of merging blocks
110
+uint8_t Planner::delay_before_delivering,     // This counter delays delivery of blocks when queue becomes empty to allow the opportunity of merging blocks
111
+        Planner::block_buffer_planned;        // Index of the optimally planned block
111
 
112
 
112
 float Planner::max_feedrate_mm_s[XYZE_N],   // Max speeds in mm per second
113
 float Planner::max_feedrate_mm_s[XYZE_N],   // Max speeds in mm per second
113
       Planner::axis_steps_per_mm[XYZE_N],
114
       Planner::axis_steps_per_mm[XYZE_N],
227
     bed_level_matrix.set_to_identity();
228
     bed_level_matrix.set_to_identity();
228
   #endif
229
   #endif
229
   clear_block_buffer();
230
   clear_block_buffer();
231
+  block_buffer_planned = 0;
230
   delay_before_delivering = 0;
232
   delay_before_delivering = 0;
231
 }
233
 }
232
 
234
 
825
   if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
827
   if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
826
 }
828
 }
827
 
829
 
830
+/*                            PLANNER SPEED DEFINITION
831
+                                     +--------+   <- current->nominal_speed
832
+                                    /          \
833
+         current->entry_speed ->   +            \
834
+                                   |             + <- next->entry_speed (aka exit speed)
835
+                                   +-------------+
836
+                                       time -->
837
+
838
+  Recalculates the motion plan according to the following basic guidelines:
839
+
840
+    1. Go over every feasible block sequentially in reverse order and calculate the junction speeds
841
+        (i.e. current->entry_speed) such that:
842
+      a. No junction speed exceeds the pre-computed maximum junction speed limit or nominal speeds of
843
+         neighboring blocks.
844
+      b. A block entry speed cannot exceed one reverse-computed from its exit speed (next->entry_speed)
845
+         with a maximum allowable deceleration over the block travel distance.
846
+      c. The last (or newest appended) block is planned from a complete stop (an exit speed of zero).
847
+    2. Go over every block in chronological (forward) order and dial down junction speed values if
848
+      a. The exit speed exceeds the one forward-computed from its entry speed with the maximum allowable
849
+         acceleration over the block travel distance.
850
+
851
+  When these stages are complete, the planner will have maximized the velocity profiles throughout the all
852
+  of the planner blocks, where every block is operating at its maximum allowable acceleration limits. In
853
+  other words, for all of the blocks in the planner, the plan is optimal and no further speed improvements
854
+  are possible. If a new block is added to the buffer, the plan is recomputed according to the said
855
+  guidelines for a new optimal plan.
856
+
857
+  To increase computational efficiency of these guidelines, a set of planner block pointers have been
858
+  created to indicate stop-compute points for when the planner guidelines cannot logically make any further
859
+  changes or improvements to the plan when in normal operation and new blocks are streamed and added to the
860
+  planner buffer. For example, if a subset of sequential blocks in the planner have been planned and are
861
+  bracketed by junction velocities at their maximums (or by the first planner block as well), no new block
862
+  added to the planner buffer will alter the velocity profiles within them. So we no longer have to compute
863
+  them. Or, if a set of sequential blocks from the first block in the planner (or a optimal stop-compute
864
+  point) are all accelerating, they are all optimal and can not be altered by a new block added to the
865
+  planner buffer, as this will only further increase the plan speed to chronological blocks until a maximum
866
+  junction velocity is reached. However, if the operational conditions of the plan changes from infrequently
867
+  used feed holds or feedrate overrides, the stop-compute pointers will be reset and the entire plan is
868
+  recomputed as stated in the general guidelines.
869
+
870
+  Planner buffer index mapping:
871
+  - block_buffer_tail: Points to the beginning of the planner buffer. First to be executed or being executed.
872
+  - block_buffer_head: Points to the buffer block after the last block in the buffer. Used to indicate whether
873
+      the buffer is full or empty. As described for standard ring buffers, this block is always empty.
874
+  - block_buffer_planned: Points to the first buffer block after the last optimally planned block for normal
875
+      streaming operating conditions. Use for planning optimizations by avoiding recomputing parts of the
876
+      planner buffer that don't change with the addition of a new block, as describe above. In addition,
877
+      this block can never be less than block_buffer_tail and will always be pushed forward and maintain
878
+      this requirement when encountered by the plan_discard_current_block() routine during a cycle.
879
+
880
+  NOTE: Since the planner only computes on what's in the planner buffer, some motions with lots of short
881
+  line segments, like G2/3 arcs or complex curves, may seem to move slow. This is because there simply isn't
882
+  enough combined distance traveled in the entire buffer to accelerate up to the nominal speed and then
883
+  decelerate to a complete stop at the end of the buffer, as stated by the guidelines. If this happens and
884
+  becomes an annoyance, there are a few simple solutions: (1) Maximize the machine acceleration. The planner
885
+  will be able to compute higher velocity profiles within the same combined distance. (2) Maximize line
886
+  motion(s) distance per block to a desired tolerance. The more combined distance the planner has to use,
887
+  the faster it can go. (3) Maximize the planner buffer size. This also will increase the combined distance
888
+  for the planner to compute over. It also increases the number of computations the planner has to perform
889
+  to compute an optimal plan, so select carefully.
890
+*/
891
+
828
 // The kernel called by recalculate() when scanning the plan from last to first entry.
892
 // The kernel called by recalculate() when scanning the plan from last to first entry.
829
 void Planner::reverse_pass_kernel(block_t* const current, const block_t * const next) {
893
 void Planner::reverse_pass_kernel(block_t* const current, const block_t * const next) {
830
   if (current) {
894
   if (current) {
851
         : MIN(max_entry_speed_sqr, max_allowable_speed_sqr(-current->acceleration, next ? next->entry_speed_sqr : sq(MINIMUM_PLANNER_SPEED), current->millimeters));
915
         : MIN(max_entry_speed_sqr, max_allowable_speed_sqr(-current->acceleration, next ? next->entry_speed_sqr : sq(MINIMUM_PLANNER_SPEED), current->millimeters));
852
       if (current->entry_speed_sqr != new_entry_speed_sqr) {
916
       if (current->entry_speed_sqr != new_entry_speed_sqr) {
853
         current->entry_speed_sqr = new_entry_speed_sqr;
917
         current->entry_speed_sqr = new_entry_speed_sqr;
918
+
919
+        // Need to recalculate the block speed
854
         SBI(current->flag, BLOCK_BIT_RECALCULATE);
920
         SBI(current->flag, BLOCK_BIT_RECALCULATE);
855
       }
921
       }
856
     }
922
     }
862
  * Once in reverse and once forward. This implements the reverse pass.
928
  * Once in reverse and once forward. This implements the reverse pass.
863
  */
929
  */
864
 void Planner::reverse_pass() {
930
 void Planner::reverse_pass() {
865
-  if (movesplanned() > 2) {
866
-    const uint8_t endnr = next_block_index(block_buffer_tail); // tail is running. tail+1 shouldn't be altered because it's connected to the running block.
867
-    uint8_t blocknr = prev_block_index(block_buffer_head);
931
+  // Initialize block index to the last block in the planner buffer.
932
+  uint8_t block_index = prev_block_index(block_buffer_head);
933
+
934
+  // Read the index of the last buffer planned block.
935
+  // The ISR may change it so get a stable local copy.
936
+  uint8_t planned_block_index = block_buffer_planned;
937
+
938
+  // If there was a race condition and block_buffer_planned was incremented
939
+  //  or was pointing at the head (queue empty) break loop now and avoid
940
+  //  planning already consumed blocks
941
+  if (planned_block_index == block_buffer_head) return;
942
+
943
+  // Reverse Pass: Coarsely maximize all possible deceleration curves back-planning from the last
944
+  // block in buffer. Cease planning when the last optimal planned or tail pointer is reached.
945
+  // NOTE: Forward pass will later refine and correct the reverse pass to create an optimal plan.
946
+  block_t *current;
947
+  const block_t *next = NULL;
948
+  while (block_index != planned_block_index) {
868
 
949
 
869
     // Perform the reverse pass
950
     // Perform the reverse pass
870
-    block_t *current, *next = NULL;
871
-    while (blocknr != endnr) {
872
-      // Perform the reverse pass - Only consider non sync blocks
873
-      current = &block_buffer[blocknr];
874
-      if (!TEST(current->flag, BLOCK_BIT_SYNC_POSITION)) {
875
-        reverse_pass_kernel(current, next);
876
-        next = current;
877
-      }
878
-      // Advance to the next
879
-      blocknr = prev_block_index(blocknr);
951
+    current = &block_buffer[block_index];
952
+
953
+    // Only consider non sync blocks
954
+    if (!TEST(current->flag, BLOCK_BIT_SYNC_POSITION)) {
955
+      reverse_pass_kernel(current, next);
956
+      next = current;
880
     }
957
     }
958
+
959
+    // Advance to the next
960
+    block_index = prev_block_index(block_index);
881
   }
961
   }
882
 }
962
 }
883
 
963
 
884
 // The kernel called by recalculate() when scanning the plan from first to last entry.
964
 // The kernel called by recalculate() when scanning the plan from first to last entry.
885
-void Planner::forward_pass_kernel(const block_t * const previous, block_t* const current) {
965
+void Planner::forward_pass_kernel(const block_t * const previous, block_t* const current, uint8_t block_index) {
886
   if (previous) {
966
   if (previous) {
887
     // If the previous block is an acceleration block, too short to complete the full speed
967
     // If the previous block is an acceleration block, too short to complete the full speed
888
     // change, adjust the entry speed accordingly. Entry speeds have already been reset,
968
     // change, adjust the entry speed accordingly. Entry speeds have already been reset,
889
     // maximized, and reverse-planned. If nominal length is set, max junction speed is
969
     // maximized, and reverse-planned. If nominal length is set, max junction speed is
890
     // guaranteed to be reached. No need to recheck.
970
     // guaranteed to be reached. No need to recheck.
891
-    if (!TEST(previous->flag, BLOCK_BIT_NOMINAL_LENGTH)) {
892
-      if (previous->entry_speed_sqr < current->entry_speed_sqr) {
893
-        // Compute the maximum allowable speed
894
-        const float new_entry_speed_sqr = max_allowable_speed_sqr(-previous->acceleration, previous->entry_speed_sqr, previous->millimeters);
895
-        // If true, current block is full-acceleration
896
-        if (current->entry_speed_sqr > new_entry_speed_sqr) {
897
-          // Always <= max_entry_speed_sqr. Backward pass sets this.
898
-          current->entry_speed_sqr = new_entry_speed_sqr;
899
-          SBI(current->flag, BLOCK_BIT_RECALCULATE);
900
-        }
971
+    if (!TEST(previous->flag, BLOCK_BIT_NOMINAL_LENGTH) &&
972
+      previous->entry_speed_sqr < current->entry_speed_sqr) {
973
+
974
+      // Compute the maximum allowable speed
975
+      const float new_entry_speed_sqr = max_allowable_speed_sqr(-previous->acceleration, previous->entry_speed_sqr, previous->millimeters);
976
+
977
+      // If true, current block is full-acceleration and we can move the planned pointer forward.
978
+      if (new_entry_speed_sqr < current->entry_speed_sqr) {
979
+
980
+        // Always <= max_entry_speed_sqr. Backward pass sets this.
981
+        current->entry_speed_sqr = new_entry_speed_sqr; // Always <= max_entry_speed_sqr. Backward pass sets this.
982
+
983
+        // Set optimal plan pointer.
984
+        block_buffer_planned = block_index;
985
+
986
+        // And mark we need to recompute the trapezoidal shape
987
+        SBI(current->flag, BLOCK_BIT_RECALCULATE);
901
       }
988
       }
902
     }
989
     }
990
+
991
+    // Any block set at its maximum entry speed also creates an optimal plan up to this
992
+    // point in the buffer. When the plan is bracketed by either the beginning of the
993
+    // buffer and a maximum entry speed or two maximum entry speeds, every block in between
994
+    // cannot logically be further improved. Hence, we don't have to recompute them anymore.
995
+    if (current->entry_speed_sqr == current->max_entry_speed_sqr)
996
+      block_buffer_planned = block_index;
903
   }
997
   }
904
 }
998
 }
905
 
999
 
908
  * Once in reverse and once forward. This implements the forward pass.
1002
  * Once in reverse and once forward. This implements the forward pass.
909
  */
1003
  */
910
 void Planner::forward_pass() {
1004
 void Planner::forward_pass() {
911
-  const uint8_t endnr = block_buffer_head;
912
-  uint8_t blocknr = block_buffer_tail;
913
-
914
-  // Perform the forward pass
915
-  block_t *current, *previous = NULL;
916
-  while (blocknr != endnr) {
917
-    // Perform the forward pass - Only consider non-sync blocks
918
-    current = &block_buffer[blocknr];
1005
+
1006
+  // Forward Pass: Forward plan the acceleration curve from the planned pointer onward.
1007
+  // Also scans for optimal plan breakpoints and appropriately updates the planned pointer.
1008
+
1009
+  // Begin at buffer planned pointer. Note that block_buffer_planned can be modified
1010
+  //  by the stepper ISR,  so read it ONCE. It it guaranteed that block_buffer_planned
1011
+  //  will never lead head, so the loop is safe to execute. Also note that the forward
1012
+  //  pass will never modify the values at the tail.
1013
+  uint8_t block_index = block_buffer_planned;
1014
+
1015
+  block_t *current;
1016
+  const block_t * previous = NULL;
1017
+  while (block_index != block_buffer_head) {
1018
+
1019
+    // Perform the forward pass
1020
+    current = &block_buffer[block_index];
1021
+
1022
+    // Skip SYNC blocks
919
     if (!TEST(current->flag, BLOCK_BIT_SYNC_POSITION)) {
1023
     if (!TEST(current->flag, BLOCK_BIT_SYNC_POSITION)) {
920
-      forward_pass_kernel(previous, current);
1024
+      forward_pass_kernel(previous, current, block_index);
921
       previous = current;
1025
       previous = current;
922
     }
1026
     }
923
     // Advance to the previous
1027
     // Advance to the previous
924
-    blocknr = next_block_index(blocknr);
1028
+    block_index = next_block_index(block_index);
925
   }
1029
   }
926
 }
1030
 }
927
 
1031
 
931
  * recalculate() after updating the blocks.
1035
  * recalculate() after updating the blocks.
932
  */
1036
  */
933
 void Planner::recalculate_trapezoids() {
1037
 void Planner::recalculate_trapezoids() {
1038
+  // The tail may be changed by the ISR so get a local copy.
934
   uint8_t block_index = block_buffer_tail;
1039
   uint8_t block_index = block_buffer_tail;
935
 
1040
 
936
   // As there could be a sync block in the head of the queue, and the next loop must not
1041
   // As there could be a sync block in the head of the queue, and the next loop must not
1004
   }
1109
   }
1005
 }
1110
 }
1006
 
1111
 
1007
-/**
1008
- * Recalculate the motion plan according to the following algorithm:
1009
- *
1010
- *   1. Go over every block in reverse order...
1011
- *
1012
- *      Calculate a junction speed reduction (block_t.entry_factor) so:
1013
- *
1014
- *      a. The junction jerk is within the set limit, and
1015
- *
1016
- *      b. No speed reduction within one block requires faster
1017
- *         deceleration than the one, true constant acceleration.
1018
- *
1019
- *   2. Go over every block in chronological order...
1020
- *
1021
- *      Dial down junction speed reduction values if:
1022
- *      a. The speed increase within one block would require faster
1023
- *         acceleration than the one, true constant acceleration.
1024
- *
1025
- * After that, all blocks will have an entry_factor allowing all speed changes to
1026
- * be performed using only the one, true constant acceleration, and where no junction
1027
- * jerk is jerkier than the set limit, Jerky. Finally it will:
1028
- *
1029
- *   3. Recalculate "trapezoids" for all blocks.
1030
- */
1031
 void Planner::recalculate() {
1112
 void Planner::recalculate() {
1032
-  reverse_pass();
1033
-  forward_pass();
1113
+  // Initialize block index to the last block in the planner buffer.
1114
+  const uint8_t block_index = prev_block_index(block_buffer_head);
1115
+  // If there is just one block, no planning can be done. Avoid it!
1116
+  if (block_index != block_buffer_planned) {
1117
+    reverse_pass();
1118
+    forward_pass();
1119
+  }
1034
   recalculate_trapezoids();
1120
   recalculate_trapezoids();
1035
 }
1121
 }
1036
 
1122
 
1348
 #endif // PLANNER_LEVELING
1434
 #endif // PLANNER_LEVELING
1349
 
1435
 
1350
 void Planner::quick_stop() {
1436
 void Planner::quick_stop() {
1437
+
1351
   // Remove all the queued blocks. Note that this function is NOT
1438
   // Remove all the queued blocks. Note that this function is NOT
1352
   // called from the Stepper ISR, so we must consider tail as readonly!
1439
   // called from the Stepper ISR, so we must consider tail as readonly!
1353
-  // that is why we set head to tail!
1354
-  block_buffer_head = block_buffer_tail;
1440
+  // that is why we set head to tail - But there is a race condition that
1441
+  // must be handled: The tail could change between the read and the assignment
1442
+  // so this must be enclosed in a critical section
1443
+
1444
+  const bool was_enabled = STEPPER_ISR_ENABLED();
1445
+  if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
1446
+
1447
+  // Drop all queue entries
1448
+  block_buffer_planned = block_buffer_head = block_buffer_tail;
1355
 
1449
 
1356
   // Restart the block delay for the first movement - As the queue was
1450
   // Restart the block delay for the first movement - As the queue was
1357
   // forced to empty, there's no risk the ISR will touch this.
1451
   // forced to empty, there's no risk the ISR will touch this.
1365
   // Make sure to drop any attempt of queuing moves for at least 1 second
1459
   // Make sure to drop any attempt of queuing moves for at least 1 second
1366
   cleaning_buffer_counter = 1000;
1460
   cleaning_buffer_counter = 1000;
1367
 
1461
 
1462
+  // Reenable Stepper ISR
1463
+  if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
1464
+
1368
   // And stop the stepper ISR
1465
   // And stop the stepper ISR
1369
   stepper.quick_stop();
1466
   stepper.quick_stop();
1370
 }
1467
 }

+ 22
- 15
Marlin/src/module/planner.h View File

177
     static volatile uint8_t block_buffer_head,      // Index of the next block to be pushed
177
     static volatile uint8_t block_buffer_head,      // Index of the next block to be pushed
178
                             block_buffer_tail;      // Index of the busy block, if any
178
                             block_buffer_tail;      // Index of the busy block, if any
179
     static uint16_t cleaning_buffer_counter;        // A counter to disable queuing of blocks
179
     static uint16_t cleaning_buffer_counter;        // A counter to disable queuing of blocks
180
-    static uint8_t delay_before_delivering;         // This counter delays delivery of blocks when queue becomes empty to allow the opportunity of merging blocks
180
+    static uint8_t delay_before_delivering,         // This counter delays delivery of blocks when queue becomes empty to allow the opportunity of merging blocks
181
+                   block_buffer_planned;            // Index of the optimally planned block
182
+                   
181
 
183
 
182
     #if ENABLED(DISTINCT_E_FACTORS)
184
     #if ENABLED(DISTINCT_E_FACTORS)
183
       static uint8_t last_extruder;                 // Respond to extruder change
185
       static uint8_t last_extruder;                 // Respond to extruder change
655
         block_t * const block = &block_buffer[block_buffer_tail];
657
         block_t * const block = &block_buffer[block_buffer_tail];
656
 
658
 
657
         // No trapezoid calculated? Don't execute yet.
659
         // No trapezoid calculated? Don't execute yet.
658
-        if ( TEST(block->flag, BLOCK_BIT_RECALCULATE)
659
-          || (movesplanned() > 1 && TEST(block_buffer[next_block_index(block_buffer_tail)].flag, BLOCK_BIT_RECALCULATE))
660
-        ) return NULL;
660
+        if (TEST(block->flag, BLOCK_BIT_RECALCULATE)) return NULL;
661
 
661
 
662
         #if ENABLED(ULTRA_LCD)
662
         #if ENABLED(ULTRA_LCD)
663
           block_buffer_runtime_us -= block->segment_time_us; // We can't be sure how long an active block will take, so don't count it.
663
           block_buffer_runtime_us -= block->segment_time_us; // We can't be sure how long an active block will take, so don't count it.
667
         SBI(block->flag, BLOCK_BIT_BUSY);
667
         SBI(block->flag, BLOCK_BIT_BUSY);
668
         return block;
668
         return block;
669
       }
669
       }
670
-      else {
671
-        // The queue became empty
672
-        #if ENABLED(ULTRA_LCD)
673
-          clear_block_buffer_runtime(); // paranoia. Buffer is empty now - so reset accumulated time to zero.
674
-        #endif
675
-        return NULL;
676
-      }
670
+
671
+      // The queue became empty
672
+      #if ENABLED(ULTRA_LCD)
673
+        clear_block_buffer_runtime(); // paranoia. Buffer is empty now - so reset accumulated time to zero.
674
+      #endif
675
+
676
+      return NULL;
677
     }
677
     }
678
 
678
 
679
     /**
679
     /**
682
      * NB: There MUST be a current block to call this function!!
682
      * NB: There MUST be a current block to call this function!!
683
      */
683
      */
684
     FORCE_INLINE static void discard_current_block() {
684
     FORCE_INLINE static void discard_current_block() {
685
-      block_buffer_tail = BLOCK_MOD(block_buffer_tail + 1);
685
+      if (has_blocks_queued()) { // Discard non-empty buffer.
686
+        uint8_t block_index = next_block_index( block_buffer_tail );
687
+
688
+        // Push block_buffer_planned pointer, if encountered.
689
+        if (!has_blocks_queued()) block_buffer_planned = block_index;
690
+
691
+        block_buffer_tail = block_index;
692
+      }
686
     }
693
     }
687
 
694
 
688
     #if ENABLED(ULTRA_LCD)
695
     #if ENABLED(ULTRA_LCD)
741
     /**
748
     /**
742
      * Get the index of the next / previous block in the ring buffer
749
      * Get the index of the next / previous block in the ring buffer
743
      */
750
      */
744
-    static constexpr int8_t next_block_index(const int8_t block_index) { return BLOCK_MOD(block_index + 1); }
745
-    static constexpr int8_t prev_block_index(const int8_t block_index) { return BLOCK_MOD(block_index - 1); }
751
+    static constexpr uint8_t next_block_index(const uint8_t block_index) { return BLOCK_MOD(block_index + 1); }
752
+    static constexpr uint8_t prev_block_index(const uint8_t block_index) { return BLOCK_MOD(block_index - 1); }
746
 
753
 
747
     /**
754
     /**
748
      * Calculate the distance (not time) it takes to accelerate
755
      * Calculate the distance (not time) it takes to accelerate
787
     static void calculate_trapezoid_for_block(block_t* const block, const float &entry_factor, const float &exit_factor);
794
     static void calculate_trapezoid_for_block(block_t* const block, const float &entry_factor, const float &exit_factor);
788
 
795
 
789
     static void reverse_pass_kernel(block_t* const current, const block_t * const next);
796
     static void reverse_pass_kernel(block_t* const current, const block_t * const next);
790
-    static void forward_pass_kernel(const block_t * const previous, block_t* const current);
797
+    static void forward_pass_kernel(const block_t * const previous, block_t* const current, uint8_t block_index);
791
 
798
 
792
     static void reverse_pass();
799
     static void reverse_pass();
793
     static void forward_pass();
800
     static void forward_pass();

Loading…
Cancel
Save