//## begin module%1.4%.codegen_version preserve=yes // Read the documentation to learn more about C++ code generator // versioning. //## end module%1.4%.codegen_version //## begin module%3D86D3570320.cm preserve=no // %X% %Q% %Z% %W% //## end module%3D86D3570320.cm //## begin module%3D86D3570320.cp preserve=no //## end module%3D86D3570320.cp //## Module: SIR%3D86D3570320; Pseudo Package specification //## Source file: C:\Program Files\Rational\Rose\C++\source\SIR.h #ifndef SIR_h #define SIR_h 1 //## begin module%3D86D3570320.additionalIncludes preserve=no //## end module%3D86D3570320.additionalIncludes //## begin module%3D86D3570320.includes preserve=yes //## end module%3D86D3570320.includes // ImageFilter #include "ImageFilter.h" // PSDs #include "PSDs.h" // Camera #include "Camera.h" // Drive #include "Drive.h" // Thread #include "Thread.h" //## begin module%3D86D3570320.additionalDeclarations preserve=yes //## end module%3D86D3570320.additionalDeclarations //## begin SIR%3D86D3570320.preface preserve=yes //## end SIR%3D86D3570320.preface //## Class: SIR%3D86D3570320 // /** // This class (Sensor and Image Recognition) provides // high-level information to the behaviors by // pre-processing the data internally. The provided // information includes current obstacle distances as // received by the infra-red sensors. But in particular // information about the locations of cubes and robots that // are visible on camera are provided. // As all behaviors should use the same SIR thread this class // is designed as a singleton class. So at any given time there // is at most one instance of the class. The method SIR::getSIR() // is used to access that instance. // @author Jia L. Du. // */ //## Category: //## Persistence: Transient //## Cardinality/Multiplicity: n class SIR : public Thread //## Inherits: %3D86D5A002BC { //## begin SIR%3D86D3570320.initialDeclarations preserve=yes //## end SIR%3D86D3570320.initialDeclarations public: //## Other Operations (specified) //## Operation: obstacleLeft%3D9296DA015E // /** // Indicates whether an obstacle is detected by the left // infra-red sensor // @return true if there is an obstacle // */ bool obstacleLeft (); //## Operation: obstacleRight%3D9296F8000A // /** // Indicates whether an obstacle is detected by the right // infra-red sensor // @return true if there is an obstacle // */ bool obstacleRight (); //## Operation: obstacleFront%3D9296F801C2 // /** // Indicates whether an obstacle is detected by the front // infra-red sensor // @return true if there is an obstacle // */ bool obstacleFront (); //## Operation: getLeftMargin%3D99481C028A // /** // Returns the distance from the robot to the next object // to the left // @return distance in meter // */ double getLeftMargin (); //## Operation: getRightMargin%3D9948230082 // /** // Returns the distance from the robot to the next object // to the right // @return distance in meter // */ double getRightMargin (); //## Operation: getFrontMargin%3D99482B0096 // /** // Returns the distance from the robot to the next object // in the front // @return distance in meter // */ double getFrontMargin (); //## Operation: robotDetected%3D99453C024E // /** // Indicates if a robot is currently visible on the camera // @return true if a robot is on the camera // */ bool robotDetected (); //## Operation: cubeDetected%3D994557000A // /** // Indicates if a cube is currently visible on the camera // @return true if a cube is on the camera // */ bool cubeDetected (); //## Operation: getRobotPosition%3D99488A033E // /** // Passes the last known position of the last detected // robot. If no robot has been detected yet (0,0,0) is // passed. SIR::robotDetected() should be used before // calling this method to check if the data is up to date // (i.e. the robot whose position is passed is indeed still // visible). If more than one robot was detected on the // image the position of the closest robot is passed // */ void getRobotPosition (double& x, double& y, double& phi); //## Operation: getGlobalCubePosition%3D9948740168 // /** // Passes the last known position of the last detected // cube in global coordinates (i.e. with (0,0) and not the // current robot position as origin). If no cube has been detected yet // (0,0) is passed. SIR::cubeDetected() should be used before // calling this method to check if the data is up to date // (i.e. the cube whose position is passed is indeed still // visible). If more than one cube was detected on the // image the position of the closest cube is passed // */ void getGlobalCubePosition (double& x, double& y); //## Operation: getDensity%3D9948C90294 // /** // Estimates the cube density in the image by counting the // pixels that have the cube color // @param density The value can range from 0.0 (no cubes) to 1.0 // (all camera pixels have the cube color) // @param centerOfDensityX x coordinate of the estimated center of the cube cluster // relative to the current robot position // @param centerOfDensityY y coordinate of the estimated center of the cube cluster // relative to the current robot position // */ void getDensity (double& density, double& centerOfDensityX, double& centerOfDensityY); //## Operation: setCubeSize%3D9972CE0334 // /** // Not used yet // */ void setCubeSize (int size); //## Operation: setCubeColor%3D9972EE00F0 // /** // Not used yet // */ void setCubeColor (int color); // Additional Public Declarations //## begin SIR%3D86D3570320.public preserve=yes // /** // This method is used to get the instance of this // singleton class // @return A pointer to the instance // */ static SIR* getSIR (); // /** // Indicates whether an obstacle is detected by // any of the infra-red sensors // @return true if there is an obstacle // */ bool obstacle (void); // /** // According to C++ convention, methods cannot be static and // virtual at once. In the initial design run was declared as // virtual which results in dynamic binding. That means the // program determines at run-time which run method to use, // the one of the Thread base class or the one of the inheritor. // Because we have to use staticRun, we cannot use the virtual // keyword anymore. Without the virtual keyword the compiler // determines at compile-time which run method is used, always // the run method of the Thread base class. To ensure that the // inheritor indeed uses its own run method, it is necessary to // overwrite the thread initialization method (spawn) as well. // @see staticRun // @return true if successful // */ bool spawn (); // /** // Passes the last known position of the last detected // cube in local coordinates. If no cube has been detected yet // (0,0) is passed. // As the position is passed in local coordinates // (that is the relative distance from cube to robot // at the time when the image - on which the cube was detected - // was taken) this information expires quickly. // SIR::cubeDetected() should definitely be used before // calling this method to check if the data is up to date // (i.e. the cube whose position is passed is indeed still // visible). If more than one cube was detected on the // image the position of the closest cube is passed // */ void getLocalCubePosition (double& x, double& y); // /** // The simulator does not allow the usage of RoBIOS functions // in class constructors. Therefore we use public // initialize methods for classes that need RoBIOS functions for // their initializations. // */ void initialize(void); //## end SIR%3D86D3570320.public protected: //## Constructors (specified) //## Operation: SIR%3D9EBF620046 // /** // Constructor for SIR. Passes standard parameters for SIR to the // Thread constructor // */ SIR (); // Additional Protected Declarations //## begin SIR%3D86D3570320.protected preserve=yes void run(void); //protected or private?? // /** // Static wrapper method for run. It does nothing but to call run. // That is necessary because the RoBIOS multi-tasking functions expect // a pointer to a C-function (not a pointer to a C++ method) containing // the code to be executed. Fortunately, pointer-to-static-C++-methods // are compatible with regular pointer-to-C-functions. But the problem // is that static methods can only use other static methods and variables. // The reasons is that a static method, which is shared by all instances, // would not know which non-static method or variable to use if there were // multiple instances of the same class. Thus, the static property would // have to be applied to all used (sub-)methods and (sub-) variables, // and propagate through the whole class structure. By using staticRun, // we can keep using our non-static run. If static methods cannot call // non-static ones, how can staticRun call run? As aforementioned the // reason why static method cannot use non-static members is because it // is not clear which non-static member to use if there are multiple // instances of the same class. That means staticRun needs a pointer // to the instance whose run method is to be called. This pointer is // stored in a static member variable called me. // @see me // */ static void staticRun(void); //protected or private?? //## end SIR%3D86D3570320.protected private: //## Other Operations (specified) //## Operation: takePicture%3D9948FB03D4 // /** // Gets a new image from the camera // and stores it in currentImage // @see currentImage // */ void takePicture (); //## Operation: takeColorPicture%3D9FC00D014A // /** // Gets a new color image from the camera // and stores it in currentColorImage // @see currentColorImage // */ void takeColorPicture (); //## Operation: detectCubes%3D99479F0168 // /** // Tries to detect cubes in the current color image // @see currentColorImage // @return true if at least one cube was detected // */ bool detectCubes (); //## Operation: detectRobots%3D9947AD00C8 // /** // Tries to detect robots in the current image // @see currentImage // @return true if at least one robot was detected // */ bool detectRobots (); // Additional Private Declarations //## begin SIR%3D86D3570320.private preserve=yes // /** // Stores pointers to instances of SIR // @see staticRun // */ static SIR* mes[NUMBER_OF_ROBOTS]; // /** // The single instance that exists of this class // @see SIR::getSIR() // */ static SIR sirs[NUMBER_OF_ROBOTS]; // /** //Camera dependent lookup table. //Factor to get x position in meters from x position in pixels. //62 values, one for each row. 0 and 61 not used by me. //Example: something is in row 1. //Distance from the robot = 0.460m = row2Meter[1]. //Something is in row 60. //Distance from the robot = 0.0023m = row2Meter[60] // */ static const double row2Meter[imagerows]; //not static?? // /** //Camera dependent lookup table. //Factor to calculate y position from pixels to meters depending on //x position (unit of yFactor is width(m)/width(pixels)). //62 values, one for each row. 0 and 61 not used by me. //Example: cube width = 0.1m. //Cube size in pixel in row 1 (top row, furthest away) = 0.1m/(0.0093m/pixel) = 11 pixel. //Cube in pixel in row 60 (bottom row, closest) = 0.1m/(0.0017m/pixel) = 59 pixel. //The other direction: something is 20 pixel from the image middle and in row 1. //Distance from the robot (y component) = 20*(0.0093m/pixel) = 0.186m. //Something is 20 pixel from the image middle and in row 60. //Distance from the robot = 20*(0.0017m/pixel) = 0.034m. //yFactor is the table for objects left of the robot. //yFactorMinus is the table for objects left of the robot. //We obtained better results using two tables. // */ static const double yFactor[imagerows]; //not static?? // /** //Camera dependent lookup table. //Factor to calculate y position from pixels to meters depending on //x position (unit of yFactor is width(m)/width(pixels)). //62 values, one for each row. 0 and 61 not used by me. //Example: cube width = 0.1m. //Cube size in pixel in row 1 (top row, furthest away) = 0.1m/(0.0093m/pixel) = 11 pixel. //Cube in pixel in row 60 (bottom row, closest) = 0.1m/(0.0017m/pixel) = 59 pixel. //The other direction: something is 20 pixel from the image middle and in row 1. //Distance from the robot (y component) = 20*(0.0093m/pixel) = 0.186m. //Something is 20 pixel from the image middle and in row 60. //Distance from the robot = 20*(0.0017m/pixel) = 0.034m. //yFactor is the table for objects left of the robot. //yFactorMinus is the table for objects right of the robot. //We obtained better results using two tables. // */ static const double yFactorMinus[imagerows]; //not static?? // /** // Stores the x value of the last known position of the last detected cube // in local coordinates (That is the x distance from cube to robot // at the time when the image - on which the cube was detected - was taken) // // */ double cubeDistanceX; // /** // Stores the y value of the last known position of the last detected cube // in local coordinates (That is the y distance from cube to robot // at the time when the image - on which the cube was detected - was taken) // // */ double cubeDistanceY; // /** // Stores the x value of the last known position of // the last detected cube (in global coordinates, i.e. with (0,0) and not the // current robot position as origin) // */ double cubePositionX; // /** // Stores the y value of the last known position of // the last detected cube (in global coordinates, i.e. with (0,0) and not the // current robot position as origin) // */ double cubePositionY; // /** // Checks if the passed hue is similar to the // cube color // @see cubeColor // @see allowedCubeColorDeviation // @return true if similar // */ bool hasCubeColor(BYTE hue); // /** // How far the distance to an object may drop before the // object is marked as an obstacle by the front PSD sensor (in meter) // */ double obstacleThresholdFront; //## end SIR%3D86D3570320.private private: //## implementation // Data Members for Class Attributes //## Attribute: robotDetectedFlag%3D99450601EA // /** // Flag to indicate that a robot is visible on the camera. // Used internally // @see SIR::robotDetected() // */ //## begin SIR::robotDetectedFlag%3D99450601EA.attr preserve=no private: bool {U} false bool robotDetectedFlag; //## end SIR::robotDetectedFlag%3D99450601EA.attr //## Attribute: cubeDetectedFlag%3D99451A021C // /** // Flag to indicate that a cube is visible on the camera. // Used internally // @see SIR::cubeDetected() // */ //## begin SIR::cubeDetectedFlag%3D99451A021C.attr preserve=no private: bool {U} false bool cubeDetectedFlag; //## end SIR::cubeDetectedFlag%3D99451A021C.attr //## Attribute: minimumCubeSize%3D9973990302 // /** // Stores the minimum size that an object must have to be // accepted as a cube (in meter) // */ //## begin SIR::minimumCubeSize%3D9973990302.attr preserve=no private: double {U} 0.015 double minimumCubeSize; //## end SIR::minimumCubeSize%3D9973990302.attr //## Attribute: cubeColor%3D9973A10348 // /** // Stores the color of the cubes to be pushed as hue // */ //## begin SIR::cubeColor%3D9973A10348.attr preserve=no private: int {U} -1 int cubeColor; //## end SIR::cubeColor%3D9973A10348.attr //## Attribute: allowedCubeColorDeviation%3D9FBCC60046 // /** // By how much the color of a pixel may deviate and still // be accepted as cube color // */ //## begin SIR::allowedCubeColorDeviation%3D9FBCC60046.attr preserve=no private: int {U} 0 int allowedCubeColorDeviation; //## end SIR::allowedCubeColorDeviation%3D9FBCC60046.attr //## Attribute: obstacleThreshold%3D9FBD200168 // /** // How far the distance to an object may drop before the // object is marked as an obstacle by the left/right PSD sensor (in meter) // */ //## begin SIR::obstacleThreshold%3D9FBD200168.attr preserve=no private: double {U} 0.15 double obstacleThresholdSides; //## end SIR::obstacleThreshold%3D9FBD200168.attr //## Attribute: currentImage%3D9FBDA600DC // /** // The grayscale image that is currently used for the // detection of robots (SIR::detectRobots()) // */ //## begin SIR::currentImage%3D9FBDA600DC.attr preserve=no private: image {U} image currentImage; //## end SIR::currentImage%3D9FBDA600DC.attr //## Attribute: currentColorImage%3D9FBDE4037A // /** // The color image that is currently used for // the detection of cubes (by SIR::detectCubes(), // SIR::getDensity()) // */ //## begin SIR::currentColorImage%3D9FBDE4037A.attr preserve=no private: colimage {U} colimage currentColorImage; //## end SIR::currentColorImage%3D9FBDE4037A.attr // Data Members for Associations //## Association: %3D86D4B801E0 //## Role: SIR::%3D86D4B9008C // /** // The SIR has a Camera to get pictures // */ //## begin SIR::%3D86D4B9008C.role preserve=no public: Camera { -> RHN} Camera *camera; //## end SIR::%3D86D4B9008C.role //## Association: %3D8843E00118 //## Role: SIR::%3D8843E0029E // /** // The SIR has an ImageFilter to process the taken pictures // */ //## begin SIR::%3D8843E0029E.role preserve=no public: ImageFilter { -> RHN} ImageFilter imageFilter; //## end SIR::%3D8843E0029E.role //## Association: %3D8FF37C0398 //## Role: SIR::%3D8FF37E0014 // /** // The SIR needs the PSDs to receive infra-red distance // information // */ //## begin SIR::%3D8FF37E0014.role preserve=no public: PSDs { -> RHN} PSDs *psds; //## end SIR::%3D8FF37E0014.role //## Association: %3D9AC9BB029E //## Role: SIR::%3D9AC9BC0032 // /** // The SIR needs the Drive to receive position information // */ //## begin SIR::%3D9AC9BC0032.role preserve=no public: Drive { -> RHN} Drive *drive; //## end SIR::%3D9AC9BC0032.role // Additional Implementation Declarations //## begin SIR%3D86D3570320.implementation preserve=yes //## end SIR%3D86D3570320.implementation }; //## begin SIR%3D86D3570320.postscript preserve=yes //## end SIR%3D86D3570320.postscript // Class SIR //## begin module%3D86D3570320.epilog preserve=yes //## end module%3D86D3570320.epilog #endif