Go Down

### Topic: Project VAG: Using Arduino Due for current control (Read 2117 times)previous topic - next topic

#### Funkenflug

##### Aug 16, 2016, 11:05 am
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
Code: [Select]
`esum = esum + ey = Kp * e + Ki * Ta * esum + Kd * (e - ealt)/Taealt = 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
Will keep this post updated.

#### DrDiettrich

#1
##### Aug 16, 2016, 11:09 pm
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?

#### Funkenflug

#2
##### Aug 17, 2016, 12:58 pm
Hello DrDiettrich, thanks for your response.

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.

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.

What's the primary voltage and desired current range?
primary voltage: ~50 V, 50 Hz
primary current: (0 ... A
secondary current: (0 ... 5) A

#### DrDiettrich

#3
##### Aug 17, 2016, 01:57 pm
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.

#### Funkenflug

#4
##### Aug 18, 2016, 11:02 amLast Edit: Aug 18, 2016, 11:10 am by Funkenflug
Hello 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?

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).

#### DrDiettrich

#5
##### Aug 18, 2016, 11:29 am
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.

#### Funkenflug

#6
##### Aug 28, 2016, 03:19 pmLast Edit: Aug 28, 2016, 03:33 pm by Funkenflug
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

#### DrDiettrich

#7
##### Aug 28, 2016, 09:36 pm
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.

#### Funkenflug

#8
##### Aug 29, 2016, 09:16 am
I see a problem with the calculated sine wave following the guide
https://www.arduino.cc/en/Tutorial/DueSimpleWaveformGenerator

In the code, they use
Code: [Select]
`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?

#### DrDiettrich

#9
##### Aug 29, 2016, 09:33 am
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.

#### Funkenflug

#10
##### Sep 03, 2016, 11:45 am
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?

#### DrDiettrich

#11
##### Sep 04, 2016, 12:08 am
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.

#### Funkenflug

#12
##### Sep 15, 2016, 10:48 am
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):
Code: [Select]
`// set constant input pinsconst int button1pin = 52;     // pin 52 is button1const int button2pin = 50;     // pin 50 is button2const int button3pin = 48;     // pin 48 is button3const int zerodetection = 40;  // pin 40 is the signal of zero detection// define variables// time since startupunsigned long micro;           // microseconds since startupunsigned long micro100;        // for sample rate of 10 kHzunsigned long oldtime = 0;     // begin of one sampleunsigned long newtime = 0;     // check if one sample is over (100 microseconds passed)// int button1state = 0;          // state of button1, default 0int button2state = 0;          // state of button2, default 0int button3state = 0;          // state of button3, default 0int 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 positveint oldzerostate = 0;          // memory for last edgeint newzerostate = 0;          // stores current edgeint zeropulse = 0;             // variable for one single pulse of 0.1 ms at zero-crossingint dctimer = 0;               // timer counting from 0 to 100, starts from zero when zeropulse occursfloat dctimerpi;               // same as dctimer, calculated from 0...100 to 0...2 PIint acdc;                      // the combined dc + ac signal for DAC1 (0 to 4095)// main setupvoid 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 loopvoid 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: