Project showcase
Ignition SCADA + MKR WiFi 1010

Ignition SCADA + MKR WiFi 1010 © GPL3+

If you're trying to learn Ignition and want a source of actual data, this tutorial demonstrates how to feed Ignition with Arduino.

  • 4,485 views
  • 2 comments
  • 12 respects

Components and supplies

Apps and online services

About this project

I started studying how to configure Ignition SCADA for a project at work and I wanted to have a real source of data to work with before the project starts. Ignition includes a PLC simulator but I found that un-exciting. So I decided to see if Ignition could interface with an Arduino and the result was a resounding yes.

This project will show you how to connect a MKR WiFi 1010 + MKR RS 485 Shield to Ignition using the Modbus driver in Ignition. A VFD is shown in this example but if you don't have a VFD you can remove that part from the code and just work with the other data which is: on-board RGB LED, push button, temp sensor, and potentiometer.

The base of the code is the example Modbus TCP server and my VFD control example which is build of off the Modbus RTU client example provided in Arduino IDE if you have the Modbus library installed.

The key functions of the code are as follows:

1) Set the board to be a Modbus TCP server (slave) for Ignition

2) Set the board to be a Modbus RTU Client (master) for the VFD

3) Acquire local data from a potentiometer, push button, and temp sensor

If you're not familiar with Modbus, one phrase that's always helped me understand it is "shared" addresses. For example in this case Ignition can write a "1" or "0" to a memory address in the board. Then in order to know if the VFD should run, the code takes whatever is in that memory address and writes it to another shared address in the VFD. If this value is always "0" the drive stays stopped, but once a "1" is written the drive starts to move given other parameters such as desired frequency are correct.

One thing to be mindful of is that pins A5 and A6 are used for controlling the RS 485 Shield RE/DE so they cannot be used for anything else. I spent a few hours struggling with that so hopefully if you're trying to replicate this you have read this section!

Ignition is really great because you can download it and start learning for free. Below are some key things you need to know in order to configure the device section of Ignition.

When you first boot up your board, getthe IP address using serial monitor.

Of course your board and Ignition instance must be on compatible IP addresses (i.e. you can do CMD --> ping 192.168..xx.xxx and get a reply).

Enter the addresses. Key point is that hex addresses (i.e. 0x01) require the "Radix" setting be 16.

In the arduino modbus library and for use with Ignition, a coil (a single bit) and a holding register (16 bits) can both have the same address value i.e. two of them can be "0" but based on how they are implemented in the controller they are two physically different addresses.

If you want to connect to your Ignition gateway from a different PC in your home, you have to setup the self signature SSL certificate and open up inbound and outbound traffic for port 8088 in your firewall.

Here is the link to a video which quickly shows things working.

v

Code

MKR_WiFI_1010_Ignition_VFDArduino
Used to connect MKR WiFi 1010 to Ignition SCADA via Modbus TCP connection
// This sketch is for the following hardware:
//      - Arduino MKR WiFi 1010 + MKR RS-485 Shield
//      - Automation Direct GS2 VFD drive, model GS2-11P0
// The manual for the VDF can be read at: 
//      - https://cdn.automationdirect.com/static/manuals/gs2m/gs2m.html
// Written by: Nick Robinson, Last Updated 26-Mar-2020

#include <SPI.h>
#include <WiFiNINA.h>          
#include <utility/wifi_drv.h>
#include <ArduinoRS485.h>       // ArduinoModbus depends on the ArduinoRS485 library
#include <ArduinoModbus.h>

//Wifi network name and password
char ssid[] = "Kaisoku";       
char pass[] = "Tsunagaru";

//Modbus coil address mapping
const int modAddButton = 0x00;
const int modAddRedLED = 0x01;
const int modAddGreenLED = 0x02;
const int modAddBlueLED = 0x03;
const int modAddRunStop = 0x04;
const int modAddFwdRev = 0x05;

//Modbus holding register address mapping
const int modAddPotVal = 0x00;
const int modAddTempVal = 0x01;
const int modAddDriveFreq = 0x02;
const int modAddAccelDecel = 0x03;
const int modAddRpm = 0x04;
const int modAddDriveStatus = 0x05;

//VFD parameters and modbus addresses
const int vfd = 0x02;                   
const int driveRatio = 29;

const int Add_accel = 0x0101;           // Acceleration time
const int Add_decel = 0x0102;           // Deceleration time
const int Add_rpm = 0x2107;             // motor rpm 
const int Add_Status1 = 0x2100;         // Status monitor 1
const int Add_driveFreq = 0x091A;       // 0 to 60 Hz                 
const int Add_stopRun = 0x091B;         // 0 = stop, 1 = run
const int Add_fwdRev = 0x091C;          // 0 = forward, 1 = reverse

//VFD related input / output variables
int inputFreq;
int inputStopGo;
int inputDirection;
int inputAccelDecelTime;
int outputRpm;
int outputDriveStatus;

//Arduino hardware input / output variables
const int buttonPin = 5;                //pushbutton on D5
const int redLED = 26;                  //uses on board RGB LED
const int greenLED = 25;
const int blueLED = 27;
int buttonValue, prevButtonValue, buttonSwitch;

int status = WL_IDLE_STATUS;

WiFiServer wifiServer(502);             //TCP Modbus on port 502
ModbusTCPServer modbusTCPServer;

void setup() {
  Serial.begin(9600);
  ModbusRTUClient.begin(19200, SERIAL_8O1);
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    status = WiFi.begin(ssid, pass);
    delay(1000);
  }
  Serial.println("Modbus TCP Server");
  printWifiStatus();  //before start-up, open serial monitor in order to see the assigned IP address
  wifiServer.begin();

  if (!modbusTCPServer.begin()) {
    Serial.println("Failed to start Modbus TCP Server!");
    while (1);
  }
  pinMode(buttonPin, INPUT);
  WiFiDrv::pinMode(redLED, OUTPUT); 
  WiFiDrv::pinMode(greenLED, OUTPUT); 
  WiFiDrv::pinMode(blueLED, OUTPUT); 
  WiFiDrv::digitalWrite(redLED, LOW);
  WiFiDrv::digitalWrite(greenLED, LOW);
  WiFiDrv::digitalWrite(blueLED, LOW);

  modbusTCPServer.configureCoils(0x00, 10);
  modbusTCPServer.configureHoldingRegisters(0x00, 10);
}

void loop() {
  WiFiClient client = wifiServer.available();
  
  if (client) {
    Serial.println("Ignition! Connected");
    modbusTCPServer.accept(client);

    while (client.connected()) {
      modbusTCPServer.poll();
      updateButton();
      updateLED();
      updatePot();
      updateTemp();
      updateVFD();
    }
    Serial.println("disconnected");
  }
}

void updateButton() {
  buttonValue = digitalRead(buttonPin);
  if(buttonValue != prevButtonValue){
    if(buttonValue == HIGH){
      buttonSwitch = !buttonSwitch;
    }
  prevButtonValue = buttonValue;
  }
  modbusTCPServer.coilWrite(modAddButton, buttonSwitch);
}

void updateLED() {
  int coilValue_red = modbusTCPServer.coilRead(modAddRedLED);
  int coilValue_green = modbusTCPServer.coilRead(modAddGreenLED);
  int coilValue_blue = modbusTCPServer.coilRead(modAddBlueLED);

  WiFiDrv::digitalWrite(redLED, coilValue_red);
  WiFiDrv::digitalWrite(greenLED, coilValue_green);
  WiFiDrv::digitalWrite(blueLED, coilValue_blue);
}

void updatePot() {
  int potRawVal = analogRead(A4);
  //raw value is sent, conversion to voltage is done in Ignition
  modbusTCPServer.holdingRegisterWrite(modAddPotVal, potRawVal);  
}

void updateTemp() {
  int tempRawVal = analogRead(A3);
  //raw value is sent, conversion to temperature is done in Ignition
  modbusTCPServer.holdingRegisterWrite(modAddTempVal, tempRawVal);
}

void updateVFD() {
  inputStopGo = modbusTCPServer.coilRead(modAddRunStop);
  inputDirection = modbusTCPServer.coilRead(modAddFwdRev);
  inputFreq = (modbusTCPServer.holdingRegisterRead(modAddDriveFreq)) * 10;
  inputAccelDecelTime = modbusTCPServer.holdingRegisterRead(modAddAccelDecel); 
  
  if(inputAccelDecelTime == 0) 
    inputAccelDecelTime = 50;
  
  if(!ModbusRTUClient.holdingRegisterWrite(vfd, Add_driveFreq, inputFreq) ||
     !ModbusRTUClient.holdingRegisterWrite(vfd, Add_stopRun, inputStopGo) ||
     !ModbusRTUClient.holdingRegisterWrite(vfd, Add_fwdRev, inputDirection) ||
     !ModbusRTUClient.holdingRegisterWrite(vfd, Add_accel, inputAccelDecelTime) ||
     !ModbusRTUClient.holdingRegisterWrite(vfd, Add_decel, inputAccelDecelTime))
        errorFlash();
        
  outputRpm = ModbusRTUClient.holdingRegisterRead(vfd, Add_rpm);
  outputDriveStatus = ModbusRTUClient.holdingRegisterRead(vfd, Add_Status1);
  if(outputRpm == -1 || outputDriveStatus == -1)
    errorFlash();
  else outputRpm = outputRpm / driveRatio;
  
  modbusTCPServer.holdingRegisterWrite(modAddRpm, outputRpm);
  modbusTCPServer.holdingRegisterWrite(modAddDriveStatus, outputDriveStatus);
}

void errorFlash(){                    
  pinMode(LED_BUILTIN, OUTPUT);                 
  digitalWrite(LED_BUILTIN, HIGH);
  delay(100);
  digitalWrite(LED_BUILTIN, LOW);
  delay(100);
}

void printWifiStatus() {
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

Schematics

Wiring for potentiometer, push button, and LM34 temp sensor
These components give you a way to create channels which can be viewed in Ignition
Img 0576 wreyy5x6jo
Modbus Address file
Import into Ignition Gateway
modbus-config_6eWW8sUkBE.csv

Comments

Similar projects you might like

Monitor Your Energy Bill via Modbus, MKR WiFi 1010 and RS485

Project tutorial by 3 developers

  • 31,136 views
  • 20 comments
  • 80 respects

Smart Plug with Arduino MKR WiFi 1010

Project tutorial by Avilmaru

  • 6,304 views
  • 1 comment
  • 16 respects

MKR WiFi 1010 + Firebase

Project tutorial by OscarF10

  • 1,700 views
  • 2 comments
  • 7 respects

[IoT] Telegram Bot with Arduino MKR WiFi 1010

Project tutorial by AppsByDavideV

  • 8,450 views
  • 15 comments
  • 26 respects

Plant Communicator with MKR WiFi 1010

Project tutorial by Arduino_Genuino

  • 5,719 views
  • 3 comments
  • 20 respects

The Nerd with MKR WiFi 1010

Project tutorial by Arduino_Genuino

  • 2,501 views
  • 0 comments
  • 4 respects
Add projectSign up / Login