Project in progress
Use Blynk + MKR Wifi w/RS-485 to control a VFD

Use Blynk + MKR Wifi w/RS-485 to control a VFD © GPL3+

This example shows how to control a variable frequency drive (VFD) from your cell phone.

  • 0 respects

Components and supplies

Necessary tools and machines

Apps and online services

About this project


Automation direct makes an inexpensive line of VFD called "GS2". The model used in this example is "GS2-11P0". It's great if your project is in the garage or like me on the kitchen table because it runs off 110v but can still drive a 220v motor up to 1 horse power and can be communicated to with RS-485 / modbus. This means that it is data rich and through a single connection to the drive you can control all drive parameters. Since the MKR WiFi 1010 can hold a MKR RS-485 shield, it is the prefect pairing to this VFD.

Drive Reference Manual

Key Drive Settings

- P1.01 - Acceleration time

- P1.02 - Deceleration time

- P3.00 - Source of operation command

- P4.00 - Source of frequency command

- P9.00 - Communication address

- P9.01 - Transmission speed

- P9.02 - Communication protocol

- P9.26 - Serial comm speed reference

- P9.27 - Serial comm RUN command

- P9.28 - Serial comm direction command

Switch Settings

On the MKR RS-485 shield switch settings are: A/B and Full = OFF, Y/Z = ON. Z is connected to the positive terminal of the distribution block, Y to the negative.

Blynk Settings

The RPM value is a computed value based on the drive current output frequency and the value you tell the drive is the speed of the motor at 60 Hz. This example does not include an encoder. In this case the internal motor speed at 60 Hz is 1690 and with a drive reducer whose ratio is 29, the physical output rpm will be 58.

When writing an integer value to the drive, the drive interprets the least signification digit as after the decimal point. So if you want the drive to run at 60 Hz, you send it 600. If you send 60, it will run at 6 Hz. This same principle applies to acceleration and deceleration times. if you send the drive "1" it will interpret that as "0.1". 100 would be 10.

RPM and Drive Status Word are set to update every 1 sec.

Both of the sliders in the Blynk app are set to "Send values on release only = off".

Below is a summary of what the program does:

1) Takes input from Blynk using virtual pins and assigns those to variables

2) Reads data from the drive (like RPM) and writes that data to virtual pins

3) Sends commands to the drive by knowing: node address, holding register address, and data to be sent (in case of a write). In case of a read command, only the node address and holding register address are needed.

Lessons Learned

Originally I had an interlock that only let 1 modbus command be sent per scan but after getting the setup to work, I removed the interlock and it ran just fine with no communication collisions. This means that when you call a function in the modbus library, when it returns, it is completely finished using the serial port already so interlocking to prevent collisions is unnecessary.

I also originally had a "previous" values for all values that would be written to the drive so at the beginning of each scan a check could be done to see if the data had changed and to only send when new data was available. The intent was to make the time from button push to drive reaction as snappy as possible. but again, after getting it working I started stripping things out to make it as simple as possible and when when that was removed, I couldn't discern a difference in reaction time.


Used to control a VFD using MKR WiFi 1010 and the Blynk App. Communication with the drive is via RS-485 and Modbus
// 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: 
//      -
// Written by: Nick Robinson, Last Updated 21-Feb-2020

#include <ArduinoRS485.h>
#include <ArduinoModbus.h>
#include <WiFiNINA.h>
#include <BlynkSimpleWifi.h>

char auth[] = " ";
char ssid[] = " ";
char pass[] = " ";

const int vfd = 0x02;                   // VFD node address, drive parameter P 9.00
const int driveRatio = 29;

// VFD Memory Addresses
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

int inputFreq;
int inputStopGo;
int inputDirection;
int inputAccelDecelTime;
int outputRpm;
int outputDriveStatus;

BLYNK_WRITE(V0){                        //V0 : drive inputFreq (Hz)slider
  inputFreq = param.asInt() * 10;
BLYNK_WRITE(V1){                        //V1 : run / stop button
  inputStopGo = param.asInt();
BLYNK_WRITE(V2){                        //V2 : fwd / rev button
  inputDirection = param.asInt();
BLYNK_READ(V3){                         //V3 : motor rpm display
  Blynk.virtualWrite(V3, outputRpm);
BLYNK_READ(V4){                         //V4 : Drive status
  Blynk.virtualWrite(V4, outputDriveStatus);
BLYNK_WRITE(V5){                        //V5 : Accel / Decel time
  inputAccelDecelTime = param.asInt();

void setup() {
  Serial.begin(9600);                         //for debugging, normally not used
  ModbusRTUClient.begin(19200, SERIAL_8O1);   // Drive parameter P9.02 : 05 = 8 bits, odd parity, 1 stop bit
  Blynk.begin(auth, ssid, pass);

void loop() {;
  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))
  outputRpm = ModbusRTUClient.holdingRegisterRead(vfd, Add_rpm);
  outputDriveStatus = ModbusRTUClient.holdingRegisterRead(vfd, Add_Status1);
  if(outputRpm == -1 || outputDriveStatus == -1)
  else outputRpm = outputRpm / driveRatio;

void errorFlash(){                    //Flash 4 times to indicate communication error
  pinMode(6, OUTPUT);                 //D6 is MKR WiFi 1010 internal LED
  for(int i = 0; i < 4; i += 1){
    digitalWrite(6, HIGH);
    digitalWrite(6, LOW);


RS-485 Connection
Should be crossed i.e. RX on one side connects to TX of the other side.
Adb459c7 7b31 49d2 9f09 7199826237b5 bqwh1tefb9


Add projectSign up / Login