5.3. Automatically Change SP Value - auto_control

This part of the program gives the PID Emulator the ability to run either manually or automatically, shifting the set point at random every specified number seconds.

[Note]

Two functions (go_auto and sp_changed) were added to this part of the program since this tutorial was written, and have not yet been documented. Their purpose is to allow the program to switch from manual to automatic mode when there has been no manual activity for 60 seconds.

   /********************************************************
    *            Automatically Change SP Value             *
    ********************************************************/
   
   /* Initialize a global variable for the automatic timer. */
   AUTO_TIMER = nil;
   AUTO_RESET_TIMER = nil;
   
   /* Register points, exceptions, and echos with the DataHub.
    * The FREQ_001 variable holds the delay for automatic change of SP. */
   AUTO_001 = register_point(#AUTO_001);
   add_exception_function(#AUTO_001, #(AUTO_TIMER = auto_control(FREQ_001)));
   add_echo_function(#AUTO_001, #(AUTO_TIMER = auto_control(FREQ_001)));
   

The on/off value is registered (using the Gamma register_point function) as a datahub point (AUTO_001), so that it can be accessed by other programs in the Cogent Tools Demo. The point gets its functionality with the add_exception_function function, which calls a specified function whenever its datahub point changes value. Here, for example, the auto_control function will be evaluated whenever the AUTO_001 datahub point changes value. The datahub point name and the auto_control function are quoted with the # quote operator to protect them from evaluation while the parser reads the code.

We also need to register the variable FREQ_001 as a datahub point. This variable holds the value corresponding to the frequency of change (number of seconds) when automatic mode is on. We write a default value of 8 if the current value is outside the desired range of 1 to 20, and then apply the add_exception_function as above.

   FREQ_001 = register_point(#FREQ_001); 
   if (FREQ_001 < 1 || FREQ_001 > 20)
        write_point(#FREQ_001, 8);    
   add_exception_function(#FREQ_001, #(AUTO_TIMER = auto_control(FREQ_001)));
   
   function round2(x)
   {
           floor (x * 100) / 100;
   }
   

The auto_control function starts and stops a timer (auto_timer) that changes the set point (SP_001) value to random numbers between 0 and 100, at regularly timed intervals.

   /*--------------------------------------------------------------------
    * Function:    auto_control
    * Returns:     a timer number
    * Description: Sets a timer to change the value of SP at a specified
    *              frequncy.
    *------------------------------------------------------------------*/
   function auto_control(freq)
   {
     if (AUTO_001 != 0)       
       {
         /* Start a timer to move SP to random settings. */
         if (AUTO_TIMER == nil)
           {
             if (45 < SP_001 && SP_001 < 55)
               write_point(#SP_001, 80);
             else
               write_point(#SP_001, 50);
             AUTO_TIMER = every(eval(freq),
                                `write_point(#SP_001, round2(random() * 100)));

In this line we set the timer with the every function. Every freq seconds the SP_001 datahub point will be changed to a random number between 0 and 100, using the Gamma random function. With that line alone, however, there would be a pause before anything changed. To give the user the feeling that "something happened" when the Automatic mode button is pressed in the Monitor interface, we force a change in the value of the SP_001 datahub point before setting the timer. If the value is at or close to 50, we move it to 80, otherwise we move it to 50. Multiple clicks will cause the value to toggle between 50 and 80.

           }
         else
           {
             /* Cancel an existing timer. */
             cancel(AUTO_TIMER);
             AUTO_TIMER = nil;
             auto_control(FREQ_001);
           }
       }

The Gamma cancel function takes a timer number for its argument, and cancels the associated timer. If the Automatic mode button is pressed On in the Monitor, we have to check first to see if AUTO_TIMER has a value, and if so, cancel the timer. Otherwise we would get two or more timers firing, causing the SP_001 value to change more frequently than we want.

Of course, we also want to cancel the timer when the Automatic mode button is pressed Off.

     else                          
       {
         /* Cancel the timer if the AUTO_001 button is not pressed. */
         if (AUTO_TIMER != nil)
           {
             cancel(AUTO_TIMER);
             AUTO_TIMER = nil;
           }
         if (AUTO_RESET_TIMER)
           cancel (AUTO_RESET_TIMER);
         AUTO_RESET_TIMER = after (60, #go_auto());
       }
     AUTO_TIMER;
   }
   
   /* Automatically revert to automatic setpoint change mode */
   function go_auto ()
   {
     if (AUTO_001 == 0)
       write_point (#AUTO_001, 1);
   }
   
   /* When the setpoint changes and the automatic setpoint mode is off,
      it means that a user has changed the setpoint manually, so reset
      the timer that throws us back into automatic setpoint mode for
      another minute. */
   function sp_changed ()
   {
     if (AUTO_001 == 0)
       {
         if (AUTO_RESET_TIMER)
           cancel (AUTO_RESET_TIMER);
         AUTO_RESET_TIMER = after (60, #go_auto());
       }
   }
   
   add_exception_function (#SP_001, #sp_changed());