iCub-main
TransformModule.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007-2010 RobotCub Consortium, European Commission FP6 Project IST-004370
3  * author: Arjan Gijsberts
4  * email: arjan.gijsberts@iit.it
5  * website: www.robotcub.org
6  * Permission is granted to copy, distribute, and/or modify this program
7  * under the terms of the GNU General Public License, version 2 or any
8  * later version published by the Free Software Foundation.
9  *
10  * A copy of the license can be found at
11  * http://www.robotcub.org/icub/license/gpl.txt
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16  * Public License for more details
17  */
18 
19 #include <iostream>
20 #include <stdexcept>
21 #include <cassert>
22 
23 #include <yarp/os/Network.h>
24 #include <yarp/os/Vocab.h>
25 
27 
28 namespace iCub {
29 namespace learningmachine {
30 
31 bool TransformPredictProcessor::read(yarp::os::ConnectionReader& connection) {
32  if(!this->getTransformerPortable().hasWrapped()) {
33  return false;
34  }
35 
36  yarp::sig::Vector input;
37  Prediction prediction;
38  bool ok = input.read(connection);
39  if(!ok) {
40  return false;
41  }
42 
43  try {
44  yarp::sig::Vector trans_input = this->getTransformer().transform(input);
45  this->getOutputPort().write(trans_input, prediction);
46  } catch(const std::exception& e) {
47  std::cerr << "Error: " << e.what() << std::endl;
48  return false;
49  }
50 
51  yarp::os::ConnectionWriter* replier = connection.getWriter();
52  if(replier != (yarp::os::ConnectionWriter*) 0) {
53  prediction.write(*replier);
54  }
55 
56  return true;
57 }
58 
59 
60 void TransformTrainProcessor::onRead(yarp::os::PortablePair<yarp::sig::Vector,yarp::sig::Vector>& input) {
61  if(this->getTransformerPortable().hasWrapped()) {
62  try {
63  yarp::os::PortablePair<yarp::sig::Vector,yarp::sig::Vector>& output = this->getOutputPort().prepare();
64  output.head = this->getTransformer().transform(input.head);
65  output.body = input.body;
66  this->getOutputPort().writeStrict();
67  } catch(const std::exception& e) {
68  std::cerr << "Error: " << e.what() << std::endl;
69  }
70  }
71 
72  return;
73 }
74 
75 
76 void TransformModule::printOptions(std::string error) {
77  if(error != "") {
78  std::cout << "Error: " << error << std::endl;
79  }
80  std::cout << "Available options" << std::endl;
81  std::cout << "--help Display this help message" << std::endl;
82  std::cout << "--list Print a list of available algorithms" << std::endl;
83  std::cout << "--load file Load serialized transformer from a file" << std::endl;
84  std::cout << "--transformer type Desired type of transformer" << std::endl;
85  std::cout << "--trainport port Data port for the training samples" << std::endl;
86  std::cout << "--predictport port Data port for the prediction samples" << std::endl;
87  std::cout << "--port pfx Prefix for registering the ports" << std::endl;
88  std::cout << "--commands file Load configuration commands from a file" << std::endl;
89 }
90 
91 void TransformModule::printTransformerList() {
92  std::vector<std::string> keys = FactoryT<std::string, ITransformer>::instance().getKeys();
93  std::cout << "Available Transformers:" << std::endl;
94  for(unsigned int i = 0; i < keys.size(); i++) {
95  std::cout << " " << keys[i] << std::endl;
96  }
97 }
98 
99 void TransformModule::registerAllPorts() {
100  //this->registerPort(this->model_out, "/" + this->portPrefix + "/model:o");
101 
102  this->registerPort(this->train_in, this->portPrefix + "/train:i");
103  this->train_in.setStrict();
104 
105  this->registerPort(this->train_out, this->portPrefix + "/train:o");
106  this->train_out.setStrict();
107 
108  this->registerPort(this->predict_inout, this->portPrefix + "/predict:io");
109  this->predict_inout.setStrict();
110 
111  this->registerPort(this->predictRelay_inout, this->portPrefix + "/predict_relay:io");
112  //this->predict_relay_inout.setStrict();
113 
114  this->registerPort(this->cmd_in, this->portPrefix + "/cmd:i");
115 }
116 
117 void TransformModule::unregisterAllPorts() {
118  this->cmd_in.close();
119  this->train_in.close();
120  this->train_out.close();
121  this->predict_inout.close();
122  this->predictRelay_inout.close();
123 }
124 
126  cmd_in.interrupt();
127  train_in.interrupt();
128  train_out.interrupt();
129  predict_inout.interrupt();
130  predictRelay_inout.interrupt();
131  return true;
132 }
133 
134 bool TransformModule::configure(yarp::os::ResourceFinder& opt) {
135  // read for the general specifiers:
136  yarp::os::Value* val;
137  std::string transformerName;
138 
139  // cache resource finder
140  this->setResourceFinder(&opt);
141 
142  // check for help request
143  if(opt.check("help")) {
144  this->printOptions();
145  return false;
146  }
147 
148  // check for algorithm listing request
149  if(opt.check("list")) {
150  this->printTransformerList();
151  return false;
152  }
153 
154  // check for port specifier: portSuffix
155  if(opt.check("port", val)) {
156  this->portPrefix = val->asString().c_str();
157  }
158 
159  if(opt.check("load", val)) {
160  this->getTransformerPortable().readFromFile(val->asString().c_str());
161  } else{
162  // check for transformer specifier: transformerName
163  if(opt.check("transformer", val)) {
164  transformerName = val->asString().c_str();
165  } else {
166  this->printOptions("no transformer type specified");
167  return false;
168  }
169 
170  // construct transformer
171  this->getTransformerPortable().setWrapped(transformerName);
172 
173  // send configuration options to the transformer
174  this->getTransformer().configure(opt);
175  }
176 
177  // add processor for incoming data (training samples)
178  this->train_in.useCallback(trainProcessor);
179 
180  // add replier for incoming data (prediction requests)
181  this->predict_inout.setReplier(this->predictProcessor);
182 
183  // register ports
184  this->registerAllPorts();
185 
186  // check for train data port
187  if(opt.check("trainport", val)) {
188  yarp::os::Network::connect(this->train_out.where().getName().c_str(),
189  val->asString().c_str());
190  } else {
191  // add message here if necessary
192  }
193 
194  // check for predict data port
195  if(opt.check("predictport", val)) {
196  yarp::os::Network::connect(this->predictRelay_inout.where().getName().c_str(),
197  val->asString().c_str());
198  } else {
199  // add message here if necessary
200  }
201 
202  // and finally load command file
203  if(opt.check("commands", val)) {
204  std::string full_fname = this->findFile(val->asString().c_str());
205  this->loadCommandFile(full_fname);
206  }
207 
208  // attach to the incoming command port and terminal
209  this->attach(cmd_in);
210  this->attachTerminal();
211 
212  return true;
213 }
214 
215 
216 bool TransformModule::respond(const yarp::os::Bottle& cmd, yarp::os::Bottle& reply) {
217  // NOTE: the module class spawns a new thread, which implies that exception
218  // handling needs to be done in this thread, so not the 'main' thread.
219  bool success = false;
220 
221  try {
222  switch(cmd.get(0).asVocab32()) {
223  case yarp::os::createVocab32('h','e','l','p'): // print help information
224  reply.add(yarp::os::Value::makeVocab32("help"));
225 
226  reply.addString("Transform module configuration options");
227  reply.addString(" help Displays this message");
228  reply.addString(" reset Resets the machine to its current state");
229  reply.addString(" info Outputs information about the transformer");
230  reply.addString(" load fname Loads a transformer from a file");
231  reply.addString(" save fname Saves the current transformer to a file");
232  reply.addString(" set key val Sets a configuration option for the transformer");
233  reply.addString(" cmd fname Loads commands from a file");
234  reply.addString(this->getTransformer().getConfigHelp().c_str());
235  success = true;
236  break;
237 
238  case yarp::os::createVocab32('c','l','e','a'): // clear the machine
239  case yarp::os::createVocab32('c','l','r'):
240  case yarp::os::createVocab32('r','e','s','e'):
241  case yarp::os::createVocab32('r','s','t'):
242  this->getTransformer().reset();
243  reply.addString("Transformer reset.");
244  success = true;
245  break;
246 
247  case yarp::os::createVocab32('i','n','f','o'): // information
248  case yarp::os::createVocab32('s','t','a','t'): // print statistics
249  { // prevent identifier initialization to cross borders of case
250  reply.add(yarp::os::Value::makeVocab32("help"));
251  reply.addString("Transformer Information: ");
252  reply.addString(this->getTransformer().getInfo().c_str());
253  success = true;
254  break;
255  }
256 
257  case yarp::os::createVocab32('s','e','t'): // set a configuration option for the machine
258  { // prevent identifier initialization to cross borders of case
259  yarp::os::Bottle property;
260  /*
261  * This is a simple hack to enable multiple parameters The need
262  * for this hack lies in the fact that a group can only be found
263  * using findGroup if it is a nested list in a Bottle. If the
264  * Bottle itself is the list, then the group will _not_ be found.
265  */
266  property.addList() = cmd.tail();
267  std::string replymsg = "Setting configuration option ";
268  bool ok = this->getTransformer().configure(property);
269  replymsg += ok ? "succeeded" :
270  "failed; please check key and value type.";
271  reply.addString(replymsg.c_str());
272  success = true;
273  break;
274  }
275 
276  case yarp::os::createVocab32('l','o','a','d'): // load
277  { // prevent identifier initialization to cross borders of case
278  reply.add(yarp::os::Value::makeVocab32("help"));
279  std::string replymsg = std::string("Loading transformer from '") +
280  cmd.get(1).asString().c_str() + "'... " ;
281  if(!cmd.get(1).isString()) {
282  replymsg += "failed";
283  } else {
284  this->getTransformerPortable().readFromFile(cmd.get(1).asString().c_str());
285  replymsg += "succeeded";
286  }
287  reply.addString(replymsg.c_str());
288  success = true;
289  break;
290  }
291 
292  case yarp::os::createVocab32('s','a','v','e'): // save
293  { // prevent identifier initialization to cross borders of case
294  reply.add(yarp::os::Value::makeVocab32("help"));
295  std::string replymsg = std::string("Saving transformer to '") +
296  cmd.get(1).asString().c_str() + "'... " ;
297  if(!cmd.get(1).isString()) {
298  replymsg += "failed";
299  } else {
300  this->getTransformerPortable().writeToFile(cmd.get(1).asString().c_str());
301  replymsg += "succeeded";
302  }
303  reply.addString(replymsg.c_str());
304  success = true;
305  break;
306  }
307 
308  case yarp::os::createVocab32('c','m','d'): // cmd
309  case yarp::os::createVocab32('c','o','m','m'): // command
310  { // prevent identifier initialization to cross borders of case
311  reply.add(yarp::os::Value::makeVocab32("help"));
312  std::string replymsg;
313  if(!cmd.get(1).isString()) {
314  replymsg = "Please supply a valid filename.";
315  } else {
316  std::string full_fname = this->findFile(cmd.get(1).asString().c_str());
317  replymsg = std::string("Loading commands from '") +
318  full_fname + "'... " ;
319  this->loadCommandFile(full_fname, &reply);
320  replymsg += "succeeded";
321  }
322  reply.addString(replymsg.c_str());
323  success = true;
324  break;
325  }
326 
327  default:
328  break;
329 
330  }
331  } catch(const std::exception& e) {
332  std::string msg = std::string("Error: ") + e.what();
333  reply.addString(msg.c_str());
334  success = true;
335  }
336 
337  return success;
338 }
339 
340 } // learningmachine
341 } // iCub
static FactoryT< K, T > & instance()
An instance retrieval method that follows the Singleton pattern.
Definition: FactoryT.h:86
std::string portPrefix
A prefix path for the ports that will be registered.
virtual void setResourceFinder(yarp::os::ResourceFinder *rf)
Mutator for the locally stored ResourceFinder.
std::string findFile(std::string fname)
Finds the full path to a specified filename using the ResourceFinder.
void registerPort(yarp::os::Contactable &port, std::string name)
Register a port with a given name.
yarp::os::Port cmd_in
An input port for commands.
virtual void loadCommandFile(std::string fname, yarp::os::Bottle *out=(yarp::os::Bottle *) 0)
Reads bottles from a file and sends these one by one to the respond method.
virtual ITransformer & getTransformer()
Retrieve the wrapped transformer.
virtual TransformerPortable & getTransformerPortable()
Retrieve the transformer portable wrapper.
virtual bool configure(yarp::os::Searchable &config)
Definition: ITransformer.h:168
virtual yarp::sig::Vector transform(const yarp::sig::Vector &input)
Transforms an input vector.
Definition: ITransformer.h:104
virtual void reset()
Forget everything and start over.
Definition: ITransformer.h:125
void setWrapped(T *w, bool wipe=true)
The mutator for the wrapped object.
Definition: PortableT.h:228
bool writeToFile(std::string filename)
Writes a wrapped object to a file.
Definition: PortableT.h:161
bool readFromFile(std::string filename)
Reads a wrapped object from a file.
Definition: PortableT.h:182
A class that represents a prediction result.
Definition: Prediction.h:44
bool write(yarp::os::ConnectionWriter &connection) const
Definition: Prediction.h:166
virtual bool respond(const yarp::os::Bottle &cmd, yarp::os::Bottle &reply)
virtual TransformerPortable & getTransformerPortable()
Retrieve the transformer portable.
virtual bool configure(yarp::os::ResourceFinder &opt)
virtual ITransformer & getTransformer()
Retrieve the transformer that is used in this TransformModule.
virtual bool read(yarp::os::ConnectionReader &connection)
virtual yarp::os::Port & getOutputPort()
Accessor for the prediction output port.
virtual yarp::os::BufferedPort< yarp::os::PortablePair< yarp::sig::Vector, yarp::sig::Vector > > & getOutputPort()
Retrieve the training output port.
virtual void onRead(yarp::os::PortablePair< yarp::sig::Vector, yarp::sig::Vector > &input)
cmd
Definition: dataTypes.h:30
This file contains the definition of unique IDs for the body parts and the skin parts of the robot.