Blogposts

PID motor control with IndustriaLogic 1.0

I’ve been playing with implementing a PID controller to control the speed of an AC motor using the IndustriaLogic 1.0 controller board these past few days.

The controlled motor is a small AC motor that is controlled by a Bonfiglioni Vectron frequency inverter. It takes a 0-10V signal from a potmeter on the front, so I replaced the GND and output wires from the potmeter with GND and output wires from the IndustriaLogic board. The motor has a rotor attached with 8 neodynium magnets equally spaced inside the rotor. The rotor was made for a previous elemctromagnetic generator project. The feedback sensor is a hall-effect sensor, type UGN3503UA from Allegro. It is used to measure a change in magnetic flux field and gives a voltage output proportional to the change in magnetic flux. It is extremely sensitive (0.75 to 1.75 mV/G, 1.30 typical) and has a flat response up to 23 kHz. It can be used to trigger on gears and similar types of trigger methods.

 

The output from the sensor is shown on the scope as the blue trace and the yellow trace is the INT0 pin signal. It gives a pulse signal out which goes into the INT0 input on the IndustriaLogic board.

The serial output from the board is displayed in the terminal and shows the measured period in microseconds, frequency, RPM and the PID controller output.

The output is written to the analogWrite function on 0-10V output 0, PC2. The frequency inverter input therefore receives an 8-bit input from 0-255, providing a resolution of

Max speed: 2750 RPM @ 50 Hz

Resolution = 2750 RPM / 256 steps = 10.74 [RPM/step]

or 

Resolution = 50 Hz / 256 steps = 0.195 [Hz/step]

Some PID parameters with a decent response time and characteristics were dtermined to be Kp = 0.08, Ki = 0.08, Kd = 0.

In the code below, I have implemented a simple serial interface to change the setpoint, Kp, Ki and Kd values, so that I don’t have to re-flash the chip just to change these values. Storing the values in EEPROM wil also be implemented in the near future.

The code, so far

#include "PID_v1.h"
#include "TimerOne.h"
double Setpoint, Input, Output;
PID motorPID(&Input, &Output, &Setpoint,0.08,0.08,0, DIRECT);

volatile boolean runCalculation = false;
volatile unsigned long TIME1;
volatile unsigned long TIME2;
volatile unsigned long T;
volatile float F;
volatile int RPM;
volatile int PULSES;

int INT_0 = 2;
int A_OUT0 = PD5;
int RE = 4;
int DE = PC1;
uint8_t SERIAL_COUNTER;
uint16_t RPM_ARRAY[5] = {0,0,0,0,0};
int MAX_LIMIT = 200;
int MIN_LIMIT = 200;
int A_OUT1 = PD6;

#define interval 100
#define PULSESPERREV 8

bool COUNT_RPM = false;

// This funtion is used when counting a single pulse period
void RPMCOUNTER(void)
{
 
 if(!TIME1)
 {
 TIME1 = micros();
 }
 else
 {
 TIME2 = micros();
 T = TIME2 - TIME1;
 F = 1/(T*0.000001)/PULSESPERREV;
 RPM = F * 60;
 TIME1 = 0;
 TIME2 = 0;
 noInterrupts();
 }
}

void intervalPassed(void)
{
 runCalculation = true;
}

int parseCommand(void)
{
 String cmd, sp, val1, val2, val3;
 
 cmd = Serial.readStringUntil(' ');
 sp = Serial.readStringUntil(' ');
 val1 = Serial.readStringUntil(' ');
 val2 = Serial.readStringUntil(' ');
 val3 = Serial.readString();
 
 if(cmd.equalsIgnoreCase("set"))
 {
  Setpoint = sp.toFloat();
 if(val1 != ' ')
 {
   motorPID.SetTunings(val1.toFloat(), motorPID.GetKi(), motorPID.GetKd());
   Serial.print("Set Kp to ");
   Serial.println(motorPID.GetKp());
 }
 if(val2 != ' ')
 {
   motorPID.SetTunings(motorPID.GetKp(), val2.toFloat(), motorPID.GetKd());
   Serial.print("Set Ki to ");
   Serial.println(motorPID.GetKi());
 }
 if(val3 != ' ')
 {
   motorPID.SetTunings(motorPID.GetKp(), motorPID.GetKi(), val3.toFloat());
   Serial.print("Set Kd to ");
   Serial.println(motorPID.GetKd());
 }
   digitalWrite(RE, HIGH);
   digitalWrite(DE, LOW);
   Serial.print("Values are now: ");
   Serial.print(motorPID.GetKp());
   Serial.print("\t");
   Serial.print(motorPID.GetKi());
   Serial.print('\t');
   Serial.println(motorPID.GetKd());
   digitalWrite(RE, LOW);
   digitalWrite(DE, HIGH);
 
 }
 else{
   Serial.flush();
   digitalWrite(RE, HIGH);
   digitalWrite(DE, LOW);
   Serial.println("Command not valid");
   digitalWrite(RE, LOW);
   digitalWrite(DE, HIGH);
 }
}

void setup() 
{
   Serial.begin(57600);
   pinMode(RE, OUTPUT);
   pinMode(DE, OUTPUT);
   pinMode(INT_0, INPUT_PULLUP);
   digitalWrite(INT_0, HIGH);
 
   digitalWrite(A_OUT0, LOW);
   digitalWrite(A_OUT1, LOW);
   digitalWrite(DE, HIGH);
   digitalWrite(RE, LOW);
   TIME1 = 0;
   TIME2 = 0;
   PULSES = 0;
   // turn the PID on
   Input= 0;
   Setpoint = 1000.0;
   motorPID.SetMode(AUTOMATIC);
   RPM = 0;
   SERIAL_COUNTER=0;
   // Set up timer and interrupts
   Timer1.initialize(50000);
   Timer1.attachInterrupt(intervalPassed);
   interrupts();
}




void loop() {
 // put your main code here, to run repeatedly:

if(Serial.available())
 {
   parseCommand();
 }
 
 if (runCalculation)
 {
   Input = RPM;
   runCalculation = false;
   motorPID.Compute();
   analogWrite(A_OUT1, (int)Output);
   analogWrite(A_OUT0, (int)Output);
 if(SERIAL_COUNTER>=2)
 {
   digitalWrite(DE, HIGH);
   digitalWrite(RE, LOW);
   delay(1);
   Serial.print(T);
   Serial.print('\t');
   Serial.print(F);
   Serial.print("\t");
   Serial.print(Input);
   Serial.print("\t");
   Serial.println((int)Output);
   digitalWrite(DE, LOW);
   digitalWrite(RE, HIGH);
   SERIAL_COUNTER =0;
 }
   SERIAL_COUNTER++;
   attachInterrupt(digitalPinToInterrupt(2), RPMCOUNTER, FALLING);
   RPM = 0;
   PULSES = 0;
 }
}

 

Advertisements
Blogposts

Atmega328P based IndustriaLogic controller 1.0

The industrial space is dominated by PLC’s/PAC’s and DCS’ for controlling manufacturing  and chemical processes and these systems do a fantastic job. However, sometimes I have found myself in a situation where the embedded/Arduino way of programming a small control application would be faster, cheaper and more fun. So, I been working on an Arduino Uno/ATMega328P based industrial controller which is meant to be used in a situations where you have a machine or system that is already validated and you don’t want to make any changes to the system and have to go through a new test and validation process. But you still need just a little something extra, say measuring a temperature, pressure or controlling a motor. This extra feature does not have to be part of the existing system, but can be a standalone system.

I was in a situation at work where I had to add a vacuumpump to an existing machine and wanted to monitor the output airtemperature from the pump, so that it didn’t overheat. This would take 10 minutes to program using the Arduino language (C/C++).

The board interfaces standard industrial signal types and has has the following specifications:

  • 24V supply power input
  • RS485 half duplex communication
  • 2 x external interrupt connected digital INPUTS
  • 2 x 4-20 mA INPUTS (native 10 bit ADC)
  • 2 x 0-10 V INPUTS (native 10 bit ADC)
  • 2 x 0-10 V OUTPUTS
  • 2 x DC MOSFET OUTPUTS (2A)
  • 2 x AC SSR OUTPUTS (2A)

IMG_20180409_164551

Board under test, not fully populated with components yet. Some still in the mail.

I have made a small demonstration where I control a frequency inverter which in turn controls a motor.

Blogposts

New lab workbench

Well, I decided to build a much needed electronics workbench to expand on my office work capabilities to include electronics work. It’s been fantastic to have the extra space for equipment and components that were previously stored in the garden shed. I still need to buy some extra storage boxes and get everything well organized.

The white board will help out in future project work.

Blogposts

Regenerative RegenX motor/generator effect

This video demonstrates the effect discovered by Thane C. Heins of Potentail Difference Inc.

When a conventional electric motor/generator is loaded it will slow down, due to the counteracting (on the rotor) magnetic field generated in the generator coil windings. The peculiar effect which Thane Heins discovered is that in a special configuration, consisting of a high inductance coil (R=240, L=24) and relatively high frequency(~400 Hz), the back EMF is delayed and the magnetic field reversed, so that instead of counteracting the rotor when the coil is under load, it actually pushes the rotor, leading to a higher RPM and a drop in input power.

This principle seems to have been adopted in electrical bikes by using the back EMF for charging the batteries while driving, thereby extending the range of the battery.

Replication by Jean-Louis Naudin.

Blogposts

Welcome to my blog

Hello and welcome to my blog.

I will use this blog to communicate with people of the same interests as myself, namely energy technology, electronics, control systems and programming. The material published here will focus primarily on research and experimentation into various energy devices, electronics and programming. It is meant to serve as a resource for like-minded to learn from my mistakes and successes and maybe inspire you to do some experimenting yourself. If we all work for a common cause, we will hopefully get to the end goal faster and enjoy the ride even more.

I will focus primarily on energy systems that produce usable heat and electricity, control systems and programming.

Welcome aboard and happy reading 🙂

Best regards, Kasper