PID Control Algorithms

advertisement
Measuresoft Development Ltd.
PID Control Algorithms
Version: 5.0.0.0
prepared for measuresoft by
Michael Kerley
24 August, 1998
© measuresoft development
This document is the copyright of Measuresoft,
and may not be modified, copied, or distributed
in any form whatsoever without the prior
permission of Measuresoft
measuresoft development limited
partnership court
the ramparts
dundalk
ireland
tel +353 42 32399
fax +353 42 27187
Implementing PID Control Algorithms
Table of Contents
Introduction ...................................................................................................................................... 3
Purpose .................................................................................................................................... 3
Scope ....................................................................................................................................... 3
References ............................................................................................................................... 3
PID Control Algorithms .................................................................................................................... 4
PID Controller Interaction with an Algorithm Component ........................................................ 4
PID Controller Interaction with Algorithm Component Property Pages ................................... 5
The Algorithm Component Module .......................................................................................... 6
IPIDAlgorithm Interface ............................................................................................................ 7
Methods............................................................................................................................. 7
IDL Definition ..................................................................................................................... 8
IPIDAlgorithm::SetPIDParameters method ....................................................................... 9
IPIDAlgorithm::CalculatePID method .............................................................................. 11
IPIDAlgorithm::StartPIDAutomatic method ..................................................................... 11
IPIDAlgorithm::LoadExtraPIDParamaters method .......................................................... 12
IPIDAlgorithm::SaveExtraPIDParamaters method.......................................................... 12
Implementing a PID Algorithm................................................................................................ 13
Development Environment ................................................................................................. 13
Sample Algorithm ............................................................................................................... 13
Create an ATL DLL Server.............................................................................................. 13
Add a Simple Object ....................................................................................................... 14
Add Support for IPIDAlgorithm ........................................................................................ 15
Implement IPIDAlgorithm Interface ................................................................................. 17
Add Non-Standard Properties ......................................................................................... 20
Add the Algorithm to CATID_PIDAlgorithm Component Category ................................. 22
Test the Algorithm ........................................................................................................... 22
Add Property Page Support ............................................................................................ 23
Test the Algorithm Property Page ................................................................................... 29
Conclusion .............................................................................................................................. 29
2
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
Introduction
The PID Controller application currently supports two PID Algorithms (Position and Velocity).
These algorithms are documented in the User Manual. There is much contention in the industry
about the effectiveness of different PID algorithms. Some algorithms are better suited to certain
types of control environments.
Therefore it is desirable that the PID Controller system be designed so that different algorithms
could be swapped in or out by the user without having to change or recompile any of the systems
code.
Purpose
This document describes how the system was designed to support different PID algorithms and
how to implement your own algorithm.
Scope
This document concentrates on implementing/coding a PID algorithm component. It does not
discuss the merits of different algorithms. This document assumes that the reader is familiar with
Microsoft’s Component Object Model (COM) and has some experience with implementing COM
objects using Visual C++/ATL.
References
For more information on COM check the following references:
1. Microsoft Developer Network Library.
2. http://www.microsoft.com/cominfo/.
3. Essential COM, Don Box, ISBN 0-201-63446-5, Addison-Wesley.
4. Inside OLE - 2nd Edition, Kraig Brockschmidt, ISBN 1-55615-843-2, Microsoft Press.
5. Beginning ATL COM Programming, Grimes, Stockton & Templeman, ISBN: 1-861000-11-1,
Wrox Press.
3
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
PID Control Algorithms
This section describes how the algorithm mechanism works within the current system, and
documents the required interfaces for such a mechanism to work.
PID Controller Interaction with an Algorithm Component
The Component Object Model (COM) is a software architecture that allows the components made
by different software vendors to be combined into a variety of applications. COM defines a
standard for component interoperability, is not dependent on any particular programming
language, is available on multiple platforms, and is extensible. Using COM technology we were
able to design a PID Controller system that allows users to replace or add new algorithms.
The PID Controller interfaces to all algorithms through a COM custom interface called
IPIDAlgorithm (defined below). This interfaces provides the PID runtime with the ability to set
standard PID parameters such as Setpoint, Kp, Ki and Kd. Every PID algorithm component must
support this interface.
The PID System interacts with an algorithm component in the following ways:
1. When the system is enabled the runtime reads in all configured loops from disk. For each
loop it creates an instance of the configured algorithm component. The runtime then queries
the algorithm component for its IPIDAlgorithm interface.
2. Each algorithm component is then asked to load its extra parameters when the runtime calls
IPIDAlgorithm::LoadExtraPIDParameters. At this stage the component can read in any nonstandard properties.
3. The runtime will then perform some calculations (e.g. calculate sample period) and then sets
the standard parameters for each algorithm component by calling
IPIDAlgorithm::SetPIDParameters.
4. If the loop moves from manual to automatic mode, the runtime will call IPIDAlgorithm::
StartPIDAutomatic. It is used to prevent integral windup.
5. As each automatic loop runs, the runtime calls IPIDAlgorithm::CalculatePID to calculate the
current PID output value, based on the configured PID properties. The output channels are
then driven.
6. When a user saves parameters for a loop to disk, the PID Configuration and Monitoring
application calls IPIDAlgorithm::SaveExtraPIDParameters to save the non-standard
parameters to disk.
4
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
PID Controller Interaction with Algorithm Component Property Pages
Because of the extensible nature of COM, you can implement your own properties and methods
on an algorithm component using other interfaces (which you define). Support is provided for
editing these non-standard properties through the use of OLE/COM Property Pages and the
Edit|Extra Algorithm Properties command in the PID Configuration and Monitoring application.
Property pages allow a COM object user to view and change COM object properties. Invoking an
object’s properties dialog box accesses these properties. This dialog box contains one or more
property pages that provide a customized, graphical interface for viewing and editing the object
properties. The PID Configuration and Monitoring application acts as a container that can display
its own modeless dialog box that shows the property pages of the selected algorithm object.
The Algorithm component can support non-standard properties and methods by implementing its
own custom interface (E.g. IMyAlgorithm). Algorithm components support visual editing of
properties using property pages by implementing the ISpecifyPropertyPages interface.
Each property page supported by the object must support the IPropertyPage and
IPropertyPage2 interfaces. The COM interfaces, ISpecifyPropertyPages, IPropertyPage and
IPropertyPage2 are documented by Microsoft.
1. When a loop document is opened in the configuration and monitoring application, its
configuration is read from disk. The application creates an instance of the configured
algorithm component.
2. When the user chooses the Edit|Extra Algorithm Properties command the algorithm
component is queried for the ISpecifyPropertyPages interface.
3. If the object does not support the ISpecifyPropertyPages interface the user is notified and
the sequence ends.
4. Otherwise the application calls ISpecifyPropertyPages::GetPages to retrieve the CLSID of
each supported property page.
5. The application then displays its own property sheet. It then creates and displays an instance
of each supported property page for the object. The user can then change any non-standard
properties and save them to disk using the File|Save command.
5
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
The Algorithm Component Module
The following diagram shows the interfaces that a PID algorithm component should implement:
Algorithm Component Module
IPIDAlgorithm
Algorithm
ISpecifyPropertyPages
IMyAlgorithm
Property
Pages
IPropertyPage
IPropertyPage
2
The Algorithm component should be implemented as an in-proc server (DLL).
An algorithm module advertises that it supports a PID algorithm by registering support for the
Component Category CATID_PIDAlgorithm (see COM documentation for discussion of
component categories). The PIDAlgorithm category is defined as:
HKEY_CLASSES_ROOT\Component Categories\{5D8839D5-EFF2-11D1-8329006097C787F8}
6
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
IPIDAlgorithm Interface
The IPIDAlgorithm is described below:
Methods
HRESULT SetPIDParameters
This method sets the standard paramaters for the PID calculation
HRESULT CalculatePID
This method calculates the current PID output value, based on the configured PID properties.
HRESULT StartPIDAutomatic
This method is called when the control loop moves from manual to automatic mode. It is used to
prevent integral windup.
HRESULT LoadExtraPIDParameters
This method reads in any non-standard PID parameters from a persistent stream.
HRESULT SaveExtraPIDParameters
This method writes out any non-standard PID parameters to a persistent stream.
7
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
IDL Definition
typedef enum DeadZoneType
{
Positive,
Negative,
PositiveAndNegative
}
DEADZONETYPE;
[
object,
uuid(B3F2A2E4-E4F1-11d1-831B-006097C787F8),
pointer_default(unique)
]
interface IPIDAlgorithm : IUnknown
{
HRESULT SetPIDParameters(
[in] float SetPoint,
[in] float SteadyState,
[in] float Kp,
[in] float Ki,
[in] float Kd,
[in] float SampleRate,
[in] BOOL InputHiLimitsOn,
[in] BOOL InputLoLimitsOn,
[in] float InputLoLimit,
[in] float InputHighLimit,
[in] float Filter,
[in] float OutputLoLimit,
[in] float OutputHiLimit,
[in] float ROC,
[in] BOOL DeadZoneOn,
[in] float DeadZoneValue,
[in] DEADZONETYPE DeadZoneType,
[in] BOOL bPIDInvertedOutput);
HRESULT CalculatePID([in] float InputValue,
[out,retval] float *OutputValue);
HRESULT StartPIDAutomatic([in] float InputValue,
[in] float OutputValue);
HRESULT LoadExtraPIDParamaters([in] IStream *PIDStream);
HRESULT SaveExtraPIDParamaters([in] IStream *PIDStream);
};
8
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
IPIDAlgorithm::SetPIDParameters method
HRESULT SetPIDParameters(
[in] float SetPoint,
[in] float SteadyState,
[in] float Kp,
[in] float Ki,
[in] float Kd,
[in] float SampleRate,
[in] BOOL InputHiLimitsOn,
[in] BOOL InputLoLimitsOn,
[in] float InputLoLimit,
[in] float InputHighLimit,
[in] float Filter,
[in] float OutputLoLimit,
[in] float OutputHiLimit,
[in] float ROC,
[in] BOOL DeadZoneOn,
[in] float DeadZoneValue,
[in] DEADZONETYPE DeadZoneType,
[in] BOOL PIDInvertedOutput )
This method sets the standard parameters for the PID calculation
Return Value
S_OK
E_INVALIDARG
Description
Success
Invalid argument
Parameters
SetPoint
The PID setpoint value.
SteadyState
Steady state output value.
Kp
The PID porportional gain constant.
Ki
The PID integral time constant.
Kd
The PID derivative time constant.
SampleRate
The measured variable sample period in minutes per sample. For example, if the controller's
output is calculated two times a second, the value of this parameter is 1 / (2 * 60) = 0.0084
minutes.
InputHiLimitsOn
Flag for high limiting inputs. Set to TRUE if youn want high output limiting on.
9
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
InputLoLimitsOn
Flag for low limiting inputs. Set to TRUE if youn want low output limiting on.
InputLoLimit
The value corresponding to the low range of the input variable.
InputHighLimit
The value corresponding to the high range of the input variable.
Filter
The PID filter constant can be used to reduce the amount of noise present in PID input
measurements. A value in the range 0.0 to 1.0, affecting the filtering of the noisy measurement
signal. A value of 0.0 means that no filtering will take place. The filtering effect is maximal when
value is 1.0. The formula for filtering is:
Filtered value = (1.0 - value) * Measured value + value * (Previous filtered value)
OutputLoLimit
The value corresponding to the low range of the output variable.
OutputHiLimit
The value corresponding to the high range of the output variable.
ROC
Rate of change output limit value.
DeadZoneOn
Flag for Deadzone limiting. Set to TRUE if youn want low deadzone limiting on.
DeadZoneValue
The value around the setpoint at which no control takes place.
DeadZoneType
The sign of the dead zone value (+, -, +-).
PIDInvertedOutput
Inverts the PID output response to an increase in the measurement variable input. Specifies the
direction of change of PID output relative to measurement. If TRUE, the direction of change is the
same. Normally this parameter should be set to FALSE (opposite directions).
10
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
IPIDAlgorithm::CalculatePID method
HRESULT CalculatePID([in] float InputValue, [out, retval] float* OutputValue)
This method calculates the current PID output value, based on the current state of the PID
properties.
Return Value
S_OK
S_FALSE
E_INVALIDARG
Description
Success
No control took place due to deadzone, maths error etc.
Invalid argument
Parameters
InputValue
Current value of the measurement (process channel).
OutputValue
Address of the PID output value.
IPIDAlgorithm::StartPIDAutomatic method
HRESULT StartPIDAutomatic([in] float InputValue, [in] float OutputValue)
This method is called when the control loop moves from manual to automatic mode. It is used to
prevent integral windup.
Return Value
S_OK
E_INVALIDARG
Description
Success
Invalid argument
Parameters
InputValue
Current value of the measurement (process channel).
OutputValue
Current PID output value.
11
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
IPIDAlgorithm::LoadExtraPIDParamaters method
HRESULT LoadExtraPIDParamaters([in] IStream * PIDStream)
This method reads any non-standard PID parameters from a stream.
Return Value
S_OK
S_FALSE
Description
Success
The data could not be read from the stream object.
The caller does not have sufficient permissions for writing to this stream
STG_E_ACCESSDENIED
object.
One of the pointer values is invalid. The PIDStream parameter must contain
STG_E_INVALIDPOINTER
a valid pointer even if cb is zero.
Parameters
PIDStream
A pointer to the stream to read from.
IPIDAlgorithm::SaveExtraPIDParamaters method
HRESULT SaveExtraPIDParamaters([in] IStream * PIDStream)
This method writes any non-standard PID parameters to a stream.
Return Value
S_OK
Description
Success
The write operation was not completed because there is no space left on the
STG_E_MEDIUMFULL
storage device
The caller does not have sufficient permissions for writing to this stream
STG_E_ACCESSDENIED
object.
STG_E_CANTSAVE
Data cannot be written for reasons other than no access or space.
One of the pointer values is invalid. The PIDStream parameter must contain
STG_E_INVALIDPOINTER
a valid pointer even if cb is zero.
STG_E_WRITEFAULT
The write operation was not completed due to a disk error
Parameters
PIDStream
A pointer to the stream to write to.
12
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
Implementing a PID Algorithm
This section describes how the implement your own algorithm.
Development Environment
The algorithms that are shipped with the PID Controller were built with the following tools and
environment:

Microsoft Windows NT 4.0 (Service Pack 3).

Microsoft Visual C++ (Visual Studio Service Pack 3).

Microsoft Active Template Library (Version 2.2).

Microsoft Platfrm SDK (Jan 98 Release).
Sample Algorithm
In this section we will go through the steps required to implement a sample algorithm.
Create an ATL DLL Server
The first thing to do is to create a new ATL DLL Server. Start Visual C++ and select the File|New
menu command. You will be presented with the following dialog box. Select to the Projects Tab
click on ATL COM AppWizard. We will call our new project PIDSample. Type PIDSample in the
project name edit box, choose a location for you project and click on OK.
13
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
The ATL COM AppWizard will present the following dialog. Select the Dynamic link Library
(DLL) Radion button and click the Allow merging of proxy/stub code check box on.
Click on the Finish button and then click OK to complete the operation. This has created a
skeleton DLL for you. This DLL will be the COM server for the algorithm component.
The next step is to create a COM component that will function as a PID algorithm. We will build a
simple object that supports the IPIDAlgorithm interface. Property page support will be added later.
Click on the New ATL Object button from the ATL toolbar.
Add a Simple Object
You will be presented with the following dialog box. Select the Objects entry from the left-hand
side and then select the Simple Object entry from the right hand side.
14
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
Click on the Next button. You will be presented with the following dialog box. Enter
SamplePIDAlgorithm into the Short Name edit field. Leave all the other settings as they are and
click on the OK button.
The Wizard adds some new files to your project. These files define and implemet your new COM
algorithm component.
SamplePIDAlgorithm.h : Declaration of the CSamplePIDAlgorithm
SamplePIDAlgorithm.cpp : Implementation of CSamplePIDAlgorithm
SamplePIDAlgorithm.rgs – Registry entries for the new object
PIDSample.idl will be changed to include entries for the ISamplePIDAlgorithm interface and the
SamplePIDAlgorithm coclass.
At this stage you can compile your DLL to see if everything went OK.
Add Support for IPIDAlgorithm
Next you must add support for the IPIDAlgorithm to the SamplePIDAlgorithm component. You
will need to add the IDL definition for this interface into your PIDSample.idl as follows (additions
are in bold):
import "oaidl.idl";
import "ocidl.idl";
[
object,
uuid(3A35D45A-31C7-11D2-838C-006097C787F8),
dual,
helpstring("ISamplePIDAlgorithm Interface"),
pointer_default(unique)
]
15
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
interface ISamplePIDAlgorithm : IDispatch
{
};
typedef enum DeadZoneType
{
Positive,
Negative,
PositiveAndNegative
}
DEADZONETYPE;
[
object,
uuid(B3F2A2E4-E4F1-11d1-831B-006097C787F8),
pointer_default(unique)
]
interface IPIDAlgorithm : IUnknown
{
HRESULT SetPIDParameters(
[in] float SetPoint,
[in] float SteadyState,
[in] float Kp,
[in] float Ki,
[in] float Kd,
[in] float SampleRate,
[in] BOOL InputHiLimitsOn,
[in] BOOL InputLoLimitsOn,
[in] float InputLoLimit,
[in] float InputHighLimit,
[in] float Filter,
[in] float OutputLoLimit,
[in] float OutputHiLimit,
[in] float ROC,
[in] BOOL DeadZoneOn,
[in] float DeadZoneValue,
[in] DEADZONETYPE DeadZoneType,
[in] BOOL bPIDInvertedOutput);
HRESULT CalculatePID([in] float InputValue,
[out,retval] float *OutputValue);
HRESULT StartPIDAutomatic([in] float InputValue,
[in] float OutputValue);
HRESULT LoadExtraPIDParamaters([in] IStream *PIDStream);
HRESULT SaveExtraPIDParamaters([in] IStream *PIDStream);
};
[
16
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
uuid(3A35D44A-31C7-11D2-838C-006097C787F8),
version(1.0),
helpstring("PIDSample 1.0 Type Library")
]
library PIDSAMPLELib
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
[
uuid(3A35D45B-31C7-11D2-838C-006097C787F8),
helpstring("SamplePIDAlgorithm Class")
]
coclass SamplePIDAlgorithm
{
[default] interface ISamplePIDAlgorithm;
interface IPIDAlgorithm
};
};
Implement IPIDAlgorithm Interface
The next thing to do is to add code to implement the IPIDAlgorithm interface in the
CSamplePIDAlgorithm class. To do this, make the class inherit directly from IPIDAlgorithm,
add an interface entry into the classes COM Map, declare each method of the interface in the
class and then implement them. The following code shows the CSamplePIDAlgorithm class with
the required changes in bold:
// SamplePIDAlgorithm.h : Declaration of the CSamplePIDAlgorithm
#ifndef __SAMPLEPIDALGORITHM_H_
#define __SAMPLEPIDALGORITHM_H_
#include "resource.h"
// main symbols
///////////////////////////////////////////////////////////////////////
//////
// CSamplePIDAlgorithm
class ATL_NO_VTABLE CSamplePIDAlgorithm :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CSamplePIDAlgorithm,
&CLSID_SamplePIDAlgorithm>,
public IDispatchImpl<ISamplePIDAlgorithm,
&IID_ISamplePIDAlgorithm,
&LIBID_PIDSAMPLELib>,
public IPIDAlgorithm
{
public:
CSamplePIDAlgorithm()
{
}
17
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
DECLARE_REGISTRY_RESOURCEID(IDR_SAMPLEPIDALGORITHM)
BEGIN_COM_MAP(CSamplePIDAlgorithm)
COM_INTERFACE_ENTRY(ISamplePIDAlgorithm)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IPIDAlgorithm)
END_COM_MAP()
//IPIDPositionAlgorithm Implementation
public:
STDMETHOD(SetPIDParameters)(float fSetPoint,
float fSteadyState,
float fKp,
float fKi,
float fKd,
float fSampleRate,
BOOL bInputHiLimitsOn,
BOOL bInputLoLimitsOn,
float fInputLoLimit,
float fInputHighLimit,
float fFilter,
float fOutputLoLimit,
float fOutputHiLimit,
float fROC,
BOOL bDeadZoneOn,
float fDeadZone,
DEADZONETYPE DeadZoneType,
BOOL bPIDInvertedOutput);
STDMETHOD(CalculatePID)(float fInputValue, float *pfOutputValue);
STDMETHOD(StartPIDAutomatic)(float fInputValue,
float fOutputValue);
STDMETHOD(LoadExtraPIDParamaters)(IStream *PIDStream);
STDMETHOD(SaveExtraPIDParamaters)(IStream *PIDStream);
// ISamplePIDAlgorithm
public:
};
#endif //__SAMPLEPIDALGORITHM_H_
18
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
Change the SamplePIDAlgorithm.cpp file to include the implementation of these methods as
follows:
// SamplePIDAlgorithm.cpp : Implementation of CSamplePIDAlgorithm
STDMETHODIMP CSamplePIDAlgorithm::SetPIDParameters(
float fSetPoint,
float fSteadyState,
float fKp,
float fKi,
float fKd,
float fSampleRate,
BOOL bInputHiLimitsOn,
BOOL bInputLoLimitsOn,
float fInputLoLimit,
float fInputHighLimit,
float fFilter,
float fOutputLoLimit,
float fOutputHiLimit,
float fROC,
BOOL bDeadZoneOn,
float fDeadZone,
DEADZONETYPE DeadZoneType,
BOOL bPIDInvertedOutput)
{
return S_OK;
}
STDMETHODIMP CSamplePIDAlgorithm::CalculatePID(
float fInputValue,
float *pfOutputValue)
{
return S_FALSE;
}
STDMETHODIMP CSamplePIDAlgorithm::StartPIDAutomatic(float fInputValue,
float fOutputValue)
{
return S_OK;
}
STDMETHODIMP CSamplePIDAlgorithm::LoadExtraPIDParamaters(
IStream *PIDStream)
{
return S_OK;
}
STDMETHODIMP CSamplePIDAlgorithm::SaveExtraPIDParamaters(
IStream *PIDStream)
{
return S_OK;
}
19
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
The above methods are in skeletal form and simply return HRESULTS that will not cause an error
in the PID runtime. It is up to you how you implement your algorithm. You can add as many
member variables or methods as you want.
Recompile again your DLL to see if everything went OK.
Add Non-Standard Properties
This section is optional.
At this stage it would be appropriate to add any non-standard properties or methods to the
ISamplePIDAlgorithm interface. Adding properties and methods can be done simply by going to
the class view for the propject, highlighting the ISamplePIDAlgorithm entry, right-mouse clicking
and selecting the Add Property… or Add Method… option. In this sample we will add a property
of type Long called TestProp. The following dialog is presented when you choose Add
Property. Enter the type and name of the property.
Click on the OK button. This will add entries for the property to the .idl and header and cpp files.
To implement the property we must add a member variable for it to act as a placeholder and then
implement the get and set methods. Add the following changes to the header file
SamplePIDAlgorithm.h:
20
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
CSamplePIDAlgorithm()
{
m_lTestProp = 0;
}
public:
long m_lTestProp;
// ISamplePIDAlgorithm
STDMETHOD(get_TestProp)(/*[out, retval]*/ long *pVal);
STDMETHOD(put_TestProp)(/*[in]*/ long newVal);
The file SamplePIDAlgorithm.cpp will be changed to hold the implementation for the property.
Implement the property as follows:
STDMETHODIMP CSamplePIDAlgorithm::get_TestProp(long * pVal)
{
if ( !pVal )
{
return E_POINTER;
}
*pVal = m_lTestProp;
return S_OK;
}
STDMETHODIMP CSamplePIDAlgorithm::put_TestProp(long newVal)
{
m_lTestProp = newVal;
return S_OK;
}
21
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
Add the Algorithm to CATID_PIDAlgorithm Component Category
We now have a PID algorithm component that implements its own non-standard properties on the
IPIDAmpleAlgorithm interface. To make this component visible to the PID system it must register
itself on the system as being an object that belongs to the CATID_PIDAlgorithm component
category. You can do this by adding the following entry into the object .rgs file
SamplePIDAlgorithm.rgs. Your CLSID value will be different than the one below. The name
‘SamplePIDAlgorithm Class’ will be the name visible to the user. You can change this here if you
wish by doing a replace command.
HKCR
{
SamplePIDAlgorithm.SamplePIDAlgorithm.1 = s 'SamplePIDAlgorithm
Class'
{
CLSID = s '{3A35D45B-31C7-11D2-838C-006097C787F8}'
}
SamplePIDAlgorithm.SamplePIDAlgorithm = s 'SamplePIDAlgorithm
Class'
{
CurVer = s 'SamplePIDAlgorithm.SamplePIDAlgorithm.1'
}
NoRemove CLSID
{
ForceRemove {3A35D45B-31C7-11D2-838C-006097C787F8} = s
'SamplePIDAlgorithm Class'
{
ProgID = s 'SamplePIDAlgorithm.SamplePIDAlgorithm.1'
VersionIndependentProgID = s
'SamplePIDAlgorithm.SamplePIDAlgorithm'
'Implemented Categories'
{
ForceRemove '{5D8839D5-EFF2-11D1-8329006097C787F8}'
}
ForceRemove 'Programmable'
InprocServer32 = s '%MODULE%'
{
val ThreadingModel = s 'Apartment'
}
}
}
}
Test the Algorithm
Recompile your DLL. When the build finishes the component will be registered. At this stage you
can launch the PID Configuration and Monitoring application. Configure a loop and see if you can
select the sample algorithm in the output properties dialog.
22
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
Add Property Page Support
This section is optional.
In this section we add a property page to the algorithm so that its non-standard properties can be
editited from the PID Configuration and monitoring application.
Click on the New ATL Object button from the ATL toolbar. Select the Controls entry from the
left-hand side and then select the Property Page entry from the right hand side. Click on the
Next button. You will be presented with the following dialog:
Enter PIDSamplePropPage in the short name edit field. Leave all other settings as they are and
click OK. This will create a property page class and add a dialog resource to your project.
PIDSamplePropPage.h : Declaration of the CPIDSamplePropPage
PIDSamplePropPage.cpp : Implementation of CPIDSamplePropPage
IDD_PIDSAMPLEPROPPAGE – Dialog Resourec
We will now add an edit box to the property page for editing the TestProp property. Go to the
resource editor and add an edit box to the dialog IDD_PIDSAMPLEPROPPAGE. Set the ID of the
edit box to be IDC_EDIT_TESTPROP.
The following code changes are required.
Add member variable for TestProp edit field.
Override initialization of property page to get TestProp value to edit box.
Add command handlers for the TestProp edit field (EN_KILLFOCUS, EN_CHANGE).
Override button clicks of property page to get TestProp value from edit box to component.
The following code (changes in bold) shows how to do this. Implementing property pages in ATL
is beyond the scope of this document.
23
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
// PIDSamplePropPage.h : Declaration of the CPIDSamplePropPage
#ifndef __PIDSAMPLEPROPPAGE_H_
#define __PIDSAMPLEPROPPAGE_H_
#include "resource.h"
// main symbols
EXTERN_C const CLSID CLSID_PIDSamplePropPage;
///////////////////////////////////////////////////////////////////////
//////
// CPIDSamplePropPage
class ATL_NO_VTABLE CPIDSamplePropPage :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CPIDSamplePropPage, &CLSID_PIDSamplePropPage>,
public IPropertyPageImpl<CPIDSamplePropPage>,
public CDialogImpl<CPIDSamplePropPage>
{
public:
CPIDSamplePropPage()
{
m_dwTitleID = IDS_TITLEPIDSamplePropPage;
m_dwHelpFileID = IDS_HELPFILEPIDSamplePropPage;
m_dwDocStringID = IDS_DOCSTRINGPIDSamplePropPage;
m_lTestProp = 0;
}
enum {IDD = IDD_PIDSAMPLEPROPPAGE};
long m_lTestProp;
DECLARE_REGISTRY_RESOURCEID(IDR_PIDSAMPLEPROPPAGE)
BEGIN_COM_MAP(CPIDSamplePropPage)
COM_INTERFACE_ENTRY_IMPL(IPropertyPage)
END_COM_MAP()
BEGIN_MSG_MAP(CPIDSamplePropPage)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_HANDLER(IDC_EDIT_TESTPROP, EN_CHANGE, OnTestPropChange)
COMMAND_HANDLER(IDC_EDIT_TESTPROP, EN_KILLFOCUS, OnTestPropKillFocus)
CHAIN_MSG_MAP(IPropertyPageImpl<CPIDSamplePropPage>)
END_MSG_MAP()
24
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
public:
// Handles the WM_INITDIALOG messages
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam,
LPARAM lParam, BOOL& bHandled)
{
// Set initial state of controls
for (UINT i = 0; i < m_nObjects; i++)
{
CComQIPtr<ISamplePIDAlgorithm,
&IID_ISamplePIDAlgorithm>
pSPIPA(m_ppUnk[i]);
if (pSPIPA != NULL)
{
pSPIPA->get_TestProp(&m_lTestProp);
}
}
// Set TestProp edit control
SetDlgItemInt( IDC_EDIT_TESTPROP, m_lTestProp, TRUE );
SetDirty(FALSE);
return 0;
}
// Edit Field Change Handler
LRESULT OnTestPropChange(WORD wNotify, WORD wID,
HWND hWnd, BOOL& bHandled)
{
SetDirty(TRUE);
return 0;
}
// Edit Field KillFocus Handler
LRESULT OnTestPropKillFocus(WORD wNotify, WORD wID,
HWND hWnd, BOOL& bHandled)
{
long lTestProp;
BOOL bResult;
lTestProp = GetDlgItemInt( wID, &bResult, TRUE );
m_lTestProp = lTestProp;
SetDlgItemInt( wID, lTestProp, TRUE );
return 0;
}
25
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
// IPropertyPage Implementation
STDMETHOD(Apply)(void)
{
for (UINT i = 0; i < m_nObjects; i++)
{
CComQIPtr<ISamplePIDAlgorithm,
&IID_ISamplePIDAlgorithm>
pSPIPA(m_ppUnk[i]);
if ( pSPIPA != NULL )
{
pSPIPA->put_TestProp(m_lTestProp);
}
}
m_bDirty = FALSE;
return S_OK;
}
//--------------------------------------------------------------// Initializes a property page and provides the property page
// object with the IPropertyPageSite interface through which the
// property page communicates with the property frame.
//
// Overridden to fix a bug in the ATL implementation.
//--------------------------------------------------------------HRESULT STDMETHODCALLTYPE SetPageSite(
IPropertyPageSite *pPageSite)
{
if (!pPageSite && m_pPageSite)
{
m_pPageSite->Release();
// Next line added to fix the problem
m_pPageSite = NULL;
return S_OK;
}
if (!pPageSite && !m_pPageSite)
{
return S_OK;
}
if (pPageSite && m_pPageSite)
{
return E_UNEXPECTED;
}
m_pPageSite = pPageSite;
m_pPageSite->AddRef();
return S_OK;
}
26
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
//--------------------------------------------------------------// Flags the property page's state as changed or unchanged,
// depending on the value of bDirty. If necessary, SetDirty
// informs the frame that the property page has changed.
//
// Overridden to fix a bug in the ATL implementation.
//--------------------------------------------------------------void SetDirty(BOOL bDirty)
{
if (bDirty)
{
m_pPageSite-> OnStatusChange(
PROPPAGESTATUS_DIRTY|PROPPAGESTATUS_VALIDATE);
}
m_bDirty = bDirty;
}
};
#endif //__PIDSAMPLEPROPPAGE_H_
// PIDSamplePropPage.cpp : Implementation of CPIDSamplePropPage
#include "stdafx.h"
#include "PIDSample.h"
#include "PIDSamplePropPage.h"
The above code implemented the property page. We must change the algorithm component to
support property pages. ATL normally only supports property pages in ActiveX Controls. However
with a few changes we can easily add this support to a simple COM object.
To do this, make the CSamplePIDAlgorithm class inherit from ISpecifyPropertyPagesImpl
(ATL’s implemenation of ISpecifyPropertyPages), add an interface entry into the classes COM
Map, declare the one method of the interface in the class and then implement it. We also have to
implement a PROPERTY_MAP in the class. One of the uses of an ATL property map is to
indicate what property pages an object supports. The implementation of the
ISpecifyPropertyPages_GetPages is copied directly from ATL.
The following code shows the CSamplePIDAlgorithm class with the required changes in bold:
// SamplePIDAlgorithm.h : Declaration of the CSamplePIDAlgorithm
class ATL_NO_VTABLE CSamplePIDAlgorithm :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CSamplePIDAlgorithm,
&CLSID_SamplePIDAlgorithm>,
public IDispatchImpl<ISamplePIDAlgorithm,
&IID_ISamplePIDAlgorithm, &LIBID_PIDSAMPLELib>,
public IPIDAlgorithm,
public ISpecifyPropertyPagesImpl<CSamplePIDAlgorithm>
{
27
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
. . .
BEGIN_PROPERTY_MAP(CSamplePIDAlgorithm)
PROP_PAGE(CLSID_PIDSamplePropPage)
END_PROPERTY_MAP()
// ISpecifyPropertyPages
public:
HRESULT ISpecifyPropertyPages_GetPages(
CAUUID* pPages,
ATL_PROPMAP_ENTRY* pMap);
. . .
. . .
}
// SamplePIDAlgorithm.cpp : Implementation of CSamplePIDAlgorithm
. . .
HRESULT CSamplePIDAlgorithm::ISpecifyPropertyPages_GetPages(
CAUUID* pPages,
ATL_PROPMAP_ENTRY* pMap)
{
_ASSERTE(pMap != NULL);
int nCnt = 0;
// Get count of unique pages
for(int i = 0; pMap[i].pclsidPropPage != NULL; i++)
{
if (!InlineIsEqualGUID(
*pMap[i].pclsidPropPage,
CLSID_NULL))
nCnt++;
}
pPages->pElems = NULL;
pPages->pElems = (GUID*) CoTaskMemAlloc(sizeof(CLSID)*nCnt);
if (pPages->pElems == NULL)
return E_OUTOFMEMORY;
nCnt = 0;
for(i = 0; pMap[i].pclsidPropPage != NULL; i++)
{
if (!InlineIsEqualGUID(
*pMap[i].pclsidPropPage,
CLSID_NULL))
{
BOOL bMatch = FALSE;
for (int j=0;j<nCnt;j++)
{
if (InlineIsEqualGUID(
*(pMap[i].pclsidPropPage),
pPages->pElems[j]))
{
bMatch = TRUE;
break;
}
28
Document1
 Measuresoft Development Ltd.
Version
Implementing PID Control Algorithms
}
if (!bMatch)
pPages->pElems[nCnt++] =
*pMap[i].pclsidPropPage;
}
}
pPages->cElems = nCnt;
return S_OK;
}
Test the Algorithm Property Page
Recompile your DLL. When the build finishes the component will be registered. At this stage you
can launch the PID Configuration and Monitoring application. Configure a loop and see if you can
select the sample algorithm in the output properties dialog. Then select the Edit|Extra Algorithm
Properties… command. The algorithms property page should be displayed allowing you to
change the TestProp property.
You can add as many property pages to the component as you wish.
Conclusion
It is hoped that this document has clearly explained how PID Control Algorithms interact with the
Controller. The sample algorithm, while not very functional, can be built upon to implement a
useful PID Control Algorithm. If you have any problems contact you supplier for technical support.
29
Document1
 Measuresoft Development Ltd.
Version
Download