Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Motivation

There are some challenges building up the code structure that will run on the Arduino:

  1. Create an exchangeable interface that offers all methods, which are required to communicate with the hardware and environment.
    The benefit from this is, that the interface can be chosen depending on the sensors and if the flight is real or simulated.

  2. Make sure that within a single tick some sensor value is not measured multiple times just because it is requested on several occasions.
    This is important because every measurement takes time and consumes power. For that reason the above-mentioned interface should serve a resetTick function to know when a new tick hast begun. 

  3. Perform the implementation of the SCCharts-generated code as simple as possible.
    The Arduino code provides a setup method and a loop method, which are equivalent to the reset function and the tick function in SCCharts. Though KIELER can easily create some Arduino code out of any SCChart, important host code is missing:
    • At the very beginning of the Arduino code some dependencies like libraries and the interface need to be included.
    • Before every new tick the interface must be notified.


Update: Due to first actual SCCharts testings the following code got some updates.


Basic Arduino sketch

...

QuadcopterController

Code Block
languagecpp
#include "CompInterface.h"
#include "FlightController.c"
void setup() {
  CompInterface::init();
  reset();
}
void loop() {
  CompInterface::resetTick();
  tick();
}

This file is not generated by KIELER. It includes the interface header and the header of the SSCharts-generated FlightController, which will be output in C, not explicit for Arduino.

In the setup and loop methods the reset and tick functions of the FlightController are triggered, while before the tick function the instanced CompInterface is notified about a new tick. each call the static CompInterface ist notified.

CompInterface.h

Code Block
languagecpp
#ifndef CompInterface_h
#define CompInterface_h
#define lightPin 13
#include "Arduino.h"
#include "HardwareConnector.h"
#include "SimulationConnector.h"
void setLightOn();
void setLightOff();
int getProximity();

class CompInterface {
  private:
  static boolean simulation;
  static HardwareConnector connector;
  static int distance;
  
  public:
  CompInterface();
  static void init();
  static void resetTick();
  static int getProximity();
  static void setLightOn();
  static void setLightOff();
  static void simulate(boolean active);
};
#endif

The CompInterface represents the communication interface to the sensors and actuators. It has a boolean, which knows if a simulation or real flight is running and gives the ability to get notified about a new tick.

Since the Arduino supports C++, most custom routines are written in it. This gives the ability to use classes for example. Note also that Arduino.h is an Arduino library for using Arduino methods in C/C++ code.

The CompInterface header declares a static storage class with all used attributes and methods. It also creates equivalent methods without any class, which are reachable from the KIELER-generated C file.

CompInterface.cpp

Code Block
languagecpp
#include "

...

Arduino.h"
#include "

...

CompInterface.h"
int getProximity() { return CompInterface

...

::getProximity(); }
void setLightOn() { CompInterface::setLightOn(); }
void setLightOff() { CompInterface::setLightOff(); }

boolean CompInterface::simulation;
HardwareConnector CompInterface::connector;
int CompInterface::distance = -1;
CompInterface::CompInterface() {}
void CompInterface::init() {
  simulation = false;
  pinMode(lightPin, OUTPUT);
}
void CompInterface::resetTick() {
  distance = -1;
}
int CompInterface::getProximity() {
  return distance>=0 ? distance : connector.getProximity();
}
void CompInterface::setLightOn() {
  

...

digitalWrite(lightPin, HIGH);
}
void CompInterface::setLightOff() {
  digitalWrite(lightPin, LOW);    

...

}
void CompInterface::simulate(boolean active) {
  simulation = active;
}

This file is just the implementation of the CompInterface.h. Notice that the classless methods at the top of the file just call the storage classes methods, which are not accessible in the C file.

Connector.h

Code Block
languagecpp
#ifndef Connector_h
#define Connector_h
class Connector { 
  public:
  virtual int getProximity() = 0;
  //TODO: Implement more methods
};
#endif

Connector.h creates an abstract class which cannot be instanced but forces all inheriting classes to implement the virtual methods equaling 0.

Heirs will be the HardwareConnector, which uses the real sensors and actuators for the methods, and the SimulationConnector, which contacts the simulation software for getting and setting values.

HardwareConnector.h / SimulationConnector.h

Code Block
languagecpp
#ifndef HardwareConnector_h
#define HardwareConnector_h
#include "Arduino.h"
#include "Connector.h"
class HardwareConnector : public Connector { 
  public:
  HardwareConnector();
  int getProximity();
};
#endif
Code Block
languagecpp
#ifndef SimulationConnector_h
#define SimulationConnector_h
#include "Arduino.h"
#include "Connector.h"
class SimulationConnector : public Connector { 
  public:
  SimulationConnector();
  int getProximity();
};
#endif

The HardwareConnector.h and SimulationConnector.h inherit from the Connector abstract class and thus implement all of its virtual methods.

HardwareConnector.cpp / SimulationConnector.cpp

Code Block
languagecpp
#include "Arduino.h"
#include "HardwareConnector.h"
HardwareConnector::HardwareConnector() {
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
}
int HardwareConnector::getProximity() {
  long duration;
  int distance;
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = (int) (duration/2) / 29.1;
  
  if (distance >= 400 || distance <= 0){
      distance = HardwareConnector::getProximity();
  }
  
  return (int) distance;
}
Code Block
languagecpp
#include "SimulationConnector.h"
SimulationConnector::SimulationConnector() {
}
int SimulationConnector::getProximity() {
  //TODO: Implement
}

These are the pure implementations of the HardwareConnector and the SimulationConnector. The HardwareConnector.cpp now actually measures some distance with the real sensor.

FlightController.h

Code Block
languagecpp
#ifndef FlightController_h
  
  #define FlightController_h
  #include "Arduino.h"
  
  #ifdef __cplusplus
    extern "C" {
  #endif
  
  extern void reset();
  extern void tick();
  
  #ifdef __cplusplus
    }
  #endif
  
#endif

The FlightController.h marks explicitly that its implementation is written in C and declared the reset and tick functions in the KIELER-generated code.

FlightController.c

Code Block
languagecpp
/*****************************************************************************/
/*                 G E N E R A T E D       C    C O D E                      */
/*****************************************************************************/
/* KIELER - Kiel Integrated Environment for Layout Eclipse RichClient        */
/*                                                                           */
/* http://www.informatik.uni-kiel.de/rtsys/kieler/                           */
/* Copyright 2014 by                                                         */
/* + Christian-Albrechts-University of Kiel                                  */
/*   + Department of Computer Science                                        */
/*     + Real-Time and Embedded Systems Group                                */
/*                                                                           */
/* This code is provided under the terms of the Eclipse Public License (EPL).*/
/*****************************************************************************/
int distance;
int _GO;
int g0;
int g1;
int g2;
int PRE_g2;
int g3;
int g4;
int g5;
int g6;
int _condg5;
int _condg3;
void reset(){
   _GO = 1;
   PRE_g2 = 0;
   return;
}
void tick(){
   {
      g0 = _GO;
      if(g0){
         distance = 0;
      }
      g3 =(PRE_g2);
      _condg3 =(distance < 10);
      g4 =(g3&&_condg3);
      if(g4){
         setLightOn();
      }
      g5 =(g3&&(!(_condg3)));
      _condg5 =(distance >= 10);
      g6 =(g5&&_condg5);
      if(g6){
         setLightOff();
      }
      g1 =(g4||(g6||g0));
      if(g1){
         distance =(getProximity());
      }
      g2 =((g5&&(!(_condg5)))||g1);
   }
   PRE_g2 = g2;
   _GO = 0;
   return;
}

This is the generated C file, which can just be saved as FlightController.c out of KIELER in the Sketch folder. Within the SCChart any method of the CompInterface can be used without thinking about its realization. 

This is some basic machine, which controls the LED on the Arduino depending on how near an object is detected in front of the sensor.

Download

QuadcopterController.zip