Exemplo n.º 1
0
int DaqDevice::readData(int subdev,int channel,int range_idx,int aref){
    if (comedi_data_read(_dev, subdev, channel, range_idx, aref, &_an_input[channel]) < 0){
        return COMEDI_ERROR;
    } else {
        return COMEDI_OK;
    }
}
Exemplo n.º 2
0
double readpin(int chan)
{
  comedi_t *it;
  lsampl_t data, maxdata;
  comedi_range *rang;
  int readres;
  double outval;

  if((it=comedi_open("/dev/comedi0"))==NULL) {
    printf("fail open");
  }

  comedi_set_global_oor_behavior(COMEDI_OOR_NUMBER);

  readres=comedi_data_read(it,subdev,chan,0,aref, & data);
  if(!readres) {
    comedi_perror("comedi_data_read: ");
  }
 

  rang = comedi_get_range(it, subdev, chan, 0);
  maxdata = comedi_get_maxdata(it, subdev, chan);

  outval = comedi_to_phys(data, rang, maxdata);

  printf("data=%d\noutval=%g\nreadres=%d\n",data, outval, readres);

  return outval;
}
Exemplo n.º 3
0
int DaqDevice::readCounter(int subdev,int channel)
{
   if (comedi_data_read(_dev, subdev, channel, 0, 0, &_counter[channel]) < 0){
        return COMEDI_ERROR;
    } else {
        return COMEDI_OK;
    }
}
Exemplo n.º 4
0
 /**
  * @brief read_sample reads the sapmle from the input channel; corrects it using soft calibration and returns the true value
  * @return softcalibrated value
  */
 lsampl_t read_sample()
     {
     lsampl_t data;
     comedi_data_read(it, subdevice,Channel,0,0,&data);
     double d=TheSlope*data;
     d+=TheIntercept;
     return d;
     }
//READ THE data from the card here
int32 ATIDAQHardwareInterface::ReadSingleSample( float64 buffer[] )
{
    int32 retVal = 0; /*the return code*/
    unsigned long numRawSamples; /*the number of raw gauge value samples*/
    numRawSamples = m_uiNumChannels * m_uiAveragingSize;
    unsigned int i, j; /*loop/array indices*/
    float64 * rawBuffer = new float64[numRawSamples]; /*the buffer which holds the raw, unaveraged gauge values*/
    int res = 0;

//    retVal = comedi_do_insnlist(comediDev,&il);
//    if(retVal < 0){
//        comedi_perror("");
//        return retVal;
//    }

    for (unsigned int ch = 0; ch < m_uiNumChannels; ch++) {

        //  buffer[ch] = comedi_to_phys(dataArray[ch],  &range,  maxdata);

        // old single read

        res = comedi_data_read(comediDev, 0, ch, 0, AREF_DIFF , &data);
        // if (res == 1){

         buffer[ch] = comedi_to_phys(data,  &range,  maxdata);

    }

    delete []rawBuffer;

    return retVal;


    //        float64 timeOut = ( numRawSamples / m_f64SamplingFrequency ) + 1; /*allow a full second
    //                for Windows timing inaccuracies	(definitely overkill, but whatever)*/
    //        int32 read; /*number samples read*/
    //        retVal = DAQmxReadAnalogF64( *m_thDAQTask, m_uiAveragingSize, timeOut, DAQmx_Val_GroupByScanNumber,
    //                                rawBuffer, numRawSamples, &read, NULL );
    //
    //        for ( i = 0; i < m_uiNumChannels; i++ )
    //        {
    //                /*sum the raw values, storing the sum in the first raw data point*/
    //                for ( j = 1; j < m_uiAveragingSize; j++ )
    //                {
    //                        rawBuffer[i] += rawBuffer[ i + ( j * m_uiNumChannels ) ];
    //                }
    //                /*store the average values in the output buffer*/
    //                buffer[i] = rawBuffer[i] / m_uiAveragingSize;
    //        }
    //
    //        delete []rawBuffer; /*gotta keep up with those unmanaged pointers*/


}
Exemplo n.º 6
0
void com_data_read(unsigned int index, uint64_t* value)
{
    lsampl_t data; 
    comedi_data_read(it,
 	    Comedi_subdev_ai,
 	    index,
 	    0,//unsigned int range,
 	    AREF_GROUND,//unsigned int aref,
 	    &data);
 	*value = (uint64_t)data;    
}
Exemplo n.º 7
0
int
main ( int argc, char *argb[] ) {
	comedi_t *it;
	lsampl_t data;
	it = comedi_open("/dev/comedi0");
	int i = 0;
	for ( i = 0; i < 16; i++ ) {
		comedi_data_read(it, subdev, i, range, aref, &data);
		printf("%d\n", data);
	}
}
Exemplo n.º 8
0
double PIDFlowController::readVolts(bool *ok) const
{ 
  lsampl_t samp = 0;
  if (ok) *ok = true;
  if (daq_ai) {
      samp = daq_ai->getSample(params.chan_ai);
  } else if ( comedi_data_read(dev_ai, params.subdev_ai, params.chan_ai, 0, 0, &samp) < 1 ) {
      if (ok) *ok = false;
      return 0.0;
  }
  return ais2v(samp); 
}
Exemplo n.º 9
0
static void data_read( void )
{
	comedi_t *dev = lookup_dev( *sp++ );
	unsigned int subdev = *sp++;
	unsigned int chan = *sp++;
	unsigned int range = *sp++;
	unsigned int aref = *sp++;
	lsampl_t data;
	int c = comedi_data_read( dev, subdev, chan, range, aref, &data );
	if( c < 1 ) comedi_perror( "@daq " );
	*--sp = data;
}
Exemplo n.º 10
0
int get_dio_bit(int chan) {
    lsampl_t data;
    int retval;

    DIO_ERROR = FALSE;
    retval = comedi_data_read(it, subdev_dio, chan, range_dio, aref_dio, &data);
    if (retval < 0) {
        comedi_perror("comedi_data_read in get_dio_bits");
        DIO_ERROR = TRUE;
        return 0;
    }
    if (data != 0) data = 1;
    return data;
}
Exemplo n.º 11
0
int comedi_data_read_delayed(comedi_t * dev, unsigned int subdev,
	unsigned int chan, unsigned int range, unsigned int aref,
	lsampl_t * data, unsigned int nano_sec)
{
	int retval;

	retval = comedi_data_read_hint(dev, subdev, chan, range, aref);
	if (retval < 0)
		return retval;

	comedi_udelay((nano_sec + 999) / 1000);

	return comedi_data_read(dev, subdev, chan, range, aref, data);
}
Exemplo n.º 12
0
double ComediChan::dataRead(bool *ok) const
{
  lsampl_t samp;
  bool myok = true;
  double ret = 0.;
  if (daq) {
    samp = daq->readSample(m_chan, &myok);
  } else if ( comedi_data_read(dev(), m_subdev, m_chan, m_range, 0, &samp) < 1 ) {
    err = "Read error.";
    myok = false;
    return 0.;
  }
  if (!myok) err = "Read error.";
  else ret = (samp/static_cast<double>(m_maxdata) * (m_rangeMax-m_rangeMin)) + m_rangeMin;
  if (ok) *ok = myok;
  return ret;
}
Exemplo n.º 13
0
double read_volts(int subdev, int chan, int range) {
  lsampl_t data, maxdata;
  int readres;
  comedi_range *rang;
  double outval;

  comedi_set_global_oor_behavior(COMEDI_OOR_NUMBER);
  readres=comedi_data_read(it,subdev,chan,range,aref, & data);
  if(!readres) {
    comedi_perror("comedi_data_read: ");
  }
  rang = comedi_get_range(it, subdev, chan, range);
  maxdata = comedi_get_maxdata(it, subdev, chan);
  outval = comedi_to_phys(data, rang, maxdata);
  //printf("data=%d\noutval=%g\nreadres=%d\n",data, outval, readres);
  return outval;

}
Exemplo n.º 14
0
int setup_read_wave(int subd, int chan, int range, int npnts) {
  //  assert(it!=NULL);

  printf("setup_read_wave...");fflush(stdout);
  int ret;
  int wv_n=++cmd->chanlist_len, wv_i=wv_n-1;
  lsampl_t data;
  //printf("wv_i %d \n", wv_i);

  ///assert(cmd!=NULL);

  if(cmd->chanlist==NULL) {
    cmd->chanlist=malloc(sizeof(unsigned int));
  } else {
    if(realloc(cmd->chanlist, (wv_n)*sizeof(unsigned int))==NULL) 
      { printf("realloc cmd fail \n"); return -1;}
  }
  cmd->chanlist[wv_i]= CR_PACK(chan,range,aref);
  if(npnts>cmd->stop_arg) cmd->stop_arg=npnts;

  cmd->scan_end_arg=wv_n;

  //test_board_read(it);

  comedi_command_test(it,cmd);
  ret=comedi_command_test(it,cmd);
  if(ret!=0){
    comedi_perror("comedi_command_test fail on read");
    return -1;
  }
  //test_board_read(it);

  inp_res[wv_i]=malloc(npnts*sizeof(double));
  inp_rang[wv_i]=comedi_get_range(it, subd, chan, range);
  inp_maxdata[wv_i]=comedi_get_maxdata(it, subd, chan);
  comedi_data_read(it,subd,chan,range,aref, & data);
  //printf("found sdtype %d \n", comedi_find_subdevice_by_type(it, COMEDI_SUBD_AI,0));

  //printf("setup subd %d chan %d rng %d:  data=%d outval=%g\n",subd, chan, range, data, comedi_to_phys(data, inp_rang[wv_i], inp_maxdata[wv_i]));
  printf("done\n");fflush(stdout);

  return wv_i;
}
Exemplo n.º 15
0
static void inout(scicos_block *block)
{
  struct ADCOMDev * comdev = (struct ADCOMDev *) (*block->work);

  lsampl_t data;
  double x = 0;
  double term = 1;
  double *y = block->outptr[0];

  comedi_data_read(comdev->dev, comdev->subdev, comdev->channel, comdev->range, comdev->aref, &data);
  if (comdev->use_softcal) {
    unsigned i;
    for(i = 0; i <= 4; ++i) {
      x += comdev->coefficients[i+1] * term;
      term *= data - comdev->coefficients[0];
    }
  } else {
    x = comdev->range_min + data*(comdev->range_max - comdev->range_min)/comdev->maxdata;
  }
  y[0] = x;
}
Exemplo n.º 16
0
static void mdlOutputs(SimStruct *S, int_T tid)
{
  double *y = ssGetOutputPortRealSignal(S,0);

#ifndef MATLAB_MEX_FILE
  unsigned int channel = (unsigned int)COMEDI_CHANNEL;
  unsigned int range   = (unsigned int)COMEDI_RANGE;
  unsigned int aref    = (unsigned int)COMEDI_REFERENCE - 1;
  void *dev        = (void *)ssGetPWork(S)[0];
  int subdev       = ssGetIWork(S)[0];
  double range_min = ssGetRWork(S)[0];
  double range_max = ssGetRWork(S)[1];
  lsampl_t data, maxdata = comedi_get_maxdata(dev, subdev, COMEDI_CHANNEL);
  double x;
	
  comedi_data_read(dev, subdev, channel, range, aref, &data);
  x = data;
  x /= maxdata;
  x *= (range_max - range_min);
  x += range_min;
  *y = x;
#endif
}
Exemplo n.º 17
0
double ComediAnalogInputHardCal::read()
{
        lsampl_t sample;
        comedi_data_read(m_device, m_subdevice, m_channels[0], m_range, m_aref, &sample);
        return comedi_to_phys(sample, m_dataRange, m_maxData) * m_inputConversionFactor;
}
Exemplo n.º 18
0
double ComediAnalogInputSoftCal::read()
{
        lsampl_t sample;
        comedi_data_read(m_device, m_subdevice, m_channels[0], m_range, m_aref, &sample);
        return comedi_to_physical(sample, &m_converter) * m_inputConversionFactor;
}
Exemplo n.º 19
0
/* -------------------------------------------------------------------- */
static long dsetRead_devAiSyncComedi(aiRecord *pai)
{
  CONTEXT  *p_myContext;
  int       mySubdevice;
  int       myChannel;
  int       myRange = 0;
  int       myAnalogReference;
  int       myPinNumber;
  char      p_myDeviceFile[BUFLEN];
  comedi_t *p_myComediFileHandle;
  lsampl_t  data;
  int       maxdata;
  int       ret;

  dsetLog(3, __FILE__ "[%d] -> %s(%s)\n", __LINE__, __func__, pai->name );

  p_myContext = pai->dpvt;
  p_myComediFileHandle = p_myContext->p_comediFileHandle;
  myChannel            = p_myContext->channel;
  myRange              = p_myContext->range;
  myAnalogReference    = p_myContext->analogReference;
  mySubdevice          = p_myContext->subdevice;
  myPinNumber          = p_myContext->pinNumber;
  strcpy(p_myDeviceFile, p_myContext->p_deviceFile);

#if 0
  dsetLog(7,__FILE__ "[%d] Subdevice  = %d PinNumber =%d\n",
          __LINE__,  mySubdevice, myPinNumber);
  dsetLog(7,__FILE__ "[%d] AnalogReference  = %d Channel=%d\n",
          __LINE__,  myAnalogReference, myChannel);

  dsetLog(7, __FILE__ "[%d] -> Range is %d\n", __LINE__, myRange);

#endif

  maxdata = comedi_get_maxdata(p_myComediFileHandle, mySubdevice, myChannel);

#if 0
  dsetLog(7,__FILE__ "[%d] maxdata  = %d pn=%d\n",
          __LINE__,  maxdata, myPinNumber);
  dsetLog(7,__FILE__ "[%d] Data %d -> device %s\n", __LINE__, data, pai->name);

  dsetLog(7,__FILE__ "[%d] New Range  = %lg\n",
          comedi_get_range(p_myComediFileHandle, mySubdevice,
                           myChannel, myRange));
#endif

  ret = comedi_data_read(p_myComediFileHandle, mySubdevice, myChannel,
                         myRange, myAnalogReference, &data);
  if (ret < 0) {
    comedi_perror(p_myDeviceFile);
    dsetLog(1, __FILE__ "[%d] Error: Couldn't read hardware\n", __LINE__);
    sleep(SLEEPTIME_ERROR);

    return(ERROR);
  }

  pai->val = comedi_to_phys(data,
                             comedi_get_range(p_myComediFileHandle, mySubdevice,
                                              myChannel, myRange),
                             maxdata);

  pai->udf = isnan(pai->val);

  dsetLog(7,__FILE__ "[%d] pai->udf is %d \n", __LINE__, pai->udf);

  if (pai->udf) {
    pai->val = 10;
    dsetLog(7,__FILE__ "[%d] Error: Cable is disconnected, please verify\n", __LINE__);
  }

  dsetLog(7,__FILE__ "[%d] val,rval=%lg,%d -> %s\n",
          __LINE__, pai->val, pai->rval, pai->name);

  dsetLog(3,__FILE__ "[%d] <- %s\n", __LINE__, __func__);

  return(NO_AUTOMATIC_CONVERSION);
  /*return(DO_AUTOMATIC_CONVERSION); */
}
Exemplo n.º 20
0
//*******************************************************************************
int pid_loop()

//Modified on May 8 to take into account a moving average, and a moving variance
//and also to remove the retraction of the piezo except on the first pass.

{
//This is the function to output a PID loop
//PID algorithm taken from Control System Desgin, by Karl Johan Astrom
//Chapter 6
//This algorithm is supposed to include integral wind-up and bumpless transition

    int m;
    lsampl_t data_to_card, data_from_card;
    static comedi_t * dev_output, * dev_input;
    static double bi, ad, bd; //PID coefficients
    static double Pcontrib, Icontrib, Dcontrib; //individual PID contributions
    static double FeedbackReading; //Readings of the error chann
    static double v; //u is the actuator output, and v is the calculated output
    static int j = 0;
    static double LastDiffContrib;
    static double Error;
    static double LastError =0;
    static double SecondLastError =0;
    static double LastOutput =0;
    //static double SummedPIDOutput; //Summed PID Output
    static double SummedFeedbackReading; //Summed FeedbackReading
    //static double SummedVariance;
    static double M2_n;
    static double delta;
    static double alpha;
    static struct queue PIDOutput_queue;//these are two queues to calculate the moving mean and variance
    static struct queue FeedbackReadingVar_queue;
    static struct queue FeedbackReading_queue;
    static int NumbFirstSteps;
    static double InitialStepSizeVoltage = 0.1;
    static double InitialVoltageStep;
    double last_mean, last_var, new_var; //popped values of mean and variance



    //Initialize the queues
    init_queue(&PIDOutput_queue);
    init_queue(&FeedbackReadingVar_queue);
    init_queue(&FeedbackReading_queue);

    //rt_printk("Control channel device name is %s \n",device_names[ControlChannel.board_number]);
    //rt_printk("Control channel subdevice %d and channel %d \n", ControlChannel.subdevice, ControlChannel.channel);

    //rt_printk("Feedback channel device name is %s \n",device_names[FeedbackChannel.board_number]);
    //rt_printk("Feedback channel subdevice %d and channel %d \n", FeedbackChannel.subdevice, FeedbackChannel.channel);

    //dev_output is the channel that is to be controlled
    dev_output = comedi_open(device_names[ControlChannel.board_number]);
    //dev_input is the channel from which the error signal is read
    dev_input = comedi_open(device_names[FeedbackChannel.board_number]);

    //initialize the task
    if(!(PIDloop_Task = rt_task_init_schmod(nam2num( "PIDLoop" ), // Name
                                        0, // Priority
                                        0, // Stack Size
                                        0, //, // max_msg_size
                                        SCHED_FIFO, // Policy
                                        CPUMAP ))) // cpus_allowed
        {
            rt_printk("ERROR: Cannot initialize PIDLoop task\n");
            exit(1);
        }

    //specify that this is to run on one CPU
    rt_set_runnable_on_cpuid(PIDloop_Task, 0);


    //lock memory and make hard real time
    mlockall(MCL_CURRENT|MCL_FUTURE);
    rt_make_hard_real_time();

    //Convert PIDLoop_time, which is in nanoseconds, to tick time (sampling_interval, in counts)
    sampling_interval =nano2count(PIDLoop_Time);
    //sampling_interval =nano2count_cpuid(PIDLoop_Time, 0);

    // Let's make this task periodic..
    expected = rt_get_time() + 100*sampling_interval;
    //expected = rt_get_time_cpuid(0) + 100*sampling_interval;
    rt_task_make_periodic(PIDloop_Task, expected, sampling_interval); //period in counts


    pid_loop_running = 1; //set the pid loop running flag to FALSE

    //retract the tip completely, if it is the first PID pass
    if(FirstPIDPass)
      {
        //data_to_card = (lsampl_t) 0;
        //MaxZVoltage corresponds to the fully retracted piezo
        //rt_printk("MaxZVoltage is %f \n", MaxZVoltage);
        //rt_printk("MinZVoltage is %f \n", MinZVoltage);
        //rt_printk("MinOutputVoltage is %f \n", MinOutputVoltage);
        //rt_printk("PIDOutput is %f \n", PIDOutput);
        //rt_printk("AmplifierGainSign is %i \n", AmplifierGainSign);
        //rt_printk("OutputPhase is %i \n", OutputPhase);
        NumbFirstSteps = (nearbyint((MaxZVoltage-PIDOutput)/InitialStepSizeVoltage))-1;
        //rt_printk("NumbFirstSteps is %i \n", NumbFirstSteps);
       //NumbFirstSteps = ((MaxZVoltage - PIDOutput)/InitialStepSizeVoltage)); //-1 to  be safe
        //Set the direction of the voltage step
        //PIDOutput = CurrentZVoltage;
        if (MaxZVoltage>=PIDOutput)
          {InitialVoltageStep=InitialStepSizeVoltage;}
         else {InitialVoltageStep=-InitialStepSizeVoltage;};

        if (NumbFirstSteps>1)
          {
            for(j=0;j<NumbFirstSteps;j++)
              {  PIDOutput+=InitialVoltageStep;
                 data_to_card = (lsampl_t) nearbyint(((PIDOutput - MinOutputVoltage)/OutputRange)*MaxOutputBits);
                 //rt_printk("Data_to_card is %i \n", data_to_card);
                 comedi_lock(dev_output, ControlChannel.subdevice);
                 m=comedi_data_write(dev_output, ControlChannel.subdevice, ControlChannel.channel, AO_RANGE, AREF_DIFF, data_to_card);
                 comedi_unlock(dev_output, ControlChannel.subdevice);
                // And wait until the end of the period.
                rt_task_wait_period();
              }
          }
        //Initialize the errors
        LastError = 0;
        SecondLastError = 0;
        LastOutput = PIDOutput;
        LastDiffContrib =0;
        Dcontrib = 0;
        Icontrib = 0;
        AveragedPIDOutput=LastOutput;  //This is what the main program will actually read
        FirstPIDPass = 0;
      }




    //rt_printk("AntiWindup time is %f \n", AntiWindup_Time);
    bi = PropCoff*PIDLoop_Time/IntTime;  //integral gain
    //rt_printk("PropCoff is %f \n", PropCoff);
    //rt_printk("IntTime is %f \n", IntTime);
    //in Astrom's article, ad is defined as below in the code, but the actual
    //derivation gives the coefficient we actually use
    //ad = (2*DiffTime- PID_cutoff_N*PIDLoop_Time)/(2*DiffTime+PID_cutoff_N*PIDLoop_Time);
    ad = (DiffTime)/(DiffTime+PID_cutoff_N*PIDLoop_Time);
    //rt_printk("DiffTime is %f \n", DiffTime);
    //same comment about bd
    //bd = 2*PropCoff*PID_cutoff_N*DiffTime/(2*DiffTime + PID_cutoff_N*PIDLoop_Time);    //derivative gain
    bd = PropCoff*PID_cutoff_N*DiffTime/(DiffTime + PID_cutoff_N*PIDLoop_Time);
    //rt_printk("MaxZVoltage is %f \n", MaxZVoltage);


    //Now calculate the initial means and variances
    //SummedPIDOutput = 0; //initialize parameters if we take averages
    //First means
    SummedFeedbackReading =0;
    //j=1;
    alpha =  ((float) 1)/(PID_averages+1);
    for (j=0;j<PID_averages;j++)
      {

        //make a first reading
        comedi_lock(dev_input, FeedbackChannel.subdevice);
        m = comedi_data_read(dev_input, FeedbackChannel.subdevice, FeedbackChannel.channel, AI_RANGE, AREF_DIFF, &data_from_card);
        comedi_unlock(dev_input, FeedbackChannel.subdevice);

        //Convert to a voltage reading
        SummedFeedbackReading += ((((float) data_from_card)/MaxInputBits)*InputRange + MinInputVoltage);
      }
    AveragedFeedbackReading =SummedFeedbackReading/PID_averages;


    //Since we are not changing the output, the mean has not changed, and the variance is 0
    M2_n = 0;
    PIDOutputVariance = 0;

    //Initialize the circular buffers
    for (j=0; j<PID_averages; j++)
      {
        push_queue(&FeedbackReading_queue, AveragedFeedbackReading);
        push_queue(&FeedbackReadingVar_queue, PIDOutputVariance);
        push_queue(&PIDOutput_queue, LastOutput);
      }

    //Now do the regular loop
    while(pid_loop_running)
      {
      //rt_printk("Got here 1 \n");
      //check to see if the PID parameters have changed
      if(PIDParametersChanged)
        {
          //update the PID coefficients
          bi = PropCoff*PIDLoop_Time/IntTime;  //integral gain
          ad = (DiffTime)/(DiffTime+PID_cutoff_N*PIDLoop_Time);
          bd = PropCoff*PID_cutoff_N*DiffTime/(DiffTime + PID_cutoff_N*PIDLoop_Time);
          PIDParametersChanged = 0;
        } //end of if(PIDParametersChanged)

      //continue with the rest of the loop

      //Read the input reading
      comedi_lock(dev_input, FeedbackChannel.subdevice);
      m = comedi_data_read(dev_input, FeedbackChannel.subdevice, FeedbackChannel.channel, AI_RANGE, AREF_DIFF, &data_from_card);
      comedi_unlock(dev_input, FeedbackChannel.subdevice);

      //Convert to a voltage reading
      FeedbackReading = ((((float) data_from_card)/MaxInputBits)*InputRange + MinInputVoltage);
      //rt_printk("Data from card is %d \n", data_from_card);
      //rt_printk("Feedback reading is %f \n", FeedbackReading);
      //rt_printk("Input m is %d \n", m);
      delta = (FeedbackReading - AveragedFeedbackReading);
      //AveragedFeedbackReading = alpha*FeedbackReading+(1-alpha)*AveragedFeedbackReading;  //running averange
      //PIDOutputVariance = alpha*(delta*delta) + (1-alpha)*PIDOutputVariance;
      //Venkat changed the following line to add logarithmic averaging on January 10, 2012
      if(Logarithmic){
        Error = AmplifierGainSign*OutputPhase*log10(fabs(FeedbackReading/SetPoint));
        }
       else {
         Error = AmplifierGainSign*OutputPhase*(SetPoint - FeedbackReading);//multiply by OutputPhase+AmplifierGainSign
       }
      //Error = AmplifierGainSign*OutputPhase*(SetPoint - FeedbackReading);//multiply by OutputPhase+AmplifierGainSign
      Pcontrib = PropCoff*(Error - LastError);
      //Not sure of sign of second contribution in line below...should it be - ?
      Dcontrib = ad*LastDiffContrib - bd*(Error - 2*LastError + SecondLastError);
      v = LastOutput + Pcontrib + Icontrib + Dcontrib;

      //next, take care of saturation of the output....anti-windup
      PIDOutput = v;
      PIDOutput =(PIDOutput>MaxOutputVoltage)? MaxOutputVoltage:PIDOutput;
      PIDOutput =(PIDOutput<MinOutputVoltage)? MinOutputVoltage:PIDOutput;

      //Calculate the averaged quantities
      pop_queue(&FeedbackReading_queue, &last_mean);
      AveragedFeedbackReading += (FeedbackReading - last_mean)/PID_averages;
      push_queue(&FeedbackReading_queue, FeedbackReading);

      pop_queue(&FeedbackReadingVar_queue, &last_var);
      new_var = delta*delta;
      PIDOutputVariance += (new_var - last_var)/PID_averages;
      push_queue(&FeedbackReadingVar_queue, new_var);

      //send the control signal
      //rt_printk("FeedbackReading is %f \n", FeedbackReading);
      //rt_printk("v is %f \n", v);
      //rt_printk("PID output should be %f \n", PIDOutput);
      data_to_card = (lsampl_t) nearbyint(((PIDOutput - MinOutputVoltage)/OutputRange)*MaxOutputBits);
      //data_to_card = (lsampl_t) 0;
      comedi_lock(dev_output, ControlChannel.subdevice);
      m=comedi_data_write(dev_output, ControlChannel.subdevice, ControlChannel.channel, AO_RANGE, AREF_DIFF, data_to_card);
      comedi_unlock(dev_output, ControlChannel.subdevice);
      //rt_printk("Output m is %d \n", m);

      //Update the integral contribution after the loop
      Icontrib = bi*Error;

      //Update parameters
      LastError = Error;
      SecondLastError = LastError;
      LastDiffContrib = Dcontrib;
      LastOutput = PIDOutput;


      //rt_printk("PContrib is %f \n", Pcontrib);
      //rt_printk("IContrib is %f \n", Icontrib);
      //rt_printk("DContrib is %f \n", Dcontrib);
      //rt_printk("PIDOutput is %f \n", PIDOutput);

      //Next part is to take the averaged PID output for recording if j>PID_averages and PID_averages>1
      //SummedPIDOutput+=PIDOutput;
      //SummedFeedbackReading += FeedbackReading;
      //j++;
      //AveragedPIDOutput=((PID_averages>1)&&(j>PID_averages))?(SummedPIDOutput/PID_averages):AveragedPIDOutput;
      //AveragedFeedbackReading=((PID_averages>1)&&(j>PID_averages))?(SummedFeedbackReading/PID_averages):AveragedFeedbackReading;
      //SummedPIDOutput=(j>PID_averages)? 0:SummedPIDOutput;
      //SummedFeedbackReading=(j>PID_averages)? 0:SummedFeedbackReading;
      //j=(j>PID_averages)? 1:j;

      //Calculate moving exponential averages and variance
      //delta = PIDOutput - AveragedPIDOutput;
      //AveragedPIDOutput = alpha*PIDOutput + (1-alpha)*AveragedPIDOutput;
      //PIDOutputVariance = alpha*(delta*delta) + (1-alpha)*PIDOutputVariance;
      //PIDOutputVariance = alpha*abs(delta) + (1-alpha)*PIDOutputVariance;

      pop_queue(&PIDOutput_queue, &last_mean);
      AveragedPIDOutput += (PIDOutput - last_mean)/PID_averages;
      push_queue(&PIDOutput_queue, PIDOutput);
         // And wait until the end of the period.
        rt_task_wait_period();

       }

    //rt_printk("Got here 3 \n");
    //rt_printk("pid_loop_running is %d \n", pid_loop_running);
    rt_make_soft_real_time();
    comedi_close(dev_input);
    comedi_close(dev_output);
    rt_task_delete(PIDloop_Task); //Self termination at end.

    pthread_exit(NULL);
    return 0;


}