Reguliatoriaus naudojimo ir taikymo pavyzdžiai. PID valdiklis - pilnas aprašymas, taikymas. Nuolatinių reguliatorių išvesties įtaisų koordinavimas

Automatinės valdymo sistemos (ACS) yra skirti automatiškai pakeisti vieną ar kelis valdymo objekto parametrus, kad būtų nustatytas reikiamas jo veikimo režimas. ACS užtikrina reguliuojamų parametrų nurodytų verčių pastovumo palaikymą arba jų keitimą pagal duotą įstatymą arba optimizuoja tam tikrus kontrolės kokybės kriterijus. Pavyzdžiui, tokios sistemos apima:

  • stabilizavimo sistemos,
  • programų valdymo sistemos,
  • sekimo sistemos

Tai gana plati sistemų klasė, kurią galima rasti bet kur. Bet ką tai turi bendro su Unity3D ir tikriausiai žaidimais? Iš esmės viskas paprasta: bet kuriame žaidime, kuriame modeliavimas kažkaip naudojamas kaip žaidimo elementas, naudojami savaeigiai ginklai, tokie žaidimai apima, pavyzdžiui, Kerbal Space Program, Digital Combat Simulator (anksčiau Lock On), Strike Suit Zero, ir tt (kas žino daugiau pavyzdžių - rašykite komentaruose). Iš esmės bet koks žaidimas, imituojantis realius fizinius procesus, įskaitant tiesiog kinematiką su judesio dinamika, gali įdiegti vienokius ar kitokius savaeigius ginklus – toks požiūris yra paprastesnis, natūralesnis, o kūrėjas jau turi paruoštų įrankių rinkinį, kurį pateikia visokie vyšnegradskiai, liapunovai, kalmanai, čebyševai ir kiti Kolomogorovai, todėl galite išsiversti ir neišradę dviračio, nes ji jau buvo išrasta, tiek, kad tapo atskiru mokslu: Automatinio valdymo teorija. Svarbiausia čia nepersistengti. Yra tik viena bėda: apie TAU kalbama ne visur, ne visiems, dažnai mažai ir nelabai aiškiai.

Šiek tiek teorijos

Klasikinė automatinio valdymo sistema parodyta paveikslėlyje:



Pagrindinis bet kurio savaeigio ginklo elementas yra reguliatorius kuris yra valdymo objekto būseną stebintis ir reikalaujamą valdymo dėsnį suteikiantis įrenginys. Valdymo procesas apima: valdymo klaidos arba klaidos signalo apskaičiavimą e(t) kuo skiriasi norimas nustatymą(nustatyti tašką arba SP ) ir dabartinę proceso reikšmę (proceso vertę arba PV ), po kurio reguliatorius generuoja valdymo signalus (manipuliuojama vertė arba MV ).


Vienas iš reguliatorių tipų yra proporcingas integralinis išvestinis (PID) valdiklis, kuris generuoja valdymo signalą, kuris yra trijų terminų suma: proporcingas, integralus ir diferencinis.



Kur, neatitikimo paklaida, taip pat - proporcingas, - integralas, - diferencialiniai valdymo dėsnio komponentai (terminai), kurie galutinėje formoje apibūdinami šiomis formulėmis




Proporcinis komponentas P- yra atsakingas už vadinamąjį proporcingas valdymas, kurio prasmė ta, kad valdiklio išėjimo signalas neutralizuoja valdomo kintamojo nuokrypį (nesumatymo klaidą arba dar vadinamą likutine) nuo nustatytos vertės. Kuo didesnė neatitikimo klaida, tuo didesnis valdiklio komandų nuokrypis. Tai paprasčiausias ir akivaizdžiausias kontrolės dėsnis. Trūkumas Proporcinio valdymo dėsnis yra tas, kad reguliatorius niekada nenustoja stabilizuoti tam tikroje vertėje, o proporcingumo koeficiento padidėjimas visada sukelia savaiminius svyravimus. Štai kodėl, be proporcinės kontrolės dėsnio, būtina naudoti integralinį ir diferencialinį.


Neatsiejama dalis I kaupia (integruoja) valdymo klaidą, kuri leidžia PID valdikliui pašalinti statinę klaidą (nuolatinė klaida, liekamoji klaida). Arba kitaip: integrali nuoroda visada įveda tam tikrą šališkumą ir jei sistemoje yra kokių nors nuolatinių klaidų, tada ji jas kompensuoja (dėl savo šališkumo). Bet jei tokių klaidų nėra arba jos yra nežymiai mažos, tada poveikis bus priešingas – pats integralus komponentas įves poslinkio paklaidą. Būtent dėl ​​šios priežasties jis nenaudojamas, pavyzdžiui, atliekant itin tikslias padėties nustatymo užduotis. Raktas trūkumas Integralinio valdymo dėsnis yra integratoriaus prisotinimo efektas (Integrator windup).


Diferencialinis komponentas D yra proporcingas kontroliuojamo kintamojo nuokrypio kitimo greičiui ir yra skirtas neutralizuoti nukrypimus nuo tikslinės vertės, prognozuojamos ateityje. Pažymėtina, kad diferencialo komponentas pašalina slopintus svyravimus. Diferencialinis valdymas ypač efektyvus procesams, kurių vėlavimai yra dideli. Trūkumas Diferencialinio valdymo dėsnis yra jo nestabilumas triukšmo poveikiui (diferencijavimo triukšmas).


Taigi, priklausomai nuo situacijos, gali būti naudojami P-, PD-, PI- ir PID-reguliatoriai, tačiau pagrindinis valdymo dėsnis iš esmės yra proporcingas (nors kai kuriose konkrečiose užduotyse gali būti naudojami išskirtinai tik diferenciatorių ir integratorių elementai).


Atrodo, kad PID valdiklių diegimo klausimas jau seniai buvo nulaužtas ir čia, Habré, yra keletas gerų straipsnių šia tema, įskaitant Unity3D, taip pat yra geras straipsnis PID be daktaro laipsnio (vertimas) ir serija straipsniai žurnale „Šiuolaikinės automatikos technologijos“ dviem dalimis: pirma ir antra. Taip pat jūsų paslaugoms yra straipsnis Vikipedijoje (išsamiausią skaitykite angliškoje versijoje). Ir Unity3D bendruomenės forumuose ne, ne, ir PID valdiklis pasirodys kaip gamedev.stackexchange


Klausimas apie PID valdiklių diegimą yra šiek tiek gilesnis nei atrodo. Tiek, kad tokią reguliavimo schemą nusprendusių įgyvendinti jaunųjų „pasidaryk pats“ kūrėjų laukia daug nuostabių atradimų, o tema aktuali. Taigi tikiuosi, kad šis opusas kažkam bus naudingas, tad pradėkime.

Bandymas numeris vienas

Kaip pavyzdį bandysime įgyvendinti valdymo schemą naudodami valdymo pasukimo pavyzdį paprastame 2D erdvės arkadiniame žaidime, žingsnis po žingsnio, pradedant nuo pat pradžių (ar pamiršote, kad tai pamoka?).


Kodėl ne 3D? Nes įgyvendinimas nepasikeis, išskyrus tai, kad turėsite įjungti PID valdiklį, kad galėtumėte valdyti žingsnį, posūkį ir posūkį. Nors teisingo PID valdymo pritaikymo kartu su kvaternionais klausimas tikrai įdomus, galbūt dar aptarsiu ateityje, bet net NASA pirmenybę teikia Eulerio kampams, o ne kvaternionams, todėl apsieisime su paprastu modeliu ant dvimačio. lėktuvas.


Pirmiausia sukurkime patį erdvėlaivio žaidimo objektą, kurį sudarys pats tikrasis laivo objektas aukščiausiame hierarchijos lygyje, ir prie jo pritvirtinkime antrinį variklio objektą (tik specialiųjų efektų sumetimais). Štai kaip man atrodo:



Ir mes metame ant paties erdvėlaivio objekto inspektorius visų rūšių komponentai. Žvelgdamas į ateitį, pabaigoje pateiksiu ekrano kopiją, kaip ji atrodys:



Bet tai vėlesniam laikui, o kol kas jame nėra jokių scenarijų, tik standartinis džentelmenų rinkinys: Sprite Render, RigidBody2D, Polygon Collider, Audio Source (kodėl?).


Tiesą sakant, fizika mums dabar yra svarbiausia ir valdymas bus vykdomas tik per ją, kitaip PID valdiklio naudojimas netektų prasmės. Taip pat palikime savo erdvėlaivio masę 1 kg, o visi trinties ir gravitacijos koeficientai lygūs nuliui – erdvėje.


Nes Be paties erdvėlaivio, yra daugybė kitų, ne tokių protingų kosminių objektų, todėl pirmiausia apibūdinsime pagrindinę klasę BaseBody, kuriame bus nuorodos į mūsų komponentus, inicijavimo ir naikinimo metodus, taip pat daugybę papildomų laukų ir metodų, pavyzdžiui, skirtų dangaus mechanikai įgyvendinti:


BaseBody.cs

naudojant UnityEngine; naudojant System.Collections; naudojant System.Collections.Generic; vardų sritis Assets.Scripts.SpaceShooter.Bodies ( viešoji klasė BaseBody: MonoBehaviour ( tik skaitoma float _deafultTimeDelay = 0.05f; viešas statinis sąrašas _body = naujas sąrašas (); #region RigidBody public Rigidbody2D _rb2d; viešas Collider2D_c2d; #endregion #region Nuorodos viešos Transformuoti _myTransform; viešas GameObject _myObject; ///

/// Objektas, kuris atsiranda sunaikinus /// viešas GameObject_explodePrefab; #endregion #region Garsas viešas Garso šaltinis _garso šaltinis; /// /// Garsai, kurie leidžiami gavus žalą /// viešieji AudioClip_hitSounds; /// /// Garsai, kurie atkuriami pasirodžius objektui /// viešieji AudioClip_awakeSounds; /// /// Garsai, skambantys prieš mirtį /// vieši AudioClip_deadSounds; #endregion #region Išoriniai jėgos kintamieji /// /// Išorinės jėgos, veikiančios objektą /// viešasis Vector2 _Išorinės jėgos = naujas Vector2(); /// /// Dabartinio greičio vektorius /// viešasis Vector2 _V = naujas Vector2(); /// /// Dabartinis gravitacijos vektorius /// viešasis Vector2 _G = naujas Vector2(); #endregion public virtual void Awake() ( Init(); ) public virtual void Start() ( ) public virtual void Init() ( _myTransform = this.transform; _myObject = gameObject; _rb2d = GetComponent (); _c2d = GetComponentsInChildren (); _audioSource = Gauti komponentą (); PlayRandomSound(_awakeSounds); BaseBody bb = GetComponent (); _bodies.Add(bb); ) /// /// Personažo sunaikinimas /// vieša virtualioji void Destroy() ( _bodies.Remove(this); for (int i = 0; i< _c2d.Length; i++) { _c2d[i].enabled = false; } float _t = PlayRandomSound(_deadSounds); StartCoroutine(WaitAndDestroy(_t)); } /// /// Laukiame šiek tiek laiko iki sunaikinimo /// /// Laukimo laikas /// public IEnumerator WaitAndDestroy(float waitTime) ( duoda grąžinimą new WaitForSeconds(waitTime); if (_explodePrefab) ( Instantiate(_explodePrefab, transform.position, Quaternion.identity); ) Destroy(gameObject, _deafult)/Time/); /// Leisti atsitiktinį garsą /// /// Garsų masyvas /// Grojo garso trukmė viešas slankusis PlayRandomSound(AudioClip audioClip) ( float _t = 0; if (audioClip.Length > 0) ( int _i = UnityEngine.Random.Range(0, audioClip.Length - 1); AudioClip _audioClip = audioClip[_i]; _ _audioClip.length; _audioSource.PlayOneShot(_audioClip); ) return _t; ) /// /// Žalos padarymas /// /// Žalos lygis vieša virtuali tuštuma Pažeidimas (plaukiojantis pažeidimas) ( PlayRandomSound(_hitSounds); ) ) )


Atrodo, kad aprašėme viską, ko reikėjo, net daugiau nei reikėjo (šio straipsnio rėmuose). Dabar iš jo paveldėkime laivo klasę Laivas, kuris turėtų galėti judėti ir suktis:


SpaceShip.cs

naudojant UnityEngine; naudojant System.Collections; naudojant System.Collections.Generic; vardų sritis Assets.Scripts.SpaceShooter.Bodies ( viešoji klasė Laivas: BaseBody ( public Vector2 _movement = new Vector2(); public Vector2 _target = new Vector2(); public float _rotation = 0f; public void FixedUpdate()) ( float torque = ControlRotate() _sukimas); Vector2 jėga = ControlForce(_Movement); _rb2d.AddTorque(sukimo momentas); _rb2d.AddRelativeForce(force); ) vieša plūdė ControlRotate(Vector2 rotate) (plaukimo rezultatas = 0f; grąžinimo rezultatas; ) viešas Vector2 ControlForce(Vector2 judėjimas) ( Vector2 rezultatas = naujas Vector2(); grąžinti rezultatą; ) ) )


Nors joje nėra nieko įdomaus, šiuo metu tai tik stuburo klasė.


Taip pat aprašysime bazinę (abstrakčią) klasę visiems įvesties valdikliams BaseInputController:


BaseInputController.cs

naudojant UnityEngine; naudojant Assets.Scripts.SpaceShooter.Bodies; vardų sritis Assets.Scripts.SpaceShooter.InputController ( viešasis enum eSpriteRotation ( dešinė = 0, aukštyn = -90, kairėje = ​​-180, žemyn = -270 ) vieša abstrakčioji klasė BaseInputController: MonoBehaviour ( viešas GameObject _agentyp_bjecta; //B public GameObject _agentdyp_bjecta; į laivo loginį komponentą public eSpriteRotation _spriteOrientation = eSpriteRotation.Up; //Taip yra dėl nestandartinės // sprite orientacijos "aukštyn", o ne "dešinėn" public abstract void ControlRotate(float dt); public abstract void ControlForce (float dt); vieša virtuali tuštuma Start() ( _agentObject = gameObject; _agentBody = gameObject.GetComponent (); ) public virtual void FixedUpdate() ( float dt = Time.fixedDeltaTime; ControlRotate(dt); ControlForce(dt); ) public virtual void Update() ( //TO DO ) ) )


Ir galiausiai, grotuvo valdiklio klasė PlayerFigtherInput:


PlayerInput.cs

naudojant UnityEngine; naudojant Assets.Scripts.SpaceShooter.Bodies; vardų sritis Assets.Scripts.SpaceShooter.InputController ( viešoji klasė PlayerFigtherInput: BaseInputController ( public override void ControlRotate(float dt)) ( // Nustatykite pelės padėtį, palyginti su grotuvu Vector3 worldPos = Input.mousePosition; worldPos = ToWorldScreen. (worldPos); / / Išsaugokite pelės žymeklio koordinates float dx = -this.transform.position.x + worldPos.x; float dy = -this.transform.position.y + worldPos.y; //Perduokite kryptį Vector2 target = naujas Vector2(dx, dy ); _agentBody._target = taikinys; //Apskaičiuokite sukimąsi pagal klavišų paspaudimus float targetAngle = Mathf.Atan2(dy, dx) * Mathf.Rad2Deg; _agentBody._targetAngle = targetAngle)_spriteOatrientation ; ) viešas nepaisymas void ControlForce( float dt) ( //Perduoti judėjimą _agentBody._movement = Input.GetAxis("Vertikali") * Vector2.up + Input.GetAxis("Horizontali") * Vector2.right; ) ) )


Atrodo, kad baigėme, dabar pagaliau galime pereiti prie to, dėl ko visa tai buvo pradėta, t.y. PID valdikliai (tikiuosi, nepamiršote?). Jo įgyvendinimas atrodo paprastas:


naudojant sistemą; naudojant System.Collections.Generic; naudojant System.Linq; naudojant System.Text; vardų sritis Assets.Scripts.Regulator ( // Šis atributas reikalingas, kad reguliatoriaus laukai // būtų rodomi inspektoriuje ir serializuotoje viešoje klasėje SimplePID ( public float Kp, Ki, Kd; private float lastError; private float P, I, D ; viešasis paprastas PID() ( Kp = 1f; Ki = 0; Kd = 0,2f; ) viešasis paprastas PID (slankioji pFactor, float iFactor, float dFactor) ( this.Kp = pFactor; this.Ki = iFactor; this.Kd = dFactor ; ) viešas slankusis atnaujinimas (slankioji klaida, slankioji dt) ( P = klaida; I + = klaida * dt; D = (klaida - paskutinė klaida) / dt; paskutinė klaida = klaida; plūduriuoti CO = P * Kp + I * Ki + D * Kd ; grąžinti CO; ) ) )

Numatytąsias koeficientų vertes paimsime iš oro: tai bus trivialus vienas proporcinio valdymo dėsnio koeficientas Kp = 1, maža diferencialinio valdymo dėsnio koeficiento reikšmė Kd = 0,2, kuri turėtų pašalinti tikėtini svyravimai ir nulinė Ki reikšmė, kuri buvo pasirinkta todėl, kad mūsų programinėje įrangoje modelis neturi statinių klaidų (bet visada galite jas įvesti, o paskui didvyriškai kovoti su integratoriaus pagalba).


Dabar grįžkime į savo SpaceShip klasę ir pabandykite panaudoti savo kūrinį kaip erdvėlaivio sukimosi valdiklį ControlRotate metodu:


public float ControlRotate(Vector2 rotate) ( float MV = 0f; float dt = Time.fixedDeltaTime; //Apskaičiuokite klaidą float angleError = Mathf.DeltaAngle(_myTransform.eulerAngles.z, targetAngle); //Gaukite korekcinį MV = Controller acceleration .Atnaujinti (angleError, dt); grąžinti MV; )

PID valdiklis tiksliai nustatys erdvėlaivio kampinę padėtį, naudodamas tik sukimo momentą. Viskas sąžininga, fizika ir savaeigiai ginklai, beveik kaip tikrame gyvenime.


Ir be šių Ketvirčio. Tavo Lerp

if (!_rb2d.freezeRotation) rb2d.freezeRotation = tiesa; float deltaAngle = Mathf.DeltaAngle(_myTransform.eulerAngles.z, targetAngle); float T = dt * Mathf.Abs(_rotationSpeed ​​​​/ deltaAngle); // Kampą paversti vektoriumi Quaternion rot = Quaternion.Lerp(_myTransform.rotation, Quaternion.Euler(new Vector3(0, 0, targetAngle)), T); // Keisti objekto sukimąsi _myTransform.rotation = rot;


Gautas Ship.cs šaltinio kodas yra po spoileriu

naudojant UnityEngine; naudojant Assets.Scripts.Regulator; vardų sritis Assets.Scripts.SpaceShooter.Bodies (viešoji klasė Laivas: BaseBody (viešas GameObject _flame; public Vector2 _movement = new Vector2(); public Vector2 _target = new Vector2(); viešas slankusis _targetAngle = 0f; viešas plaukimas _kampas = 0f; viešas SimplePID _angleController = new SimplePID(); public void FixedUpdate() ( float sukimo momentas = ControlRotate(_targetAngle); Vector2 force = ControlForce(_movement); _rb2d.AddTorque(sukimo momentas); _rb2d.AddRelativeRotate public(floattate); pasukti) ( float MV = 0f; float dt = Time.fixedDeltaTime; _angle = _myTransform.eulerAngles.z; //Apskaičiuokite klaidą float angleError = Mathf.DeltaAngle(_angle, rotate); //Gaukite korekcinį pagreitįContro =. Atnaujinti (angl. angleError, dt); return MV; ) public Vector2 ControlForce (Vektoriaus2 judėjimas) ( Vector2 MV = new Vector2(); //Kodo dalis, skirta specialiam veikiančio variklio efektui, siekiant if (judėjimas != Vector2.zero) ( if (_flame != null) ( _flame.SetActive(true); ) ) else ( if (_flame != null) ( _flame.SetActive(false); ) ) MV = judėjimas; grąžinti MV; ) ) )


Visi? Eime namo?



WTF! Kas vyksta? Kodėl laivas keistai sukasi? Ir kodėl jis taip smarkiai atsimuša į kitus objektus? Ar šis kvailas PID valdiklis neveikia?


Nepanikuokite! Pabandykime išsiaiškinti, kas vyksta.


Tuo metu, kai gaunama nauja SP reikšmė, yra staigus (laipsniškas) klaidų neatitikimo šuolis, kuris, kaip mes prisimename, apskaičiuojamas taip: atitinkamai yra staigus išvestinės paklaidos šuolis, kurį apskaičiuojame ši kodo eilutė:


D = (klaida - paskutinė klaida) / dt;

Žinoma, galite išbandyti ir kitas diferenciacijos schemas, pavyzdžiui, tritaškį, penkiabalę, arba... bet tai vis tiek nepadės. Na, jie nemėgsta aštrių šuolių darinių - tokiuose taškuose funkcija nėra diferencijuojamas. Tačiau verta eksperimentuoti su skirtingomis diferenciacijos ir integravimo schemomis, bet tada, o ne šiame straipsnyje.


Manau, atėjo laikas sudaryti perėjimo proceso grafikus: laipsniškas veiksmas nuo S(t) = 0 iki SP(t) = 90 laipsnių kūnui, sveriančiam 1 kg, jėgos rankos ilgiui 1 metrą ir diferenciacijos tinklelio žingsniui. 0,02 s - kaip ir mūsų pavyzdyje Unity3D (tiesą sakant, ne visiškai; konstruojant šiuos grafikus nebuvo atsižvelgta į tai, kad inercijos momentas priklauso nuo kietojo kūno geometrijos, todėl pereinamasis procesas bus šiek tiek kitoks, bet vis tiek pakankamai panašus demonstravimui). Visos diagramos reikšmės pateiktos absoliučiomis vertėmis:


Hmm, kas čia vyksta? Kur dingo PID valdiklio atsakas?


Sveikiname, ką tik susidūrėme su tokiu reiškiniu kaip „spyris“. Akivaizdu, kad tuo metu, kai procesas vis dar yra PV = 0, o kontrolinė vertė jau yra SP = 90, tada su skaitine diferenciacija gauname 4500 eilės išvestinę reikšmę, kuri bus padauginta iš Kd = 0,2 ir pridėti proporcingą therom, kad išvestyje gautume kampinio pagreičio reikšmę 990, ir tai jau yra visiškas Unity3D fizinio modelio pasipiktinimas (kampiniai greičiai sieks 18000 laipsnių/s... Manau, kad tai yra RigidBody2D kampinio greičio ribinė vertė).


  • Gal verta rankiniu būdu parinkti koeficientus, kad šuolis nebūtų toks stiprus?
  • Ne! Geriausias dalykas, kurį galime pasiekti tokiu būdu, yra nedidelė išvestinio šuolio amplitudė, tačiau pats šuolis liks toks, koks buvo, ir tokiu atveju diferencialinis komponentas gali tapti visiškai neveiksmingas.

Tačiau galite eksperimentuoti.

Bandymas numeris du. Sodrumas

Tai logiška pavaros blokas(mūsų atveju, virtualūs manevriniai SpaceShip varikliai), negali susidoroti su didelėmis vertybėmis, kurias gali sukurti mūsų beprotiškas reguliatorius. Taigi pirmas dalykas, kurį padarysime, yra prisotinti reguliatoriaus išvestį:


viešas plūduriavimas ControlRotate(2 vektorius pasukti, plūduriuoti trauka) ( plūduriuoti CO = 0f; plūduriuoti MV = 0f; plūduriuoti dt = Time.fixedDeltaTime; //Apskaičiuokite klaidą float angleError = Mathf.DeltaAngle(_myTransform.eulerAngles.z); / targetAngles.z); / Gauname korekcinį pagreitį CO = _angleController.Update(angleError, dt); //Sotina MV = CO; if (MV > thrust) MV = trauka; if (MV< -thrust) MV = -thrust; return MV; }

Ir vėl perrašyta laivo klasė atrodo taip:

vardų sritis Assets.Scripts.SpaceShooter.Bodies (viešoji klasė Laivas: BaseBody (viešas GameObject _flame; public Vector2 _movement = new Vector2(); public Vector2 _target = new Vector2(); viešas slankusis _targetAngle = 0f; viešas plaukimas _kampas = 0f; viešas float _thrust = 1f; public SimplePID _angleController = new SimplePID(0.1f,0f,0.05f); public void FixedUpdate() ( _torque = ControlRotate(_targetAngle, _thrust); _force = ControlForce(_movement);Adquerrb2quement); _rb2d.AddRelativeForce(_force) eulerAngles .z, targetAngle); //Gaukite korekcinį pagreitį CO = _angleController.Update(angleError, dt); //Sotinimas MV = CO; if (MV > thrust) MV = trauka; if (MV< -thrust) MV = -thrust; return MV; } public Vector2 ControlForce(Vector2 movement) { Vector2 MV = new Vector2(); if (movement != Vector2.zero) { if (_flame != null) { _flame.SetActive(true); } } else { if (_flame != null) { _flame.SetActive(false); } } MV = movement * _thrust; return MV; } public void Update() { } } }


Tada galutinė mūsų savaeigių ginklų schema atrodys taip


Tuo pačiu metu tampa aišku, kad valdiklio išvestis CO(t)šiek tiek skiriasi nuo kontroliuojamo proceso kintamojo MV(t).


Tiesą sakant, iš šios vietos jau galite pridėti naują žaidimo objektą - pavaros blokas, per kurį bus valdomas procesas, kurio logika gali būti sudėtingesnė nei tik Mathf.Clamp(), pavyzdžiui, galite įvesti reikšmių diskretizavimą (kad neapkrautumėte žaidimo fizikos ateinančiomis reikšmėmis). šeštosiose dalyse po kablelio) negyvąją zoną (vėlgi ne. Prasminga perkrauti fiziką itin mažomis reakcijomis), įvesti pavaros valdymo delsą ir netiesiškumą (pavyzdžiui, sigmoidą) ir tada žr. kas iš to išeina.


Paleidę žaidimą pamatysime, kad erdvėlaivis pagaliau tapo valdomas:



Jei kuriate grafikus, galite pamatyti, kad valdiklio atsakas tapo toks:


Čia jau naudojamos normalizuotos vertės, kampai dalijami iš SP vertės, o valdiklio išvestis normalizuojama atsižvelgiant į maksimalią vertę, kuriai esant jau yra sodrumas.

Žemiau yra gerai žinoma PID valdiklio parametrų padidinimo efekto lentelė ( Kaip sumažinti šriftą, kitaip meringue brūkšnelių lentelė netilps?):



Ir bendras PID valdiklio rankinio derinimo algoritmas yra toks:


  1. Proporcinius koeficientus parenkame išjungę diferencialinę ir integralinę jungtis, kol prasidės savaiminiai svyravimai.
  2. Palaipsniui didindami diferencialinį komponentą, atsikratome savaiminių virpesių
  3. Jei yra likutinė valdymo klaida (poslinkis), pašaliname ją naudodami integruotą komponentą.

Nėra bendrų PID valdiklio parametrų verčių: konkrečios reikšmės priklauso tik nuo proceso parametrų (jo perdavimo charakteristikos): PID valdiklis, kuris puikiai veikia su vienu valdymo objektu, neveiks su kitu. Be to, proporcinių, integralinių ir diferencinių komponentų koeficientai taip pat yra tarpusavyje susiję.


Bandymas numeris trys. Dar kartą išvestiniai

Pritvirtinę ramentą, ribojantį valdiklio išėjimo reikšmes, vis tiek neišsprendėme svarbiausios savo valdiklio problemos - diferencialo komponentas neveikia gerai, kai laipsniškai keičiasi klaida valdiklio įėjime. Tiesą sakant, yra daug kitų ramentų, pavyzdžiui, staigiai pasikeitus SP, „išjunkite“ diferencialo komponentą arba įdiekite žemo dažnio filtrus. SP(t) ir operacija, dėl kurios klaida palaipsniui didės, arba galite visiškai apsisukti ir naudoti tikrą Kalmano filtrą, kad išlygintumėte įvesties duomenis. Apskritai, yra daug ramentų, ir pridėkite stebėtojasŽinoma, norėčiau, bet ne šį kartą.


Todėl grįžkime prie neatitikimo klaidos išvestinės ir atidžiai ją pažvelkime:



Ar ką nors pastebėjote? Atidžiau pažvelgę ​​pamatysite, kad apskritai SP(t) laikui bėgant nekinta (išskyrus žingsnių keitimo momentus, kai valdiklis gauna naują komandą), t.y. jo išvestinė yra nulis:





Kitaip tariant, vietoj išvestinės paklaidos, kuri yra diferencijuojama ne visur galime naudoti proceso išvestinę, kuri klasikinės mechanikos pasaulyje paprastai yra nuolatinė ir visur diferencijuota, o mūsų automatinio valdymo sistemos schema jau bus tokia:




Pakeiskime valdiklio kodą:


naudojant sistemą; naudojant System.Collections.Generic; naudojant System.Linq; naudojant System.Text; vardų sritis Assets.Scripts.Regulator ( viešoji klasė SimplePID ( viešas slankusis Kp, Ki, Kd; privatus slankusis P, I, D; privatus plūdimas paskutinisPV = 0f; viešas SimplePID() ( Kp = 1f; Ki = 0f; Kd = 0,2 f ; ) viešas paprastas PID(float pFactor, float iFactor, float dFactor) ( this.Kp = pFactor; this.Ki = iFactor; this.Kd = dFactor; ) public float Update(float error, float PV, float dt) ( P = klaida; I + = klaida * dt; D = -(PV - paskutinisPV) / dt; paskutinisPV = PV; plūduriuoti CO = Kp * P + Ki * I + Kd * D; grąžinti CO; ) ) )

Ir šiek tiek pakeiskime ControlRotate metodą:


viešas plūduriavimas ControlRotate(2 vektorius pasukti, plūduriuoti trauka) ( plūduriuoti CO = 0f; plūduriuoti MV = 0f; plūduriuoti dt = Time.fixedDeltaTime; //Apskaičiuokite klaidą float angleError = Mathf.DeltaAngle(_myTransform.eulerAngles.z); / targetAngles.z); / Gauname korekcinį pagreitį CO = _angleController.Update(angleError, _myTransform.eulerAngles.z, dt); //Saturate MV = CO; if (CO >< -thrust) MV = -thrust; return MV; }

Ir-ir-ir-ir... jei pradėsite žaidimą, pamatysite, kad iš tikrųjų niekas nepasikeitė nuo paskutinio bandymo, o tai ir reikėjo įrodyti. Tačiau jei pašalinsite sodrumą, reguliatoriaus atsako grafikas atrodys taip:


Šokinėti CO(t) tebėra, bet nebėra toks didelis, koks buvo pačioje pradžioje, o svarbiausia – tapo nuspėjamas, nes yra teikiama tik proporcinio komponento, o jį riboja didžiausia galima nesutapimo klaida ir proporcingas PID valdiklio stiprinimas (ir tai jau rodo, kad Kp prasminga pasirinkti mažesnį nei vienetą, pavyzdžiui, 1/90f), bet tai nepriklauso nuo diferenciacijos tinklelio žingsnio (t. y. dt). Apskritai primygtinai rekomenduoju naudoti proceso išvestinę, o ne klaidą.


Manau, kad dabar tai nieko nenustebins, bet lygiai taip pat galite jį pakeisti , bet mes apie tai nesigilinsime, galite patys eksperimentuoti ir komentaruose papasakoti, kas iš to išėjo (įdomiausia)

Ketvirtas bandymas. Alternatyvūs PID valdiklio diegimai

Be aukščiau aprašyto idealaus PID valdiklio vaizdavimo, praktikoje dažnai naudojama standartinė forma be koeficientų Ki Ir Kd, vietoj kurių naudojamos laikinosios konstantos.


Šis metodas pagrįstas tuo, kad daugelis PID valdiklio derinimo būdų yra pagrįsti PID valdiklio ir proceso dažninėmis charakteristikomis. Tiesą sakant, visas TAU sukasi apie procesų dažnines charakteristikas, todėl norintiems pasigilinti ir staiga susidūrusiems su alternatyvia nomenklatūra pateiksiu pavyzdį vadinamąją. Standartinė forma PID valdiklis:




kur yra diferenciacijos konstanta, kuri turi įtakos reguliatoriaus prognozei sistemos būsenai,
- integravimo konstanta, įtakojanti integralios jungties klaidų vidurkio intervalą.


Pagrindiniai PID valdiklio derinimo standartine forma principai yra panašūs į idealizuotą PID valdiklį:

  • proporcinio koeficiento padidinimas padidina našumą ir sumažina stabilumo ribą;
  • sumažėjus integruotam komponentui, valdymo paklaida laikui bėgant mažėja greičiau;
  • sumažinus integravimo konstantą, sumažėja stabilumo riba;
  • diferencialo komponento padidėjimas padidina stabilumo ribą ir našumą

Standartinės formos šaltinio kodą rasite po spoileriu

vardų sritis Assets.Scripts.Regulator ( viešoji klasė StandartPID ( vieša slankioji Kp, Ti, Td; vieša slankioji klaida, CO; viešoji plūdė P, I, D; privati ​​float paskutinisPV = 0f; viešoji StandartPID() ( Kp = 0.1f; Ti = 10000f; Td = 0,5f; poslinkis = 0f; ) viešasis standartinis PID(float Kp, float Ti, float Td) ( this.Kp = Kp; this.Ti = Ti; this.Td = Td; ) public float Update(float klaida, float PV, float dt) ( tai.klaida = klaida; P = klaida; I += (1 / Ti) * klaida * dt; D = -Td * (PV - paskutinisPV) / dt; CO = Kp * ( P + I + D); paskutinisPV = PV; grąžinti CO; ) ) )

Numatytos vertės yra Kp = 0,01, Ti = 10000, Td = 0,5 - su šiomis vertėmis laivas sukasi gana greitai ir turi tam tikrą stabilumo ribą.


Be šios formos PID valdiklio, vadinamasis pasikartojanti forma:



Mes apie tai nesigilinsime, nes... tai aktualu pirmiausia aparatūros programuotojams, dirbantiems su FPGA ir mikrovaldikliais, kur toks diegimas yra daug patogesnis ir efektyvesnis. Mūsų atveju - duokime ką nors į krūvas Unity3D - tai tik dar vienas PID valdiklio įgyvendinimas, kuris nėra geresnis už kitus ir dar mažiau suprantamas, todėl dar kartą džiaukimės visi, kaip gera programuoti jaukiu C#. , o ne, pavyzdžiui, baisiame ir siaubingame VHDL.

Vietoj išvados. Kur dar pridėtumėte PID valdiklį?

Dabar pabandykime šiek tiek apsunkinti laivo valdymą naudojant dviejų kilpų valdymą: vienas jau mums pažįstamas PID valdiklis _angleController vis dar yra atsakingas už kampinį pozicionavimą, tačiau antrasis - naujas, _angularVelocityController - valdo sukimosi greitį:


viešasis plūduriavimas ControlRotate(plūduriuoti taikinysKampas, plūduriuojanti trauka) (plūduriuoti CO = 0f; plūduriuoti MV = 0f; plūduriuoti dt = Time.fixedDeltaTime; _angle = _myTransform.eulerAngles.z; //Pasukimo kampo valdiklis plūdės kampo klaida,_angle = Mathlef. targetAngle); float torqueCorrectionForAngle = _angleController.Update(angleError, _angle, dt); //Greičio stabilizavimo valdiklis float angularVelocityError = -_rb2d.angularVelocity; float torqueVanreloCorrectionForAelngu. gularVelocityError, -angularVelocityError, dt); //Iš viso valdiklio išvestis CO = torqueCorrectionForAngle + torqueCorrectionForAngularVelocity; //Pavyzdys po 100 CO = Mathf.Round (100f * CO) / 100f; //Sotinimas MV = CO; jei (CO > trauka) MV = trauka; if (CO)< -thrust) MV = -thrust; return MV; }

Antrojo reguliatoriaus tikslas yra slopinti perteklinius kampinius greičius keičiant sukimo momentą - tai panašu į kampinę trintį, kurią išjungėme kurdami žaidimo objektą. Tokia valdymo schema [galbūt] leis pasiekti stabilesnį laivo elgesį ir netgi išsiversti tik su proporcingais valdymo koeficientais - antrasis reguliatorius slopins visus svyravimus, atlikdamas funkciją, panašią į pirmojo reguliatoriaus diferencialinį komponentą. .


Be to, pridėsime naują grotuvo įvesties klasę - PlayerInputCorvette, kurioje posūkiai bus atliekami spaudžiant dešinįjį-kairėjį klavišus, o taikinio žymėjimą pele paliksime kam nors naudingesniam, pavyzdžiui, bokštelio valdymui. . Tuo pačiu metu dabar turime tokį parametrą kaip _turnRate - kuris yra atsakingas už posūkio greitį / reakciją (neaišku, kur jį geriau dėti į InputCONtroller ar vis dar Ship).


viešoji klasė PlayerCorvetteInput: BaseInputController ( viešas plaukimas _turnSpeed ​​​​= 90f; viešas nepaisymas void ControlRotate() ( // Raskite pelės žymeklį Vector3 worldPos = Input.mousePosition; worldPos = Camera.main.ScreenToWorldPoint(worldPos); // Išsaugokite santykį); // pelės žymeklio plūdės koordinatės dx = -this.transform.position.x + worldPos.x; float dy = -this.transform.position.y + worldPos.y; //Perduokite pelės žymeklio kryptį Vector2 target = new Vector2( dx, dy); _agentBody. _target = target; //Apskaičiuokite sukimąsi pagal klavišų paspaudimus _agentBody._rotation -= Input.GetAxis("Horizontalus") * _turnSpeed* Time.deltaTime; ) viešas nepaisymas ControlForce() void ( //Perduoti judėjimą _agentBody._movement = Įvestis .GetAxis("Vertikali") * Vector2.up; ) )

Be to, aiškumo dėlei mes atsiklaupsime scenarijų, kad būtų rodoma derinimo informacija

vardų sritis Assets.Scripts.SpaceShooter.UI ( viešosios klasės derinimo priemonė: MonoBehaviour ( Laivas _laivas; BaseInputController _valdiklis; sąrašas _pids = naujas sąrašas (); Sąrašas _names = naujas sąrašas (); Vector2 _orientacija = naujas Vector2(); // Naudokite tai inicijavimui void Start() ( _ship = GetComponent (); _controller = Gauti komponentą (); _pids.Add(_ship._angleController); _names.Add("Kampo valdiklis"); _pids.Add(_ship._angularVelocityController); _names.Add("Kampinio greičio valdiklis"); ) // Atnaujinimas iškviečiamas vieną kartą per kadrą void Update() ( DrawDebug(); ) Vector3 GetDiretion(eSpriteRotation spriteRotation) ( jungiklis (_controller._spriteOrientation) ( atvejis eSpriteRotation.Rigth: return transform.right; atvejis eSpriteRotation.Up: grįžti .up; atvejis eSpriteRotation.Left: return -transform.right; atvejis eSpriteRotation.Down: return -transform.up; ) return Vector3.zero; ) void DrawDebug() ( //Rotation direction Vector3 vectorToTarget = transform.position + 5f * new Vector3(-Mathf.Sin(_ship._targetAngle * Mathf.Deg2Rad), Mathf.Cos(_ship._targetAngle * Mathf.Deg2Rad), 0f); // Dabartinė kryptis Vector3 antraštė = transform.position + 4f * GetDiretion(_controller. _spriteOrientation); //Kampinis pagreitis Vector3 sukimo momentas = kryptis - transform.right * _ship._Torque; Debug.DrawLine(transform.position, vectorToTarget, Color.white); Debug.DrawLine(transform.position, heading, Color.green); Debug.DrawLine(antraštė, sukimo momentas, spalva.raudona); ) void OnGUI() ( float x0 = 10; plūduriuoti y0 = 100; plūduriuoti dx = 200; plūdės dy = 40; float SliderKpMax = 1; float SliderKpMin = 0; float SliderKiMax = .5f; float SliderKiMin = -.5f; float SliderKdMax = .5f; float SliderKdMin = 0; int i = 0; foreach (SimplePID pid _pids) ( y0 += 2 * dy; GUI.Box(new Rect(25 + x0, 5 + y0, dx, dy), ""); pid.Kp = GUI.HorizontalSlider(new Rect( 25 + x0, 5 + y0, 200, 10), pid.Kp, SliderKpMin, SliderKpMax); pid.Ki = GUI.HorizontalSlider(new Rect(25 + x0, 20 + y0, 200, 10), pid.Ki, SliderKiMin, SliderKiMax); pid.Kd = GUI.HorizontalSlider(new Rect(25 + x0, 35 + y0, 200, 10), pid.Kd, SliderKdMin, SliderKdMax); GUIStyle style1 = new GUIStyle1.alignment( = style1.alignment(); TextAnchor.MiddleRight; style1.fontStyle = FontStyle.Bold; style1.normal.textColor = Color.yellow; style1.fontSize = 9; GUI.Label(new Rect(0 + x0, 5 + y0, 20, 10), "Kp ", style1); GUI.Label(new Rect(0 + x0, 20 + y0, 20, 10), "Ki", ​​​​style1); GUI.Label(new Rect(0 + x0, 35 + y0, 20) , 10 ), "Kd", style1); GUIStyle style2 = naujas GUIStyle(); style2.alignment = TextAnchor.MiddleLeft; style2.fontStyle = FontStyle.Bold; style2.normal.textColor = Spalva.geltona; style2.fontSize = 9 GUI .TextField(new Rect(235 + x0, 5 + y0, 60, 10), pid.Kp.ToString(), style2); GUI.TextField(new Rect(235 + x0, 20 + y0, 60, 10), pid. Ki.ToString(), style2); GUI.TextField(new Rect(235 + x0, 35 + y0, 60, 10), pid.Kd.ToString(), style2); GUI.Label(new Rect(0 + x0, -8 + y0, 200, 10), _pavadinimai, stilius2); ) ) ) )


Laivų klasė taip pat patyrė negrįžtamų mutacijų ir dabar turėtų atrodyti taip:

vardų sritis Assets.Scripts.SpaceShooter.Bodies (viešoji klasė Laivas: BaseBody (viešas GameObject _flame; public Vector2 _movement = new Vector2(); public Vector2 _target = new Vector2(); viešas slankusis _targetAngle = 0f; viešas plaukimas _kampas = 0f; viešas float _thrust = 1f; viešasis SimplePID _angleController = naujas SimplePID(0.1f,0f,0.05f); viešas SimplePID _angularVelocityController = naujas SimplePID(0f,0f,0f); privatus plūduriavimas _sukimo momentas = 0f; viešas plūdimas (gaunamas _Torquetorque) ) ) private Vector2 _force = new Vector2(); public Vector2 _Force ( get ( return _force; ) ) public void FixedUpdate() ( _torque = ControlRotate(_targetAngle, _thrust); _force = ControlForce(_movement, _thrust);Ad _rb _torque); _rb2d.AddRelativeForce(_force); ) viešasis plūduriavimas ControlRotate(plūduriuojantis tikslasKampas, plūduriuojanti trauka) (plūduriuoti CO = 0f; plūduriuoti MV = 0f; plūduriuoti dt = Time.fixedDeltaTime; _angle = _myTransformlez.eu; sukimosi kampas plūduriavimo kampasError = Mathf.DeltaAngle(_kampas, tikslinis kampas); float torqueCorrectionForAngle = _angleController.Update(angleError, _kampas, dt); //Greičio stabilizavimo valdiklis float angularVelocityError = -_rb2d.angularVelocity; float torqueCorrectionForAngularVelocity = _angularVelocityController.Update(kampinisVelocityError, -angularVelocityError, dt); //Bendra valdiklio išvestis CO = torqueCorrectionForAngle + torqueCorrectionForAngularVelocity; //Diskretizuoti 100 CO žingsniais = Mathf.Round(100f * CO) / 100f; //Sotinimas MV = CO; if (CO > trauka) MV = trauka; if(CO< -thrust) MV = -thrust; return MV; } public Vector2 ControlForce(Vector2 movement, float thrust) { Vector2 MV = new Vector2(); if (movement != Vector2.zero) { if (_flame != null) { _flame.SetActive(true); } } else { if (_flame != null) { _flame.SetActive(false); } } MV = movement * thrust; return MV; } public void Update() { } } }

Dar keletas nuorodų į kitus pavyzdžius

Proporcingumo juosta X p, kaip ir nuokrypis E, išreiškiama valdomo parametro vienetais. Kuo platesnė proporcinga juosta X p, tuo mažesnis išėjimo signalas Y tam pačiam nuokrypiui E.

Už proporcinės juostos ribų Y išvestis yra 0 arba 100%.

Kai veikia P dėsnis, valdiklis gamina impulsus, kuriuose yra tik proporcingas išėjimo signalo vertės komponentas.


Kai įrenginys veikia PD valdiklio režimu, išėjimo signalo Yi dydis priklauso ne tik nuo nuokrypio Ei dydžio, bet ir nuo jo kitimo greičio:

Valdiklio išėjimo signalo pokytis su laipsnišku nuokrypio pokyčiu parodytas paveikslėlyje. Pirmuoju periodu po žingsnio pakeitimo E i, valdiklis išduoda valdymo impulsą, kuriame be proporcinio komponento, kurį sukelia neatitikimas E i, pridedamas diferencialas (tamsesnė dalis) ΔYd, kuris priklauso nuo reikšmės. ΔE i ir τ l koeficientų. Vėlesniuose impulsuose yra tik proporcingas komponentas, nes E i nesikeičia.


Paveikslėlyje parodyta, kad pirmuoju laiko momentu, kai nėra nuokrypio (E i =0), nėra išėjimo signalo (Y i =0). Atsiradus nuokrypiui E i, atsiranda impulsai, kurių trukmė palaipsniui didėja. Impulsuose yra proporcinis komponentas, kuris priklauso nuo E reikšmės (neužtemdyta impulsų dalis) ir integralioji dalis (tamsesnė dalis). Impulso trukmės padidėjimas atsiranda dėl integralinio komponento padidėjimo, kuris priklauso nuo neatitikimo E i ir koeficiento τ i.

Diferencialinis proporcinis-integralus valdiklis yra įrenginys, kuris yra įdiegtas automatizuotose sistemose, kad būtų palaikomas tam tikras parametras, kuris gali keistis.

Iš pirmo žvilgsnio viskas painu, bet PID valdymą galima paaiškinti manekenams, t.y. žmonių, kurie nėra visiškai susipažinę su elektroninėmis sistemomis ir įrenginiais.

Kas yra PID valdiklis?

PID valdiklis yra įtaisas, įmontuotas į valdymo grandinę su privalomu grįžtamuoju ryšiu. Jis skirtas palaikyti nustatytus nurodytų verčių lygius, pavyzdžiui, oro temperatūrą.

Įrenginys tiekia valdymo arba išvesties signalą į valdymo įrenginį, remdamasis duomenimis, gautais iš jutiklių ar jutiklių. Valdikliai pasižymi dideliu pereinamųjų procesų tikslumu ir pavestos užduoties atlikimo kokybe.

Trys PID valdiklio koeficientai ir veikimo principas

PID valdiklio darbas yra pateikti išėjimo signalą apie galią, reikalingą kontroliuojamam parametrui palaikyti tam tikru lygiu. Rodikliui apskaičiuoti naudojama sudėtinga matematinė formulė, kurioje yra 3 koeficientai - proporcinis, integralus, diferencinis.

Reguliavimo objektu paimkime vandens indą, kuriame būtina palaikyti temperatūrą tam tikrame lygyje, reguliuojant vožtuvo atsidarymo laipsnį garais.

Proporcinis komponentas pasirodo neatitikimo su įvesties duomenimis momentu. Paprastais žodžiais tariant, tai skamba taip - imamas skirtumas tarp tikrosios ir norimos temperatūros, padauginamas iš reguliuojamo koeficiento ir gaunamas išėjimo signalas, kuris turėtų būti tiekiamas į vožtuvą. Tie. Vos nukritus laipsniams, prasideda šildymo procesas, jei jie pakyla virš norimo lygio, įvyksta išjungimas ar net vėsinimas.

Toliau seka neatskiriama sudedamoji dalis, skirta kompensuoti aplinkos įtaką ar kitus nerimą keliančius veiksnius palaikant mūsų temperatūrą tam tikrame lygyje. Kadangi visada yra papildomų veiksnių, įtakojančių valdomus įrenginius, tuo metu, kai gaunami duomenys proporcingajai dedamajai apskaičiuoti, skaičius jau keičiasi. Ir kuo didesnė išorinė įtaka, tuo stipresni rodiklio svyravimai. Yra tiekiamos galios šuolių.

Integruotasis komponentas bando, remdamasis ankstesnėmis temperatūros vertėmis, grąžinti savo vertę, jei ji pasikeitė. Procesas išsamiau aprašytas toliau pateiktame vaizdo įraše.

Integralas naudojamas klaidoms pašalinti skaičiuojant statinę paklaidą. Šiame procese svarbiausia pasirinkti teisingą koeficientą, kitaip klaida (neatitikimas) taip pat turės įtakos integruotam komponentui.

Trečiasis PID komponentas yra diferencijavimas. Jis skirtas kompensuoti vėlavimų, atsirandančių tarp poveikio sistemai ir grįžtamojo ryšio, padarinius. Proporcinis valdiklis tiekia maitinimą tol, kol temperatūra pasiekia norimą lygį, tačiau visada atsiranda klaidų, kai informacija patenka į įrenginį, ypač esant didelėms reikšmėms. Tai gali sukelti perkaitimą. Diferencialas numato nuokrypius, atsiradusius dėl vėlavimo ar aplinkos poveikio, ir iš anksto sumažina tiekiamą galią.

PID valdiklio nustatymas

PID valdiklis sukonfigūruojamas dviem būdais:

  1. Sintezė apima parametrų skaičiavimą pagal sistemos modelį. Šis nustatymas yra tikslus, tačiau reikalauja gilių žinių apie automatinio valdymo teoriją. Tai priklauso tik inžinieriams ir mokslininkams. Kadangi reikia atsižvelgti į vartojimo charakteristikas ir atlikti daugybę skaičiavimų.
  2. Rankinis metodas pagrįstas bandymais ir klaidomis. Tam remiamasi paruoštos sistemos duomenimis ir atliekami kai kurie vieno ar kelių reguliatoriaus koeficientų koregavimai. Įjungus ir stebint galutinį rezultatą, parametrai keičiami norima kryptimi. Ir taip toliau, kol pasiekiamas norimas našumo lygis.

Teorinis analizės ir koregavimo metodas praktikoje naudojamas itin retai, o tai lemia valdymo objekto savybių nežinojimas ir daugybė galimų trikdančių poveikių. Labiau paplitę eksperimentiniai metodai, pagrįsti sistemos stebėjimu.

Šiuolaikiniai automatizuoti procesai realizuojami kaip specializuoti moduliai, valdomi valdiklių koeficientų koregavimo programomis.

PID valdiklio paskirtis

PID valdiklis skirtas palaikyti tam tikrą reikšmę reikiamame lygyje – temperatūrą, slėgį, lygį bake, srautą vamzdyne, kažko koncentraciją ir pan., keičiant pavarų, pavyzdžiui, automatinio valdymo vožtuvų, valdymo veiksmus. , naudojant proporcingus , integruojančius, diferencijuojančius dydžius jo nustatymui.

Naudojimo tikslas – gauti tikslų valdymo signalą, galintį valdyti dideles pramonės šakas ir net elektrinių reaktorius.

Temperatūros valdymo grandinės pavyzdys

PID valdikliai dažnai naudojami temperatūrai reguliuoti; pažvelkime į šį automatinį procesą naudodami paprastą vandens šildymo inde pavyzdį.

Talpykla pripildoma skysčio, kurį reikia pašildyti iki norimos temperatūros ir palaikyti tam tikru lygiu. Temperatūros matavimo jutiklis yra sumontuotas bako viduje arba yra tiesiogiai prijungtas prie PID valdiklio.

Norėdami pašildyti skystį, mes tieksime garą, kaip parodyta paveikslėlyje žemiau, su automatiniu valdymo vožtuvu. Pats vožtuvas gauna signalą iš reguliatoriaus. Operatorius į PID valdiklį įveda temperatūros nustatytosios vertės vertę, kuri turi būti palaikoma bake.

Jei reguliatoriaus koeficiento nustatymai yra neteisingi, vandens temperatūra svyruos, kai vožtuvas bus visiškai atidarytas arba visiškai uždarytas. Tokiu atveju reikia apskaičiuoti PID reguliatoriaus koeficientus ir vėl juos įvesti. Jei viskas bus padaryta teisingai, po trumpo laiko sistema išlygins procesą ir temperatūra konteineryje bus palaikoma nustatytame taške, o valdymo vožtuvo atsidarymo laipsnis bus vidurinėje padėtyje.

PID valdiklis yra paruoštas įrenginys, kuris leis vartotojui įdiegti programinį algoritmą tam tikrai automatizuotos sistemos įrangai valdyti. Valdymo sistemų kūrimas ir konfigūravimas tampa daug lengvesnis, jei naudojate paruoštus įrenginius, tokius kaip TRM148 universalus 8 kanalų PID valdiklis iš Aries kompanijos.

Tarkime, reikia automatizuoti tinkamų klimato sąlygų palaikymą šiltnamyje: atsižvelgti į dirvos temperatūrą prie augalų šaknų, oro slėgį, oro ir dirvožemio drėgmę bei palaikyti nustatytus parametrus valdant ventiliatorius. Nėra nieko paprastesnio, tiesiog sukonfigūruokite PID valdiklį.

Pirmiausia prisiminkime, kas yra PID valdiklis? PID valdiklis – tai specialus įrenginys, kuris nuolat tiksliai atlieka išėjimo parametrų reguliavimą trimis būdais: proporcingai, integruotai ir diferencijuotai, o pradiniai parametrai yra įvesties parametrai, gaunami iš jutiklių (slėgis, drėgmė, temperatūra, apšvietimas ir kt.).

Įvesties parametras į PID reguliatoriaus įvestį tiekiamas iš jutiklio, pavyzdžiui, iš drėgmės jutiklio. Reguliatorius gauna įtampos arba srovės reikšmę, ją išmatuoja, tada pagal savo algoritmą atlieka skaičiavimus ir galiausiai siunčia signalą į atitinkamą išėjimą, ko pasekoje automatizuota sistema gauna valdymo veiksmą. Sumažėjo dirvožemio drėgmė – kelioms sekundėms įjungtas laistymas.

Tikslas yra pasiekti vartotojo nurodytą drėgmės vertę. Arba pvz.: sumažėjo apšvietimas – įjunkite fitolampas virš augalų ir pan.

PID valdymas

Tiesą sakant, nors viskas atrodo paprasta, reguliatoriaus viduje matematika yra sudėtingesnė, viskas nevyksta vienu žingsniu. Įjungus drėkinimą, PID valdiklis vėl atlieka matavimą, matuoja, kiek dabar pasikeitė įvesties reikšmė – taip randama valdymo klaida. Kitas poveikis vykdomajai institucijai bus koreguojamas atsižvelgiant į išmatuotą reguliavimo paklaidą ir taip toliau kiekviename valdymo žingsnyje, kol bus pasiektas tikslas – vartotojo nurodytas parametras.

Reguliuojant dalyvauja trys komponentai: proporcinis, integralus ir diferencinis. Kiekvienas komponentas turi savo reikšmingumo laipsnį kiekvienoje konkrečioje sistemoje ir kuo didesnį indėlį įneš vienas ar kitas komponentas, tuo reikšmingiau jis turėtų būti keičiamas reguliavimo procese.

Proporcinė dedamoji yra pati paprasčiausia, kuo didesnis pokytis, tuo didesnis koeficientas (proporcingumas formulėje), o norint sumažinti poveikį, pakanka tiesiog sumažinti koeficientą (daugiklį).

Tarkime, dirvožemio drėgnumas šiltnamyje yra daug mažesnis nei nustatyta – tuomet laistymo laikas turėtų būti tiek pat ilgesnis, nes esama drėgmė yra mažesnė už nustatytą. Tai apytikslis pavyzdys, bet toks yra bendras principas.

Integralus komponentas – būtina padidinti valdymo tikslumą remiantis ankstesniais valdymo įvykiais: integruojamos ankstesnės klaidos ir atliekamos jų pataisos, kad galiausiai būtų gautas nulinis nuokrypis reguliuojant ateityje.

Galiausiai, diferencialinis komponentas. Čia atsižvelgiama į kontroliuojamo kintamojo kitimo greitį. Nesvarbu, ar nurodyta vertė keičiasi sklandžiai ar staigiai, atitinkamai, reguliavimo veiksmai neturėtų sukelti pernelyg didelių vertės nukrypimų reguliavimo metu.

Belieka pasirinkti įrenginį PID valdymui. Šiandien rinkoje jų yra daug, yra kelių kanalų, leidžiančių vienu metu keisti kelis parametrus, kaip minėtame pavyzdyje su šiltnamiu.

Pažvelkime į valdiklio konstrukciją, naudodamiesi Aries kompanijos universalaus PID valdiklio TRM148 pavyzdžiu.

Aštuoni įvesties jutikliai perduoda signalus į atitinkamus įėjimus. Signalai keičiami, filtruojami, koreguojami, jų reikšmes galima peržiūrėti ekrane perjungus mygtukais.

Įrenginio išėjimai gaminami skirtingomis modifikacijomis, reikiamais deriniais iš šių:

    relė 4 A 220 V;

    tranzistoriniai optronai n–p–n tipo 400 mA 60 V;

    triaciniai optronai 50 mA 300 V;

    DAC „parametras-srovė 4...20 mA“;

    DAC “parametras-įtampa 0...10 V”;

    4...6 V 100 mA išėjimas kietojo kūno relės valdymui.

Taigi valdymo veiksmas gali būti analoginis arba skaitmeninis. - tai kintamo pločio impulsai, o analoginiai - sklandžiai kintančios įtampos arba srovės pavidalu vieningame diapazone: nuo 0 iki 10 V įtampai ir nuo 4 iki 20 mA srovės signalui.

Šie išėjimo signalai tiksliai naudojami valdant pavaras, tarkime, laistymo sistemos siurblį arba relę, kuri įjungia ir išjungia šildymo elementą arba vožtuvo valdymo variklį. Reguliatoriaus skydelyje yra signalų indikatoriai.


Norint sąveikauti su kompiuteriu, TRM148 reguliatorius turi RS-485 sąsają, kuri leidžia:

    konfigūruoti įrenginį kompiuteryje (konfigūravimo programos pateikiamos nemokamai);

    perduoti į tinklą dabartines išmatuotų verčių reikšmes, valdiklio išėjimo galią, taip pat visus programuojamus parametrus;

  • gauti operatyvinius duomenis iš tinklo, kad generuotų valdymo signalus.

Galima teigti, kad didžiausią našumą suteikia P-teisė, - remiantis santykiu tp / T d .

Tačiau jei P reguliatoriaus Kr stiprinimas yra mažas (dažniausiai tai pastebima su vėlavimu), tai nesuteikia didelio valdymo tikslumo, nes šiuo atveju vertė yra didelė.

Jei Kp > 10, tai P reguliatorius yra priimtinas, o jei Kp< 10, то требуется введение в закон управления составляющей.

PI reguliavimo įstatymas

Dažniausiai praktikoje yra PI valdiklis, kuri turi šiuos privalumus:

  1. Suteikia nulinį reguliavimą.
  2. Gana lengva nustatyti, nes... Koreguojami tik du parametrai, būtent stiprinimas Kp ir integravimo laiko konstanta Ti. Tokiame valdiklyje galima optimizuoti santykio Kp/Ti-min reikšmę, kuri užtikrina valdymą su minimaliu įmanomu šaknies vidurkiu-kvadratiniu reguliavimu.
  3. Mažas jautrumas triukšmui atliekant matavimus (skirtingai nei PID valdiklis).

PID kontrolės įstatymas

Svarbiausioms valdymo kilpoms galime rekomenduoti naudoti , užtikrina aukščiausią našumą sistemoje.

Tačiau atkreipkite dėmesį, kad tai daroma tik su optimaliais nustatymais (sukonfigūruoti trys parametrai).

Didėjant sistemos vėlavimui, neigiami fazių poslinkiai smarkiai padidėja, o tai sumažina reguliatoriaus diferencinio komponento poveikį. Todėl sistemų su dideliu vėlavimu PID valdiklio kokybė tampa panaši į PI valdiklio kokybę.

Be to, sistemoje su PID valdikliu matavimo kanale esantis triukšmas lemia didelius atsitiktinius valdiklio valdymo signalo svyravimus, o tai padidina valdymo paklaidos dispersiją ir mechanizmo susidėvėjimą.

Taigi, PID reguliatorius turėtų būti parinktas valdymo sistemoms, turinčioms santykinai žemą triukšmo lygį ir valdymo vėlavimą. Tokių sistemų pavyzdžiai yra temperatūros reguliavimo sistemos.



Tęsiant temą:
Gipsas

Visi žino, kas yra grūdai. Juk žmogus šiuos augalus pradėjo auginti daugiau nei prieš 10 tūkstančių metų. Štai kodėl ir dabar tokie grūdų pavadinimai kaip kviečiai, rugiai, miežiai, ryžiai,...