Not sure if you ever wonder how Marlin movement works, but if you did, I hope the following serie of posts will bring some light to have a better understanding.
Fig. Marlin by National Geographic
[Disclaimer] this is my marlin interpretation, I might be wrong so feel free to correct me if you find any mistakes.
Everything starts from a GCode movement command from our fab slicer or manual-GCode-generator-ninja skills.
I.E. G1 X50 Y50 Z10 E10 F1000
We have 4 axis X,Y,Z and E. Each one has a value that holds the target position that we want to reach.
F represents the feedrate or speed for this movement in millimetres per minute.
Movement GCodes goes from G0 to G3, but for now on we will use just G1 as an example.
Ok, but… how does Marlin takes this characters and transform them into movement?
That is a heavy-weight question that we are going to break down into several parts.
Today we are going to get and overall picture(half) of the trip a GCode does within Marlin until a motor is stepped.
In my head I picture this GCode trip going through 3 different countries (bad joke mode on).
- Fetching Data Kingdom
- Planning Republica
- Stepping States
Fetching Data Kingdom
First stage of the GCode command trip is where all the information the command is carrying is fetched.
Everything starts at the main loop in Marlin_main.cpp file.
A function called get_command() reads the serial port (where GCode commands arrive) looking for a new GCode line to add to the command buffer aka cmdbuffer.
This command buffer is just a list with all the received GCode commands Marlin is pending to precess yet.
After that, within the main loop, a function called process_command() is executed. This (endless) function parses the oldest GCode in the command buffer and executes its corresponding functionality. You can learn more about GCode functionalities HERE.
G1 functionality is: moving to coordinate (X,Y,Z,E) at Feedrate (speed).
G1 code, executes two functions to do that get_coordinates() & prepare_move().
First one reads the command values and keeps them into the variables: destination[x,y,z,e] (where we want to go) and feedrate (moving speed). Here is where the fetching data happens.
And the second is in charge of passing this values to the next stage (or country) calling the function plan_buffer_line(…).
For us, Planning Republica is a wonderful land with lots of magic going on. And for most of it, for today, we want to keep it this way.
The planner (.h & .cpp) is the FW part in charge of ordering and managing the movements. Listing aka buffering them and calculating the acceleration profiles and others.
The planner (plan_buffer_line(…)) takes care of transforming the destination and feedrate values into a data structure used later to move the motors.
IT IS IMPORTANT TO NOTICE that this data structure is created following our desired movement profile.
We will go deeper into this in upcoming posts. For now lets just BELIEVE in the planner.
This data structure is organized in blocks, where each block represent one linear movement.
Ideally each linear movement has the shape of a trapezoid. With and entry speed, acceleration, target speed or feedrate and deceleration values. Each one of the different acceleration zones has its own timing. And this is really important because it is how the stepping intervals are calculated to have the desired step rate for each axis. The proper step interval time fixes the motors (steppers) speed.
Fig. Trapezoid profile
Once we have the right values (data blocks) for our motors, how do we move them?
There is just one ISR that controls all 4 motors.
Each motor might have a different speed profile to reach a target speed between origin and destination. This means that our target speed from A to B is fixed. But when we break down this is speed into each axis component (X, Y, Z, E), these axis speed components are likely to not have same values.
Fig. Speed vector break down into components example
With just one ISR Marlin (this awesomeness is thanks to GRBL) handles all motors by setting the ISR timer at the fastest stepping rate of all. The rest of them are sync based in a Bressenham algorythm.
The above mentioned ISR time out setting is incrementally adapted to match the trapezoid speed curve. Meaning that controlling the timeout we can control position, speed and motors acceleration.
I hope this short and modest introduction to Marlin movements helps somebody out to understand more about it 🙂
Meanwhile feel free to go hardcore into Marlin to found the answers you are seeking. And remember the REAL truth is written HERE.