/*

 COPYRIGHT (C) 2004 BY Cerebellum Automation, SAS.

 ************************************************************************
 *                                                                      *
 *     The information set forth in this document is the property       *
 *     of Cerebellum Automation, SAS. and is to be held in trust and    *
 *     confidence.  Publication, duplication, disclosure, or use        *
 *     for any purpose not expressly authorized by Cerebellum Auto-     *
 *     mation in writing is prohibited.                                 *
 *                                                                      *
 *     The information in this document is subject to change            *
 *     without notice and should not be construed as a commitment       *
 *     by Cerebellum Automation.                                        *
 *                                                                      *
 *     Cerebellum Automation makes no warranty as to the suitability    *
 *     of this material for use by the recipient, and assumes no        *
 *     responsibility for any consequences resulting from such use.     *
 *                                                                      *
 ************************************************************************


 DESCRIPTION:
    2-axis collating unit controller.

   $Log$
    

*/


#include <math.h>
#include <stdio.h>
#include <string.h>
#include "cde.h"

// IO Parameters.

#define IN_PART          (IOBUS_LOCAL + 10)  
// Whether a part as fallen into the pocket or not
#define IN_CAL1          (IOBUS_LOCAL
+ 11)  // Used to calibrate the collating unit
#define IN_CAL2          (IOBUS_LOCAL
+ 12)  // Used to calibrate the collating unit
#define IN_USER_OK       (IOBUS_LOCAL
+ 13)  // The user needs to press this button to power up the system
#define IN_UNLOADED      (IOBUS_LOCAL
+ 14)  // Used by the top loader to tell us that it unloaded the collating unit
#define OUT_READY_UNLOAD (IOBUS_LOCAL
+ 10)  // Tell the top loader that the collating unit is ready for unload
#define OUT_ERROR        (IOBUS_LOCAL
+ 11)  // Turns the error light ON

// Collating Unit Parameters.

const UInt32 nbPocket = 10;     // Number of Pockets in one collating train
const UInt32 pocketSize = 50;   // The size of one pocket (distance between 2 pockets) in mm
const double loadPos = 10;      // Position where the first pocket needs to stop to be loaded, in mm
const double unloadPos = 1500;  // Position where the first pocket needs to stop to be unloaded, in mm
const double cycleLength = 3500;// Length of a complete cycle (from loadPos to loadPos) in mm.
                                 // This is used as the roll-over value
const double maxVel = 2.0;      // limit the velocity at 2 m/s


ANY_VAR checkStatus
= TRUE, run_appli = FALSE;
BOOL loading[
3];                
// Flag used to communicate between the 2 trains


/********************************************************
*
* ABSTRACT:    Driver for each collating train.
*      It is a requirement that this task is started when the 2 trains are in
*      their starting position.
*
*/

void CollatingDriver(UInt32 mtr)
{
   
UInt32 otherMtr, pocket;

    
if (mtr == 1)
        otherMtr
= 2;
   
else
       otherMtr
= 1;

  
CA_SetMaxVel(mtr, maxVel);                      
// Use full speed
   
    
while (run_appli) {

       
// Wait until other motor is loaded
       
while (loading[otherMtr]) CA_Wait(.01);

       
// Load first train
       loading[mtr]
= TRUE;
        
for (pocket = 1; pocket <= nbPocket; pocket++) {
            
CA_WaitSig(IN_PART, SIG_HIGH, NO_TIMEOUT);
            
CA_MoveAbs(mtr, loadPos
+ pocket * pocketSize, FALSE);
        
}
       
        
// Disengage e-gearing for second train
       
CA_GearOut(otherMtr);
       loading[mtr]
= FALSE;
        
        
// Move first train to unload position
       
CA_MoveAbs(mtr, unloadPos, FALSE);
        
CA_WaitEndMotion(mtr, NO_TIMEOUT);

        
// Signal to the robot that we're ready to unload
       
CA_WriteDIO(OUT_READY_UNLOAD, SIG_HIGH);

        
// Wait until the robot has unloaded the collating unit
       
CA_WaitSig(IN_UNLOADED, SIG_LOW_TO_HIGH, NO_TIMEOUT);
       
CA_WriteDIO(OUT_READY_UNLOAD, SIG_HIGH);    
// reset flag

       
// Adjust the position to keep within acceptable limits
       
CA_AdjustMotorPos(mtr, -cycleLength);
       
        
// Engage e-gearing for first train
       
CA_GearInAbs(mtr, otherMtr, - nbPocket * pocketSize, 1.0);
       
        
// Move first train around U-Turn at slower speed
       
CA_SetMaxVel(mtr, maxVel * 0.5);            // limit speed to 50%
       
while (CA_ReadMotorPos(mtr) < (nbPocket * pocketSize))
            
CA_Wait(
0.1);
       
        
CA_SetMaxVel(mtr, maxVel);                  
// Use full speed
       
    
}
}


/* Initialise() *******************************************************
*
* ABSTRACT:    routine run before the main tasks are started.
*
*/



void Initialise()
{
   ANY_VAR mtr, stt;
    
    
// Do some initialization.
   
CA_WriteDIO(OUT_READY_UNLOAD, LOW);     // Tell the robot that we're not ready
   
    
if (CA_ReadDIO(IN_PART) == HIGH) {     // Check whether a part is already in the system
       
printf("Error! Please remove part from system\n");
       
CA_WriteDIO(OUT_READY_UNLOAD, HIGH);
    
}

   
// Tell the system which axes are used.
   
for(mtr = 1; mtr <= 2; mtr++) {
       stt
= CA_ConfigureAxis(mtr, TRUE);
        
if (stt<0) {
            
printf("Error setting up axis %f: %f", mtr, stt);
        
}
   
}
}

Int32 Calibrate()
{
   ANY_VAR calOffset1
= 0, calOffset2 = 0, timeOut = 0;
    BOOL found1
= FALSE, found2 = FALSE;
    
    
// Move both axis together by the length of one cycle and latch there position
   // in front of the sensor
   
CA_SetMaxVel(1, maxVel * 0.05);     // Move at 5% speed
   
CA_GearInRel(2, 1, 0.0, 1.0);       // Slave the second motor to the first
   
CA_MoveRel(1, cycleLength, FALSE);  // Move the first motor to its starting position

   
while (!found1 OR !found2) {
      
if (CA_ReadDIO(IN_CAL1)) {
           found1
= TRUE;
            calOffset1
= CA_ReadMotorPos(1);
       
}
       
if (CA_ReadDIO(IN_CAL2)) {
           found2
= TRUE;
            calOffset2
= CA_ReadMotorPos(2);
       
}
       
CA_Wait(0.001);

       
// if after 100s we haven't seen the sensor, there must be an error.
       
if ((timeOut+=0.001) > 100) return ERROR;
    
}

   
// Make sure there is no gearing while we adjust the speed of the master
   
CA_GearOut(2);
   
    
/* Adjust motor position
     */

   
CA_AdjustMotorPos(1, -calOffset1);
   
CA_AdjustMotorPos(
2, -calOffset2);
   
    
// Move first axis to its starting location
   
CA_GearInRel(2, 1, 0.0, 1.0);       // Slave the second motor to the first
   
CA_SetMaxVel(1, maxVel);            // Move at full speed
   
CA_MoveAbs(1, loadPos, FALSE);      // Move the first motor to its starting position

   
// Move second axis to its starting location
   
CA_WaitEndMotion(1, 5.0);
  
CA_GearOut(2);                      
// Detach the second axis from the first one
   
CA_MoveAbs(1, loadPos - nbPocket * pocketSize, FALSE);
    
CA_WaitEndMotion(
2, 5.0);
  
    
return SUCCESS;
}


/* controlTask() *******************************************************
*
* ABSTRACT:    main task.
*
*/

void ControlTask()
{
   
int stt;

startup:
    
/* Start-up / recovery sequence
     */


   
CA_WaitSig(IN_USER_OK, SIG_HIGH, NO_TIMEOUT);   // Wait until the user tells us to go on

   
/* Enable High Power.
     */

   stt
= CA_Power(HIGH);
  
if (stt <0 )
        
printf("Error enabling High Power : %d\n", stt);
   
else
       
printf(
"High Power ON\n");

   
Calibrate();

   
CA_GearInAbs(
2, 1, - nbPocket * pocketSize, 1.0);   
// Slave the second motor to the end of the first
   loading[1]
= TRUE;
    loading[
2]
= FALSE;
    run_appli
= TRUE;
    
    
/* Main loop
     */

   
CA_StartTask(CollatingDriver, 20, 1);
   
CA_StartTask(CollatingDriver, 20, 2);
   
    
while (run_appli) CA_Wait(0.1);

   
// Something went wrong.
   
CA_Power(LOW);
   
goto startup;

}


/* CheckStatusTask() *******************************************************
*
* ABSTRACT:    status checking task. Reads the error sensors for each
*          axis and shuts down the system if there is an error.
*
*/

void StatusTask(ANY_VAR argument) {

   ANY_VAR mtr;
    AXIS_ERROR_BITS stt;
    
Int32 error=0;

   
while (checkStatus) {

       
// Read the latched error word for each mtr.
       
for(mtr = 1; mtr <= 2; mtr++) {
            
// Check if an error occured.
           stt
= CA_ReadMtrError(mtr);
           
if (stt.reg != 0) {
               run_appli
= FALSE;
                error
++;
               
CA_EStop();
               
if (!(error%100)) printf("An error occured on axis %g: %x\n", mtr, (int) stt.reg);
            
}
       
}

       
// Verify the line from the Machine-tool (Digital Input #12)
       
if (!CA_ReadDIO(12)){
           run_appli
= FALSE;
            error
++;
           
CA_EStop();
           
printf(
"The machine tool is not ready \n");
       
}
       
        
CA_Wait(10);        
// check status every 10 ms
   }

}


/* CA_UserProgram() **************************************************************
*
* ABSTRACT:    This is the entry point of the user application program.
*          It initializes all variables and potentially the system and then
*          starts the run time tasks.
*
* INPUT PARAMETERS:
*      none
*
* OUTPUT PARAMETERS:
*
*      none.
*/


void CA_UserProgram()
{
   ANY_VAR control_task_id, status_task_id, priority, robotNum;
  
    
Initialise();
   checkStatus
= TRUE;
// Set global flag
   
    priority
= 0;   // the highest priority
   robotNum
= 1;   // An argument that can be passed to the task
   
    control_task_id
= CA_StartTask( ControlTask, priority, robotNum);
    
if (control_task_id < 0)
        
printf("The following error occured while creating the task: %f\n", control_task_id);
    
    priority
= 30;  
// a lower priority
   robotNum
= 1;   // An argument that can be passed to the task
   
    status_task_id
= CA_StartTask( StatusTask, priority, robotNum);
    
if (status_task_id < 0)
        
printf("The following error occured while creating the task: %f\n", status_task_id);
    
}