ESP32: Guru Meditation Error: Core 1 panic'ed (Coprocessor exception)

Hi - I have a sketch that runs a bunch of functions for a stepper motor on one core, and a nextion on the second core.


edited out dual core issue because the problem now seems to be a matter of calculations in functions not filling the needed arrays with data - please see posts below!

Any help would be greatly appreciated - I’m new to ESP32, and I’m not even good at Arduino, so this sort of thing derails me when there’s no data online for my specific issue.

edit: I’ve also noticed some of my global array variables aren’t being calculated - they’re coming from math performed in functions like this:

for (int i=0; i<20; i++) {
variable[`i] = some math between other variables declared outside of core-specific functions.
}

Is it possible there’s issues if both cores are calculating for statements working with int i at the same time?

The Guru Meditation error is similar to a segmentation fault and occurs if you're not taking care of your garbage or many times if the stack runs into the heap and you overwrite something the ESP needs to function.

jtbennett:
I’ve read about some issues with external interrupts using floats or not being stored in RAM, but mine just sends some commands via AccelStepper (and it’s in the RAM as far as I know).

The stepper2.stop() line in the ISR performs floating point arithmetic, and could be a likely cause of error on the ESP32 as your search indicated.
Fundamentally an ISR should be as short and as quick as possible; ideally just setting a flag that you then poll in your main code.

jtbennett:
The crashing still seems to occur when I remove the limit switch (except now there’s no error).

If there is no crash error, then how are you determining that it is still crashing?
Did you physically disconnect the limit switch? Was the input then left floating?

jtbennett:
Just a little more insight, I have vTaskDelay(10); in the Nextion core void because I was getting Task Watchdog crashes before, that seems fine now. I also have both cores set up with a 10,000 word stack. When I run uxTaskGetStackHighWaterMark(NULL) on the Nextion core, it stays under 10k at its busiest, but the stepper core will take as much as possible, even when I set the stack up to 100,000, it’ll be eating 99k constantly.

uxTaskGetStackHighWaterMark():

The stack used by a task will grow and shrink as the task executes and interrupts are processed. uxTaskGetStackHighWaterMark() returns the minimum amount of remaining stack space that was available to the task since the task started executing - that is the amount of stack that remained unused when the task stack was at its greatest (deepest) value. This is what is referred to as the stack ‘high water mark’.

I’m not familiar with the ESP, so can’t really help, but it is rarely useful to post random snippets of code - they often raise more questions than answers. Either post all your code, or a minimal compilable version that exhibits the fault.

arduarn:
I’m not familiar with the ESP, so can’t really help, but it is rarely useful to post random snippets of code - they often raise more questions than answers. Either post all your code, or a minimal compilable version that exhibits the fault.

I was a little reluctant to post the whole sketch because of its size, but I’m attaching it to this post.

I seem to be having new issues though - basically, this sketch was created from two separate sketches. One for the steppers and one for the screen. They use the same variables so they were designed to work perfectly together once I put them together, but clearly that’s not the case.

I decided to put it all on a single core sketch for now to see if I could get closer to narrowing the issue - now my sketch still fails at the point of the interrupt switch (or the stepper2.stop() command in the interrupt script that you pointed out).

I am also running different serial monitor prints of variables at critical times and when the sketches are combined, suddenly the s2_aCon() function’s math is spitting out 0s into the arrays. That may be a separate issue but right now it’s hard to tell…there’s a lot going on so it’s very hard to trace things.

esp32-code.txt (59.1 KB)

A lot of the critical math before the actual winding begins occurs in the s2_aCon() function, and that seems to be where a lot of the variables are failing - I just don’t know what the conflict is because it works fine without all the nextion stuff

e: I’ve been trying to figure out the issue, and now I’m just focusing on these variables failing to calculate. It appears all of the ones that are failing involve some floating math:

MaxSpeed1
MaxSpeed2
Move2_A
Move2_B

They’re all being divided or multiplied by fractions. The frustrating thing is that the math works absolutely fine when I define the main arrays (blockWinds, blockStrafe, blockArea) in the setup - but when I’m using the nextion screen code that takes the data from the screen or saved files and puts them into the arrays, suddenly that those functions don’t work (it’s something that works separately and populates the arrays just fine - and still does, as far as I can see…).

I’m way out of my element now though so I’m hoping anyone with a keen eye for stupid math conflicts can see it.

jtbennett:
Any help would be greatly appreciated - I’m new to ESP32, and I’m not even good at Arduino, so this sort of thing derails me when there’s no data online for my specific issue.

In the nicest possible way: you have written rather a lot of code for a beginner and it is not as shiny as it could be. This is one of those cases where it would have been helpful to ask the forum questions early on in the project and get feedback (maybe you did? I didn’t check your post history).

As it is, your code is opaque and appears to be poorly structured (I get that you have combined two modules). Lots of repetitive stuff looks like it could be done more simply, but it is a struggle just to figure out what it’s all about.
A major mistake was going down the multi-threaded route. Parallel programming is really difficult, even for advanced programmers; so many hidden pitfalls and traps. I would absolutely not recommend it for the inexperienced.

There is a useful sticky at the top of the programming forum that explains some useful ground rules: Useful links - check here for reference posts / tutorials.
There are techniques there that would likely make it unnecessary to use multiple threads; they are worth considering. Sadly it will probably be fairly challenging to make such changes now.

Maybe someone else has a silver bullet…

arduarn:
Fundamentally an ISR should be as short and as quick as possible; ideally just setting a flag that you then poll in your main code.

I'll take it a step further. Since you'd have to poll for the flag before taking time-consuming or problematic (referenced interrupt / float problem) steps, why not just poll for switch to be actuated and dump the whole interrupt idea?

Agree that newbie programmer combined with interrupts and multi-threaded code is a recipe for disaster.

arduarn:
A major mistake was going down the multi-threaded route. Parallel programming is really difficult, even for advanced programmers; so many hidden pitfalls and traps. I would absolutely not recommend it for the inexperienced.

I'm just looking for the issues with the variables now, I made an edit before to say that - multithreading isn't the issue anymore, just the fact that the variable math is churning out zeros suddenly when it worked outside of the screen code. If you want I can post both of the functional sketches separately, but I doubt you're wanting to look at them.

gfvalvo:
I'll take it a step further. Since you'd have to poll for the flag before taking time-consuming or problematic (referenced interrupt / float problem) steps, why not just poll for switch to be actuated and dump the whole interrupt idea?

Agree that newbie programmer combined with interrupts and multi-threaded code is a recipe for disaster.

I've already addressed that part of the issue, I made an edit before that you might not have seen. I'm just using a single core now and still having issues at the same point due to the variable math filling my arrays with zeros where they worked fine before combining the codes.

The difference now is that the math is being done after the variables are defined by user-entered data on a nextion screen - that also works fine on its own, but the common thread is that all of the variables that aren't calculating properly contain fractions somewhere along the line. I made a list of the important variables in the previous post, maybe you could help me by just looking at the chain of math happening on a couple of them and see if you can identify the problem?

I’m attaching the current sketch that’s on a single core, just a regular sketch - setup and loop are at the bottom.

s2_aCon() is turning out 0s for all the results suddenly, the only thing that’s changed is that the main arrays (blockStrafe, blockAreas, blockWinds) are being generated by a user entering info on a Nextion screen, which comes through serial and is parsed and inserted into the proper array positions…

I’m only asking here because I’ve spent all day trying to track down the point where it fails:

esp32-1-core.txt (48.9 KB)

I've run out of time tonight, but if all the data is becoming zero, then add some debug to the fieldClear() function to check that it is not being invoked unexpectedly.

arduarn:
I’ve run out of time tonight, but if all the data is becoming zero, then add some debug to the fieldClear() function to check that it is not being invoked unexpectedly.

I commented it out and nothing changed - could it be accelstepper conflicting with the other libraries?

#include <vfs_api.h>
#include <FS.h>
#include <FSImpl.h>
#include <SPIFFS.h>
#include <AccelStepper.h>

There’s something going wrong with the math in s2_aCon, that’s all I can figure out right now - printing the arrays beforehand shows that they are filled with the correct numbers, so I cannot understand why the calculations in s2_aCon that use those arrays are suddenly churning out zeros :’[

I am a little confused on how this works.

s.toCharArray(c,100);
    int result = sscanf(c, "%i,%i", &saveStat, &saveBlock);

When c is defined as char c[100]

Seem to do the same for g, only g is not declared upfront but inside a loop.

char g[100];
    s.toCharArray(g,100);

I get your looking at variables that suddenly go kaput, but the reason they go kaput very well might be because somewhere else your writing out of bounds into a array corrupting their memory location spots.

Slumpert:
I am a little confused on how this works.

s.toCharArray(c,100);

int result = sscanf(c, "%i,%i", &saveStat, &saveBlock);



When c is defined as char c[100]

Seem to do the same for g, only g is not declared upfront but inside a loop.


char g[100];
    s.toCharArray(g,100);




I get your looking at variables that suddenly go kaput, but the reason they go kaput very well might be because somewhere else your writing out of bounds into a array corrupting their memory location spots.

I can't remember exactly why I made that g array when I had the c array already for the same purpose...good catch though, I'm just happy someone actually went through all my ugly code.

So regarding out of bounds memory writing, would making sure not to define arrays inside loops prevent this? Sorry if that's a dumb question, but it's new to me - I'm not sure about the mechanics of how memory is used, I didn't expect it would interfere with globally defined stuff.

Doesn’t matter where you define the array. If it has N elements, they are numbered 0, 1, 3, .... N-1. The rule is quite simple: Don’t try to access elements of the array that don’t exists. If you do that anywhere in the code it will likely cause problems in totally unrelated areas.

gfvalvo:
Doesn’t matter where you define the array. If it has N elements, they are numbered 0, 1, 3, .... N-1. The rule is quite simple: Don’t try to access elements of the array that don’t exists. If you do that anywhere in the code it will likely cause problems in totally unrelated areas.

Sorry to be an annoying noob, but are you saying that the char g[100] array is a possible cause for this? Or one of the many for statements that populates the various other arrays?

jtbennett:
Sorry to be an annoying noob, but are you saying that the char g[100] array is a possible cause for this? Or one of the many for statements that populates the various other arrays?

I don't think gfvalvo is pointing out a specific error he has found; rather just making clear that you must only write in memory that you have correctly allocated. So, writing in g[0] to g[99] is fine. Writing in g[100] is an error. The error may cause a problem immediately in the next line or two of code, or it may cause an error 10000 lines of code later. The behaviour is undefined and must be avoided to begin with.

A browse through your code didn't reveal the cause of your problem, but perhaps I don't understand what you are seeing.

If I understood, the loadFile() function slurps up the data into the arrays and correctly Serial.print()'s them out, right?

So what exactly is the output of the Serial.print()'s in s2_aCon()?
And what are you expecting them to be?

In fact, why not just post all the serial console output (matching the code you most recently posted).

arduarn:
If I understood, the loadFile() function slurps up the data into the arrays and correctly Serial.print()'s them out, right?

So what exactly is the output of the Serial.print()'s in s2_aCon()?
And what are you expecting them to be?

In fact, why not just post all the serial console output (matching the code you most recently posted).

The loadFile function takes the lines from a text file one by one and parses them into respective arrays. The serial prints were just for my own ability to check that the work was being done by printing off the array values afterward.

This is the printout that shows the arrays that are getting zeros:

16:43:38.603 -> 1=======Load Save=======
16:43:39.174 -> saveStat / saveBlock
16:43:39.174 -> 1
16:43:39.174 -> 1
16:43:39.174 -> PICKUP NAME
16:43:39.174 -> File 1 :]
16:43:39.174 -> RPMs
16:43:39.174 -> 900
16:43:39.174 -> bobbinPlate
16:43:39.174 -> 1.20
16:43:39.174 -> bobbinSpace
16:43:39.174 -> 22.00
16:43:39.174 -> gauge
16:43:39.211 -> 0.06
16:43:39.211 -> dirCW
16:43:39.211 -> false
16:43:39.211 -> false
16:43:39.211 -> BLOCK NUMBERS
16:43:39.211 -> 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,
16:43:39.211 -> BLOCK AREA
16:43:39.211 -> 1,6,3,4,5,1,6,3,4,5,1,6,3,4,5,1,6,3,4,5,
16:43:39.211 -> BLOCK STRAFE
16:43:39.211 -> 1,4,3,2,1,3,2,4,1,2,1,4,3,2,1,3,2,4,1,2,
16:43:39.211 -> BLOCK WINDS
16:43:39.211 -> 1000,100,400,600,2000,6000,4000,200,100,400,600,2000,6000,4000,200,100,400,600,2000,6000,0
16:43:39.354 -> Move1: 800000
16:43:39.354 -> blockArea: 1
16:43:39.354 -> blockStrafe: 1
16:43:39.354 -> Move2_A: 0
16:43:39.354 -> Move2_B: 0
16:43:39.354 -> 1
16:43:39.354 -> Move1: 80000
16:43:39.354 -> blockArea: 6
16:43:39.354 -> blockStrafe: 4
16:43:39.354 -> Move2_A: 0
16:43:39.354 -> Move2_B: 0
16:43:39.354 -> 2
16:43:39.354 -> Move1: 320000
16:43:39.354 -> blockArea: 3
16:43:39.354 -> blockStrafe: 3
16:43:39.354 -> Move2_A: 0
16:43:39.354 -> Move2_B: 0
16:43:39.354 -> 3
16:43:39.354 -> Move1: 480000
16:43:39.354 -> blockArea: 4
16:43:39.354 -> blockStrafe: 2
16:43:39.354 -> Move2_A: 0
16:43:39.354 -> Move2_B: 0
16:43:39.354 -> 4
16:43:39.354 -> Move1: 1600000
16:43:39.354 -> blockArea: 5
16:43:39.354 -> blockStrafe: 1
16:43:39.354 -> Move2_A: 0
16:43:39.354 -> Move2_B: 0
16:43:39.387 -> 5
16:43:39.387 -> Move1: 4800000
16:43:39.387 -> blockArea: 1
16:43:39.387 -> blockStrafe: 3
16:43:39.387 -> Move2_A: 0
16:43:39.387 -> Move2_B: 0
16:43:39.387 -> 6
16:43:39.387 -> Move1: 3200000
16:43:39.387 -> blockArea: 6
16:43:39.387 -> blockStrafe: 2
16:43:39.387 -> Move2_A: 0
16:43:39.387 -> Move2_B: 0
16:43:39.387 -> 7
16:43:39.387 -> Move1: 160000
16:43:39.387 -> blockArea: 3
16:43:39.387 -> blockStrafe: 4
16:43:39.387 -> Move2_A: 0
16:43:39.387 -> Move2_B: 0
16:43:39.387 -> 8
16:43:39.387 -> Move1: 80000
16:43:39.387 -> blockArea: 4
16:43:39.387 -> blockStrafe: 1
16:43:39.387 -> Move2_A: 0
16:43:39.387 -> Move2_B: 0
16:43:39.387 -> 9
16:43:39.387 -> Move1: 320000
16:43:39.387 -> blockArea: 5
16:43:39.387 -> blockStrafe: 2
16:43:39.387 -> Move2_A: 0
16:43:39.387 -> Move2_B: 0
16:43:39.387 -> 10
16:43:39.387 -> Move1: 480000
16:43:39.423 -> blockArea: 1
16:43:39.423 -> blockStrafe: 1
16:43:39.423 -> Move2_A: 0
16:43:39.423 -> Move2_B: 0
16:43:39.423 -> 11
16:43:39.423 -> Move1: 1600000
16:43:39.423 -> blockArea: 6
16:43:39.423 -> blockStrafe: 4
16:43:39.423 -> Move2_A: 0
16:43:39.423 -> Move2_B: 0
16:43:39.423 -> 12
16:43:39.423 -> Move1: 4800000
16:43:39.423 -> blockArea: 3
16:43:39.423 -> blockStrafe: 3
16:43:39.423 -> Move2_A: 0
16:43:39.423 -> Move2_B: 0
16:43:39.423 -> 13
16:43:39.423 -> Move1: 3200000
16:43:39.423 -> blockArea: 4
16:43:39.423 -> blockStrafe: 2
16:43:39.423 -> Move2_A: 0
16:43:39.423 -> Move2_B: 0
16:43:39.423 -> 14
16:43:39.423 -> Move1: 160000
16:43:39.423 -> blockArea: 5
16:43:39.423 -> blockStrafe: 1
16:43:39.423 -> Move2_A: 0
16:43:39.423 -> Move2_B: 0
16:43:39.423 -> 15
16:43:39.423 -> Move1: 80000
16:43:39.423 -> blockArea: 1
16:43:39.423 -> blockStrafe: 3
16:43:39.423 -> Move2_A: 0
16:43:39.423 -> Move2_B: 0
16:43:39.461 -> 16
16:43:39.461 -> Move1: 320000
16:43:39.461 -> blockArea: 6
16:43:39.461 -> blockStrafe: 2
16:43:39.461 -> Move2_A: 0
16:43:39.461 -> Move2_B: 0
16:43:39.461 -> 17
16:43:39.461 -> Move1: 480000
16:43:39.461 -> blockArea: 3
16:43:39.461 -> blockStrafe: 4
16:43:39.461 -> Move2_A: 0
16:43:39.461 -> Move2_B: 0
16:43:39.461 -> 18
16:43:39.461 -> Move1: 1600000
16:43:39.461 -> blockArea: 4
16:43:39.461 -> blockStrafe: 1
16:43:39.461 -> Move2_A: 0
16:43:39.461 -> Move2_B: 0
16:43:39.461 -> 19
16:43:39.461 -> Move1: 4800000
16:43:39.461 -> blockArea: 5
16:43:39.461 -> blockStrafe: 2
16:43:39.461 -> Move2_A: 0
16:43:39.461 -> Move2_B: 0

I had some more detailed serial prints before that showed the rest of the arrays, but these are the ones that are not receiving their results:

long MaxSpeed1 = (RPMs*800)/60;
long Accel1 = 2000;   // I don't know if this one is getting its numbers or not since I didn't print it
long Move1[21];    // Move1 comes out fine.
long MaxSpeed2[21];
int Move2_A[21];
int Move2_B[21];

// the dysfunctional ones are calculated in s2_aCon() - and they each have some floating / fractional type math going into the calculations. Move1 is also calculated in that function and it prints out fine.

All of this math worked when the two sketches were separate - this is the functional motor code and this is the functional nextion code.

I'm going to try increasing the char array size maybe - I checked over the for statements and they appear to all be referencing allotted array space, but I'm also dumb so maybe that needs some checking on too..

edit:

for reference, here is a serial print out from the functional separated motor code:

17:14:01.732 -> MAX_SPD:5000
17:14:01.732 -> MAX_XCL:100000
17:14:01.732 -> MaxSpeed1:14666
17:14:01.732 -> 1
17:14:01.732 -> Move1[]:800000
17:14:01.732 -> MaxSpeed2[]:432
17:14:01.732 -> Move2_A[]:0
17:14:01.732 -> Move2_B[]:858
17:14:01.732 -> 2
17:14:01.732 -> Move1[]:80000
17:14:01.732 -> MaxSpeed2[]:108
17:14:01.732 -> Move2_A[]:0
17:14:01.767 -> Move2_B[]:2600
17:14:01.767 -> 3
17:14:01.767 -> Move1[]:320000
17:14:01.767 -> MaxSpeed2[]:108
17:14:01.767 -> Move2_A[]:1716
17:14:01.767 -> Move2_B[]:2600
17:14:01.767 -> 4
17:14:01.767 -> Move1[]:480000
17:14:01.767 -> MaxSpeed2[]:432
17:14:01.767 -> Move2_A[]:0
17:14:01.767 -> Move2_B[]:1716
17:14:01.767 -> 5
17:14:01.767 -> Move1[]:1600000
17:14:01.767 -> MaxSpeed2[]:865
17:14:01.767 -> Move2_A[]:858
17:14:01.767 -> Move2_B[]:2600
17:14:01.767 -> 6
17:14:01.767 -> Move1[]:4800000
17:14:01.767 -> MaxSpeed2[]:108
17:14:01.767 -> Move2_A[]:0
17:14:01.767 -> Move2_B[]:858
17:14:01.767 -> 7
17:14:01.767 -> Move1[]:3200000
17:14:01.767 -> MaxSpeed2[]:650
17:14:01.767 -> Move2_A[]:0
17:14:01.767 -> Move2_B[]:2600
17:14:01.767 -> 8
17:14:01.767 -> Move1[]:160000
17:14:01.767 -> MaxSpeed2[]:35
17:14:01.767 -> Move2_A[]:1716
17:14:01.767 -> Move2_B[]:2600
17:14:01.806 -> 9
17:14:01.806 -> Move1[]:80000
17:14:01.806 -> MaxSpeed2[]:865
17:14:01.806 -> Move2_A[]:0
17:14:01.806 -> Move2_B[]:1716
17:14:01.806 -> 10
17:14:01.806 -> Move1[]:320000
17:14:01.806 -> MaxSpeed2[]:432
17:14:01.806 -> Move2_A[]:858
17:14:01.806 -> Move2_B[]:2600
17:14:01.806 -> 11
17:14:01.806 -> Move1[]:480000
17:14:01.806 -> MaxSpeed2[]:432
17:14:01.806 -> Move2_A[]:0
17:14:01.806 -> Move2_B[]:858
17:14:01.806 -> 12
17:14:01.806 -> Move1[]:1600000
17:14:01.806 -> MaxSpeed2[]:108
17:14:01.806 -> Move2_A[]:0
17:14:01.806 -> Move2_B[]:2600
17:14:01.806 -> 13
17:14:01.806 -> Move1[]:4800000
17:14:01.806 -> MaxSpeed2[]:108
17:14:01.806 -> Move2_A[]:1716
17:14:01.806 -> Move2_B[]:2600
17:14:01.806 -> 14
17:14:01.806 -> Move1[]:3200000
17:14:01.806 -> MaxSpeed2[]:432
17:14:01.806 -> Move2_A[]:0
17:14:01.806 -> Move2_B[]:1716
17:14:01.806 -> 15
17:14:01.806 -> Move1[]:160000
17:14:01.806 -> MaxSpeed2[]:865
17:14:01.806 -> Move2_A[]:858
17:14:01.840 -> Move2_B[]:2600
17:14:01.840 -> 16
17:14:01.840 -> Move1[]:80000
17:14:01.840 -> MaxSpeed2[]:108
17:14:01.840 -> Move2_A[]:0
17:14:01.840 -> Move2_B[]:858
17:14:01.840 -> 17
17:14:01.840 -> Move1[]:320000
17:14:01.840 -> MaxSpeed2[]:650
17:14:01.840 -> Move2_A[]:0
17:14:01.840 -> Move2_B[]:2600
17:14:01.840 -> 18
17:14:01.840 -> Move1[]:480000
17:14:01.840 -> MaxSpeed2[]:35
17:14:01.840 -> Move2_A[]:1716
17:14:01.840 -> Move2_B[]:2600
17:14:01.840 -> 19
17:14:01.840 -> Move1[]:1600000
17:14:01.840 -> MaxSpeed2[]:865
17:14:01.840 -> Move2_A[]:0
17:14:01.840 -> Move2_B[]:1716
17:14:01.840 -> 20
17:14:01.840 -> Move1[]:4800000
17:14:01.840 -> MaxSpeed2[]:432
17:14:01.840 -> Move2_A[]:858
17:14:01.840 -> Move2_B[]:2600

Please don't edit posts heavily like post #1, it make the follow-ups nonsensical.

I see, then I didn't quite understand the problem. So Move2_A and Move2_B are just getting zeros.

Have you checked the values of Strafe_1, Strafe_2, Strafe_3 and Strafe_4?
When I look at them they appear to have the values 0, 0, 0 and 0 respectively.

arduarn:
Please don't edit posts heavily like post #1, it make the follow-ups nonsensical.

I see, then I didn't quite understand the problem. So Move2_A and Move2_B are just getting zeros.

Have you checked the values of Strafe_1, Strafe_2, Strafe_3 and Strafe_4?
When I look at them they appear to have the values 0, 0, 0 and 0 respectively.

Sorry about the edit, I did leave the full code posted below it - I just figured people were reading that and not that the issue had changed. I'd have opened a new thread if I thought this wasn't going to go on as long as it has :expressionless:

Anyway, regarding your value checking, you are 100% correct - at the time of the blockWinder loop running (after all the calculations have supposedly finished), I printed out this just now:

18:36:04.838 -> to_step: 100
18:36:04.838 -> s2_bobbinPlate: 0
18:36:04.838 -> s2_bobbinSpace: 0
18:36:04.838 -> bobbinPlate: 1.20
18:36:04.838 -> bobbinSpace: 22.00
18:36:04.838 -> Strafe_4: 0
18:36:04.838 -> Strafe_3: 0
18:36:04.838 -> Strafe_2: 0
18:36:04.838 -> Strafe_1: 0
18:36:04.838 -> gaugeLen: 0
18:36:04.872 -> gauge: 0.06
18:36:04.872 -> RawSpeed2: 0

And this is how they appear in the sketch, at the bottom of the initial list of variables/arrays:

long MaxSpeed1 = (RPMs*800)/60;
long Accel1 = 2000;
long Move1[21];
long MaxSpeed2[21];
int Move2_A[21];
int Move2_B[21];


int s2_bobbinPlate = bobbinPlate*to_step;
int s2_bobbinSpace = bobbinSpace*to_step;

int Strafe_4 = s2_bobbinSpace;
int Strafe_3 = s2_bobbinSpace*.66;
int Strafe_2 = s2_bobbinSpace*.33;
int Strafe_1 = 0;
int gaugeLen = gauge*to_step;
int RawSpeed2 = 0;

I'm told that the location of these things won't affect anything, but if it's a memory corruption, is it possible that something just above these things in the sequence is blanking all the stuff immediately after?

e: also, thank you for helping me with this - I've been working on it every day after work for a couple months and this is hopefully the last hurdle

Ok, I guess I was too subtle and you have spent so long looking at this that you can't see the forest for the trees.

The values of Strafe_* are zero because you explicitly set them to zero and they never change.

float bobbinSpace = 0;

int s2_bobbinSpace = bobbinSpace*to_step;

  int Strafe_4 = s2_bobbinSpace;
  int Strafe_3 = Strafe_4*.66;
  int Strafe_2 = Strafe_4*.33;
  int Strafe_1 = 0;