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