Real-time ASCEND/Data reader

From ASCEND

Jump to: navigation, search

←back to Real-time ASCEND.


Contributed by: Dipak Chirmade

Contents

New data reader and test for real-time data

There are many ways by which one can fetch and attach temperature reading from the DA hardware. Following model shows one method out of other proposed.

Please visit here for video demo and for source dipak:models/dipak/realtime/Examples/AvgTempExample

(* This model is written to test real-time data reader module with two temperature sensors. *)

REQUIRE "atoms.a4l";

(* Import modules if any *)
IMPORT "dipak/realtimeascend/terminal";

(* Real-time data reader configuration *)
MODEL datareaderconfiguration;

NOTES
        'author' SELF {Dipak Chirmade}
        'description' SELF { To calculate an average of two temperature feeds}

END NOTES;

	terminaldevice IS_A symbol_constant;
        (* Wow! We are reading the data from DA hardware and not from a file.*)
        (* Please assign a customized baud rate for terminal otherwise get *)
        (* ready for default 115200 *)
	terminaldevice :== '/dev/ttyUSB0:115200';

END datareaderconfiguration;

MODEL realtimeascend;

        (* Configure the DA_Hardware and see if DA_Hardware is Okey with an ASCEND.*)
        terminalconfig IS_A datareaderconfiguration;

        (* Configure DA hardware adaptively *)
        daTimeSteppingSize, daDataSmoothingLaps ,unUsed IS_A variable;
        hardware_initialization : da_hardware_configurator(
		daTimeSteppingSize, daDataSmoothingLaps: INPUT;
                unUsed : OUTPUT;
                terminalconfig : DATA
	);

        (* Sensor readings*)
        analogSensorReading, digitalSensorReading IS_A variable;
        averageTemperature IS_A variable;

        (* Average of two temperature feeds*)
        average_calculation : averageTemperature =
        (analogSensorReading + digitalSensorReading) / 2;

METHODS

METHOD specify;

        (* Decide who is FREE or FIX...*)
        FIX daTimeSteppingSize;
        FIX daDataSmoothingLaps;
        FIX unUsed;
        FIX analogSensorReading;
        FIX digitalSensorReading;
        FREE averageTemperature;
END specify;

METHOD values;

        (* Initialize to hardcoded value *)
        daTimeSteppingSize := 10;
        daDataSmoothingLaps := 4;
        unUsed:= 0;
        analogSensorReading := -999;
        digitalSensorReading := -999;
        averageTemperature := -999;
END values;

METHOD on_load;

        (* Initial automation of few task*)
	RUN specify;
        RUN values;
END on_load;

METHOD on_da_hookup;

        (* Fetch live feeds from DA_Hardware*)
        EXTERNAL da_event_processor(SELF);
END on_da_hookup;

END realtimeascend;

Other approaches

Other possible solutions would be to make an event-based simulation system, allowing recalculation in response to a 'new_data_is_ready' signal sent from the DA hardware. Currently, ASCEND is not particular event-based (except in the GUI) so this would be more difficult.


Sample demonstration of generation of event in response to temperature sensors (can be extended to other sensors later)

The idea to make an event-based simulation system is good enough as 'new_data_is_ready' kind of signals which are sent from the DA hardware may make recalculation of targeted feeds easy.

To investigate the issues with an event based system, I wrote a sample code within firmware for Arduino. Surprisingly it worked according to the expectations. Following section describes one short scenario and events generated from DA hardware in response to the same.

Before going for the scenario lets explore few things about communication structure in between ASCEND and DA hardware.

Communication protocol (in between DA hardware and ASCEND)

For brief sequence diagram visit [DA_Sequence]

Commands to Arduino board Response from Arduino board only on valid command
RTA*0*a0# Temperature reading from analog port no 'a0' with other an event-based attribute.
RTA*0*d7# Temperature reading from digital port no 'd7' with other an event-based attribute.
RTA*1# followed by 100# Should initiate sequence in the firmware to set a new value of time-step and 100# will set new value of time-step to 100msec. response is only get generated if debugging(*) on Arduino is enabled.
RTA*2# followed by 4# Should initiate sequence in the firmware to set a new value of raw data smoothing lap and 4# will set new value of smoothing lap to 4. response is only get generated if debugging(*) on Arduino is enabled. Also 0# will disable on-board data smoothing.
RTA*-1# Should send the string-chars in order to flush the serial port from initial invalid characters. This command is recommended at initialisation in order to avoid failure of connection in between DA-hardware and data reader etc
Other invalid command Nothing will happen in arduino side and "Invalid command!" response can be sent from firmware if debugging is enabled.

(*) Please use raw real-time ascend data reader as unwanted debug messages may produce conflicts in parsing with actual real-time ascend data reader if debugging is enabled at Arduino side.

Following is a typical an event-based attribute stamp.

 SensorTypeValue:==SensorType
 SensorDescription:==SensorDescription
 SensorFuction:==SensorFunction
 SensorStatus:==SensorStatus
 SensorEvent:==SensorEvent
 SensorEventType:==SensorEventType
 SensorReading:==SensorReading
 SensorMountPort:==SensorMountPort
 SensorTimeHr:==SensorTimeStampHours 
 SensorTimeMin:==SensorTimeStampMinutes
 SensorTimeSec:==SensorTimeStampSeconds


DA hardware will generate an event upon change in temperature (or other parameter in future) or in change in status of sensors. Upon change in event or other event that will be needing at ASCEND side to take into consideration, ASCEND module will probably recalculation the model at real time. Either batch processing can be done at ASCEND side or to handle the each and every event request to calculate the targeted model can be done.

Following table describes few events in case of temperature sensors.

Event Parameter (MUST Parameters)
Brief description
Sensor's Status This parameter may generate an event on which ASCEND will suspend/resume the talk with DA upon the status state of sensor.
Sensor's Event for temperature (can be changed to other parameter than temperature) Up on this event, ASCEND may come to know that if new data is available to take into consideration. If there is no change temperature then with can be skipped or logged for other purposes.
Sensor's Event type. This parameter will take ASCEND to consider the event is compulsory or optional one. Compulsory events may force to trigger recalculation procedure at ASCEND side.


Event Parameters (Supplementary)
Description
Sensor's Type May be needed to understand the behavior and correctness of the model according to sensor's type.
Sensor's description Vendor id and serial no if any etc
Sensor's Function May be needed to identify the event processing when there are different kinds of sensors present in the system.
Sensor's Reading This value will be actually used in re-calculation of the model at ASCEND side upon real time events.
Sensor's Mount Port Port number where sensor is ported on DA hardware.
Additional extra parameters To be added in future in case of new type of sensor etc

Test for an event-based DA hardware

To test these events, I made a small experiment in which I kept one digital sensor to read the room temperature. After some time later I touched it so that it should detect the event to inform that there is change in temperature and the reading for that. When I left the sensor alone as before, there should be one more event need to be generated by DA hardware saying there is change is temperature as it is falling back to room temperature. And finally I unplugged the sensor so that it should generate event of 'device is not working' or inactive etc.

The sample code for an event based DA module can be found here

Test results

Initial raw trace without any events in the system looked like as per following graph when plotted in real-time.

Plot for raw temperature feed with no preprocessing

(Where each valley represent the event generation state from DA hardware. Generation of event is done by doing little preprocessing of raw data to avoid too many generation of events . Preprocessing can be disabled if needed, of course.)

Following graphs represents the real time events generated from DA hardware to send to ascend for above mentioned test scenario.

Plot for real time events triggered from DA hardware (Please don't consider the magnitude for a plots as they are chosen randomly to make plotting simple)

According to obtained graphs it can be seen that different triggering state for event may allow ASCEND to respond in real time data feeds. For approximately 140 raw reading only 6-7 compulsory events were triggered meaning it is quite optimistic to use event based system to hook DA hardware to ASCEND to handle real time feeds.

Program snippets

Complete source code can be downloaded from dipak:models/dipak/realtime/SensorFirmware/EventGeneration.

On Arduino I/O board an events can be generated as

/**
Desc: Event Generation to send to ascend
Params: @Param, char* tSensorType, Is sensor digital or analog?
        @Param, char* tSensorDescription, Vendor id etc
        @Param, char* tSensorFunction, Is temperature or humidity etc?
        @Param, char* tSensorStatus, Sensor Status active or inactive
        @Param, char* tSensorEvent, Reading changed or not changed from last snap etc
        @Param, char* tSensorEventType, Is optional or compulsory
        @Param, unsigned long tSensorReading, Value that need to be send to ascend
        @Param, unsigned int tSensorMountPort, Port number where the sensor is mounted
Returns: void, nothing
*/

void GenerateNotificationEvent(
   char tSensorType[], /*Is sensor digital or analog?*/
   char tSensorDescription[], /*Vendor id etc*/
   char tSensorFunction[], /*Is temperature or humidity etc?*/
   char tSensorStatus[], /*Sensor Status active or inactive*/
   char tSensorEvent[], /*Reading changed or not changed from last snap etc*/
   char tSensorEventType[], /*Is optional or compulsory*/
   unsigned long tSensorReading, /*Value that need to be send to ascend*/
   unsigned int tSensorMountPort /*Port number where the sensor is mounted*/
   /*Add more parameters in future*/
   ){

  /*Temporary variables*/
  int second = -1;
  int minute = -1;
  int hours = -1;
  unsigned long now;

  /**
    Please do not use 'millis()' with interrupts enabled as after catching the
    interrupt, 'millis()' may return garbage value.
  */

  cli();  /*Disable interrupts*/
  now = millis();/*Get system clocks bits*/
  sei();  /*Enable interrupts*/

  /**
    Adjust the time ticks up to 1 sec precision.
  */
  while( now - prevMillis >= 1000){

    sysTime++;
    prevMillis += 1000;
  }

  AdjustTime(now);

  /*Calculate hours, minutes and seconds*/
  second = sysTime % 60;
  minute = (sysTime / 60) % 60;
  hours  = (sysTime  / 3600) % 24;

  /**
   Send feeds to ASCEND for future processing
  */

  Serial.print(tSensorType);Serial.print(":==SensorType\n");
  Serial.print(tSensorDescription);Serial.print(":==SensorDescription\n");
  Serial.print(tSensorFunction);Serial.print(":==SensorFunction\n");
  Serial.print(tSensorStatus);Serial.print(":==SensorStatus\n");
  Serial.print(tSensorEvent);Serial.print(":==SensorEvent\n");
  Serial.print(tSensorEventType);Serial.print(":==SensorEventType\n");
  Serial.print(tSensorReading);Serial.print(":==SensorReading\n");
  Serial.print(tSensorMountPort);Serial.print(":==SensorMountPort\n");
  Serial.print(hours,DEC);Serial.print(":==SensorTimeStampHours\n");
  Serial.print(minute,DEC);Serial.print(":==SensorTimeStampMinutes\n");
  Serial.print(second,DEC);Serial.print(":==SensorTimeStampSeconds\n");

}
.
.
.

/**

Desc: Preprocessing for SMT16030 and LM35CZ and Outward Data feed to ASCEND module
Params: @params, bool isDigital, Specifies the DA processing for either digital or analog sensor
Returns: void, Nothing

*/

void SensorSpecificPreprocessingAndDataAcquisition(bool isDigital){

  /*Temp Variable cleanup/initialization if any*/

    unsigned long tTemperatureCurrent = INCORRECTTEMPERATUREREADING; /*Invalid temperature initlization*/
    static unsigned long tTemperaturePrevious = INCORRECTTEMPERATUREREADING; /*Invalid temperature initlization*/
    unsigned long tRawTemperatureReading;
    char *tSensorType = NULL;  /*Type of a sensor*/
    char *tSensorVendor = NULL; /*Vendor for a sensor*/
    int tSensorMountPin = -1;

  if(PREPROCESSINGCOUNT > 0){ /*Preprocessing is enabled*/

     tTemperatureCurrent = 0; /*NULL reading at the start*/
     /*Take an average to get stable reading*/
   for(int AverageCount = 0; AverageCount < PREPROCESSINGCOUNT; AverageCount++){

     if(isDigital)
          /*Fetch temperature feed from SMT16930 sensor*/
       tRawTemperatureReading = CalculateTemperatureUsingSMT16930(
       pulseIn(DIGITALSENSORPIN_SMT16030, HIGH, 1000),
          /*Read high time for square wave with 1000 microsend timeout*/
       pulseIn(DIGITALSENSORPIN_SMT16030, LOW, 1000)
          /*Read low time for square wave with 1000 microsend timeout*/
      );
     else
          /*Fetch temperature feed from LM35CZ sensor*/
      tRawTemperatureReading = CalculateTemperatureUsingLM35CZ(
      analogRead(ANALOGSENSORPIN_LM35CZ) /*Read analog stepping value*/
      );


      /*Print raw temperature feed for debugging purpose. Uncommented if needed*/
      /*Serial.println(tRawTemperatureReading);*/

     if(tRawTemperatureReading != INCORRECTTEMPERATUREREADING)
                   /*Take an average only if valid reading fetched*/
      tTemperatureCurrent = tTemperatureCurrent + tRawTemperatureReading;
     else {
      tTemperatureCurrent = INCORRECTTEMPERATUREREADING; /*Bad reading*/
      break;
     }

     delay(PORTREADDELAY);
   }
     if(tTemperatureCurrent != INCORRECTTEMPERATUREREADING)
        /*Take an average only of reading is correct one*/
     tTemperatureCurrent /= PREPROCESSINGCOUNT;
   }
  else { /*Preprocessing is disabled*/

     if(isDigital)
          /*Fetch temperature feed from SMT16930 sensor*/
     tTemperatureCurrent = CalculateTemperatureUsingSMT16930(
      pulseIn(DIGITALSENSORPIN_SMT16030, HIGH, 1000),
          /*Read high time for square wave with 1000 microsend timeout*/
      pulseIn(DIGITALSENSORPIN_SMT16030, LOW, 1000)
          /*Read low time for square wave with 1000 microsend timeout*/
      );
     else
          /*Fetch temperature feed from LM35CZ sensor*/
      tTemperatureCurrent = CalculateTemperatureUsingLM35CZ(
      analogRead(ANALOGSENSORPIN_LM35CZ) /*Read analog stepping value*/
      );


     delay(PORTREADDELAY);
  }
  /**
   Before creating an event, assign sensor specific parameters
   Lets make it simple by hardcoded malloc sizes. This will avoid
   addition of an external and an expensive libraries like 'WString' etc
   into project space.
  */

   if(isDigital){

      /*Digital sensor specific information*/
      tSensorType = (char*)malloc(sizeof(char)*8);
                    strcpy(tSensorType,"digital");
      tSensorVendor = (char*)malloc(sizeof(char)*9);
                    strcpy(tSensorVendor,"SMT16030");
      tSensorMountPin = DIGITALSENSORPIN_SMT16030;
   }
   else{

      /*An analog sensor specific information*/
      tSensorType = (char*)malloc(sizeof(char)*7);
                    strcpy(tSensorType,"analog");
      tSensorVendor = (char*)malloc(sizeof(char)*9);
                    strcpy(tSensorVendor,"LM35CZ");
      tSensorMountPin = ANALOGSENSORPIN_LM35CZ;

   }

  /*Now try to create events that we need to send to ASCEND*/
  if(
      (tTemperaturePrevious != INCORRECTTEMPERATUREREADING)
       &&
      ((tTemperatureCurrent != INCORRECTTEMPERATUREREADING))
     ){
       /*Check if change in the temperature happens or what*/

      if( tTemperaturePrevious - tTemperatureCurrent)
             /*Yes change in temperature detected*/
         GenerateNotificationEvent( /*Send change in temperature event*/
           tSensorType, /*Is sensor digital or analog?*/
           tSensorVendor, /*Vendor id etc*/
          "temperature", /*Is temperature or humidity etc?*/
          "active",/*Sensor Status active or inactive*/
          "changed", /*Reading changed etc*/
          "compulsory", /*Is optional or compulsory*/
           tTemperatureCurrent,/*Value that need to be send to ascend*/
           tSensorMountPin
         );
      else
           /*No, Change in temeprature is not detected*/
         GenerateNotificationEvent( /*Send change in temperature event*/
           tSensorType, /*Is sensor digital or analog?*/
           tSensorVendor, /*Vendor id etc*/
          "temperature", /*Is temperature or humidity etc?*/
          "active",/*Sensor Status active or inactive*/
          "notchanged", /*Reading changed etc*/
          "optional", /*Is optional or compulsory*/
           tTemperatureCurrent,/*Value that need to be send to ascend*/
           tSensorMountPin
         );
  }
  else { /*Skip the event generation*/
  }

  if(tTemperatureCurrent == INCORRECTTEMPERATUREREADING)
     /*Event for inactive sensoe state*/
      GenerateNotificationEvent( /*Send change in temperature event*/
           tSensorType, /*Is sensor digital or analog?*/
           tSensorVendor, /*Vendor id etc*/
          "temperature", /*Is temperature or humidity etc?*/
          "inactive",/*Sensor Status active or inactive*/
          "nil", /*Reading changed etc*/
          "compulsory", /*Is optional or compulsory*/
           0,/*Value that need to be send to ascend*/
           tSensorMountPin
         );

  /*Store the last temperature log*/
  if(tTemperatureCurrent != INCORRECTTEMPERATUREREADING)
     tTemperaturePrevious = tTemperatureCurrent;

  /*Free the allocated memory if any*/
   if(tSensorType != NULL)
      free(tSensorType);
   if(tSensorVendor != NULL)
      free(tSensorVendor);
}
.
.
.

Summary

  1. Event generated from DA hardware for 'new_data_is_ready' kind of signal may force ASCEND to recalculation the targeted model to do simulation in real time.
  2. This system is much easy that than of Agent based system.
  3. Number of events (that are generated in real time responses) are way less in number than that of all raw readings thus it is much optimistic (both in time and space complexity) while re-calculation at ASCEND side.
  4. Since there is a clear boundary in between events in proposed communication protocol, it is very easy to deal with multiple sensors with almost no modification unlike agent based system.