From dfb06cf7955ed7f45b7bbb7a35bf73a3a83eceda Mon Sep 17 00:00:00 2001 From: Joseph Coffland Date: Wed, 21 Sep 2016 10:59:09 -0700 Subject: [PATCH] Separate forward differencing code --- Makefile | 4 +- src/main.c | 5 +- src/plan/exec.c | 170 ++---------------------------------- src/plan/exec.h | 2 - src/plan/forward_dif.c | 190 +++++++++++++++++++++++++++++++++++++++++ src/plan/forward_dif.h | 34 ++++++++ src/plan/jog.c | 8 +- src/plan/planner.c | 3 - 8 files changed, 239 insertions(+), 177 deletions(-) create mode 100644 src/plan/forward_dif.c create mode 100644 src/plan/forward_dif.h diff --git a/Makefile b/Makefile index 4b19e30..a4e91b6 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ CLOCK = 32000000 TARGET = $(PROJECT).elf -# Compile falgs +# Compile flags CC = avr-gcc CPP = avr-g++ @@ -13,7 +13,7 @@ COMMON = -mmcu=$(MCU) CFLAGS += $(COMMON) CFLAGS += -Wall -Werror # -Wno-error=unused-function -CFLAGS += -gdwarf-2 -std=gnu99 -DF_CPU=$(CLOCK)UL -O3 +CFLAGS += -gdwarf-2 -std=gnu99 -DF_CPU=$(CLOCK)UL -O3 -funroll-loops CFLAGS += -funsigned-bitfields -fpack-struct -fshort-enums -funsigned-char CFLAGS += -MD -MP -MT $@ -MF build/dep/$(@F).d CFLAGS += -Isrc diff --git a/src/main.c b/src/main.c index 90521de..faa6cde 100644 --- a/src/main.c +++ b/src/main.c @@ -67,7 +67,7 @@ int main() { stepper_init(); // steppers motor_init(); // motors switch_init(); // switches - mp_init(); // motion planning + mp_init(); // motion planning machine_init(); // gcode machine vars_init(); // configuration variables estop_init(); // emergency stop handler @@ -79,6 +79,9 @@ int main() { fprintf_P(stdout, PSTR("\n{\"firmware\": \"Buildbotics AVR\", " "\"version\": \"" VERSION "\"}\n")); + // Nominal segment time cannot be longer than maximum + if (MAX_SEGMENT_TIME < NOM_SEGMENT_TIME) ALARM(STAT_INTERNAL_ERROR); + // Main loop while (true) { hw_reset_handler(); // handle hard reset requests diff --git a/src/plan/exec.c b/src/plan/exec.c index 3948245..4049ed8 100644 --- a/src/plan/exec.c +++ b/src/plan/exec.c @@ -32,6 +32,7 @@ #include "util.h" #include "runtime.h" #include "state.h" +#include "forward_dif.h" #include "stepper.h" #include "motor.h" #include "rtc.h" @@ -61,7 +62,7 @@ typedef struct { uint32_t segment_count; // count of running segments float segment_velocity; // computed velocity for aline segment float segment_time; // actual time increment per aline segment - float forward_diff[5]; // forward difference levels + forward_dif_t fdif; // forward difference levels bool hold_planned; // true when a feedhold has been planned move_section_t section; // what section is the move in? bool section_new; // true if it's a new section @@ -97,166 +98,6 @@ static stat_t _exec_aline_segment() { } -/// Forward differencing math -/// -/// We are using a quintic (fifth-degree) Bezier polynomial for the velocity -/// curve. This gives us a "linear pop" velocity curve; with pop being the -/// sixth derivative of position: velocity - 1st, acceleration - 2nd, jerk - -/// 3rd, snap - 4th, crackle - 5th, pop - 6th -/// -/// The Bezier curve takes the form: -/// -/// V(t) = P_0 * B_0(t) + P_1 * B_1(t) + P_2 * B_2(t) + P_3 * B_3(t) + -/// P_4 * B_4(t) + P_5 * B_5(t) -/// -/// Where 0 <= t <= 1, and V(t) is the velocity. P_0 through P_5 are -/// the control points, and B_0(t) through B_5(t) are the Bernstein -/// basis as follows: -/// -/// B_0(t) = (1 - t)^5 = -t^5 + 5t^4 - 10t^3 + 10t^2 - 5t + 1 -/// B_1(t) = 5(1 - t)^4 * t = 5t^5 - 20t^4 + 30t^3 - 20t^2 + 5t -/// B_2(t) = 10(1 - t)^3 * t^2 = -10t^5 + 30t^4 - 30t^3 + 10t^2 -/// B_3(t) = 10(1 - t)^2 * t^3 = 10t^5 - 20t^4 + 10t^3 -/// B_4(t) = 5(1 - t) * t^4 = -5t^5 + 5t^4 -/// B_5(t) = t^5 = t^5 -/// -/// ^ ^ ^ ^ ^ ^ -/// A B C D E F -/// -/// We use forward-differencing to calculate each position through the curve. -/// This requires a formula of the form: -/// -/// V_f(t) = A * t^5 + B * t^4 + C * t^3 + D * t^2 + E * t + F -/// -/// Looking at the above B_0(t) through B_5(t) expanded forms, if we take the -/// coefficients of t^5 through t of the Bezier form of V(t), we can determine -/// that: -/// -/// A = -P_0 + 5 * P_1 - 10 * P_2 + 10 * P_3 - 5 * P_4 + P_5 -/// B = 5 * P_0 - 20 * P_1 + 30 * P_2 - 20 * P_3 + 5 * P_4 -/// C = -10 * P_0 + 30 * P_1 - 30 * P_2 + 10 * P_3 -/// D = 10 * P_0 - 20 * P_1 + 10 * P_2 -/// E = - 5 * P_0 + 5 * P_1 -/// F = P_0 -/// -/// Now, since we will (currently) *always* want the initial acceleration and -/// jerk values to be 0, We set P_i = P_0 = P_1 = P_2 (initial velocity), and -/// P_t = P_3 = P_4 = P_5 (target velocity), which, after simplification, -/// resolves to: -/// -/// A = - 6 * P_i + 6 * P_t -/// B = 15 * P_i - 15 * P_t -/// C = -10 * P_i + 10 * P_t -/// D = 0 -/// E = 0 -/// F = P_i -/// -/// Given an interval count of I to get from P_i to P_t, we get the parametric -/// "step" size of h = 1/I. We need to calculate the initial value of forward -/// differences (F_0 - F_5) such that the inital velocity V = P_i, then we -/// iterate over the following I times: -/// -/// V += F_5 -/// F_5 += F_4 -/// F_4 += F_3 -/// F_3 += F_2 -/// F_2 += F_1 -/// -/// See -/// http://www.drdobbs.com/forward-difference-calculation-of-bezier/184403417 -/// for an example of how to calculate F_0 - F_5 for a cubic bezier curve. Since -/// this is a quintic bezier curve, we need to extend the formulas somewhat. -/// I'll not go into the long-winded step-by-step here, but it gives the -/// resulting formulas: -/// -/// a = A, b = B, c = C, d = D, e = E, f = F -/// -/// F_5(t + h) - F_5(t) = (5ah)t^4 + (10ah^2 + 4bh)t^3 + -/// (10ah^3 + 6bh^2 + 3ch)t^2 + (5ah^4 + 4bh^3 + 3ch^2 + 2dh)t + ah^5 + -/// bh^4 + ch^3 + dh^2 + eh -/// -/// a = 5ah -/// b = 10ah^2 + 4bh -/// c = 10ah^3 + 6bh^2 + 3ch -/// d = 5ah^4 + 4bh^3 + 3ch^2 + 2dh -/// -/// After substitution, simplification, and rearranging: -/// -/// F_4(t + h) - F_4(t) = (20ah^2)t^3 + (60ah^3 + 12bh^2)t^2 + -/// (70ah^4 + 24bh^3 + 6ch^2)t + 30ah^5 + 14bh^4 + 6ch^3 + 2dh^2 -/// -/// a = 20ah^2 -/// b = 60ah^3 + 12bh^2 -/// c = 70ah^4 + 24bh^3 + 6ch^2 -/// -/// After substitution, simplification, and rearranging: -/// -/// F_3(t + h) - F_3(t) = (60ah^3)t^2 + (180ah^4 + 24bh^3)t + 150ah^5 + -/// 36bh^4 + 6ch^3 -/// -/// You get the picture... -/// -/// F_2(t + h) - F_2(t) = (120ah^4)t + 240ah^5 + 24bh^4 -/// F_1(t + h) - F_1(t) = 120ah^5 -/// -/// Normally, we could then assign t = 0, use the A-F values from above, and get -/// out initial F_* values. However, for the sake of "averaging" the velocity -/// of each segment, we actually want to have the initial V be be at t = h/2 and -/// iterate I-1 times. So, the resulting F_* values are (steps not shown): -/// -/// F_5 = 121Ah^5 / 16 + 5Bh^4 + 13Ch^3 / 4 + 2Dh^2 + Eh -/// F_4 = 165Ah^5 / 2 + 29Bh^4 + 9Ch^3 + 2Dh^2 -/// F_3 = 255Ah^5 + 48Bh^4 + 6Ch^3 -/// F_2 = 300Ah^5 + 24Bh^4 -/// F_1 = 120Ah^5 -/// -/// Note that with our current control points, D and E are actually 0. -/// -/// This can be simplified even further by subsituting Ah, Bh & Ch back in and -/// reducing to: -/// -/// F_5 = (32.5 * s^2 - 75 * s + 45.375)(Vt - Vi) * h^5 -/// F_4 = (90.0 * s^2 - 435 * s + 495.0 )(Vt - Vi) * h^5 -/// F_3 = (60.0 * s^2 - 720 * s + 1530.0 )(Vt - Vi) * h^5 -/// F_2 = ( - 360 * s + 1800.0 )(Vt - Vi) * h^5 -/// F_1 = ( 720.0 )(Vt - Vi) * h^5 -/// -float mp_init_forward_diffs(float fdifs[5], float Vi, float Vt, float s) { - const float h = 1 / s; - const float s2 = square(s); - const float Vdxh5 = (Vt - Vi) * h * h * h * h * h; - - fdifs[4] = (32.5 * s2 - 75.0 * s + 45.375) * Vdxh5; - fdifs[3] = (90.0 * s2 - 435.0 * s + 495.0 ) * Vdxh5; - fdifs[2] = (60.0 * s2 - 720.0 * s + 1530.0 ) * Vdxh5; - fdifs[1] = ( - 360.0 * s + 1800.0 ) * Vdxh5; - fdifs[0] = ( 720.0 ) * Vdxh5; - - // Calculate the initial velocity by calculating: - // - // V(h / 2) = - // - // ( -6Vi + 6Vt) / (2^5 * s^8) + - // ( 15Vi - 15Vt) / (2^4 * s^8) + - // (-10Vi + 10Vt) / (2^3 * s^8) + Vi = - // - // (Vt - Vi) * 1/2 * h^8 + Vi - return (Vt - Vi) * 0.5 * square(square(square(h))) + Vi; -} - - -float mp_next_forward_diff(float fdifs[5]) { - float delta = fdifs[4]; - - fdifs[4] += fdifs[3]; - fdifs[3] += fdifs[2]; - fdifs[2] += fdifs[1]; - fdifs[1] += fdifs[0]; - - return delta; -} - - /// Common code for head and tail sections static stat_t _exec_aline_section(float length, float vin, float vout) { if (ex.section_new) { @@ -270,7 +111,7 @@ static stat_t _exec_aline_section(float length, float vin, float vout) { if (vin == vout) ex.segment_velocity = vin; else ex.segment_velocity = - mp_init_forward_diffs(ex.forward_diff, vin, vout, ex.segments); + mp_init_forward_dif(ex.fdif, vin, vout, ex.segments); if (ex.segment_time < MIN_SEGMENT_TIME) return STAT_MINIMUM_TIME_MOVE; // exit /wo advancing position @@ -284,8 +125,7 @@ static stat_t _exec_aline_section(float length, float vin, float vout) { ex.section_new = false; } else { - if (vin != vout) - ex.segment_velocity += mp_next_forward_diff(ex.forward_diff); + if (vin != vout) ex.segment_velocity += mp_next_forward_dif(ex.fdif); // Subsequent segments if (_exec_aline_segment() == STAT_OK) return STAT_OK; @@ -349,7 +189,7 @@ static float _compute_next_segment_velocity() { } return ex.segment_velocity + - (ex.section == SECTION_BODY ? 0 : mp_next_forward_diff(ex.forward_diff)); + (ex.section == SECTION_BODY ? 0 : mp_next_forward_dif(ex.fdif)); } diff --git a/src/plan/exec.h b/src/plan/exec.h index 7db35f7..00972b2 100644 --- a/src/plan/exec.h +++ b/src/plan/exec.h @@ -32,5 +32,3 @@ stat_t mp_exec_move(); stat_t mp_exec_aline(mp_buffer_t *bf); -float mp_init_forward_diffs(float fdifs[5], float Vi, float Vt, float s); -float mp_next_forward_diff(float fdifs[5]); diff --git a/src/plan/forward_dif.c b/src/plan/forward_dif.c new file mode 100644 index 0000000..955b15e --- /dev/null +++ b/src/plan/forward_dif.c @@ -0,0 +1,190 @@ +/******************************************************************************\ + + This file is part of the Buildbotics firmware. + + Copyright (c) 2015 - 2016 Buildbotics LLC + Copyright (c) 2010 - 2015 Alden S. Hart, Jr. + Copyright (c) 2012 - 2015 Rob Giseburt + All rights reserved. + + This file ("the software") is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License, + version 2 as published by the Free Software Foundation. You should + have received a copy of the GNU General Public License, version 2 + along with the software. If not, see . + + The software is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the software. If not, see + . + + For information regarding this software email: + "Joseph Coffland" + +\******************************************************************************/ + +#include "forward_dif.h" + +#include + + +/// Forward differencing math +/// +/// We are using a quintic (fifth-degree) Bezier polynomial for the velocity +/// curve. This gives us a "linear pop" velocity curve; with pop being the +/// sixth derivative of position: velocity - 1st, acceleration - 2nd, jerk - +/// 3rd, snap - 4th, crackle - 5th, pop - 6th +/// +/// The Bezier curve takes the form: +/// +/// V(t) = P_0 * B_0(t) + P_1 * B_1(t) + P_2 * B_2(t) + P_3 * B_3(t) + +/// P_4 * B_4(t) + P_5 * B_5(t) +/// +/// Where 0 <= t <= 1, and V(t) is the velocity. P_0 through P_5 are +/// the control points, and B_0(t) through B_5(t) are the Bernstein +/// basis as follows: +/// +/// B_0(t) = (1 - t)^5 = -t^5 + 5t^4 - 10t^3 + 10t^2 - 5t + 1 +/// B_1(t) = 5(1 - t)^4 * t = 5t^5 - 20t^4 + 30t^3 - 20t^2 + 5t +/// B_2(t) = 10(1 - t)^3 * t^2 = -10t^5 + 30t^4 - 30t^3 + 10t^2 +/// B_3(t) = 10(1 - t)^2 * t^3 = 10t^5 - 20t^4 + 10t^3 +/// B_4(t) = 5(1 - t) * t^4 = -5t^5 + 5t^4 +/// B_5(t) = t^5 = t^5 +/// +/// ^ ^ ^ ^ ^ ^ +/// A B C D E F +/// +/// We use forward-differencing to calculate each position through the curve. +/// This requires a formula of the form: +/// +/// V_f(t) = A * t^5 + B * t^4 + C * t^3 + D * t^2 + E * t + F +/// +/// Looking at the above B_0(t) through B_5(t) expanded forms, if we take the +/// coefficients of t^5 through t of the Bezier form of V(t), we can determine +/// that: +/// +/// A = -P_0 + 5 * P_1 - 10 * P_2 + 10 * P_3 - 5 * P_4 + P_5 +/// B = 5 * P_0 - 20 * P_1 + 30 * P_2 - 20 * P_3 + 5 * P_4 +/// C = -10 * P_0 + 30 * P_1 - 30 * P_2 + 10 * P_3 +/// D = 10 * P_0 - 20 * P_1 + 10 * P_2 +/// E = - 5 * P_0 + 5 * P_1 +/// F = P_0 +/// +/// Now, since we will (currently) *always* want the initial acceleration and +/// jerk values to be 0, We set P_i = P_0 = P_1 = P_2 (initial velocity), and +/// P_t = P_3 = P_4 = P_5 (target velocity), which, after simplification, +/// resolves to: +/// +/// A = - 6 * P_i + 6 * P_t +/// B = 15 * P_i - 15 * P_t +/// C = -10 * P_i + 10 * P_t +/// D = 0 +/// E = 0 +/// F = P_i +/// +/// Given an interval count of I to get from P_i to P_t, we get the parametric +/// "step" size of h = 1/I. We need to calculate the initial value of forward +/// differences (F_0 - F_5) such that the inital velocity V = P_i, then we +/// iterate over the following I times: +/// +/// V += F_5 +/// F_5 += F_4 +/// F_4 += F_3 +/// F_3 += F_2 +/// F_2 += F_1 +/// +/// See +/// http://www.drdobbs.com/forward-difference-calculation-of-bezier/184403417 +/// for an example of how to calculate F_0 - F_5 for a cubic bezier curve. Since +/// this is a quintic bezier curve, we need to extend the formulas somewhat. +/// I'll not go into the long-winded step-by-step here, but it gives the +/// resulting formulas: +/// +/// a = A, b = B, c = C, d = D, e = E, f = F +/// +/// F_5(t + h) - F_5(t) = (5ah)t^4 + (10ah^2 + 4bh)t^3 + +/// (10ah^3 + 6bh^2 + 3ch)t^2 + (5ah^4 + 4bh^3 + 3ch^2 + 2dh)t + ah^5 + +/// bh^4 + ch^3 + dh^2 + eh +/// +/// a = 5ah +/// b = 10ah^2 + 4bh +/// c = 10ah^3 + 6bh^2 + 3ch +/// d = 5ah^4 + 4bh^3 + 3ch^2 + 2dh +/// +/// After substitution, simplification, and rearranging: +/// +/// F_4(t + h) - F_4(t) = (20ah^2)t^3 + (60ah^3 + 12bh^2)t^2 + +/// (70ah^4 + 24bh^3 + 6ch^2)t + 30ah^5 + 14bh^4 + 6ch^3 + 2dh^2 +/// +/// a = 20ah^2 +/// b = 60ah^3 + 12bh^2 +/// c = 70ah^4 + 24bh^3 + 6ch^2 +/// +/// After substitution, simplification, and rearranging: +/// +/// F_3(t + h) - F_3(t) = (60ah^3)t^2 + (180ah^4 + 24bh^3)t + 150ah^5 + +/// 36bh^4 + 6ch^3 +/// +/// You get the picture... +/// +/// F_2(t + h) - F_2(t) = (120ah^4)t + 240ah^5 + 24bh^4 +/// F_1(t + h) - F_1(t) = 120ah^5 +/// +/// Normally, we could then assign t = 0, use the A-F values from above, and get +/// out initial F_* values. However, for the sake of "averaging" the velocity +/// of each segment, we actually want to have the initial V be be at t = h/2 and +/// iterate I-1 times. So, the resulting F_* values are (steps not shown): +/// +/// F_5 = 121Ah^5 / 16 + 5Bh^4 + 13Ch^3 / 4 + 2Dh^2 + Eh +/// F_4 = 165Ah^5 / 2 + 29Bh^4 + 9Ch^3 + 2Dh^2 +/// F_3 = 255Ah^5 + 48Bh^4 + 6Ch^3 +/// F_2 = 300Ah^5 + 24Bh^4 +/// F_1 = 120Ah^5 +/// +/// Note that with our current control points, D and E are actually 0. +/// +/// This can be simplified even further by subsituting Ah, Bh & Ch back in and +/// reducing to: +/// +/// F_5 = (32.5 * s^2 - 75 * s + 45.375)(Vt - Vi) * h^5 +/// F_4 = (90.0 * s^2 - 435 * s + 495.0 )(Vt - Vi) * h^5 +/// F_3 = (60.0 * s^2 - 720 * s + 1530.0 )(Vt - Vi) * h^5 +/// F_2 = ( - 360 * s + 1800.0 )(Vt - Vi) * h^5 +/// F_1 = ( 720.0 )(Vt - Vi) * h^5 +/// +float mp_init_forward_dif(forward_dif_t fdif, float Vi, float Vt, float s) { + const float h = 1 / s; + const float s2 = square(s); + const float Vdxh5 = (Vt - Vi) * h * h * h * h * h; + + fdif[4] = (32.5 * s2 - 75.0 * s + 45.375) * Vdxh5; + fdif[3] = (90.0 * s2 - 435.0 * s + 495.0 ) * Vdxh5; + fdif[2] = (60.0 * s2 - 720.0 * s + 1530.0 ) * Vdxh5; + fdif[1] = ( - 360.0 * s + 1800.0 ) * Vdxh5; + fdif[0] = ( 720.0 ) * Vdxh5; + + // Calculate the initial velocity by calculating: + // + // V(h / 2) = + // + // ( -6Vi + 6Vt) / (2^5 * s^8) + + // ( 15Vi - 15Vt) / (2^4 * s^8) + + // (-10Vi + 10Vt) / (2^3 * s^8) + Vi = + // + // (Vt - Vi) * 1/2 * h^8 + Vi + return (Vt - Vi) * 0.5 * square(square(square(h))) + Vi; +} + + +float mp_next_forward_dif(forward_dif_t fdif) { + float delta = fdif[4]; + + for (int i = 4; i; i--) + fdif[i] += fdif[i - 1]; + + return delta; +} diff --git a/src/plan/forward_dif.h b/src/plan/forward_dif.h new file mode 100644 index 0000000..d1ceb75 --- /dev/null +++ b/src/plan/forward_dif.h @@ -0,0 +1,34 @@ +/******************************************************************************\ + + This file is part of the Buildbotics firmware. + + Copyright (c) 2015 - 2016 Buildbotics LLC + All rights reserved. + + This file ("the software") is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License, + version 2 as published by the Free Software Foundation. You should + have received a copy of the GNU General Public License, version 2 + along with the software. If not, see . + + The software is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the software. If not, see + . + + For information regarding this software email: + "Joseph Coffland" + +\******************************************************************************/ + +#pragma once + + +typedef float forward_dif_t[5]; + +float mp_init_forward_dif(forward_dif_t fdif, float Vi, float Vt, float s); +float mp_next_forward_dif(forward_dif_t fdif); diff --git a/src/plan/jog.c b/src/plan/jog.c index ed17675..6606441 100644 --- a/src/plan/jog.c +++ b/src/plan/jog.c @@ -31,7 +31,7 @@ #include "planner.h" #include "buffer.h" #include "line.h" -#include "exec.h" +#include "forward_dif.h" #include "runtime.h" #include "machine.h" #include "state.h" @@ -48,7 +48,7 @@ typedef struct { bool writing; float Vi; float Vt; - float fdifs[AXES][5]; + forward_dif_t fdifs[AXES]; unsigned segments[AXES]; int sign[AXES]; @@ -112,13 +112,13 @@ static stat_t _exec_jog(mp_buffer_t *bf) { } else { jr.segments[axis] = ceil(move_time / NOM_SEGMENT_TIME); - Vi = mp_init_forward_diffs(jr.fdifs[axis], Vi, Vt, jr.segments[axis]); + Vi = mp_init_forward_dif(jr.fdifs[axis], Vi, Vt, jr.segments[axis]); jr.segments[axis]--; } } } else if (jr.segments[axis]) { - Vi += mp_next_forward_diff(jr.fdifs[axis]); + Vi += mp_next_forward_dif(jr.fdifs[axis]); jr.segments[axis]--; } else Vi = Vt; diff --git a/src/plan/planner.c b/src/plan/planner.c index 1e77ff7..de21961 100644 --- a/src/plan/planner.c +++ b/src/plan/planner.c @@ -81,9 +81,6 @@ static planner_t mp = {{0}}; void mp_init() { - // Nominal segment time cannot be longer than maximum - if (MAX_SEGMENT_TIME < NOM_SEGMENT_USEC) ALARM(STAT_INTERNAL_ERROR); - mp_queue_init(); } -- 2.27.0