Hello Guest it is March 28, 2024, 06:45:24 PM

Author Topic: My experiments with Mach3 ModBus and Arduino, Part I  (Read 100410 times)

0 Members and 1 Guest are viewing this topic.

My experiments with Mach3 ModBus and Arduino, Part I
« on: February 18, 2013, 11:05:58 AM »
Hi,

My project is add some external Inputs and Outputs to Mach3 using Arduino. For that last several days I read many posts about this.
I test Arduino ModBus library. Is very well documented, work but is too complicated for me in a moment. Zafarsalam too have good tutorial who I read carefully.
So I try share here step by step all my experiments when learn Mach3 ModBus and because don't know well Mach3 will thankful all who join and test.

PLEASE DON'T TEST USING MACH3 CONNECTED TO WORKING MACHINE!

Equipment:
1. Arduino board (I using Arduino Duemilanove but you can use any other Arduino board)
2. PC with Windows XP and Mach3 because software who I using for monitoring ModBus communication no support new versions Windows.
3. Software's
  - Arduino IDE
  - Mach3
  - Free Serial Port Monitor from http://www.serial-port-monitor.com


Part I: "Hello Word" or "Running Cycle Start button from Arduino Input pin".

(1) Mach3 ModBus settings


1. Connect Arduino to PC and upload any blank sketch or Blink Led example. My Arduino using COM5 so recommend change your to using the same COM Port.

2. Run Serial Port Monitor, go to New Session >> Serial Port Monitor >> Choose COM port(COM5), mark Request View and click "OK"
    Don't close Serial Port Monitor. Here you will see ModBus communication!

3. Run Mach3, go to Config, Ports&Pins and mark "ModBus InputOutput support".
   - Click OK and restart Mach3.
   - Go to Setup Serial ModBus control and set parameters exactly thereby:




Click Apply.

Now time for first checking break you to sure that all until now is correct.
 - Mach3 in ModBus status show 'Receive timeout'. In a moment this is normal. Arduino no programmed to receive command and reply.
 - Minimize Mach3 and go to Serial Port Monitor. Because default timeout settings is 500ms you will see that any half second Mach3 send to Arduino this request "01 04 00 00 00 01 31 CA". Don't try now understand what this mean in a moment. Will expand in next parts.
 - RX LED Arduino must blink too any half second.



If you don't see exactly this go back and try to find problem.
And don't continue until this step no work correctly! Any error bring no working project.

Now close Mach3 and Serial Port Monitor.


(2) Arduino programming

1. Upload this simple code who emulate ModBus slave to Arduino.
    Please use this code only for test because no have any safeguard!

Quote

int pin = 2;  //Cycle Start button
int in_buffer[8]; // receiving buffer
int reply_1[] ={0x01, 0x04, 0x02, 0x00, 0x01, 0x78, 0xF0};
int reply_0[] ={0x01, 0x04, 0x02, 0x00, 0x00, 0xB9, 0x30};

void setup()
{
  Serial.begin(9600);            // Init serial communication
  pinMode(pin, INPUT);           // Set pin to input
  digitalWrite(pin, HIGH);       // Turn on pullup resistor
}

void loop()
{
   if ( Serial.available() == 8 ) {
     
     // read ModBus command from Mach3
     // in this example we only read, don't check anything
     for (int i=0; i < 8; i++) in_buffer[ i ] = Serial.read();
     
     // Read Input PIN and reply with 0 or 1
     // Reply is inverted because PIN default state is HIGH and we connect to GND
     if ( digitalRead(2) == 0 )
         for (int i=0; i < 7; i++) Serial.write(reply_1[ i ]);
        else
         for (int i=0; i < 7; i++) Serial.write(reply_0[ i] );
 
   }   
}



Don't hurry to run Mach3. First try to understand what Arduino reply to Mach3 request.

Please download this ModBus test software:
http://www.kmtronic.com/software/ModBus/KMtronic_ModBus_Tester.zip

Run, set COM5, 9600, click Open, put this "01 04 00 00 00 01" command in text box and send to Arduino.
Next connect PIN2 Arduino to GND and click send again.





Now time to expand...
Please ignore last two bytes commands and replies. This is Check Sum and software calculate before send command for easy usage.

Command "01 04 00 00 00 01" is ModBus command who send Mach3 (check previous part).
You see in log that first reply when PIN2 is unconnected is:
1 - Rx: 01 04 02 00 00 
and
3 - Rx: 01 04 02 00 01
when PIN2 is connected to GND.

So Arduino now will reply 0 or 1 when Mach3 ask for status Input.

Again time for break if all is not the same.
Mach3 and Arduino must 'talk' together so if one of this two no work correctly no sense you to continue...


(3) Mach3 & Arduino

1. Close all programs
2. First run Serial Port Monitor >> Request View
3. Next run Mach3
If all is OK:
- Mach3 in "ModBus InputOutput support" will show 'No error'
- Arduino TX and RX LEDs will blink very fast.
- In Serial Port Monitor you will see a lot of Mach3 requests and Arduino replies.



Again break if all is not the same!


Time for last step - using brain tell Mach3 what command to execute when button is push down (PIN2 connected to GND).
 
(4) Create a brain who read ModBus and control Cycle Start button

1. Close again all programs.
2. Run Mach3 only and open Brain editor. Click on '+', go to ModBus and mark this:



Save file to Mach3\Brains in example 'Arduino_Test_01.brn'.
Now go to Brian control, click 'ReloadAll', enable it and next 'ViewBrain'.

Test that all until now work.
When you leave free PIN2 you will see Input blue. When connect to GND - green.




Brain now read Input!!!

This Input you can connect now to any function in Mach3. This example is how connect to Cycle Start button.

Go back to Brain editor, mark Input and using '+' add to Input:



Next mark again and go to Mach3 function '1000- CycleStart'





Save brain, re-load from Brian control, open any G-Code and try!

Hope this will be usefully Mach3 users understand how ModBus works .

Happy fun!


Offline Chaoticone

*
  • *
  •  5,624 5,624
  • Precision Chaos
    • View Profile
Re: My experiments with Mach3 ModBus and Arduino, Part I
« Reply #1 on: February 18, 2013, 11:28:36 AM »
Thanks KM, I'm sure this will help many.  It's so nice of you to put this together and share it with us.  I'll be trying this soon.

Brett
;D If you could see the things I have in my head, you would be laughing too. ;D

My guard dog is not what you need to worry about!

Offline Tweakie.CNC

*
  • *
  •  9,196 9,196
  • Super Kitty
    • View Profile
Re: My experiments with Mach3 ModBus and Arduino, Part I
« Reply #2 on: February 19, 2013, 02:47:11 AM »
Hi KM,

An excellent, informative and well prepared article - thanks for posting.

Tweakie.
PEACE
Re: My experiments with Mach3 ModBus and Arduino, Part I
« Reply #3 on: February 20, 2013, 12:04:55 PM »
Thanks KMtronic, It's useful for me.

Laotou.
Re: My experiments with Mach3 ModBus and Arduino, Part I
« Reply #4 on: February 22, 2013, 05:51:32 AM »
Hi again and thanks all for replies!

Yesterday I have free time and continue learning ModBus.

Here is next revision where I add some more Inputs and functions.
- 7 more Digital Inputs
- Calculating check sum function
- Error reply (but no sure that it work as much because Mach3 no show).

If I understand correctly Mach3 have 16 bytes registers from 0 to ...
I this code is used half of first register - MOD:0 but just support first 5 registers ( MOD:0 - MOD:4) and if need can add more Inputs.



Code no have comments and can be optimized, but work well:

Quote
unsigned int CRC16, SEED, GP; //for CRC16
#define SEED 0xFFFF  //initialization for CRC16
#define GP   0xA001  //generating polynomial
int in_buffer[8]; // receiving buffer

#define CycleStart 2;  //MOD:0-D0
#define FeedHold 3;  //MOD:0-D1
#define StopFile 4;  //MOD:0-D2
#define SingleStep 5;  //MOD:0-D3
#define ResumeFile 6;  //MOD:0-D4
#define ZeroX 7;  //MOD:0-D5
#define ZeroY 8;  //MOD:0-D6
#define ZeroZ 9;  //MOD:0-D7


void setup()
{
  Serial.begin(9600);            // Init serial communication
  pinMode(2, INPUT);           // Set pin to input
  pinMode(3, INPUT);           // Set pin to input
  pinMode(4, INPUT);           // Set pin to input
  pinMode(5, INPUT);           // Set pin to input
  pinMode(6, INPUT);           // Set pin to input
  pinMode(7, INPUT);           // Set pin to input
  pinMode(8, INPUT);           // Set pin to input
  pinMode(9, INPUT);           // Set pin to input
  digitalWrite(2, HIGH);       // Turn on pullup resistor
  digitalWrite(3, HIGH);       // Turn on pullup resistor
  digitalWrite(4, HIGH);       // Turn on pullup resistor
  digitalWrite(5, HIGH);       // Turn on pullup resistor
  digitalWrite(6, HIGH);       // Turn on pullup resistor
  digitalWrite(7, HIGH);       // Turn on pullup resistor
  digitalWrite(8, HIGH);       // Turn on pullup resistor
  digitalWrite(9, HIGH);       // Turn on pullup resistor
}

void loop()
{
   if ( Serial.available() == 8 ) {
     
     // read ModBus command from Mach3
     for (int i=0; i < 8; i++) in_buffer[ i ] = Serial.read();
     
     if ((in_buffer[0]== 0x01)&(in_buffer[1]== 0x04))
         Reply_Inputs();
         else
         Reply_Error();
         
     Serial.flush();
 
   }   
}

/// ----------------------- Functions -----------------------
void Reply_Inputs()
{
   CRC16 = SEED;
   int Inputs[] ={0x01, 0x04, 0x0A, 0x00, 0x00,
                  0x00, 0x00, 0x00, 0x00, 0x00,
                  0x00, 0x00, 0x00, 0x00, 0x00};

   Inputs[4] = (
               ((!digitalRead( 9 ))<<7) |
               ((!digitalRead( 8 ))<<6) |
               ((!digitalRead( 7 ))<<5) |
               ((!digitalRead( 6 ))<<4) |
               ((!digitalRead( 5 ))<<3) |
               ((!digitalRead( 4 ))<<2) |
               ((!digitalRead( 3 ))<<1) |
               ((!digitalRead( 2 ))   ) );

   for (int i = 0; i < 13; i++)
        {   
        Calc_CRC(Inputs[ i ], &CRC16);
        }     
       
        Inputs[13]=CRC16 ;
        CRC16=CRC16>>8 ;
        Inputs[14]=CRC16 ;
   
   for (int i=0; i < 15; i++) Serial.write(Inputs[ i ]);
}
/// ---------------------------------------------------------
void Reply_Error()
{
   int Error[] ={0x01, 0x84, 0x00, 0x43, 0x00};
   for (int i=0; i < 5; i++) Serial.write(Error[ i ]);
}
/// ---------------------------------------------------------
void Calc_CRC(unsigned char b, unsigned int* CRC)
{
   int carry, i ;

   CRC[0] ^= b & 0xFF;
   for (i=0; i<8; i++)
   {
      carry = CRC[0] & 0x0001;
      CRC[0]>>=1;
      if (carry) CRC[0] ^= GP;
   }
}
/// ---------------------------------------------------------


Here is brain:



And settings:





I use first some buttons for test connected between PINs and GND.
 
Attachment contain Arduino code & ready brain.
You can modify buttons using "Terminate Lobe" function Brain Editor.

TODO: test ad add Analog Inputs using Zafarsalam tutorial.

Can someone know way how to configure ModBus Inputs to change screens? When button pressed in example Mach3 go to MDI?
I don't find such commands in Brain Editor.


Regards



Offline Chaoticone

*
  • *
  •  5,624 5,624
  • Precision Chaos
    • View Profile
Re: My experiments with Mach3 ModBus and Arduino, Part I
« Reply #5 on: February 22, 2013, 08:29:10 AM »
The screens are Buttons 1-100.  The mdi page is button 2 or 3 I think.

Brett
;D If you could see the things I have in my head, you would be laughing too. ;D

My guard dog is not what you need to worry about!
Re: My experiments with Mach3 ModBus and Arduino, Part I
« Reply #6 on: January 08, 2014, 01:53:30 PM »
Hi!
Thank you of this info. I'm building wireless remote controller for my router and this helped me to get started.

This remote controller what I'm building have, around 20 function buttons (under every button can save 2 functions), one analog joystick for X/Y jog, one potentiometer for feed override, small encoder for precise axis movement and 2x16 LCD screen for pos. info (bit to small).

First I tried to modify arduino code from this thread, but I wasn't able to increase the amount of modbus registers. Seemed to be some issue with arduino Serial.write.

Then I searched Arduino modbus library. I founded this library: SimpleModbusSlave http://code.google.com/p/simple-modbus/downloads/detail?name=SimpleModbusSlaveV8.zip&can=2&q=label%3AFeatured

It works me very well so I like to share it!  :)

It only suports modbus holding registres, but its ok atleast for me. If you want to use it with Arduino Leonardo or Micro ( as I did) then you need to modify this library. Otherwise serial over USB does not work.

Here one sample how to use this:

Arduino code:
Code: [Select]
// Modbus:
#include <SimpleModbusSlave.h> //http://code.google.com/p/simple-modbus/
const int HOLDING_REGS_SIZE = 22; // I use 22 registers, first 11 for sendidng info to Mach3
//and next 11 registers for receiving info from Mach3
unsigned int holdingRegs[HOLDING_REGS_SIZE]; // function 3 and 16 register array

int rcd[11]; //holds sending info
int mcd[11]; //holds received info

void setup(){

  pinMode(13, OUTPUT); //indicator LED

  //modbus_configure(&Serial, 115200, SERIAL_8N2, 2, 13, HOLDING_REGS_SIZE, holdingRegs);
//2 is slave address, 13 is indicator led pin (useless)

  // with Arduino Micro I used modified library files and this line:
  //modbus_configure(115200, SERIAL_8N2, 2, 13, HOLDING_REGS_SIZE, holdingRegs);
}

void loop(){

  //Reads buttons:
  if(digitalRead(4) == 1) bitSet(rcd[0],0);
  else bitClear(rcd[0],0);

  if(digitalRead(5) == 1) bitSet(rcd[0],1);
  else bitClear(rcd[0],1);

  if(digitalRead(6) == 1) bitSet(rcd[0],2);   //can be up to 15
  else bitClear(rcd[0],2);

  //Potens´iometers:
  rcd[3] = analogRead(A0);
  rcd[4] = analogRead(A1);

  //Other variables:
  rcd[1] = 0x1111;
  rcd[2] = 0x2222;
  rcd[5] = 0x3333;
  rcd[6] = 32767;
  rcd[7] = 12345;
  rcd[8] = 54321;
  rcd[9] = 0;
  rcd[10] = 1;


  //Sending and receiving info:
  for (int i=0; i < 11; i++)
    holdingRegs[i] = rcd[i];

  modbus_update();

  for (int i=0; i < 11; i++)
    mcd[i] = holdingRegs[i+11];

  /* Writes cordinates to LCD:
   float Xpos = mcd[0]+(mcd[1]/100.00);
   float Ypos = mcd[2]+(mcd[3]/100.00);
   float Zpos = mcd[4]+(mcd[5]/100.00);
   
   lcd.setCursor(0, 0);
   lcd.print("                ");
   lcd.setCursor(0, 0);
   lcd.print("X");
   lcd.setCursor(0, 1);
   lcd.print(Xpos);
   lcd.setCursor(0, 8);
   lcd.print("Y");
   lcd.setCursor(0, 9);
   lcd.print(Ypos);
   lcd.setCursor(1, 0);
   lcd.print("        ");
   lcd.setCursor(1, 0);
   lcd.print("Z");
   lcd.setCursor(1, 1);
   lcd.print(Zpos);
   */
}

Mach3 settings and test images :
« Last Edit: January 08, 2014, 01:56:12 PM by M2rt »
Re: My experiments with Mach3 ModBus and Arduino, Part I
« Reply #7 on: January 08, 2014, 02:26:14 PM »
In case you want to use this library with Arduino Leonardo or Micro, you can use this library files.

Sorry abut my english.
« Last Edit: January 08, 2014, 02:39:46 PM by M2rt »
Re: My experiments with Mach3 ModBus and Arduino, Part I
« Reply #8 on: January 08, 2014, 03:22:57 PM »
Is there simple way to control machine axis with analog joystick in brain?  ???
Re: My experiments with Mach3 ModBus and Arduino, Part I
« Reply #9 on: March 26, 2014, 06:36:07 PM »
Hi,

what is brain solution for jogs ?