The aim of this is to provide a step-by-step overview of how to create a basic module for use with Smoothie.
The example here will be a laser control module.

In smoothie, everything is a module.
A module is basically a piece of code ( an object ), that's connected to the rest of the code only by event calls and event handlers.
The core of smoothie ( serial communication, motion planning, actual stepping ) is separated in modules.
And then you can write modules for additional tasks, like controlling a laser, 3D printing or whatever the cool idea you have.
The big idea is to be able to add these additional functionalities in the simplest way possible, without having to edit the core, just connect to/call events.

For the example we'll create a simple module that turns the laser on and off depending on received G codes, and PWM adjusts the laser power to the robot's speed so that it plays nice with look-ahead acceleration management. This should actually be sufficient to do basic laser cutting.
Also there'll be a lot of explaining here, but if you landed on this page, you will probably understand everything just looking at the code, it's not that complicated.
Good examples also are the core modules, in /modules/communication/ and /modules/robot/ .

For this example, we'll put all of the function code within the class definition. You should obviously not do that for real life coding, but it makes life easier for an example.

So here is what your basic module skeleton looks like :

code type="Cpp" Basic laser control module
class Laser : public Module{
public:
Laser(){}
void on_module_loaded() { }
};
</code> We make a Laser class, extending the base Module class.
The on_module_loaded method will be called automagically when the kernel is done loading the module. You shouldn't call the kernel, like to register for an event, before on_module_loaded is called, like in the constructor. == About the Kernel The kernel ( libs/Kernel.h ) is basically what you talk to when registering for an event, calling an event, and what calls you ( the Module ) when you have registered for an event, and another Module calls this event. Your module must be added to it like this, in main.cpp : code type="Cpp"
Add Laser module to Kernel
Laser laser = Laser();
kernel→add_module( &laser );
</code>

Once the module is added, on_module_loaded() is called so that you can register for events.

So in our example we want to turn the laser on/off depending on the G codes we recieve. But because of the acceleration management ( G code look-ahead, see the Planner class ), received G codes are not executed when they are received. They are pushed in a queue, and then poped out when the previous movement has finished executing.
So there are two events : on_gcode_received and on_gcode_execute. The one that's of interrest to us now is on_gcode_execute, which is called right before the movement corresponding to that G code line is executed.

So here is how we register for an event in our code :

code type="Cpp"

class Laser : public Module{

  public:
      Laser(){}
      
      void on_module_loaded() {
          this->register_for_event(ON_GCODE_EXECUTE);       // Tell the kernel to call us whenever a gcode is executed ( not received )
      }
      void on_gcode_execute(void* argument){                // Callback function
          Gcode* gcode = static_cast<Gcode*>(argument);     // Casting of the argument ( a Gcode object )
      }

};
</code>

So now, whenever a module calls the on_gcode_execute event, this callback function will be called. In this case, the Stepper module calls this upon deleting a move it has just finished stepping.
Because of the way C++ works, arguments to events here must be passed as void pointers and then manually cast in the callback function. You can see how that's done : here we cast a Gcode object.

You can find more information about the different events in ListOfEvents.

We have to modify the class a bit to add a PwmOut to it. Then we can do some usefull stuff : 

code type="Cpp" class Laser : public Module{

  public:
      Laser(PinName pin) : laser_pin(pin){
          this->laser_pin.period_us(10);
      }
      
      void on_module_loaded() {
          this->register_for_event(ON_GCODE_EXECUTE);
          this->register_for_event(ON_SPEED_CHANGE);
      }
      void on_gcode_execute(void* argument){
          Gcode* gcode = static_cast<Gcode*>(argument);
          if( gcode->has_letter('G' )){
              int code = gcode->get_value('G');
              if( code == 0 ){                  // G0
                  this->laser_pin = 0;
                  this->laser_on =  false;
              }else if( code > 0 && code < 4 ){ // G1, G2, G3
                  this->laser_on =  true;
              }
          }
      }
      void on_speed_change(void* argument){
          Stepper* stepper = static_cast<Stepper*>(argument);
          if( this->laser_on ){ 
              this->laser_pin = double(stepper->trapezoid_adjusted_rate)/double(stepper->current_block->nominal_rate);
          }
      }
      PwmOut laser_pin;
      bool   laser_on;
 

};
</code>

And also change a bit the way we instantiate the module :

code type="Cpp" Laser laser = Laser(p21);
</code>

That's it, now the Laser pin will be LOW during G0 moves, and HIGH during G1 G2 and G3 moves.
But that's not enough. Because we use acceleration, the speed is not constant. And thus if the power of the laser stays constant, that power will be too much when accelerating and decelerating.
So we need to have a laser power that is proportional to the instant speed of the robot.
That's the kind of thing the on_speed_change event is for.

As you can see here, we have added functionality to Smoothie without having to modify the core, which is the whole point of the modular design.