Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug in ServoDyn When Controlling Yaw from DLL #25

Closed
jjonkman opened this issue May 8, 2017 · 6 comments
Closed

Bug in ServoDyn When Controlling Yaw from DLL #25

jjonkman opened this issue May 8, 2017 · 6 comments

Comments

@jjonkman
Copy link
Collaborator

jjonkman commented May 8, 2017

In routine CalculateStandardYaw of ServoDyn.f90, the yaw angle (position) command when the yaw rate is commanded from a Bladed-style DLL is calculated by adding an increment of YawRateCom*DT to the current yaw angle. However, the yaw angle command should be defined as the integral of the yaw rate command, regardless of the current yaw angle (i.e. the yaw angle command must become a state of ServoDyn). As it is currently implemented (incorrectly), when the yaw rate commanded from a Bladed-style DLL is zero, the yaw angle is commanded to be current yaw angle, effectively eliminating the yaw spring stiffness, yielding large yaw errors. I would not use yaw control from Bladed-style DLL controllers until this bug is fixed.

See the following forum topic for more information: https://wind.nrel.gov/forum/wind/viewtopic.php?f=30&t=1844&p=9256.

@spmulders
Copy link

spmulders commented Oct 16, 2017

I created a workaround/solution for this problem. Replace the CalculateStandardYaw subroutine in the .\Source\dependencies\ServoDyn\ ServoDyn.f90-file, and recompile FAST.

SUBROUTINE CalculateStandardYaw(t, u, p, m, YawPosCom, YawRateCom, ErrStat, ErrMsg)

REAL(DbKi), INTENT(IN ) :: t !< Current simulation time in seconds
TYPE(SrvD_InputType), INTENT(IN ) :: u !< Inputs at t
TYPE(SrvD_ParameterType), INTENT(IN ) :: p !< Parameters
TYPE(SrvD_MiscVarType), INTENT(INOUT) :: m !< Misc (optimization) variables
REAL(ReKi), INTENT( OUT) :: YawPosCom !< Commanded yaw angle from user-defined routines, rad.
REAL(ReKi), INTENT( OUT) :: YawRateCom !< Commanded yaw rate from user-defined routines, rad/s.
INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation
CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None

REAL(4), SAVE :: YawPosComInt !< Internal variable that integrates the commanded yaw rate and passes it to YawPosCom

ErrStat = ErrID_None
ErrMsg = ""

!...................................................................
! Calculate standard yaw position and rate commands:
!...................................................................

IF ( t >= p%TYCOn .AND. p%YCMode /= ControlMode_NONE ) THEN ! Time now to enable active yaw control.

  SELECT CASE ( p%YCMode )  ! Which yaw control mode are we using? (we already took care of ControlMode_None)
        
     CASE ( ControlMode_SIMPLE )            ! Simple ... BJJ: THIS will be NEW

        
     CASE ( ControlMode_USER )              ! User-defined from routine UserYawCont().
     
        CALL UserYawCont ( u%Yaw, u%YawRate, u%WindDir, u%YawErr, p%NumBl, t, p%DT, p%RootName, YawPosCom, YawRateCom )         

     CASE ( ControlMode_EXTERN )              ! User-defined from Simulink or LabVIEW

        YawPosCom  = u%ExternalYawPosCom
        YawRateCom = u%ExternalYawRateCom

     CASE ( ControlMode_DLL )                                ! User-defined yaw control from Bladed-style DLL
        
        YawPosComInt =           YawPosComInt + m%dll_data%YawRateCom*p%DT
        YawPosCom  =             YawPosComInt !bjj: was this: LastYawPosCom + YawRateCom*( ZTime - LastTime )
        YawRateCom =             m%dll_data%YawRateCom
        
                    
  END SELECT

ELSE ! Do not control yaw, maintain initial (neutral) yaw angles

     YawPosCom  = p%YawNeut
     YawRateCom = 0.0_ReKi

ENDIF

END SUBROUTINE CalculateStandardYaw

Regards,
Sebastiaan Mulders
PhD candidate - Delft University of Technology

@jjonkman
Copy link
Collaborator Author

Dear Sabastiaan,

Thanks for updated code. However, I see three problems that will need to be fixed for the general solution:

  1. According to the NWTC Programmer's Handbook (https://nwtc.nrel.gov/system/files/ProgrammingHandbook_Mod20130717.pdf), you should not use the SAVE attribute for variables within a FAST module. Instead, YawPosComInt must become a state of the ServoDyn module (included in the FAST Registry, passed as a subroutine argument, etc.)
  2. YawPosComInt needs to be initialized at simulation initialization i.e. within SrvD_Init. I would guess a good initial value would be the initial yaw angle or YawNeut.
  3. Routine CalculateStandardYaw is called both within routines SrvD_UpdateStates and SrvD_CalcOutput. Because YawPosComInt must become a state of ServoDyn, its value can only be set within Srv_UpdateStates.

I hope that helps.

Best regards,

@spmulders
Copy link

Dear Jason,

Thank you very much for your suggestions. I will implement these changes later, and create a pull request accordingly.

Best regards,
Sebastiaan Mulders

@rafmudaf
Copy link
Collaborator

rafmudaf commented Nov 6, 2017

@sebastiaanmuld,

Thank you for your efforts in isolating and finding a solution for the ServoDyn bug.

A couple of weeks ago we launched a new workflow for OpenFAST contribution which aims to support a larger magnitude of community driven development than we have in the past. To that end, we have established a basic regression test and unit test system to maintain confidence and stability in OpenFAST. Being the first to propose a bug fix since our latest release, you are in a lucky position to try it all out!

The procedure for bug fixes is as follows:

  1. File a bug report in GitHub issues (DONE: issue Bug in ServoDyn When Controlling Yaw from DLL #25)
  2. Develop a unit test which isolates the bug and document the failure
  3. Implement the bug fix on a bugfix/issue## branch on your fork of OpenFAST
  4. Document the unit test which no longer fails
  5. Document the full regression test suite passing or note any failing cases
  6. Issue a pull request referencing the GitHub issue and including the test documentation

For reference, the test specific documentation is at http://openfast.readthedocs.io/en/latest/source/testing/index.html, and the git usage is described at
http://openfast.readthedocs.io/en/latest/source/dev/github_workflow.html.

I understand that this is a heavy lift for a simple bug fix, especially since some of the infrastructure for unit testing does not yet exist for ServoDyn. I am happy to support by working with you to establish the ServoDyn testing infrastructure which you can then build on to implement the unit test and bug fix more easily.

Please let me know if you'd like to talk about this in more detail or work together to develop a plan for implementing the bug fix.

Thanks again for your contribution to OpenFAST.

Rafael M Mudafort

@spmulders
Copy link

Dear Rafael,

Thanks you very much for your e-mail! I would like to work with you on solving this bug. I think it is best for me to first get more familiar with the NWTC Programmer’s Handbook as Jason suggested. I will contact you in 1-2 weeks once I have done this, and then we can work out a plan for implementing the bugfix and setting up the ServoDyn testing infrastructure.

Best regards,
Sebastiaan Mulders

andrew-platt added a commit to andrew-platt/openfast that referenced this issue Jun 5, 2020
andrew-platt added a commit to andrew-platt/openfast that referenced this issue Jun 5, 2020
rafmudaf pushed a commit that referenced this issue Jun 5, 2020
* SrvD: add variable for integrated yaw commands

This fixes bug report #25

* SrvD: fix previous commit so correction steps work correctly
@andrew-platt
Copy link
Collaborator

Closed with PR #456

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants