Project VAG: Using Arduino Due for current control

Hello Arduino Community!

I've just started to discover the wide range of Arduino applications and now I'm familiar with the basics (what ports to use and such things). However, I could use some help/ideas with the current control for my project.

The setup:

  1. Measuring a (primary) current using a shunt gives me a (0 ... 1,5) V signal (not a perfect sine)
  2. With the help of a secondary current, I'm able to control the primary current (I'll describe more, if necessary)
  3. The higher the secondary current, the higher the primary current (although not linear)
  4. The secondary current is controlled by an d.c. regulator, it just needs an analog signal from the Arduino board

What I found out so far:

a) I can use the analog input- and output-pins for signal processing
b) Using analogReadResolution(12); and analogWriteResolution(12); for the maximum resolution
c) The analog input seems to range from 0 to ~1,6 V
d) I can watch the inputs and outputs using up to a 250000 baud rate in serial monitor
e) I can creat a sine reference signal using this arduino due guide: click
f) The software PID controller would be

esum = esum + e
y = Kp * e + Ki * Ta * esum + Kd * (e – ealt)/Ta
ealt = e

The problems so far:

1- I've got sine signal (bipolar), so the negative wave-part won't be recognized by the input. Two solutions came to my mind: using a bipolar to unipolar converter as described in click or just converting the negative half-wave to a positive half-wave:

2- How do I synchronize my reference signal with the primary current?

3- Will this basic PID controller be able to do the job? My experience with controllers are very limited.

I'll try to figure it out on my own, but I would appreciate a little help :slight_smile:
Will keep this post updated.

Perhaps your project depends more on the sensor and current regulator than you may think.

AC is usually measured in RMS or peak values, so that catching the peaks of an undistorted sine wave will be sufficient. A diode and a RC filter can do that, in addition to the isolation (transformer, opto coupler?) you need anyhow.

But when the current control enters the scene, does it affect the wave shape of the primary current?

A PID may be useful, but its parameters depend on the entire closed loop circuit.

So please describe your circuits in more detail, or give a circuit diagram. What's the primary voltage and desired current range?

Hello DrDiettrich, thanks for your response.

DrDiettrich:
AC is usually measured in RMS or peak values, so that catching the peaks of an undistorted sine wave will be sufficient.

The primary current is distorted (50 Hz base frequency with overlain 150 Hz and 250 Hz parts of varying portions), so the resulting peaks aren't necessary on the 50 Hz peak.

DrDiettrich:
But when the current control enters the scene, does it affect the wave shape of the primary current?

This would actually be the final target:
The primary current contains various frequencies because of an non-linear load (150 Hz, 250 Hz as written above). While increasing the secondary current, we can increase the primary current. Using a current control, we should be able to filter out the 150 Hz and 250 Hz parts of the primary current, too.

I'm not sure if this explanation is understandable, so here is a short explanation with numbers:
secondary current: 0 A -> primary current: 1 A (50 Hz) + 0,1 A (150 Hz)
secondary current: 1 A -> primary current: 2 A (50 Hz) + ~0,01 A (150 Hz)

This means I would like to increase the primary current and change it's wave shape with the secondary current.

DrDiettrich:
What's the primary voltage and desired current range?

primary voltage: ~50 V, 50 Hz
primary current: (0 ... 8) A
secondary current: (0 ... 5) A

How do you specify the current of interest, based on such a distorted signal?
Provided that the other frequencies have a low amplitude only, you could filter the signal in hardware or software, then take the peak value and compute the RMS value from it.

Next you need some circuit to provide the right current to the secondary controller. Using PWM may distort the primary current further, so that a linear current source can be required.

Hello DrDiettrich

DrDiettrich:
Provided that the other frequencies have a low amplitude only, you could filter the signal in hardware or software, then take the peak value and compute the RMS value from it.

I think this will be possible, is the a way to do this within the Arduino Due? Something like a build in FFT maybe?

DrDiettrich:
Using PWM may distort the primary current further, so that a linear current source can be required.

This is why I want to use the analog output (12 bit, 4096 steps). This resolution can be doubled by using only positive flanks (as in my picture posted above). The current source itself provides a full d.c. current based on the voltage input (programmable, e.g. 1 V input -> 10 A output).

A simple solution could be a resistor in the primary line, whose temperature is measured to obtain the true effective current, independent of the wave form. I found such a circuit in a RF ammeter, where a thermocouple directly drives an analog meter.

In a digital solution you have to integrate (sum up) the current readings for a half wave, in order to obtain the effective current. The point is to find out where a half wave starts and ends. In theory the integrated value of a bipolar (signed) signal should continuously increase and decrease back to zero, so that it would be sufficient to track the last maximum and minimum sums, whose difference corresponds to the effective current. In practice the sum may run away, due to offsets in the measured values, so that the base line (zero) should be readjusted every now and then, to prevent integer overflows.

For driving the secondary current source a DAC is required, either built into the controller or an external one.

Hello again!

I've managed to transfer the signal using the unipolar to bipolar converter. The signal of the primary current can now be read with the analog input pins (zero-crossing gives an 2000-value to the analog input, sine wave will therefor be about 500 ... 3500.

Calculating the RMS value is easy as that:
-> read the highest/lowest number between two zero-crossings
-> calculate the difference between the highest/lowest number and 200
-> RMS = difference / sqrt(2)

For the next step, I would like to add a 100 Hz wave to the (DC-)auxillary current. The modulated auxiliary current (secondary) must also be synchronized such that maximum auxiliary current occurs precisely at positive and negative peaks of the main reactor current (primary).

Any ideas for this?

Edit: This is what I want to be the secondary current

What if you use a fraction of the rectified primary current signal?
Otherwise you have to calculate and add a synchronized sine wave for the output signal.

I see a problem with the calculated sine wave following the guide

In the code, they use

delayMicroseconds(sample);  // Hold the sample value for the sample time

As far as I understand, the code delays for a minimal amount of time the hold the voltage level. Wouldn't this be a problem when I have to check the primary current for zero-crossings? I mean:
set voltage -> wait for 1 ms -> set new voltage
and in the meantime a zero-crossing occurs, will the code detect it?

Zero crossing detection must have precedence, because it is required to synchronize the output signal.

The wave output can be implemented interrupt-driven, using a timer, or on another dedicated controller.

The problem with interrupts would be that I don't have a digital interrupt-condition (only analog). As far as I understand, I have to use a second Arduino board that checks for the zero-crossing and sends a digital ON to an digital input of the first Arduino?

Do you know the sample rate of the Arduino Due board? For implementing a current control, I have to know the exact sample rate. Would there be a way to set the sample rate (one complete loop) to, let's say, 10 kHz?

I'm not sure how you want to implement your project at all. An Uno has analog interrupt capability, and timer interrupts for outputting something at regular time intervals. It only lacks a DAC and, perhaps, speed. Dunno of the Due capabilities.

For zero crossing detection an external comparator is sufficient, no controller required.

Hello everyone, I've made so progress:

  1. Transform bipolar to unipolar signal (analog):


  2. zero-crossing detection using Schmitt trigger (analog):


  3. the code so far (Arduino Due):

// set constant input pins
const int button1pin = 52;     // pin 52 is button1
const int button2pin = 50;     // pin 50 is button2
const int button3pin = 48;     // pin 48 is button3
const int zerodetection = 40;  // pin 40 is the signal of zero detection

// define variables

// time since startup
unsigned long micro;           // microseconds since startup
unsigned long micro100;        // for sample rate of 10 kHz
unsigned long oldtime = 0;     // begin of one sample
unsigned long newtime = 0;     // check if one sample is over (100 microseconds passed)

// 
int button1state = 0;          // state of button1, default 0
int button2state = 0;          // state of button2, default 0
int button3state = 0;          // state of button3, default 0
int modeselect = 0;            // runmode (0 for no current, 1 for dc current, 2 for ac+dc current, 4 for current control)
int edge = 0;                  // edge of the input signal, 0 for negative and 1 for positve

int oldzerostate = 0;          // memory for last edge
int newzerostate = 0;          // stores current edge
int zeropulse = 0;             // variable for one single pulse of 0.1 ms at zero-crossing

int dctimer = 0;               // timer counting from 0 to 100, starts from zero when zeropulse occurs
float dctimerpi;               // same as dctimer, calculated from 0...100 to 0...2 PI
int acdc;                      // the combined dc + ac signal for DAC1 (0 to 4095)


// main setup
void setup() {

  // initialize the pushbutton pins as an input
  pinMode(button1pin, INPUT);
  pinMode(button2pin, INPUT);
  pinMode(button3pin, INPUT);

  // initialize the zero-detection as input
  pinMode(zerodetection, INPUT);
  
  // change the analog read and write resolution to 12 bits
  analogReadResolution(12);
  analogWriteResolution(12);
}

// main loop
void loop() {

  micro = micros();             // read the micros passed since board reset and save it into the variable micro
  micro100 = micro / 100;       // divide micro by 100 and save it into the variable micro100 (counts up by one every 100 microseconds / 0.1 milliseconds)

  if (oldtime == newtime) {     // if there is no difference between oldtime and newtime
    newtime = micro100;         // continue to read newtime
  }
  else {                        // until newtime is different from oldtime

  oldtime = micro100;           // set oldtime to the current time (newtime)

  
  
  // check if buttons are pressed (0 for false, 1 for true)
  button1state = digitalRead(button1pin);
  button2state = digitalRead(button2pin);
  button3state = digitalRead(button3pin);

  // read the input on analog pin 0
  int analogvalue0 = analogRead(A0);

  // runmode (values can be 0, 1, 2, 3, 4, 5, 6, 7)
  modeselect = button1state + (2 * button2state) + (4 * button3state);

  // if button1 AND button2 pressed, just use button 2
  if (modeselect == 3) {
    modeselect = 2;
  }

  // if button3 AND another button is pressed (4, 5, 6, 7), just use button 3
  if (modeselect > 4) {
    modeselect = 4;
  }


  // runmode (0 for no current, 1 for dc current, 2 for ac+dc current, 4 for current control)
  switch (modeselect) {
    case 1:                                                       // dc only mode
    
    analogWrite(DAC1, analogvalue0);                              // set A0 = DAC1 (write the value from analog in 0 to analog out 1)
    
    break;
    case 2:                                                       // dc + ac mode
    
    edge = digitalRead(zerodetection);                            // 1 for positive edge, 0 for negative edge

    if (oldzerostate == newzerostate) {                           // if no change of the edge state (says positive or stays negative)
      newzerostate = edge;                                        // check for edge state again
      zeropulse = 0;                                              // no zero-crossing detected
    }
    else {                                                        // if zero-crossing detected
      oldzerostate = edge;                                        // set oldzerostate zu current state
      zeropulse = 1;                                              // activate zero-crossing pulse
    }

    if (zeropulse == 1) {                                          // pulse received
       dctimer = 0;                                                // reset timer
      }
      else {                                                       // no pulse received
       dctimer++;                                                  // increase timer by one
      }

     dctimerpi = (dctimer + 3) * 0.062832;                         // calculate 0...100 to 0...2 PI, +3 for phase correction
     acdc = analogvalue0 * (0.8 - 0.2 * cos(dctimerpi));           // voltage 80% DC + 20% AC

      analogWrite(DAC1, acdc);                                     // write voltage to DAC1
   
    break;
    case 4:
    
    //control
    
    break;
    default:                                                       // no mode selected
    analogWrite(DAC1, 0);                                          // set secondary current to zero
    break;

    oldtime = micro100;                                            // program executed successfull, set oldtime to current time   
  }

  }

}

What works:

  • read analog in
  • read zero-crossing
  • write analog out (DC only)
  • write analog out (DC + snychronized AC)

What needs to be done:

  • current control (mode 4 in code) - guess this will be the hardest part