Having Trouble with M4 G-Code

If it works when you use the “normal” firmware and “extruder-style” config, but not when you use the 4-axis firmware and “6axis-style” config, my suspicion would be there is some issue with how you compiled or flashed the 4 axis firmware. I recommend you start that from scratch, and follow the instructions scrupulously. Also use the “version” command to make sure you have the right firmware running.

Glad you’re making progress.

1 Like

Arthur, Mcdanlj, et all,

My apologies. I think I figured out what the problem most likely is.
I am using a 5 year old version of the firmware.

Why?

5 years ago when I purchased my first Smoothieboard, I needed a way for the Smoothieboard to send me REAL TIME progress messages on when it was

  • adding a move to the 32 move block queue
  • starting execution of a move in the block queue
  • finishing execution of a move in the block queue

To do so I had to modify the firmware code to create an additional module which added this capability. The new module worked (and still works) beautifully. I’ve never had any issues/hiccups. Execution has always been speedy, fast and flawless running actual xyz axis rotary machines.

Since then, I’ve never downloaded the latest firmware because:

  • it’s not broken, works great
  • It would necessitate me having to constantly add my new module code to any new firmware I downloaded

Also, since then, I have purchased around 15-20 additional Smoothieboard’s, even as recently as a few months ago. I’ve always flashed the new Smoothieboard’s with my 5 year old modified firmware and they always work great. (Plug for Smoothieboard reliability).

Fast forward to today. I have finally been confronted with the need to use 4 axis, XYZA. In looking through the Smoothieboard “things to do list” I noticed that adding (or fixing) 4 axis support was once on the list, and has since been checked off as accomplished, probably years ago.

So, if my hunch is correct, once I download the newest latest Smoothieboard firmware code, and go through the effort to re-add my custom module for real time block queue messages, and compile THAT new version for 4 axis support, then most likely XYZA gcodes will work correct.

New question:

Once I do this, is it possible for me to add my new module publicly to the Smoothieboard firmware code, so that from now on, whenever I need to grab latest code, it would no longer be necessary to go through effort to stitch my module in again?

1 Like

About adding your code, you should first add it into a fork that you maintain yourself, second get some users to use your fork and confirm it works for them in a variety of machines/setups, and three, if you get to this point, and you can argue your code/module is generally helpful, and the quality matches the standards of the project, we can start the process of trying to integrate it into the main codebase.
it all takes a bit of work, but it does work/happen, and it’s how we have made sure the codebase stays this solid over the years.

glad you figured this out btw.

2 Likes

Arthur, thanks for the help/advice, I’ve been chewing on this.

Is there a way to use g-code to remap the alpha from M1 pins to M4 pins?

So if the board starts out as follows:

alpha_step_pin 2.0 # Pin for alpha stepper step signal
alpha_dir_pin 0.5 # Pin for alpha stepper direction
alpha_en_pin 0.4 # Pin for alpha enable pin

Can one send g-codes to set them as follows:

alpha_step_pin 2.3 # Pin for alpha stepper step signal
alpha_dir_pin 0.22 # Pin for alpha stepper direction
alpha_en_pin 0.21 # Pin for alpha enable pin

I understand this can be done by changing the values in the config file, but that requires rebooting the Smoothieboard. If at any given time, without rebooting the Smoothieboard, if I could send commands to remap the alpha driver from M1 to M4, then later from M4 back to M1, that would be the solution to what I am trying to accomplish.

In the type jobs I am streaming to the Smoothieboard, I am never actually using all 4 axis simultaneously. I am always using only 3 axis, either as:

M1
M2
M3

or…

M4
M2
M3

or…

M1
M4
M3

Basically, the users of my software need a way to always stream jobs as 3 axis XYZ, but have the capability to route the X to either M1 or M4, or route the Y to either M2 or M4.

So I really don’t need the overhead of the Smoothieboard being 4 axis

in theory, you could have two config files on the sd card, use cp to copy one config file to the default position, then “reset” to reset the board. that would change the mapping.

I don’t see any other way, you’d need to code for anything “cleaner”

I am going to go through the firmware code today. I’ll locate and identify the point where the pin assignments are read from the config file (to study/learn what is happening), and see if I can create a new command that will do so via serial over USB, etc.

I’m going to put effort into making the new command community friendly, so that it would have the potential to possibly later be added to main branch.

Concerning making it friendly, I’m thinking I should avoid using board nomenclature such as M1, M4, etc. It would probably be better to use identifications such as alpha, delta, etc.

Also should avoid actual PIN numbers in command, i.e, no 2.0, 2.3, etc.

I’ll let you know when I have something.

1 Like

Ok, here is how far I’ve gotten.

First, I wanted to verify (with config file I’m using and firmware I’m using), whether the pin assignments could be changed manually in config file. So, I did the following:

alpha_step_pin                               2.3              # Pin for alpha stepper step signal
alpha_dir_pin                                0.22              # Pin for alpha stepper direction
alpha_en_pin                                 0.21              # Pin for alpha enable pin
alpha_current                                1.5              # X stepper motor current
alpha_max_rate                               30000.0          # mm/min

beta_step_pin                                2.1              # Pin for beta stepper step signal
beta_dir_pin                                 0.11             # Pin for beta stepper direction
beta_en_pin                                  0.10             # Pin for beta enable
beta_current                                 1.5              # Y stepper motor current
beta_max_rate                                30000.0          # mm/min

gamma_step_pin                               2.2              # Pin for gamma stepper step signal
gamma_dir_pin                                0.20             # Pin for gamma stepper direction
gamma_en_pin                                 0.19             # Pin for gamma enable
gamma_current                                1.5              # Z stepper motor current
gamma_max_rate                               30000.0          # mm/min

Note that above there is no delta section, and I merely assigned the alpha section the M4 pin numbers.

After rebooting the Smoothieboard, I streamed a regular XYZ job to it, and got the desired results: the X moves were assigned to the M4 stepper, the Y and Z remained as normal.

That exercise verified that merely assigning different numbers DOES work, and WITH my CURRENT config file (NO delta section) and current firmware.

I then set the values back to normal:

alpha_step_pin                               2.0              # Pin for alpha stepper step signal
alpha_dir_pin                                0.5              # Pin for alpha stepper direction
alpha_en_pin                                 0.4              # Pin for alpha enable pin
alpha_current                                1.5              # X stepper motor current
alpha_max_rate                               30000.0          # mm/min

beta_step_pin                                2.1              # Pin for beta stepper step signal
beta_dir_pin                                 0.11             # Pin for beta stepper direction
beta_en_pin                                  0.10             # Pin for beta enable
beta_current                                 1.5              # Y stepper motor current
beta_max_rate                                30000.0          # mm/min

gamma_step_pin                               2.2              # Pin for gamma stepper step signal
gamma_dir_pin                                0.20             # Pin for gamma stepper direction
gamma_en_pin                                 0.19             # Pin for gamma enable
gamma_current                                1.5              # Z stepper motor current
gamma_max_rate                               30000.0          # mm/min

…basically making sure that the alpha section was assigned to M1 pins in config file.

Then I started working on the firmware to create a programmatic way to use g-codes to remap the pin assignments.

For the g-code, I settled on the arbitrary value of 800 because I didn’t see where there was any 800 g-code. I decided to use a format like:

M800 X1 Y2

meaning that the X axis would be mapped to the M1 motor, and the Y axis would be mapped to the M2 motor. To remap, the idea is to do something like as follows:

M800 X4 Y2

This would map the X axis to the M4 motor, and leave the Y axis on the M4 motor, etc.

Working from the bottom up, the first thing I did was add a new function to the StepperMotor Class:

void StepperMotor::RemapPins(std::string step, std::string dir, std::string en)
{ 
    step_pin.from_string(step);
    dir_pin.from_string(dir);
    en_pin.from_string(en);
}

The Pin class already provided the Pin::from_string() function, which is already used by the Robot class to create and assign pins.

Next, I added the following block to the Robot::on_gcode_received() function:

 case 800: // this is for remapping pins on stepper motors
    if (gcode->has_letter('X'))
    {
        switch ((char)gcode->get_value('X'))
        {
        case 1:
            this->alpha_stepper_motor->RemapPins("2.0", "0.5", "0.4");
            break;
        case 2:
            this->alpha_stepper_motor->RemapPins("2.1", "0.11", "0.10");
            break;
        case 3:
            this->alpha_stepper_motor->RemapPins("2.2", "0.20", "0.19");
            break;
        case 4:
            this->alpha_stepper_motor->RemapPins("2.3", "0.22", "0.21");
            break;
        }
    }
    if (gcode->has_letter('Y'))
    {
        switch ((char)gcode->get_value('Y'))
        {
        case 1:
            this->beta_stepper_motor->RemapPins("2.0", "0.5", "0.4");
            break;
        case 2:
            this->beta_stepper_motor->RemapPins("2.1", "0.11", "0.10");
            break;
        case 3:
            this->beta_stepper_motor->RemapPins("2.2", "0.20", "0.19");
            break;
        case 4:
            this->beta_stepper_motor->RemapPins("2.3", "0.22", "0.21");
            break;
        }
    }
    break;

I then successfully compiled the modified firmware and loaded it onto the Smoothieboard and rebooted the Smoothieboard. Then came the big moment.

First, without using the new gcode, I streamed a regular XYZ job to the controller. Everything worked fine, the modifications did not break current capability, etc.

Then, before running the job again, I had my software send the following gcode to the Smoothieboard:

M800 X2 Y1

This was to see whether the new code would work, and should merely swap (remap) the X and Y axis with each other. I pressed the “run” button to begin the stream…

It worked!!

The job ran completely, with the X and Y axis swapped, i.e., the X axis was running the M2 motor and the Y axis was running the M1 motor.

I then sent the following gocde to the controller:

M800 X1 Y2

this was to see if the code would correctly swap the pins back to their usual assignments. I hit the "run: button, and it worked! The job completely ran, with the X moves running the M1 motor and the Y moves running the M2 motor.

So now I thought I was sitting pretty good. I had proven to myself that the new code would remap the axis to the desired motors, without any hiccups or errors.

Then came the test for the M4 motor. So, I sent out the following gcode:

M800 X4 Y2

The idea here is to have the Y axis remain as usual running the M2 motor, but have the X axis run the M4 motor rather than the M1. I hit the “run” button…

And it didn’t work. The complete job streamed, with only the Y axis moving the M2 motor, but the X axis was NOT moving the M4 motor: it just sat there as if it wasn’t receiving any commands.

So, the sum of it is this:

  • with my current config file and modified firmware, which has NO delta section, I can manually remap the config file to send either the X or Y axis to (alpha or beta) to the M4 motor.
  • with my modified firmware, I can send new gcode to send X axis to either M1 or M2 motor
  • with my modified firmware, I can send new gcode to send Y axis to either M1 or M2 motor
  • but I CANNOT use the new code to map either axis to the M4 motor

I find that strange. Why would the new functionality allow me to remap the M1 and M2 motors, but not the M4?

It’s possible your M4 steppermotor object is attached to something else than Robot (maybe an extruder module) ?

I don’t see how. My config file has all extruder stuff commented out, and there are no delta entries in my config file either.

As far as I can tell, the process seems to be:

  • main creates the kernel
  • kernel creates the robot
  • kernel calls the robots on_module_loaded
  • robots::on_module_loaded calls on_config_reload
  • on_config_reload creates 3 stepper motors, alpha, beta and gamma
  • the pin assignments are read from the config.txt file for alpha, beta, gamma
  • the motors are pushed onto the actuator stack

Now, having said that, if the config file has alpha pins set for M4 (2.3, 0.22, 0.21), the pin assignments work, and the robot’s alpha stepper will drive the M4 connector.

If I use the new M800 gcode to swap the X and Y axis like such:

M800 X2 Y1

the X gets mapped to M2 and Y gets mapped to M1, and everything works. If I use the code

M800 X1 Y2

the assignments are swapped back to X mapped to M1 and Y to M2.

The only thing that doesn’t seem to be working is using the gcode to swap a motor to M4…

M800 X4 Y2

the Y will be swapped to Y2, but the X doesn’t seem to be swapped to M4, the alpha sits idle

I don’t see anywhere in the process, streaming a job, sending new gcode, etc, where the robot would release whatever actuator is mapped to M4.

I’m curious if something is causing the pin reassignment to not “stick” when the assignment is for the M4 pins. I’m going to add a temporary function:

void StepperMotor::GetPins(*char step, *char dir, *char en)
{
// write out current pin assignents
}

And also add a temp gcode

M801 // get pin assignments

And then I am going to try the following:

  • send M800 X2 Y1 gcode to swap motors
  • send M801 gcode to verify that new GetPins() function works
  • send M800 X4 Y2 gcode to assign pins
  • send M801 to see whether the X alpha gets assigned to M4

If the M801 verifies the correct pin mapping on M800 X2 Y1, but comes back with wrong values after the M800 M4 Y2, then I’ll know that for some reason the pins aren’t being mapped to M4, which would explain the robot alpha stepper sitting idle.

I’m not sure what’s up here, sounds like you might need to debug with printfs in the code to see what exactly is actually happening.

I took your advice and used printfs to dig down to the problem. Here’s what I found.

The enable pin is being turned off, or more properly, staying off.
That explains why the axis is sitting idle.
When the Smoothie boots up and reads the config file, 3 StepperMotor objects are created and named

alpha_stepper_motor
beta_stepper_motor
gamma_stepper_motor

Regardless of config file pin assignments(to M1, M2, M3 or M4, etc), the enable pins work correct after bootup. So under the following scenario:

  • smoothie boots up
  • config sets alpha to M1
  • config sets beta to M2
  • config sets gamma to M3
  • start to stream a job
  • printf shows that alpha M1 en_pin.enable pin is set to 0, alpha en_pin.valid pin is set to 1
  • the job streams fine, the apha/M1 axis works fine

Then I send a M800 X4 gcode which hits the following line in Robot::on_gcode received()…

case 800:
{
    if (gcode->has_letter('X'))
    {
        switch ((char)gcode->get_value('X'))
        {
        case 4:
            this->alpha_stepper_motor->RemapPins("2.3", "0.22", "0.21");
            break;
         }
     }
}

That then hits the following function in StepperMotor:

void StepperMotor::RemapPins(std::string step, std::string dir, std::string en)
{ 
    step_pin.from_string(step); 
    dir_pin.from_string(dir);
    en_pin.from_string(en);
    this->enable(true); // added to enable the enable pin
}

You can see where I added the extra line to enable the enable pin.
I then do the following:

  • start to stream a job
  • printf shows that alpha M4 en_pin.enable pin is set to 1, alpha en_pin.valid pin is set to 1
  • the job streams, but the the apha/M4 axis sits idle, because the M4 en_pin.enable is set to 1

No matter what combination of attempts I throw at it, I cannot get the enable pin to stay on.

Now, for comparison purposes, here’s what happens if I assign M4 via the config file like this:

alpha_step_pin                               2.3              # Pin for alpha stepper step signal
alpha_dir_pin                                0.22              # Pin for alpha stepper direction
alpha_en_pin                                 0.21              # Pin for alpha enable pin
alpha_current                                1.5              # X stepper motor current
alpha_max_rate                               30000.0          # mm/min

When I do so, and boot the system up, and send a job, here’s what happens:

  • smoothie boots up
  • config sets alpha to M4
  • config sets beta to M2
  • config sets gamma to M3
  • start to stream a job
  • printf shows that alpha M4 en_pin.enable pin is set to 0, alpha en_pin.valid pin is set to 1
  • the job streams fine, the apha/M4 axis works fine

When the config file assigns the M4 pins to alpha during init, the M4 en_pin.enable is set to 0 and the M4 axis works fine.

So what seems to be happening is this:

Upon bootup, any pin assignments done AT THAT TIME seem to “stick” and work.
Since the default alpha is M1, M4 is understandably left “disabled”, because it won’t be used.

Once the M4 boots up in that disabled state, and the new M800 X4 gocde is sent,
the new functions do indeed assign the alpha pins to M4 pins, but all attempts to enable the M4 en_pin fail, it stays at 1 and will therefore not work.

So the question is: what is the proper way to enable the pin AFTER THE FACT (way after bootup initialization)? Is there some “check” later that, for some reason, is continuing to turn the M4 en_pin.enable tp disabled? Something that is keeping track of its initial bootup state and wants to keep it that way?

maybe try creating the pin object when you want to swap pins around (and not just set its value), it’s possible it works in the beginning because the pins gets created and the registers gets set, but after that you’re doing “less” on the pin somehow?

1 Like

Arthur, you’re a genius. That was the solution, and it now works.

Instead of creating the pin every time, I decided to create it once upon board initialization with the other pins. You are correct that, upon board initialization, there is some code “somewhere” that is being called deep in the bowels (which I couldn’t locate) but treated your assumption as correct.

In the robot boot init code I added the lines to create a delta motor with the M4 pins assigned and had that pushed onto the actuator stack along with alpha, beta and gamma. Somewhere, I don’t know if it’s deep in kernel or somewhere else, this caused the M4 pins to be “legitimate” as you surmised.

Now, I can send the new gocde to remap the XY pins to any combination to either M1, M2, M3 or M4, and it works great. If I have a job that consists of thousands of XYZ gcodes, and I send the following commands:

M800 X1 Y2 // map X (alpha) to M1 and Y (beta) to M2
thousands of XYZ gcodes

The complete job runs fine on M1 and M2 steppers

If I then send the following commands:

M800 X4 Y2 // map X (alpha) to M4 and Y (beta) to M2
same thousands of XYZ gcodes

The complete job runs fine on M4 and M2 steppers

If I then send the following commands:

M800 X1 Y4 // map X (alpha) to M1 and Y (beta) to M4

The complete job runs fine on M1 and M4 steppers

So, everything is now working fine, and I am marking this forum topic as SOLVED.

Speaking of gcode, I am not emotionally attached to M800 nor committed to it. If there is some protocol I should follow, I of course would rather use whatever gcode number the developers/smoothie community thinks would be most appropriate.

2 Likes