Wydział Elektrotechniki i Automatyki

Transkrypt

Wydział Elektrotechniki i Automatyki
Politechnika Gdańska
Wydział Elektrotechniki i Automatyki
Katedra Inżynierii Systemów Sterowania
Przemysłowe układy sterowania PID
Układy regulacji PID w strukturze sprzętowej
Pytania i zadania do zajęć laboratoryjnych 5
Opracowanie:
Tomasz Rutkowski, dr inż.
Jarosław Tarnawski, dr inż.
Cel laboratorium
Celem laboratorium jest:
- nabycie umiejętności wykorzystywania kart akwizycji w zastosowaniach akwizycji
danych oraz budowaniu układów sterowania,
- zilustrowanie struktury pętli sprzętowej i weryfikacji metody sterowania w czasie
rzeczywistym
- realizacji programowej regulatora PID w językach C/C++,
- wykorzystania NAVI SDK i budowy aplikacji dla OS Windows realizującej regulator
PID z wykorzystaniem karty akwizycji.
Plan przebiegu laboratorium
- Zapoznanie się ze sposobem połączenia obiektu sterowania z kartą akwizycji
- Konfiguracja Matlab/Simulink/Real-Time Windows Target (RTWT) do realizacji
symulacji w czasie rzeczywistym
- Identyfikacja obiektów sterowania
- Budowa regulatora PID w środowisku RTWT
- budowa programu/aplikacji (niezależnej od M/S) dla Windows z wykorzystaniem
karty akwizycji:
- odczytujących stan wejść analogowych
- zapisujących (ustawiających) stan wyjść analogowych
- budowa aplikacji dla Windows realizującej zadania regulatora PID
2
Karta Advantech PCI-1711
Przyłącze PCLD-8712
Obiekt
3
Instrukcja budowy aplikacji dla Windows z wykorzystaniem kart
Advantech PCI-1711 i pakietu SDK
Instrukcję sporządzono w oparciu o wersje oprogramowania: DAQNavi_SDK_3.2.5.0, SDK 7.1 dla Windows 7
1. Konfiguracja win7 SDK
1.1. Uruchom linię poleceń Windows SDK v7.1 Start -> Wszystkie Programy -> Microsoft
Windows SDK v7.1 -> Windows SDK v7.1 -> Command Prompt. Rekomendacja: zamień
czcionkę w konsoli na rozmiar 12x16.
1.2. Dokonaj konfiguracji ustawiając domyślnie 32-bitowy kompilator i środowisko docelowe
Windows 7 wpisując polecenie: SetEnv /win7 /x86
1.3. Konwersja projektów Visual C++ do formatu Visual C++ 2010 (niezbędne do
zastosowania SDK)
vcupgrade.exe Hello.vcproj, gdzie Hello to przykładowa nazwa uaktualnianego
projektu
Powinno powstać kilka nowych plików w katalogu źródłowym, a pośród nich plik
Hello.vcxproj
2. Przygotowanie struktury plików i katalogów
Załóż katalog z nazwiskami członków grupy w katalogu Moje Dokumenty
Pobierz dołączony do instrukcji plik Źródła.zip wypakuj do trzech różnych katalogów w
założonym folderze opatrzonym nazwą członków grupy:
do obsługi analogowych wejść: InstantAI
do obsługi analogowych wyjść: StaticAO
obsługa we/wy na potrzeby budowy regulatora: PID
Odznacz właściwości katalogów: tylko do odczytu
Dokonaj konwersji projektów opisanej w pkt. 1.3 dla obu katalogów
Zapoznaj się z plikami projektów, a w szczególności z plikami programów *.cpp
Poszukaj plików bibliotecznych Advantech NAVI (przeważnie c:\Advantech\) i ustal ścieżkę
dostępu
Dokonaj zmiany odnośników do plików LIB ze względnych na bezwzględne – uwzględniając
położenie plików. Przykłady w tabeli
Adres względny (do
Adres bezwzględny (zastępujący)
zastąpienia)
#include
#include "C:\Advantech\DAQNavi\Examples\C++_Console\inc\
"../inc/compatibility.h"
compatibility.h"
#include
"../../../inc/bdaqctrl.h"
#include "C:\Advantech\DAQNavi\Inc\bdaqctrl.h"
3. Kompilacja plików Examples
Usuń poniższe linie z pliku *.vcxproj co spowoduje wyłączenie przyrostowego sposobu
działania Linkera (niezbędne dla popranej budowy aplikacji przez SDK)
<LinkIncremental
Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
<LinkIncremental
Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
Dokonaj kompilacji za pomocą polecenia MSBuild Hello.vcxproj
Uruchom aplikację, którą odnajdziesz w katalogu bin/Debug
4
Źródła
Konfiguracja SDK https://msdn.microsoft.com/en-us/library/ff660764%28v=vs.100%29.aspx
(01.06.2015)
5
KOD OBSŁUGI WEJŚĆ ANALOGOWYCH
******************************************************************************/
#include <stdlib.h>
#include <stdio.h>
//#include "../inc/compatibility.h"
#include "C:\Advantech\DAQNavi\Examples\C++_Console\inc\compatibility.h”
//#include "../../../inc/bdaqctrl.h"
#include "C:\Advantech\DAQNavi\Inc\bdaqctrl.h”
using namespace Automation::BDaq;
//----------------------------------------------------------------------------------// Configure the following three parameters before running the example
//----------------------------------------------------------------------------------#define
deviceDescription L"DemoDevice,BID#0"
int32
startChannel = 0;
const int32 channelCount = 3;
inline void waitAnyKey()
{
do{SLEEP(1);} while(!kbhit());
}
int main(int argc, char* argv[])
{
ErrorCode
ret = Success;
// Step 1: Create a 'instantAiCtrl' for InstantAI function.
InstantAiCtrl * instantAiCtrl = AdxInstantAiCtrlCreate();
do
{
// Step 2: Select a device by device number or device description and specify the access
mode.
// in this example we use AccessWriteWithReset(default) mode so that we can
// fully control the device, including configuring, sampling, etc.
DeviceInformation devInfo(deviceDescription);
ret = instantAiCtrl->setSelectedDevice(devInfo);
CHK_RESULT(ret);
// Step 3: Read samples and do post-process, we show data here.
printf("Acquisition is in progress, any key to quit!\n\n");
double
scaledData[channelCount] = {0};//the count of elements in this array should not
be less than the value of the variable channelCount
int32 channelCountMax = instantAiCtrl->getFeatures()->getChannelCountMax();
do
{
//read samples and save to buffer 'scaledData'.
ret = instantAiCtrl->Read(startChannel,channelCount,scaledData);
CHK_RESULT(ret);
// process the acquired data. only show data here.
for (int32 i = startChannel; i< startChannel+channelCount;++i)
{
printf("Channel %d data: %10.6f\n", i % channelCountMax, scaledData[istartChannel]);
}
printf("\n");
SLEEP(1);
} while(!kbhit());
}while(false);
// Step 4 : Close device and release any allocated resource.
instantAiCtrl->Dispose();
// If something wrong in this execution, print the error code on screen for tracking.
if(BioFailed(ret))
{
printf("Some error occurred. And the last error code is Ox%X.\n", ret);
waitAnyKey();// wait any key to quit!
}
return 0;
}
6
KOD OBSŁUGI WYJŚĆ ANALOGOWYCH
******************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
//#include "../inc/compatibility.h"
#include "C:\Advantech\DAQNavi\Examples\C++_Console\inc\compatibility.h"
//#include "../../../inc/bdaqctrl.h"
#include "C:\Advantech\DAQNavi\Inc\bdaqctrl.h"
using namespace Automation::BDaq;
//----------------------------------------------------------------------------------// Configure the following three parameters before running the demo
//----------------------------------------------------------------------------------#define
ONE_WAVE_POINT_COUNT 512 //define how many data to makeup a waveform period.
#define
deviceDescription L"DemoDevice,BID#0"
int32
channelStart = 0;
int32
channelCount = 1;
enum WaveStyle{ Sine, Sawtooth, Square };
//function GenerateWaveform: generate one waveform for each selected analog data output
channel
ErrorCode GenerateWaveform( InstantAoCtrl * instantAoCtrl,int32 channelStart,int32
channelCount, double * waveBuffer, int32 SamplesCount,WaveStyle style);
inline void waitAnyKey()
{
do{SLEEP(1);} while(!kbhit());
}
int main(int argc, char* argv[])
{
ErrorCode ret = Success;
// Step 1: Create a 'InstantAoCtrl' for Static AO function.
InstantAoCtrl * instantAoCtrl = AdxInstantAoCtrlCreate();
do
{
// Step 2: Select a device by device number or device description and specify the access
mode.
// in this example we use AccessWriteWithReset(default) mode so that we can
// fully control the device, including configuring, sampling, etc.
DeviceInformation devInfo(deviceDescription);
ret = instantAoCtrl->setSelectedDevice(devInfo);
CHK_RESULT(ret);
// Step 3: Output data
// Generate waveform data
double *waveform = (double*)malloc( channelCount*ONE_WAVE_POINT_COUNT*sizeof(double));
if( NULL == waveform )
{
printf( "Insufficient memory available\n" );
break;
}
ret = GenerateWaveform( instantAoCtrl,channelStart,channelCount,
waveform,channelCount*ONE_WAVE_POINT_COUNT,Sine);
CHK_RESULT(ret);
printf("\n Outputting data... any key to quit!\n");
bool enforced = false;
do
{
for( int32 i = 0; i < ONE_WAVE_POINT_COUNT; i++ )
{
ret = instantAoCtrl->Write(
channelStart,channelCount,&waveform[channelCount*i] );
CHK_RESULT(ret);
SLEEP(1);
if(kbhit())
{
printf("\n Static AO is over compulsorily");
enforced = true;
break;
}
}
} while (false);
free(waveform);
if (!enforced)
{
7
printf("\n Static AO is over, press any key to quit!\n");
}
}while(false);
// Step 4: Close device and release any allocated resource.
instantAoCtrl->Dispose();
// If something wrong in this execution, print the error code on screen for tracking.
if(BioFailed(ret))
{
printf("Some error occurred. And the last error code is Ox%X.\n", ret);
waitAnyKey();// Wait any key to quit!.
}
waitAnyKey();// Wait any key to quit !
return 0;
}
ErrorCode GenerateWaveform( InstantAoCtrl * instantAoCtrl, int32 channelStart,int32
channelCount,double * waveBuffer,int32 SamplesCount,WaveStyle style)
{
ErrorCode ret = Success;
int32
channel = 0;
int32
channelCountMax = 0;
int32
oneWaveSamplesCount = SamplesCount/channelCount;
int32
i = 0;
MathInterval ranges[64] ;
ValueRange valRange;
channelCountMax = instantAoCtrl->getFeatures()->getChannelCountMax();
for(i = 0;i < channelCountMax ;i++ )
{
valRange = instantAoCtrl->getChannels()->getItem(i).getValueRange();
if ( V_ExternalRefBipolar == valRange || valRange == V_ExternalRefUnipolar )
{
if (instantAoCtrl->getFeatures()->getExternalRefAntiPolar())
{
double referenceValue;
if (valRange == V_ExternalRefBipolar)
{
referenceValue = instantAoCtrl->getExtRefValueForBipolar();
if (referenceValue >= 0) {
ranges[i].Max = referenceValue;
ranges[i].Min = 0 - referenceValue;
} else {
ranges[i].Max = 0 - referenceValue;
ranges[i].Min = referenceValue;
}
}
else
{
referenceValue = instantAoCtrl->getExtRefValueForUnipolar();
if (referenceValue >= 0) {
ranges[i].Max = 0;
ranges[i].Min = 0 - referenceValue;
} else {
ranges[i].Max = 0 - referenceValue;
ranges[i].Min = 0;
}
}
}
else
{
double referenceValue;
if (valRange == V_ExternalRefBipolar)
{
referenceValue = instantAoCtrl->getExtRefValueForBipolar();
if (referenceValue >= 0) {
ranges[i].Max = referenceValue;
ranges[i].Min = 0 - referenceValue;
} else {
ranges[i].Max = 0 - referenceValue;
ranges[i].Min = referenceValue;
}
}
else
8
{
referenceValue = instantAoCtrl->getExtRefValueForUnipolar();
if (referenceValue >= 0) {
ranges[i].Max = referenceValue;
ranges[i].Min = 0;
} else {
ranges[i].Max = 0;
ranges[i].Min = referenceValue;
}
}
}
}
else {
ret = AdxGetValueRangeInformation( valRange,0,NULL,&ranges[i],NULL);
if(BioFailed(ret))
{
return ret;
}
}
}
//generate waveform data and put them into the buffer which the parameter 'waveBuffer' give
in, the Amplitude these waveform
for(i = 0; i < oneWaveSamplesCount; i++ )
{
for( int32 j = channelStart; j < channelStart+channelCount; j++ )
{
//pay attention to channel rollback(when startChannel+channelCount>chNumberMax+1)
channel = j%channelCountMax;
double amplitude = (ranges[channel].Max - ranges[channel].Min) / 2;
double offset = (ranges[channel].Max + ranges[channel].Min) / 2;
switch ( style)
{
case Sine:
*waveBuffer++ = amplitude*(sin((double)i*2.0*( 3.14159 )/oneWaveSamplesCount )) +
offset;
break;
case Sawtooth:
if ((i >= 0) && (i < (oneWaveSamplesCount / 4.0)))
{
*waveBuffer++ = amplitude*( i/(oneWaveSamplesCount/4.0)) + offset;
}
else
{
if ((i >= (oneWaveSamplesCount / 4.0)) && (i < 3 * (oneWaveSamplesCount/4.0)))
{
*waveBuffer++ = amplitude* ((2.0*(oneWaveSamplesCount/4.0)i)/(oneWaveSamplesCount/4.0)) + offset;
}
else
{
*waveBuffer++ = amplitude* ((ioneWaveSamplesCount)/(oneWaveSamplesCount/4.0)) + offset;
}
}
break;
case Square:
if ((i >= 0) && (i < (oneWaveSamplesCount / 2)))
{
*waveBuffer++ = amplitude * 1 + offset;
}
else
{
*waveBuffer++ = amplitude * (-1) + offset;
}
break;
default:
printf("invalid wave style,generate waveform error !");
ret = ErrorUndefined;
}
}
}
return ret;
};
9

Podobne dokumenty