Tutorial: Arduino based Jog Controller for the CNCSimulator Pro

In beta we introduce a serial port controller protocol that can be used to control the CNCSimulator via the serial port (actually the USB port via a “virtual com port”).

At CNCSimulator.com we always claim that CNC should be fun. And we think this project is a really fun one. Hobbyists and students, it is time for some Do It Yourself electronics!

Using an Arduino Uno and some basic components we can easily make a Jog controller. Here is how you can make your own:


You need:

3 1K-ohm Resistors
3 LED (Red, Green, Yellow)
1 Joystick Module (Amazon link)
1 Rotary Encoder (Amazon link)
Some cables, an Arduino Uno or compatible.
1 USB Cable
1 Breadboard

Let us test the circuit on the breadboard before putting everything together in a box.



  • Connect the short leg of each LED to ground via a 1K resistor.
  • Connect the long leg of the red LED to Arduino Pin 8.
  • Connect the long leg of the yellow LED to Arduino Pin 9.
  • Connect the long leg of the green LED to Arduino Pin 10.
  • Connect the leftmost pin of the Joystick and the Rotary encoder to the ground strip of the breadboard.
  • Connect the second left pin of both the Joystick and the Rotary encoder to the +5V strip of the breadboard.
  • Connect Arduino +5V to the positive strip of the breadboard.
  • Connect the Arduino GND (Ground) pin to the ground strip of the breadboard.
  • Connect the third pin from the left on the Joystick (VRx) to the A1 pin of the Arduino.
  • Connect the forth pin from the left on the Joystick (VRy) to the A0 pin of the Arduino.
  • Connect the rightmost pin on the Joystick (SW) to pin 0 on the Arduino.
  • Connect the forth pin on the Rotary encoder to pin 3 on the Arduino.
  • And finally, connect the fifth pin on the Rotary encoder to pin 2 on the Arduino.

When we have all wires and components in place, it is time to transfer the firmware program to the Arduino chip.

If you do not already have the Arduino software installed on your computer, please visit their website and download (and install it) using the following link.

Download the Arduino Software

Connect your Arduino and make sure you get it connected to the computer.

Copy and paste the CNCSimulator Jog Controller Sketch to the Arduino program and upload it to the board. The sketch (program) is open source, feel free to do changes as you like.

#include <Encoder.h>
// Encoder lib found here: 
// https://github.com/dc42/arduino/tree/master/Libraries/RotaryEncoder

// "Jog Controller" - CNCSimulator Pro Arduino Sketch for manual jog of the CNC axis
// Made for Arduino JoyStick Module and Rotary encoder.
// Press the center button to switch between input modes (X,Y,Z,XY,STEP etc.)
// Move joystick to jog axis or change step (depending on mode)
// Long press to set all axis to zero and generate G92 code.

// This code is provided free of charge and should be considered an experimental prototype.
// Optimize for own hardware as well as customized functionality.

// Commands to send to the CNCSimulator.
// ST+ or ST- = STEP+ and STEP- Rotary encoder increase/decrease
// J[PotH]:[PotV] Joystick Potentiometer values, both range from -100 to 100
// CJM Cycle Jog Mode - Joystick center button was pressed, cycles Jog mode settings
// SZP Joystick center button was long pressed (1 sec). Sets zero point
// JMX Jog Mode X  (unused here, we use CJM instead)
// JMY Jog Mode Y  (unused here, we use CJM instead)
// JMZ Jog Mode Z  (unused here, we use CJM instead)
// JXY Jog Mode XY  (unused here, we use CJM instead)
// STP Step Mode   (unused here, we use CJM instead)
// ETL Embedded Tool (unused here, we use CJM instead)

// Commands to receive from the CNCSimulator
// @R Simulator is running  (Red LED)
// @P Simulator has paused  (Yellow LED)
// @S Simulator has stopped (Green LED)
// @E Simulation error (Red and green LEDs)
// @C Cycle leds
// @O All LEDs off

#define joyPin1 0               // slider variable connected to analog pin 0
#define joyPin2 1               // slider variable connected to analog pin 1
#define redLedPin 8
#define yelLedPin 9
#define greenLedPin 10
#define button1Pin 0            // joystick center button
#define encoderPin1 2
#define encoderPin2 3
#define blinkdelay 50

int value1 = 0;                 // variable to read the value from the analog pin 0
int value2 = 0;                 // variable to read the value from the analog pin 1
int button1state; 
int btnval1;
int btnval2;                    // used to debounce buttons
boolean waitingForCmd = false;
int Counter = 0;
const int JoyStickDeadZone = 10;

volatile long encoderValue = 0;
long lastencoderValue = 0;

Encoder myEnc(encoderPin1, encoderPin2);

// Note: The Keyes Rot. Encoder is a bit bouncy with this sketch.
// Code changes or hardware debouncing might be needed.

void setup() 
  // Setup pin modes
  pinMode(button1Pin, INPUT);
  pinMode(redLedPin, OUTPUT);
  pinMode(yelLedPin, OUTPUT);
  pinMode(greenLedPin, OUTPUT);
  pinMode(encoderPin1, INPUT_PULLUP); 
  pinMode(encoderPin2, INPUT_PULLUP);

  button1state = digitalRead(button1Pin);

  // Do a little initial blink with the LEDs to signal wakeup

void loop() 
  // Rotary encoder part
  if((encoderValue =myEnc.read())!=lastencoderValue)
    if(encoderValue > lastencoderValue)
    lastencoderValue = encoderValue;

  // Joystick part
  if(Counter == 1)
    value1 = map(analogRead(joyPin1), 0,1023,-100,100);
  else if(Counter == 2)
    value2 = map(analogRead(joyPin2), 0,1023,-100,100);
  if(value1 < -JoyStickDeadZone || 
    value1 > JoyStickDeadZone || 
    value2 < -JoyStickDeadZone || 
    value2 > JoyStickDeadZone)
    // joystick is off center, notify the CNCSimulator
    if(value1 < -5 || value1 > 5)
    if(value2 < -5 || value2 > 5)
    btnval1 = digitalRead(button1Pin);
    btnval2 = digitalRead(button1Pin);
      if(btnval1 != button1state)
        button1state = btnval1;
        if(btnval1 == LOW)
          // Button 1 is pressed
          unsigned long timeStart = millis();
          while(digitalRead(button1Pin)==LOW)  // Wait for it to become released
            if(millis()-timeStart > 1000) // Long press

    Counter = 1;

  delay(80);  // delay needed between analog reads

  // Receive commands from the CNCSimulator
  if(Serial.available() > 0)
    char data = Serial.read();
    else if(data == '@')  // one byte command on its way
      if(Serial.available()> 0)
        waitingForCmd = true;      

void doOneByteCmd(char cmd)
  waitingForCmd = false;

  if(cmd == 'R')  // Running
    setLEDs(true, false, false);
  else if(cmd=='P')  // Paused
    setLEDs(false, true, false);
  else if(cmd=='S')  // Stopped
    setLEDs(false, false, true);
  else if(cmd=='E')  // Error (Red + Green)
    setLEDs(true, false, true);
  else if(cmd=='O')  // All LEDs off
    setLEDs(false, false, false);
  else if(cmd=='C') // Cycle LEDs

void cycleLEDs()
  setLEDs(false, false, false);

  for(int l = 0; l<3; l++)
    setLEDs(true, false, false);
    setLEDs(true, true, false);
    setLEDs(true, true, true);
    setLEDs(false, true, true);
    setLEDs(false, false, true);
    setLEDs(false, false, false);

void setLEDs(bool red, bool yellow, bool green)
  digitalWrite(redLedPin, red);
  digitalWrite(yelLedPin, yellow);
  digitalWrite(greenLedPin, green);

Time to test it out!

Start the CNCSimulator (Ver or later) and go to settings. Click on the Misc tab and check the Enable box. Set the com port (same as you have set in the Arduino software). Set the baud rate to 115200 to match the value in the Arduino sketch above.


When you close settings, the green LED should come on. This is a sign that the CNCSimulator and the Arduino is talking to each other.

Now when you turn the Rotary encoder, the feed knob should turn in the virtual CNC controller.

Feed Knob

If this does not work, check your circuit and do some checks using the serial monitor in the Arduino software to make sure the commands get sent on the com port.

If it on the other hand works, Congratulations! You have made your own hand controller! At least a prototype of it.

To activate the Jogging function in the CNCSimulator, click the Jog Enable switch at the virtual controller.


If you add a workpiece to the machine, you can even mill (or turn) it manually using the hand controller joystick.


Do you see that tiny yellow LED blinking fast on the Arduino board? It is the Tx (transmit) LED telling us that the Arduino is sending data over the serial port (via the USB cable). In this case the data is the Joystick movements.

And when you do normal simulation, check that the LEDs work. See manual below for LED signals.

Jog Controller Manual.

When Jogging is not enabled the Rotary encoder will increase and decrease simulation speed.

When Jogging is enabled it is used in the following way:

Click the center of the Joystick to cycle through the jogging modes. They are as follows for milling machines:

  • X – Jog the X axis only (Joystick sideways and Rotary encoder)
  • Y – Jog the Y axis only (Joystick vertically and Rotary encoder)
  • Z – Jog the Z axis only (Joystick vertically and Rotary encoder)
  • XY – Jog both the X and the Y axis (Joystick only)
  • ET – Cycle through the Embedded Tools (Rotary encoder)
  • STP – Increase and decrease step size (Rotary encoder)

If you long press (1 second or more) the center button, the zero point will move to the current tool position and a G92 block will be generated in the CNC program where the cursor is.

The LED:s works as follows:

Red: Simulator is running (busy)
Yellow: Simulator is paused
Green: Simulation is stopped (idle)

If you lose connection with the controller (for example if the Arduino loses power) the correct procedure to restart the connection is to exit the CNCSimulator, unplug the Arduino USB cable and after a few seconds, replug it. Then start the CNCSimulator again. The controller should now be reconnected.

Now, put everything in a nice box, put labels on it and send a picture to us, we would love to see what you come up with! :-)

Prefabricated workpieces

Did you know that you can add workpieces of your own design to your workpiece registry? They do not have to be rectangular blocks. In this short clip, we will use SimCam to make a tube that can be used as a prefabricated workpiece.

Lathe tools example DXF files

Lathe machine users, look here.

We have added a folder called “Tool Files” to the root folder of your CncSimulator Pro Version installation. This folder contains cutter and holder DXF files for our embedded turning tools. Feel free to use them when creating your own turning tools. You should be able to edit them with most DXF compatible CAD tools. We have created them with CadStd, they have a free version at:

Here is an example of creating tool number 1 (all values should be in millimeters even though you are using an inch machine as they will be automatically scaled to inches).


License collisions

What to do when you get a message that your petrol mail has been sent to an email address that is not owned by you?
In rare occasions, the ID of your computer is the same as the ID if another computer. We call this “license collisions”. When it happens, you will not be able to receive your petrol code because it is being sent to another user. 

Version brings a solution to this problem.

When you get the message that your license has expired, there will be a message box asking you if you want to open the settings. Answer Yes.

At the bottom of the settings dialog, there is a field called “License extension”.


Click on “Generate” to create an extension to your computer ID making it unique.
At next start, you will be asked to register your license from scratch.

Backup your settings!

Every now and then we do changes to the settings and registries in the CncSimulator. This may sometimes break the automatic save and restore feature for settings and registries which means you may lose all your settings, workpieces, tools and zero points if you do not have a backup. So please follow this tip to make a backup, especially if you have made lots of own tools and workpieces.

From the menu, click Settings – Simulation Settings

In the Settings Editor menu, click Files – Save Settings

Enter a filename for your file and save it in a folder outside the CncSimulator folder. For example in My Documents. Take note of the filename and folder so you remember where to find it when you need it.

That’s all! The file now contains all your settings, workpieces, tools, materials and zero points.

Remember to save regularly and after having done changes to your settings.

Demo CNC code

Ok, here is a portable demo CNC program that has some of the new features of version Copy and paste, hit play and enjoy!


M98 P9999 L1 (Call data block)
T1 M6
G0 X15 Y15 Z2
G1 Z-5 F250 S2000 M3
G2 X30 Y85 R15
G1 X85
G0 Z2
T2 M6
G0 X30 Y30 Z2
G81 Z-20 R1 M3 M8
G28 Z5 (New command)
O9999 (Data block defining registry data)
(Created for virtual machine: MillingCenterMM.machine)
($OverrideBufferQualitySetting 6)
($Message “This program uses locally defined tools, workpieces, zero points and materials.” 4 0)
($DefineMillWorkpiece “N:Tutorial1:M:Golden” 0 100.00 100.00 10.00)
($DefineMillWorkpiece “N::M:” 1 200.00 80.00 20.00)
($DefineMillWorkpiece “N::M:” 2 20.00 120.00 20.00)
($DefineMaterial “N:Golden” 0 128 128 128 218 165 32 1)
($DefineMillTool “N:Flat mill 1″ 0 0.00 0.00 0.00 10.00 50.00 0)
($DefineMillTool “N:Drill” 1 60.00 0.00 0.00 10.00 50.00 2)
($DefineMillTool “N:” 2 80.00 0.00 0.00 2.00 20.00 2)
($DefineZeropoint “N:” 0 30.00 30.00 45.00)
($AddRegPart 1, 30, 30, 35)
($AddRegPart 2, -20, 40)
($AddRegPart 3, 10 20 20.1)
($AddRegPart 3, 130, 20 20.1)

Portable CNC code

What is it and why do I need it?


Well, as you know, programs that use local settings like zero points, tools and workpieces will not run well on another computer because the settings there will probably be very different. If you want to send a program to a friend, you need to make it portable first. Same goes if you want to send a program you want to discuss with us at CncSimulator.com. Maybe you have made a very cool demo and want to send it to us so we can include it as a sample? (Please do).

With the latest version ( it is possible to make programs portable by using the menu function Tools – Make program portable.

What the function does it that it creates a sub program with tools, zero points and workpieces definitions. Instead of using your local settings when running, the CncSimulator will use the tools, zero points and workpieces defined in the sub program.

The sub program is sort of “ugly” as it is full of strange CncSimulator specific commands. That’s why we hide it away at the end of the program to not distract the user. Feel free to move other CncSimulator specific command that you use to the subprogram too. This will give your CNC program a clean look with all “strange stuff” collected in the sub program. The function will automatically add a call to the sub program in the first row. The sub program number will always be 9999 so avoid that number if you plan to make your program portable.

Please note that this function currently only works for milling programs.