Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

Config.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_Config_h
00003 #define INCLUDED_Config_h
00004 
00005 #include "Shared/plist.h"
00006 #include "Shared/string_util.h"
00007 #include "Shared/RobotInfo.h"
00008 extern "C" {
00009 #include <jpeglib.h>
00010 }
00011 #ifdef PLATFORM_APERIOS
00012 #  include <OPENR/OPrimitiveControl.h>
00013 #else
00014 typedef unsigned int OSpeakerVolume; //!< provides an OPEN-R type of the same name for compatability, see Config::sound_config::volume
00015 const OSpeakerVolume ospkvolinfdB = 0x8000; //!< 'muted' volume level, see Config::sound_config::volume
00016 const OSpeakerVolume ospkvol25dB  = 0xe700; //!< low volume, see Config::sound_config::volume
00017 const OSpeakerVolume ospkvol18dB  = 0xee00; //!< mid volume, see Config::sound_config::volume
00018 const OSpeakerVolume ospkvol10dB  = 0xf600; //!< high volume, see Config::sound_config::volume
00019 #endif
00020 #include <vector>
00021 #include <string>
00022 
00023 //! a subclass of plist::Dictionary which adds support for filtering settings by robot model, each configuration section is based on this
00024 /*! As a slight extension to standard plists, you can specify
00025  *  model-specific settings by prepending a key with:
00026  *     Model:MODEL_PATTERN:KEY_NAME
00027  *  For example, to use different 'thresh' settings on the ERS-2xx
00028  *  series vs. the ERS-7 model, you would use the keys:
00029  *   - Model:ERS-2*:thresh
00030  *   - Model:ERS-7:thresh
00031  *  You can filter several items as a group by leaving off the second
00032  *  ':' and name, and providing a dictionary as the value.  If the
00033  *  model matches, all entries from the dictionary are imported into
00034  *  the parent dictionary.
00035  */
00036 class ConfigDictionary : public plist::Dictionary {
00037 public:
00038   ConfigDictionary() : plist::Dictionary(false)
00039   {
00040     if(curModel.size()==0)
00041       curModel=RobotName;
00042   }
00043   
00044 protected:
00045   
00046   virtual bool loadXMLNode(const std::string& key, xmlNode* val, const std::string& comment);
00047   virtual bool saveOverXMLNode(xmlNode* k, xmlNode* val, const std::string& key, std::string comment, const std::string& indentStr, std::set<std::string>& seen) const;
00048 
00049   //! returns true if pattern matches model - pattern may have up to 1 '*', case insensitive
00050   static bool matchNoCase(const std::string& model, const std::string& pattern);
00051   
00052   static const std::string msPrefix; //!< the prefix indicating a model-specific key
00053   static const std::string msSep; //!< the separator string which splits the key into the prefix, model pattern, and (optionally) a single key name
00054   //static const std::string msNum;
00055   static std::string curModel; //!< will be set to the model identifier of the currently running hardware
00056   static void initCurModel(); //!< function to initialize #curModel
00057 };
00058 
00059 //! Stores an item for each joint, can be accessed via joint name or array offset
00060 /*! Two main reasons for this class are to keep outputs in offset order (not alphabetic by name),
00061  *  and to strip '~' from output names for backward compatability (used to pad output names
00062  *  to ensure constant string length. */
00063 template<typename T>
00064 class OutputConfig : public ConfigDictionary {
00065 public:
00066   //! constructor
00067   OutputConfig(unsigned int firstOffset, unsigned int numOutputsToStore, const T& defValue)
00068   : ConfigDictionary(), offset(firstOffset), outputs(numOutputsToStore,defValue)
00069   {
00070     for(unsigned int i=0; i<numOutputsToStore; ++i)
00071       addEntry(outputNames[i+firstOffset],outputs[i]);
00072   }
00073   //! strips trailing '~' characters from name before doing usual lookup
00074   virtual ObjectBase& getEntry(const std::string& name) {
00075     std::string::size_type n = name.find_last_not_of('~')+1;
00076     return ConfigDictionary::getEntry((n==name.size()) ? name : name.substr(0,n));
00077   }
00078   //! return the value at position @a index, which must exist (no range checking)
00079   T& getEntry(size_t index) { return outputs[index]; }
00080   //! return the value at position @a index, which must exist (no range checking, equivalent to getEntry(index))
00081   T& operator[](size_t index) { return outputs[index]; }
00082   using ConfigDictionary::operator[];
00083   
00084   //! small trick -- override to save outputs in indexed order instead of alphabetical order
00085   void saveXML(xmlNode* node, bool onlyOverwrite, std::set<std::string>& seen) const;
00086   using ConfigDictionary::saveXML;
00087   
00088 protected:
00089   //! strips trailing '~' characters from name before doing usual lookup
00090   bool loadXMLNode(const std::string& key, xmlNode* val, const std::string& comment) {
00091     std::string::size_type n = key.find_last_not_of('~')+1;
00092     return ConfigDictionary::loadXMLNode((n==key.size()) ? key : key.substr(0,n), val, comment);
00093   }
00094   
00095   unsigned int offset; //!< the index offset of the first entry in #outputs
00096   std::vector<T> outputs; //!< storage of data for each output
00097 };
00098 
00099 //! the root configuration object, provides some global functionality like porting pathnames (portPath())
00100 class Config : public ConfigDictionary {
00101 public:
00102   Config(const std::string& filename="") : ConfigDictionary(),
00103     behaviors(), wireless(), main(), controller(), vision(), motion(this), sound(this), fsRoot()
00104   {
00105     addEntry("wireless",wireless);
00106     addEntry("vision",vision);
00107     addEntry("main",main);
00108     addEntry("behaviors",behaviors);
00109     addEntry("controller",controller);
00110     addEntry("motion",motion);
00111     addEntry("sound",sound);
00112     if(filename.size()!=0)
00113       loadFile(filename.c_str());
00114   }
00115   
00116   enum transports { UDP, TCP }; //!< types of network transport protocols supported
00117   static const unsigned int NUM_TRANSPORTS=2; //!< number of #transports available
00118   static const char * transport_names[NUM_TRANSPORTS+1]; //!< string names for #transports
00119   
00120   void setFileSystemRoot(const std::string& fsr); //!< sets #fsRoot
00121   const std::string& getFileSystemRoot() const { return fsRoot; } //!< returns #fsRoot
00122   
00123   //! returns a portable version of @a path which should be usable on either the simulator or the robot
00124   std::string portPath(const std::string& path) const;
00125   
00126   //!returns an absolute path if @a is relative (to root), otherwise just @a name
00127   std::string makePath(const std::string& name) const { return searchPath(name,"config"); }
00128 
00129   //! searches for @a name at root/target/name, root/name, and finally just name, returns root/target/name if not found.
00130   std::string searchPath(const std::string& name, const std::string& root) const;
00131   
00132   
00133   
00134   // **************************************** //
00135   //! place for users to put their own configuration
00136   // **************************************** //
00137   /*! you can dynamically "link in" external configuration settings by passing them to the addEntry() of the
00138    *  plist::Dictionary superclass.  You may want to call writeParseTree() first to flush current settings,
00139    *  and then readParseTree() afterward to pull any pre-existing values from the configuration
00140    *  file into the instances you've just registered.
00141    *
00142    *  Of course, you could also just write your values into the configuration file first, and just rely
00143    *  on getEntry/setEntry to read/write the value.  This may be more convenient if you use the
00144    *  value infrequently and don't need an instance of it sitting around. */
00145   class behaviors_config : public ConfigDictionary {
00146   public:
00147     //! constructor
00148     behaviors_config() : ConfigDictionary(), flash_bytes(4), flash_on_start(true)
00149     {
00150       //users may want to dynamically link in their own settings when running, so don't warn if there are
00151       // unused items in this section
00152       setUnusedWarning(false);
00153       
00154       addEntry("flash_bytes",flash_bytes,"how many bytes of the address to flash\n"
00155                "You probably already know the first 3 bytes for your network,\n"
00156                "so you might only want the last byte for brevity.\n"
00157                "(valid values are 1 through 4) ");
00158       addEntry("flash_on_start",flash_on_start,"whether or not to automatically trigger on boot\n"
00159                "Will use a priority of kEmergencyPriority+1 in order to override\n"
00160                "the emergency stop's status animation ");
00161     }
00162     plist::Primitive<unsigned int> flash_bytes; //!< how many bytes of the IP to flash
00163     plist::Primitive<bool> flash_on_start;      //!< whether or not to trigger flashing when initially started
00164   } behaviors;
00165 
00166   
00167   
00168   // **************************************** //
00169   //! wireless configuration options
00170   // **************************************** //
00171   class wireless_config : public ConfigDictionary {
00172   public:
00173     //! constructor
00174     wireless_config () : ConfigDictionary(), id(1) {
00175       addEntry("id",id,"id number (in case you have more than one AIBO)");
00176     }
00177     plist::Primitive<int> id; //!< id number (in case you have more than one AIBO)
00178   } wireless;
00179   
00180   
00181   
00182   // **************************************** //
00183   //! general configuration options
00184   // **************************************** //
00185   class main_config : public ConfigDictionary {
00186   public:
00187     //!constructor
00188     main_config()
00189       : ConfigDictionary(), seed_rng(true), console_port(10001), consoleMode(CONTROLLER,consoleModeNames), stderr_port(10002),
00190       wsjoints_port(10031),wspids_port(10032),gamepadControl_port(10041),headControl_port(10052),armControl_port(10054),
00191       walkControl_port(10050),estopControl_port(10053),stewart_port(10055),aibo3d_port(10051),
00192       wmmonitor_port(10061), use_VT100(true), worldState_interval(0)
00193     {
00194       addEntry("seed_rng",seed_rng,"if true, will call srand with timestamp data, mangled by current sensor data");
00195       addEntry("console_port",console_port,"port to send/receive \"console\" information on (separate from system console)");
00196       addEntry("consoleMode",consoleMode,"determines how input on console_port is interpreted\n"+consoleMode.getDescription()+"\n"
00197                "  'controller' will pass it as input to the Controller (assumes same syntax as ControllerGUI)\n"
00198                "  'textmsg' will broadcast it as a TextMsgEvent (textmsgEGID)\n"
00199                "  'auto' is the original mode, which uses 'textmsg' if the ControllerGUI is connected, and 'controller' otherwise ");
00200       addEntry("stderr_port",stderr_port,"port to send error information to");
00201       addEntry("wsjoints_port",wsjoints_port,"port to send joint positions on");
00202       addEntry("wspids_port",wspids_port,"port to send pid info on");
00203       addEntry("gamepad", gamepadControl_port, "port to receive gamepad data\n");
00204       addEntry("headControl_port",headControl_port,"port for receiving head commands");
00205                         addEntry("armControl_port",armControl_port,"port for receiving arm commands");
00206       addEntry("walkControl_port",walkControl_port,"port for receiving walk commands");
00207       addEntry("estopControl_port",estopControl_port,"port for receiving walk commands");
00208       addEntry("stewart_port",stewart_port,"port for running a stewart platform style of control");
00209       addEntry("aibo3d_port",aibo3d_port,"port for send/receive of joint positions from Aibo 3D GUI");
00210       addEntry("wmmonitor_port",wmmonitor_port,"port for monitoring Watchable Memory");
00211       addEntry("use_VT100",use_VT100,"if true, enables VT100 console codes (currently only in Controller menus - 1.3)");
00212       addEntry("worldState_interval",worldState_interval,"time (in milliseconds) to wait between sending WorldState updates over wireless");
00213     }
00214     plist::Primitive<bool> seed_rng;     //!< if true, will call srand with timestamp data, mangled by current sensor data
00215     plist::Primitive<int> console_port;  //!< port to send/receive "console" information on (separate from system console)
00216     //! types that #consoleMode can take on
00217     enum consoleMode_t {
00218       CONTROLLER, //!< all input is interpreted as Controller commands, using same syntax as the GUI sends
00219       TEXTMSG, //!< all input is broadcast as a text message event
00220       AUTO //!< if the GUI is connected, interpret as text messages, otherwise as controller commands.  This was the historical behavior, but seems to be more confusing than helpful.
00221     };
00222     static const unsigned int NUM_CONSOLE_MODES=3; //!< the number of consoleMode_t values available
00223     static const char* consoleModeNames[NUM_CONSOLE_MODES+1]; //!< string names for #consoleMode_t
00224     //! determines how input on #console_port is interpreted
00225     plist::NamedEnumeration<consoleMode_t> consoleMode; 
00226     plist::Primitive<int> stderr_port;   //!< port to send error information to
00227     plist::Primitive<int> wsjoints_port; //!< port to send joint positions on
00228     plist::Primitive<int> wspids_port;   //!< port to send pid info on
00229     plist::Primitive<int> gamepadControl_port; //!< port for gamepad
00230     plist::Primitive<int> headControl_port;    //!< port for receiving head commands
00231                 plist::Primitive<int> armControl_port;     //!< port for receiving head commands
00232     plist::Primitive<int> walkControl_port;    //!< port for receiving walk commands
00233     plist::Primitive<int> estopControl_port;     //!< port for receiving walk commands
00234     plist::Primitive<int> stewart_port;  //!< port for running a stewart platform style of control
00235     plist::Primitive<int> aibo3d_port;   //!< port for send/receive of joint positions from Aibo 3D GUI
00236     plist::Primitive<int> wmmonitor_port; //!< port for monitoring Watchable Memory
00237     plist::Primitive<bool> use_VT100;    //!< if true, enables VT100 console codes (currently only in Controller menus - 1.3)
00238     plist::Primitive<unsigned int> worldState_interval; //!< time (in milliseconds) to wait between sending WorldState updates over wireless
00239   } main;
00240 
00241   
00242   
00243   // **************************************** //
00244   //! controller information
00245   // **************************************** //
00246   class controller_config : public ConfigDictionary {
00247   public:
00248     //!constructor
00249     controller_config() : ConfigDictionary(), gui_port(10020), select_snd(), next_snd(), prev_snd(), read_snd(), cancel_snd(), error_snd()
00250     {
00251       addEntry("gui_port",gui_port,"port to listen for the GUI to connect to aibo on");
00252       addEntry("select_snd",select_snd,"sound file to use for \"select\" action");
00253       addEntry("next_snd",next_snd,"sound file to use for \"next\" action");
00254       addEntry("prev_snd",prev_snd,"sound file to use for \"prev\" action");
00255       addEntry("read_snd",read_snd,"sound file to use for \"read from std-in\" action");
00256       addEntry("cancel_snd",cancel_snd,"sound file to use for \"cancel\" action");
00257       addEntry("error_snd",error_snd,"sound file to use to signal errors");
00258     }
00259   
00260     plist::Primitive<int> gui_port;        //!< port to listen for the GUI to connect to aibo on
00261     plist::Primitive<std::string> select_snd; //!< sound file to use for "select" action
00262     plist::Primitive<std::string> next_snd;   //!< sound file to use for "next" action
00263     plist::Primitive<std::string> prev_snd;   //!< sound file to use for "prev" action
00264     plist::Primitive<std::string> read_snd;   //!< sound file to use for "read from std-in" action
00265     plist::Primitive<std::string> cancel_snd; //!< sound file to use for "cancel" action
00266     plist::Primitive<std::string> error_snd; //!< sound file to use to signal errors
00267   } controller;
00268 
00269   
00270   
00271   // **************************************** //
00272   //! vision configuration options (this is a *big* section, with sub-sections)
00273   // **************************************** //
00274   class vision_config : public ConfigDictionary {
00275   public:
00276     //!constructor
00277     vision_config() : ConfigDictionary(), 
00278           white_balance(WB_FLUORESCENT), gain(GAIN_MID), shutter_speed(SHUTTER_MID), resolution(1),
00279       thresh(), colors("config/default.col"), restore_image(true), region_calc_total(true),
00280       jpeg_dct_method(JDCT_IFAST,dct_method_names), aspectRatio(CameraResolutionX/(float)CameraResolutionY),
00281       x_range(), y_range(), x_focalLen(), y_focalLen(), // these four values depend on aspectRatio, will be initialized by aspectRatioListener constructor
00282           rawcam(), depthcam(), segcam(), regioncam(),
00283       aspectRatioListener(aspectRatio,*this,&vision_config::aspectRatioChanged)
00284     {
00285       white_balance.addNameForVal("indoor",WB_INDOOR);
00286       white_balance.addNameForVal("outdoor",WB_OUTDOOR);
00287       white_balance.addNameForVal("fluorescent",WB_FLUORESCENT);
00288       white_balance.addNameForVal("flourescent",WB_FLUORESCENT); //catch common typo
00289       addEntry("white_balance",white_balance,"white balance shifts color spectrum in the image\n"+white_balance.getDescription());
00290       
00291       gain.addNameForVal("low",GAIN_LOW);
00292       gain.addNameForVal("mid",GAIN_MID);
00293       gain.addNameForVal("med",GAIN_MID);
00294       gain.addNameForVal("medium",GAIN_MID);
00295       gain.addNameForVal("high",GAIN_HIGH);
00296       addEntry("gain",gain,"Increasing gain will brighten the image, at the expense of more graininess/noise\n"+gain.getDescription());
00297       
00298       shutter_speed.addNameForVal("slow",SHUTTER_SLOW);
00299       shutter_speed.addNameForVal("low",SHUTTER_SLOW);
00300       shutter_speed.addNameForVal("mid",SHUTTER_MID);
00301       shutter_speed.addNameForVal("med",SHUTTER_MID);
00302       shutter_speed.addNameForVal("medium",SHUTTER_MID);
00303       shutter_speed.addNameForVal("fast",SHUTTER_FAST);
00304       shutter_speed.addNameForVal("high",SHUTTER_FAST);
00305       addEntry("shutter_speed",shutter_speed,"slower shutter will brighten image, but increases motion blur\n"+shutter_speed.getDescription());
00306       
00307       addEntry("resolution",resolution,"the resolution that object recognition system will run at.\nThis counts down from the maximum resolution layer, so higher numbers mean lower resolution. ");
00308       addEntry("thresh",thresh,"Threshold (.tm) files define the mapping from full color to indexed color.\n"
00309                "You can uncomment more than one of these - they will be loaded into separate\n"
00310                "channels of the segmenter.  The only cost of loading multiple threshold files is\n"
00311                "memory - the CPU cost of performing segmentation is only incurred if/when\n"
00312                "the channel is actually accessed for the first time for a given frame. ");
00313       addEntry("colors",colors,"The colors definition (.col) file gives names and a \"typical\" color for display.\n"
00314                "The indexes numbers it contains correspond to indexes in the .tm file\n"
00315                "This file is common to all .tm files; when doing new color segmentations,\n"
00316                "make sure you define colors in the same order as listed here! ");
00317       addEntry("restore_image",restore_image,"Apparently someone at Sony thought it would be a good idea to replace some\n"
00318                "pixels in each camera image with information like the frame number and CDT count.\n"
00319                "If non-zero, will replace those pixels with the actual image pixel value in RawCamGenerator ");
00320       addEntry("region_calc_total",region_calc_total,"When true, this will fill in the CMVision::color_class_state::total_area\n"
00321                "field for each color following region labeling.  If false, the total_area\n"
00322                "will stay 0 (or whatever the last value was), but you save a little CPU. ");
00323       addEntry("jpeg_dct_method",jpeg_dct_method,"pick between dct methods for jpeg compression\n"+jpeg_dct_method.getDescription());
00324       
00325       /* these are *not* read from configuration file, but set from most recent camera image (via RawCameraGenerator, or RobotInfo namespace values until a camera image is been received):
00326        - aspectRatio
00327        - x_range
00328        - y_range
00329        */
00330       
00331       addEntry("rawcam",rawcam);
00332       addEntry("depthcam", depthcam);
00333       addEntry("segcam",segcam);
00334       addEntry("regioncam",regioncam);
00335     }
00336     
00337 #ifdef PLATFORM_APERIOS
00338     //! white balance levels supported by the Aibo's camera
00339     enum white_balance_levels {
00340       WB_INDOOR=ocamparamWB_INDOOR_MODE,
00341       WB_OUTDOOR=ocamparamWB_OUTDOOR_MODE,
00342       WB_FLUORESCENT=ocamparamWB_FL_MODE
00343     };
00344 #else
00345     //! white balance levels supported by the Aibo's camera
00346     enum white_balance_levels { WB_INDOOR=1, WB_OUTDOOR, WB_FLUORESCENT };
00347 #endif
00348     plist::NamedEnumeration<white_balance_levels> white_balance; //!< white balance shifts color spectrum in the image
00349     
00350 #ifdef PLATFORM_APERIOS
00351     //! gain levels supported by the Aibo's camera
00352     enum gain_levels {
00353       GAIN_LOW=ocamparamGAIN_LOW,
00354       GAIN_MID=ocamparamGAIN_MID,
00355       GAIN_HIGH=ocamparamGAIN_HIGH
00356     };
00357 #else
00358     //! gain levels supported by the Aibo's camera
00359     enum gain_levels { GAIN_LOW=1, GAIN_MID, GAIN_HIGH };
00360 #endif
00361     plist::NamedEnumeration<gain_levels> gain; //!< Increasing gain will brighten the image, at the expense of more graininess/noise
00362 
00363 #ifdef PLATFORM_APERIOS
00364     //! shutter speeds supported by the Aibo's camera
00365     enum shutter_speeds {
00366       SHUTTER_SLOW=ocamparamSHUTTER_SLOW,
00367       SHUTTER_MID=ocamparamSHUTTER_MID,
00368       SHUTTER_FAST=ocamparamSHUTTER_FAST
00369     };
00370 #else
00371     //! shutter speeds supported by the Aibo's camera
00372     enum shutter_speeds { SHUTTER_SLOW=1, SHUTTER_MID, SHUTTER_FAST };
00373 #endif
00374     plist::NamedEnumeration<shutter_speeds> shutter_speed; //!< slower shutter will brighten image, but increases motion blur
00375     
00376     enum encoding_t {
00377       ENCODE_COLOR, //!< send Y, U, and V channels
00378       ENCODE_SINGLE_CHANNEL, //!< send only a single channel (which channel to send is stored in #channel) This is also used for all seg cam images
00379       ENCODE_DEPTH,
00380     };
00381     static const unsigned int NUM_ENCODINGS=3; //!< number of encodings available
00382     static const char * encoding_names[NUM_ENCODINGS+1]; //!< string names for #encoding_t
00383     
00384     plist::Primitive<int> resolution;       //!< the resolution that object recognition system will run at -- this counts down from the maximum resolution layer, so higher numbers mean lower resolution
00385     plist::ArrayOf<plist::Primitive<std::string> > thresh;      //!< threshold file names
00386     plist::Primitive<std::string> colors;      //!< colors definition (.col) file
00387     plist::Primitive<bool> restore_image;   //!< if true, replaces pixels holding image info with actual image pixels (as much as possible anyway)
00388     plist::Primitive<bool> region_calc_total; //!< if true, RegionGenerator will calculate total area for each color (has to run through the region list for each color)
00389     static const char * dct_method_names[]; //!< string names for #J_DCT_METHOD
00390     plist::NamedEnumeration<J_DCT_METHOD> jpeg_dct_method;  //!< pick between dct methods for jpeg compression
00391     plist::Primitive<float> aspectRatio;    //!< ratio of width to height (x_res/y_res); this is *not* read from configuration file, but set from most recent camera image (via RawCameraGenerator, or RobotInfo namespace values until a camera image is been received):
00392     float x_range;        //!< range of values for the x axis when using generalized coordinates; this is *not* read from configuration file, but set from most recent camera image (via RawCameraGenerator, or RobotInfo namespace values until a camera image is been received):
00393     float y_range;        //!< range of values for the y axis when using generalized coordinates; this is *not* read from configuration file, but set from most recent camera image (via RawCameraGenerator, or RobotInfo namespace values until a camera image is been received):
00394     float x_focalLen; //!< focal length of x axis: x_range / tan(RobotInfo::CameraHorizFOV); this is *not* read from configuration file, but set from most recent camera image (via RawCameraGenerator, or RobotInfo namespace values until a camera image is been received):
00395     float y_focalLen; //!< focal length of y axis: y_range / tan(RobotInfo::CameraVertFOV); this is *not* read from configuration file, but set from most recent camera image (via RawCameraGenerator, or RobotInfo namespace values until a camera image is been received):
00396     
00397     //! contains settings related to streaming video over the network
00398     class StreamingConfig : public ConfigDictionary {
00399     public:
00400       explicit StreamingConfig(int portNum) : ConfigDictionary(), port(portNum), transport(Config::UDP,transport_names), interval(0)
00401       {
00402         addEntry("port",port,"the port number to open for sending data over");
00403         addEntry("transport",transport,"the IP protocol to use when sending data");
00404         addEntry("interval",interval,"minimum amount of time (in milliseconds) which must pass between frames\nE.g. 200 yields just under 5 frames per second, 0 is as fast as possible");
00405       }
00406       plist::Primitive<unsigned short> port;
00407       plist::NamedEnumeration<Config::transports> transport;
00408       plist::Primitive<unsigned int> interval;
00409     };
00410     
00411     //! contains settings specific to the "RawCam" (original camera images) for streaming video over the network
00412     class RawCamConfig : public StreamingConfig {
00413     public:
00414       RawCamConfig() : StreamingConfig(10011),
00415         encoding(ENCODE_COLOR,encoding_names), channel(0), compression(COMPRESS_JPEG,compression_names), compress_quality(85), y_skip(2), uv_skip(3)
00416       {
00417         addEntry("encoding",encoding,"holds whether to send color or single channel\n"+encoding.getDescription());
00418         addEntry("channel",channel,"if encoding is single channel, this indicates the channel to send");
00419         addEntry("compression",compression,"the type of compression to apply the image\n"+compression.getDescription());
00420         addEntry("compress_quality",compress_quality,"0-100, compression quality (currently only used by jpeg)");
00421         addEntry("y_skip",y_skip,"resolution level to transmit y channel\nAlso used as the resolution level when in single-channel encoding mode ");
00422         addEntry("uv_skip",uv_skip,"resolution level to transmit uv channel at when using 'color' encoding mode");
00423       }
00424       //! type of information to send, stored in #encoding
00425       
00426       plist::NamedEnumeration<Config::vision_config::encoding_t> encoding; //!< holds whether to send color or single channel
00427       plist::Primitive<int> channel;    //!< RawCameraGenerator::channel_id_t, if #encoding is single channel, this indicates the channel to send
00428 
00429       //! compression format to use, stored in Config::vision_config::RawCamConfig::compression
00430       enum compression_t {
00431         COMPRESS_NONE, //!< no compression (other than subsampling)
00432         COMPRESS_JPEG, //!< JPEG compression
00433         COMPRESS_PNG, //!< PNG compression
00434       };
00435       static const unsigned int NUM_COMPRESSIONS=4; //!< number of compression algorithms available
00436       static const char * compression_names[NUM_COMPRESSIONS+1]; //!< string names for #compression_t
00437       plist::NamedEnumeration<compression_t> compression;//!< holds whether to send jpeg compression
00438 
00439       plist::Primitive<unsigned int> compress_quality;//!< 0-100, compression quality (currently only used by jpeg)
00440       plist::Primitive<unsigned int> y_skip;     //!< resolution level to transmit y channel at
00441       plist::Primitive<unsigned int> uv_skip;    //!< resolution level to transmit uv channel at
00442     } rawcam;
00443 
00444     class DepthCamConfig : public StreamingConfig {
00445     public:
00446       DepthCamConfig() : StreamingConfig(10014), compression(COMPRESS_JPEG, compression_names), compress_quality(85), y0_skip(2), y1_skip(2)
00447       {
00448         transport = Config::TCP;
00449         addEntry("compression",compression,"what compression to use on the segmented image"+compression.getDescription());
00450         addEntry("compress_quality",compress_quality,"0-100, compression quality (currently only used by jpeg)");
00451         addEntry("y0_skip",y0_skip,"resolution level to transmit y channel\nAlso used as the resolution level when in single-channel encoding mode ");
00452         addEntry("y1_skip",y1_skip,"resolution level to transmit uv channel at when using 'color' encoding mode");
00453       }
00454       //! compression format to use, stored in Config::vision_config::RawCamConfig::compression
00455       enum compression_t {
00456         COMPRESS_NONE, //!< no compression (other than subsampling)
00457         COMPRESS_JPEG, //!< JPEG compression
00458         COMPRESS_PNG   //!< PNG compression
00459       };
00460       static const unsigned int NUM_COMPRESSIONS=4; //!< number of compression algorithms available
00461       static const char * compression_names[NUM_COMPRESSIONS+1]; //!< string names for #compression_t
00462       plist::NamedEnumeration<compression_t> compression;//!< what compression to use on the segmented image
00463       plist::Primitive<unsigned int> compress_quality;//!< 0-100, compression quality (currently only used by jpeg)
00464       plist::Primitive<unsigned int> y0_skip;     //!< resolution level to transmit y channel at
00465       plist::Primitive<unsigned int> y1_skip; 
00466     } depthcam;
00467     
00468     //! contains settings specific to the "SegCam" (segmented color images) for streaming video over the network
00469     class SegCamConfig : public StreamingConfig {
00470     public:
00471       SegCamConfig() : StreamingConfig(10012), skip(1), channel(0), compression(COMPRESS_RLE, compression_names)
00472       {
00473         addEntry("skip",skip,"resolution level to transmit segmented images at");
00474         addEntry("channel",channel,"channel of RLEGenerator to send (i.e. which threshold map to use");
00475         addEntry("compression",compression,"what compression to use on the segmented image"+compression.getDescription());
00476       }
00477       plist::Primitive<unsigned int> skip;       //!< resolution level to transmit segmented images at
00478       plist::Primitive<unsigned int> channel;    //!< channel of RLEGenerator to send (i.e. which threshold map to use)
00479       
00480       //! compression format to use, stored in Config::vision_config::RawCamConfig::compression
00481       enum compression_t {
00482         COMPRESS_NONE, //!< no compression (other than subsampling)
00483         COMPRESS_RLE   //!< RLE compression
00484       };
00485       static const unsigned int NUM_COMPRESSIONS=4; //!< number of compression algorithms available
00486       static const char * compression_names[NUM_COMPRESSIONS+1]; //!< string names for #compression_t
00487       plist::NamedEnumeration<compression_t> compression;//!< what compression to use on the segmented image
00488     } segcam;
00489     
00490     //! contains settings specific to the "RegionCam" (only display a box for each blob of color) for streaming over the network
00491     class RegionCamConfig : public StreamingConfig {
00492     public:
00493       RegionCamConfig() : StreamingConfig(10013), skip(1) {
00494         addEntry("skip",skip,"resolution level to extract regions from");
00495       }
00496       plist::Primitive<unsigned int> skip; //!< resolution level to transmit segmented images at 
00497     } regioncam;
00498     
00499     //!provides a ray through camera origin from a generalized pixel coordinate
00500     /*!
00501      * Ideally this would take camera calibration into account, e.g. Lens Distortion for Close-Range Photogrammetry -  D.C. Brown, Photometric Engineering, pages 855-866, Vol. 37, No. 8, 1971.
00502      * or using 'Camera Calibration Toolbox for Matlab', by Jean-Yves Bouguet: http://www.vision.caltech.edu/bouguetj/calib_doc/
00503      *
00504      * However, at the moment this does a naïve computation mapping directly from field of view as specified by RobotInfo CameraFOV
00505      * 
00506      *  @param[in] x x position in range ±x_range (±1 assuming x is the major camera axis)
00507      *  @param[in] y y position in range ±y_range (±1/#aspectRatio assuming x is the major camera axis)
00508      *  @param[out] r_x x value of the ray
00509      *  @param[out] r_y y value of the ray
00510      *  @param[out] r_z z value of the ray (always 1) */
00511     void computeRay(float x, float y, float& r_x, float& r_y, float& r_z);
00512       
00513     //!provides a generalized pixel hit in image by a ray going through the camera origin
00514     /*! @param[in] r_x x value of the ray
00515      *  @param[in] r_y y value of the ray
00516      *  @param[in] r_z z value of the ray
00517      *  @param[out] x x position in range ±x_range (±1 assuming x is the major camera axis)
00518      *  @param[out] y y position in range ±y_range (±1/#aspectRatio assuming x is the major camera axis) */
00519     void computePixel(float r_x, float r_y, float r_z, float& x, float& y);
00520     //@}
00521     
00522     //!provides a generalized pixel hit in image by a ray going through the camera origin that is corrected via the homography
00523     /*! @param[in] r_x x value of the ray
00524      *  @param[in] r_y y value of the ray
00525      *  @param[in] r_z z value of the ray
00526      *  @param[out] x x position in range ±x_range (±1 assuming x is the major camera axis)
00527      *  @param[out] y y position in range ±y_range (±1/#aspectRatio assuming x is the major camera axis) */
00528     void computePixelCorrected(float r_x, float r_y, float r_z, float& x, float &y);
00529     
00530   protected:
00531     void aspectRatioChanged();
00532     plist::PrimitiveCallbackMember<vision_config> aspectRatioListener;
00533         
00534   } vision;
00535   
00536   
00537   
00538   //!motion information
00539   class motion_config : public ConfigDictionary {
00540   public:
00541     //!constructor
00542     motion_config(Config* c)
00543     : ConfigDictionary(), thisconfig(c), root("data/motion"), walk("walk.prm"), kinematics(std::string(RobotInfo::RobotName).append(".kin")),
00544         calibration_scale(PIDJointOffset, NumPIDJoints,1), calibration_offset(PIDJointOffset, NumPIDJoints, 0), 
00545         estop_on_snd(), estop_off_snd(), 
00546       max_head_tilt_speed(0), max_head_pan_speed(0), max_head_roll_speed(0), inf_walk_accel(false),
00547       console_port(10003), stderr_port(10004)
00548     {
00549       addEntry("root",root,"path on memory stick to \"motion\" files - for instance, position (.pos) and motion sequence (.mot)\n"
00550                "Any motion related paths which are not absolute (i.e. do not start with '/')\n"
00551                "will be assumed to be relative to this directory ");
00552       addEntry("walk",walk,"the walk parameter file to load by default for new WalkMC's");
00553       addEntry("kinematics",kinematics,"the ROBOOP format kinematics description file to load");
00554       addEntry("calibration_scale",calibration_scale,"Multiplier from desired position to command for each PID joint, applied after calibration_offset.");
00555       addEntry("calibration_offset",calibration_offset,"These values indicate the offset from user specified zero point to the\n"
00556                "physical system's zero point.  Added before calibration_scale when\n"
00557                "converting from user's desired position to command to send to hardware.");
00558       addEntry("estop_on_snd",estop_on_snd,"sound file to use when e-stop turned on");
00559       addEntry("estop_off_snd",estop_off_snd,"sound file to use when e-stop turned off");
00560       addEntry("max_head_tilt_speed",max_head_tilt_speed,"max speed for the head joints, used by HeadPointerMC; rad/s");
00561       addEntry("max_head_pan_speed",max_head_pan_speed,"max speed for the head joints, used by HeadPointerMC; rad/s");
00562       addEntry("max_head_roll_speed",max_head_roll_speed,"max speed for the head joints, used by HeadPointerMC; rad/s");
00563       addEntry("inf_walk_accel",inf_walk_accel,"if true, walks should attempt to switch directions immediately; otherwise they should do some kind of software acceleration to more smoothly switch direction");
00564       addEntry("console_port",console_port,"port to send/receive \"console\" information on (separate from system console)");
00565       addEntry("stderr_port",stderr_port,"port to send error information to");
00566     }
00567     
00568     //!returns an absolute path if @a is relative (to root), otherwise just @a name
00569     std::string makePath(const std::string& name) { return thisconfig->searchPath(name, root); }
00570     
00571     Config* thisconfig;  //!<pointer back to the containing config object
00572     plist::Primitive<std::string> root;       //!< path on memory stick to "motion" files - for instance, position (.pos) and motion sequence (.mot)
00573     plist::Primitive<std::string> walk;       //!< the walk parameter file to load by default for new WalkMC's
00574     plist::Primitive<std::string> kinematics;  //!< the kinematics description file to load
00575     OutputConfig<plist::Primitive<float> > calibration_scale; //!< Multiplier from desired position to command for each PID joint, applied after calibration_offset.
00576     OutputConfig<plist::Primitive<float> > calibration_offset; //!< Indicates the offset from user specified zero point to the physical system's zero point.  Added before calibration_scale when converting from user's desired position to command to send to hardware.
00577     plist::Primitive<std::string> estop_on_snd;  //!< sound file to use when e-stop turned on
00578     plist::Primitive<std::string> estop_off_snd; //!< sound file to use when e-stop turned off
00579     plist::Primitive<float> max_head_tilt_speed; //!< max speed for the head joints, used by HeadPointerMC; rad/s
00580     plist::Primitive<float> max_head_pan_speed; //!< max speed for the head joints, used by HeadPointerMC; rad/s
00581     plist::Primitive<float> max_head_roll_speed; //!< max speed for the head joints, used by HeadPointerMC; rad/s
00582     plist::Primitive<bool> inf_walk_accel; //!< if true, walks should attempt to switch directions immediately; otherwise they should do some kind of software acceleration to more smoothly switch direction
00583     plist::Primitive<int> console_port;  //!< port to send/receive "console" information on (separate from system console)
00584     plist::Primitive<int> stderr_port;   //!< port to send error information to
00585     
00586   private:
00587     motion_config(const motion_config&); //!< don't call
00588     motion_config& operator=(const motion_config&); //!< don't call
00589   } motion;
00590 
00591   
00592   
00593   //!sound information
00594   class sound_config : public ConfigDictionary {
00595   public:
00596     //!constructor
00597     sound_config(Config* c) : ConfigDictionary(), thisconfig(c), root("data/sound"), verbose(0), volume(HIGH), sample_rate(16000),
00598       sample_bits(16), preload(), pitchConfidenceThreshold(.6f), streaming()
00599     {
00600       addEntry("root",root,"path to sound clips");
00601       addEntry("verbose",verbose,"Controls diagnostic information on the console:\n  0 - none\n  1 - report when sounds begin to play\n  2 - also report when sounds finish playing\n  3- also report when sounds are preloaded and released");
00602       volume.addNameForVal("mute",MUTE);
00603       volume.addNameForVal("level_1",LOW);
00604       volume.addNameForVal("low",LOW);
00605       volume.addNameForVal("level_2",MID);
00606       volume.addNameForVal("mid",MID);
00607       volume.addNameForVal("level_3",HIGH);
00608       volume.addNameForVal("high",HIGH);
00609       volume.setStrict(false);
00610       addEntry("volume",volume,"volume in decibels - the value is interpreted as a signed short, where\n"
00611           "0x8000 is mute, 0xFFFF is full volume (low=0xE700, mid=0xEE00, high=0xF600)\n"
00612           "If you directly set the decibel level, be warned sony recommends against going above 0xF600\n"
00613           "However, I believe the commercial software on the ERS-7 runs at 0xFF00.\n"
00614           "Going above 0xF800 on a ERS-210 causes distortion (clipping) - full volume on a ERS-7 sounds fine though.\n"+volume.getDescription());
00615       addEntry("sample_rate",sample_rate,"sample rate to send to system, currently only 8000 or 16000 supported");
00616       addEntry("sample_bits",sample_bits,"sample bit depth, either 8 or 16");
00617       addEntry("preload",preload,"list of sounds to preload at boot");
00618       addEntry("pitchConfidenceThreshold",pitchConfidenceThreshold,"confidence threshold required to generate a pitch event [0-1]");
00619       addEntry("streaming",streaming);
00620     }
00621   
00622     //!returns an absolute path if @a is relative (to root), otherwise just @a name
00623     std::string makePath(const std::string& name) { 
00624       if(name[0]=='/')
00625         return thisconfig->portPath(name);
00626       if(root[root.size()-1]=='/')
00627         return thisconfig->portPath(root+name);
00628       else
00629         return thisconfig->portPath(root+"/"+name);
00630     }
00631   
00632     Config* thisconfig;  //!<pointer back to the containing config object
00633     plist::Primitive<std::string> root;         //!< path to sound clips
00634     
00635     //! Controls diagnostic information on the console
00636     /*! 0 - none\n
00637      *  1 - report when sounds begin to play\n
00638      *  2 - also report when sounds finish playing\n
00639      *  3- also report when sounds are preloaded and released */
00640     plist::Primitive<int> verbose;
00641     
00642     //! Provides some symbolic volume levels, although values are based on actual volume in decibels.
00643     /*! The value is interpreted as a signed short, where 0 is full volume, 0x8000 is mute */
00644     enum volume_levels { MUTE=ospkvolinfdB, LOW=ospkvol25dB, MID=ospkvol18dB, HIGH=ospkvol10dB };
00645     plist::NamedEnumeration<volume_levels> volume;      //!< volume in decibels - the value is interpreted as a signed short, where 0 is full volume, 0x8000 is mute
00646     
00647     plist::Primitive<unsigned int> sample_rate; //!< sample rate to send to system, currently only 8000 or 16000 supported
00648     plist::Primitive<unsigned int> sample_bits; //!< sample bit depth, either 8 or 16
00649     plist::ArrayOf<plist::Primitive<std::string> > preload; //!< list of sounds to preload at boot
00650     plist::Primitive<float> pitchConfidenceThreshold; //!< confidence threshold required to generate a pitch event [0-1]
00651     
00652     //! audio streaming configuration
00653     class streaming_config : public ConfigDictionary {
00654     public:
00655       //! constructor
00656       streaming_config() : ConfigDictionary(), mic_port(10070), mic_sample_rate(16000),
00657         mic_sample_bits(16), mic_stereo(true),
00658         speaker_port(10071), speaker_frame_length(64),
00659         speaker_max_delay(1000)
00660       {
00661         addEntry("mic_port",mic_port,"port for streaming microphone samples");
00662         addEntry("mic_sample_rate",mic_sample_rate,"sample rate from the microphone");
00663         addEntry("mic_sample_bits",mic_sample_bits,"sample bit depth from the microphone (either 8 or 16)");
00664         addEntry("mic_stereo",mic_stereo,"whether to stream stereo or mono from the microphone");
00665         
00666         addEntry("speaker_port",speaker_port,"port for streaming speaker samples");
00667         addEntry("speaker_frame_length",speaker_frame_length,"length of frame sent to the speaker (ms)");
00668         addEntry("speaker_max_delay",speaker_max_delay,"maximum delay (ms) during playback");
00669       }
00670       plist::Primitive<unsigned int> mic_port;        //!< port for streaming microphone samples
00671       plist::Primitive<unsigned int> mic_sample_rate; //!< sample rate from the microphone
00672       plist::Primitive<unsigned int> mic_sample_bits; //!< sample bit depth from the microphone (either 8 or 16)
00673       plist::Primitive<bool> mic_stereo; //!< whether to stream stereo or mono from the microphone
00674       
00675       plist::Primitive<unsigned int> speaker_port;    //!< port for streaming speaker samples
00676       plist::Primitive<unsigned int> speaker_frame_length; //!< length of frame sent to the speaker (ms)
00677       plist::Primitive<unsigned int> speaker_max_delay; //!< maximum delay (ms) during playback
00678     } streaming;
00679   private:
00680     sound_config(const sound_config&); //!< don't call
00681     sound_config& operator=(const sound_config&); //!< don't call
00682   } sound;
00683 
00684   
00685   
00686   virtual void saveXML(xmlNode* node, bool onlyOverwrite, std::set<std::string>& seen) const;
00687   using ConfigDictionary::saveXML;
00688   virtual unsigned int loadBuffer(const char buf[], unsigned int len, const char* filename=NULL);
00689   virtual unsigned int loadFile(const char* filename);
00690   virtual unsigned int loadFileStream(FILE* f, const char* filename=NULL);
00691   
00692   //! pass the section, item name string, item value string - sets the value and returns pointer to the item changed
00693   /*! this is the older deprecated interface -- use the inherited resolveEntry() instead to support sub-sections */
00694   void* setValue(const std::string& section, std::string key, const std::string& value);
00695   
00696 protected:
00697   static const char * xmlIntro1;
00698   static const char * xmlIntro2;
00699   static const char * xmlIntro3;
00700   
00701   static const std::locale& curLocale;
00702   static char localeToLower(char c) { return std::tolower(c,curLocale); };
00703   
00704   unsigned int loadOldFormat(const char buf[], unsigned int len);
00705   unsigned int loadOldFormat(FILE* f);
00706   void parseLine(const char buf[], unsigned int lineno, std::vector<std::string>& modelStack, bool& ignoring, std::string& section);
00707   
00708   //! a prefix representing the file system root, usually indicating the robot's storage root.
00709   /*! When running in the simulator, this is used to pretend that a subdirectory in the project folder (e.g. 'ms') is the root file system */
00710   std::string fsRoot;
00711 };
00712 
00713 template<typename T>
00714 void OutputConfig<T>::saveXML(xmlNode* node, bool onlyOverwrite, std::set<std::string>& seen) const {
00715   // first just overwrite what's already there as we normally do
00716   ConfigDictionary::saveXML(node,true,seen);
00717   // now if there's anything left...
00718   if(!onlyOverwrite && seen.size()!=dict.size()) {
00719     // clear text nodes from end of dictionary back to last entry
00720     for(xmlNode* cur=xNodeGetLastChild(node); cur!=NULL && xNodeIsText(cur); cur=xNodeGetLastChild(node)) {
00721       xmlUnlinkNode(cur);
00722       xmlFreeNode(cur);
00723     }
00724     size_t longestKeyLen = getLongestKeyLen(NULL,1);
00725     std::string indentStr=getIndentationPrefix(node);
00726     // this is the customized part -- save in "natural" output order instead of alphabetically by key
00727     for(unsigned int i=0; i<outputs.size(); ++i) {
00728       if(seen.find(outputNames[i+offset])==seen.end())
00729         saveXMLNode(node,outputNames[i+offset],&outputs[i],indentStr,longestKeyLen);
00730     }
00731     std::string parentIndent;
00732     if(indentStr.size()>=perIndent().size())
00733       parentIndent=indentStr.substr(perIndent().size());
00734     xmlAddChild(node,xmlNewText((const xmlChar*)("\n"+parentIndent).c_str()));
00735   }
00736 }
00737 
00738 //!allows global access to current settings
00739 extern Config* config;
00740 
00741 /*! @file
00742  * @brief Describes Config, which provides global access to system configuration information
00743  * @author ejt (Creator)
00744  * @author alokl (Original configuration system)
00745  */
00746 
00747 #endif

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:37 2016 by Doxygen 1.6.3