A lot of times, users have specific requests or requirements regarding communication or control of external devices and equipment. More complex CNC systems can use a lot of sensors, actuators, measuring devices and all this needs it own control logic, which sometimes can be a lot to process. So instead of putting this burden on the TNG you can use external control device to handle all the data processing and control logic, while TNG processes the data at a later stage at much reduced complexity.
TNG offers a lot of tools for USB, serial communication and data manipulation at a higher abstraction level, making them very easy to use.
Great example of an external control device is an Arduino board(or any other embedded system or even a standalone PLC). Advantage of Arduino in this case can be understood in the following points:
This and upcoming projects will show just how quickly you can create something with Arduino that can be used with TNG software.
Previous project described how to start with Arduino environment. How to install Arduino IDE, and how to create your first Arduino project using Arduino UNO board(blinking LED).
So, you should be able to know the minimum basics to move things forward.
Sections of the code are described below.
First we declare the variables which will be used for evaluation of pushbuttons state as also the pushbutton values sent trough serial port. Both btn_last
and btn
are declared as 8bit unsigned integer.
Macros BUTTON_1
and BUTTON_2
will help with more understandable naming of pin parameters for functions that will initialize the digital pins of Arduino microcontroller.
Macros OUT_1
and OUT_2
represent values used with bitwise operators in the main loop.
uint8_t btn_last; uint8_t btn; //macros for digital pins #define BUTTON_1 8 #define BUTTON_2 9 //macros for btn values #define OUT_1 0 #define OUT_2 1
Setup code will run only once, that is when microcontroller is reset or once it is powered-up.
In this function we initialize digital pins of Arduino board. This task is done with use of function pinMode(pin,mode).
I choose pins of microcontroller 8 and 9, represented with macros BUTTON_1
and BUTTON_2
. These two pins are where pushbuttons will be connected, so I set them as inputs.
On-board LED is represented with macro LED_BUILTIN
. This macro is part of Arduino internal library, this is why we did not need to declare it at the beginning. This pin will be set as output.
Here is also a good place where we set init values of button variables btn
and btn_last
. We set them at zero value.
serial.Begin(speed)
function sets the data rate for serial data transmission. We set it at 9600
bits per second.
void setup() { //digital pins 8 and 9 are set as inputs with internal pullup //digital pin for LED set at output pinMode(BUTTON_1, INPUT_PULLUP); pinMode(BUTTON_2, INPUT_PULLUP); pinMode(LED_BUILTIN, OUTPUT); //variables btn_last and btn init btn_last = btn = 0; //set up serial library baud rate to 9600 Serial.begin(9600); }
Main loop()
will run indefinitely, this is where our main code will reside.
Expression btn |= digitalRead(BUTTON_1) « OUT_1
sets the value of btn
variable. It does this by using return value(1 when idle, 0 when pushbutton pressed) of function digitalRead()
and left shifting it for value of OUT_1
, which is always 0.
Saying it in other words:
Pushbutton 1 idle: Shift value 1 for 0 places, giving us the decimal value 1.
Pushbutton 1 pressed: Shift value 0 for 0 places, giving us the decimal value 0.
If BUTTON_1
is in its idle state, meaning it is not pressed, the bit-wise OR operator |=
will add value 1, to current value of btn.
Expression btn |= digitalRead(BUTTON_2) « OUT_2
sets the value of btn
variable. It does this by using return value(1 when idle, 0 when pushbutton pressed) of function digitalRead()
and left shifting it for value of OUT_2
, which is always 1.
Saying it in other words:
Pushbutton 2 idle: Shift value 1 for 1 place, giving us the decimal value 2.
Pushbutton 2 pressed: Shift value 0 for 1 place, giving us the decimal value 0.
If BUTTON_2
is in its idle state, meaning it is not pressed, the bit-wise OR operator |=
will add value 2, to current value of btn.
So, if none of the pushbuttons is pressed, btn variable will have value of 3.
If pushbutton 1 is pressed, btn variable will have value of 2.
If pushbutton 2 is pressed, btn variable will have value of 1.
If both pushbuttons are pressed, btn variable will have value of 0.
These values will be considered in our expression file code.
void loop() { //btn variable value set at 0 btn = 0; //when no button is pressed, btn returns value 3 //when only button 1 is pressed, btn returns value 2 //when only button 2 is pressed, btn returns value 1 btn |= digitalRead(BUTTON_1) << OUT_1; btn |= digitalRead(BUTTON_2) << OUT_2;
In the setup()
loop we set btn_last = 0
. This variable is used to check if pushbuttons state have changed, and therefore, if value of btn variable has changed.
Once the btn value changes, the condition btn != btn_last
is true, and code within the body of if
statement is executed. Immediately we copy the btn
value to btn_last
.
For each such event, Serial.write(btn)
writes the btn
value to serial port and on-board LED will toggle.
Until we release the button, the condition btn != btn_last
will not be true, and btn value is not written to serial port.
//checks if pushbutton state has changed i.e. pushbutton pressed or released //on button state change, save button state and send btn value trough serial port and toggle led if(btn_last != btn) { btn_last = btn; Serial.write(btn); digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); } delay(100); }
Full code below.
// the setup function runs once when you press reset or power the board uint8_t btn_last; uint8_t btn; //macros for digital pins #define BUTTON_1 8 #define BUTTON_2 9 //macros for btn values #define OUT_1 0 #define OUT_2 1 void setup() { //digital pin 8 and 9 are set as inputs with internal pullup //digital pin for LED set at output pinMode(BUTTON_1, INPUT_PULLUP); pinMode(BUTTON_2, INPUT_PULLUP); pinMode(LED_BUILTIN, OUTPUT); //variables btn_last and btn init btn_last = btn = 0; //set up serial library baud rate to 9600 Serial.begin(9600); } // the loop function runs over and over again forever void loop() { //btn variable value set at 0 btn = 0; //when no button is pressed, btn returns value 3 //when only button 1 is pressed, btn returns value 2 //when only button 2 is pressed, btn returns value 1 btn |= digitalRead(BUTTON_1) << OUT_1; btn |= digitalRead(BUTTON_2) << OUT_2; //checks if pushbutton state has changed i.e. pushbutton pressed or released //on button state change, save button state and send btn value trough serial port and toggle led if(btn_last != btn) { btn_last = btn; Serial.write(btn); digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); } delay(100); }
Verify and upload the code to your Arduino board.
Locate your profile folder and create new expression file and name it e.g. Expr_Arduino_pushbuttons.
Open the file and paste the code below.
I recommend reading up on serial_addlistener() and array functions Functions, that play a key role in this code.
#OnInit ;!!For port variable, use port name of your Arduino board!! ;open serial port ;serial port parameter config ;add serial listener port = "COM13"; hnd = array_new(); serial_open(port); serial_config(port, 9600, 8, 0, 1, 1); serial_addlistener(port, "#On_Serial_Event", hnd, 1); ;*************************************************************** #On_Serial_Event array_printdata(.arg2); ;obtain serial data .dir = array_getdata(.arg2, 0); if(.dir == 0x01, .dirX = 1); if(.dir == 0x02, .dirX = 2); if(.dir == 0x03, .dirX = 3); .ax = 0; if(.dirX == 1, .ax = -1); if(.dirX == 2, .ax = +1); if(.dirX == 3, .ax = 0); ;jogs X axis of machine, depending on the serial data jog(0, .ax, 0, 0); ;*************************************************************** #OnShutdown serial_close(port); serial_remlistener(port); array_delete(hnd);
Launch TNG and open Output window: View/Panel/Utilities
Output window will appear:
Under Control Panel/Device Manager check if your Arduino board is presented as virtual com port. In my case as COM13. Make sure that your expression file uses this name for port
.
Now connect the Arduino board to computers USB port, and observe the output window while press one of the pushbuttons:
To interpret the values:
0x01
→ Button 2 has been pressed. As per our expression file, machine will jog in -X direction.
0x03
→ Push button has been released, and no pushbuttons is pressed.
0x01
→ Button 2 has been pressed. As per our expression file, machine will jog in -X direction.
0x03
→ Push button has been released, and no pushbuttons is pressed.
0x02
→ Button 1 has been pressed. As per our expression file, machine will jog in X direction.
0x03
→ Push button has been released, and no pushbuttons is pressed.