worldcontroller.cpp
1 /********************************************************************************
2  * WorldSim -- library for robot simulations *
3  * Copyright (C) 2008-2011 Gianluca Massera <emmegian@yahoo.it> *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the Free Software *
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
18  ********************************************************************************/
19 
20 #ifdef FARSA_USE_YARP_AND_ICUB
21 
22 #include "worldcontroller.h"
23 #include "phybox.h"
24 #include "physphere.h"
25 #include "phycylinder.h"
26 #include "wcamera.h"
27 #include "phyicub.h"
28 #include <QCoreApplication>
29 #include <QTimerEvent>
30 
31 using namespace yarp::os;
32 
33 namespace farsa {
34 
35 ServerWorldController::ServerWorldController( WorldController* ctrl ) : QThread() {
36  wctrl = ctrl;
37  //--- list of commands
38  asyn_cmds["start"] = &ServerWorldController::startCmd;
39  asyn_cmds["pause"] = &ServerWorldController::pauseCmd;
40  asyn_cmds["stop"] = &ServerWorldController::stopCmd;
41  asyn_cmds["advance"] = &ServerWorldController::advanceCmd;
42  //--- Sync Commands
43  syn_cmds["mk"] = &ServerWorldController::makeCmd;
44  syn_cmds["set"] = &ServerWorldController::setCmd;
45  setTerminationEnabled( true );
46 }
47 
49  //--- nothing to do
50 }
51 
53  Port* port = wctrl->outPort();
54  while( !queue_cmds.isEmpty() ) {
55  Bottle cmd = queue_cmds.dequeue();
56  Bottle res;
57  QString cmd0( cmd.get(0).toString().c_str() );
58  //--- we are sure that there is an entry into sync_cmds
59  //--- because it was checked into run loop
60  res = (this->*(syn_cmds[cmd0]))( cmd );
61  port->write(res);
62  }
63 }
64 
66  Port* inport = wctrl->inPort();
67  Port* outport = wctrl->outPort();
68  while( true ) {
69  Bottle cmd;
70  Bottle res;
71  //--- read the command... and will reply on outPort
72  inport->read( cmd, false );
73  //--- checking the command
74  QString cmd0( cmd.get(0).asString().c_str() );
75  if ( asyn_cmds.contains( cmd0 ) ) {
76  res = (this->*(asyn_cmds[cmd0]))( cmd );
77  } else if ( syn_cmds.contains( cmd0 ) ) {
78  res.addString( "Command Queued" );
79  queue_cmds.enqueue( cmd );
80  } else {
81  res.addString( "Unsupported Command: " );
82  res.addString( cmd.get(0).toString() );
83  }
84  //--- reply
85  outport->write(res);
86  }
87 }
88 
89 yarp::os::Bottle ServerWorldController::startCmd( const yarp::os::Bottle& ) {
90  QCoreApplication::postEvent( wctrl->world(), new QEvent( (QEvent::Type)(World::E_Play) ) );
91  Bottle res;
92  res.addString("World Running");
93  return res;
94 }
95 
96 yarp::os::Bottle ServerWorldController::pauseCmd( const yarp::os::Bottle& ) {
97  QCoreApplication::postEvent( wctrl->world(), new QEvent( (QEvent::Type)(World::E_Pause) ) );
98  Bottle res;
99  res.addString("World Paused");
100  return res;
101 }
102 
103 yarp::os::Bottle ServerWorldController::stopCmd( const yarp::os::Bottle& ) {
104  QCoreApplication::postEvent( wctrl->world(), new QEvent( (QEvent::Type)(World::E_Stop) ) );
105  Bottle res;
106  res.addString("World Stopped");
107  return res;
108 }
109 
110 yarp::os::Bottle ServerWorldController::advanceCmd( const yarp::os::Bottle& ) {
111  Bottle res;
112  if ( wctrl->world()->status() == World::playingS ) {
113  res.addString("World is currently running, pause it before use advance command");
114  } else {
115  QCoreApplication::postEvent( wctrl->world(), new QEvent( (QEvent::Type)(World::E_Advance) ) );
116  res.addString("World Advanced");
117  }
118  return res;
119 }
120 
121 yarp::os::Bottle ServerWorldController::makeCmd( const yarp::os::Bottle& cmd ) {
122  Bottle res;
123  // --- switch over the type of object to create
124  QString objtype = cmd.get(1).toString().c_str();
125  //--- The rotation will be computed on the basis of Pitch-Yaw-Roll rotations about
126  // the given euler angles (ZYX) convention
127  //--- there are many variants of the "mk" command depending on the second parameter:
128  // mk box name x_dim y_dim z_dim x_pos y_pos z_pos x_rot y_rot z_rot
129  // mk sphere name radius x_pos y_pos z_pos x_rot y_rot z_rot
130  // mk cylinder name radius length x_pos y_pos z_pos x_rot y_rot z_rot
131  // mk icub name x_pos y_pos z_pos x_rot y_rot z_rot
132  // mk camera name x_pos y_pos z_pos x_rot y_rot z_rot width heigth
133  // ------- following not yet implemented commands
134  // mk fixed name obj_parent obj_child
135  // mk hinge name obj_parent obj_child axis centre startAngle
136  if ( objtype == "box" ) {
137  // --- create a box
138  real x_dim = 1.0;
139  real y_dim = 1.0;
140  real z_dim = 1.0;
141  wMatrix tm = wMatrix::identity();
142  Value v = cmd.get(2);
143  if ( v.isNull() ) {
144  res.addString( "You must specify a name for the object" );
145  return res;
146  }
147  QString name = v.toString().c_str();
148  x_dim = cmd.get(3).asDouble();
149  y_dim = cmd.get(4).asDouble();
150  z_dim = cmd.get(5).asDouble();
151  if ( x_dim == 0 || y_dim == 0 || z_dim == 0 ) {
152  res.addString( "Dimension of the object must be greater than zero" );
153  return res;
154  }
155  wVector pos( cmd.get(6).asDouble(), cmd.get(7).asDouble(), cmd.get(8).asDouble() );
156  tm = tm * wMatrix::pitch( toRad( cmd.get(9).asDouble() ) );
157  tm = tm * wMatrix::yaw( toRad( cmd.get(10).asDouble() ) );
158  tm = tm * wMatrix::roll( toRad( cmd.get(11).asDouble() ) );
159  tm.w_pos = pos;
160  new PhyBox( x_dim, y_dim, z_dim, wctrl->world(), name, tm );
161  } else if ( objtype == "sphere" ) {
162  // --- create a sphere
163  real radius = 1.0;
164  wMatrix tm = wMatrix::identity();
165  Value v = cmd.get(2);
166  if ( v.isNull() ) {
167  res.addString( "You must specify a name for the object" );
168  return res;
169  }
170  QString name = v.toString().c_str();
171  radius = cmd.get(3).asDouble();
172  if ( radius == 0 ) {
173  res.addString( "Dimension of the object must be greater than zero" );
174  return res;
175  }
176  wVector pos( cmd.get(4).asDouble(), cmd.get(5).asDouble(), cmd.get(6).asDouble() );
177  tm = tm * wMatrix::pitch( toRad( cmd.get(7).asDouble() ) );
178  tm = tm * wMatrix::yaw( toRad( cmd.get(8).asDouble() ) );
179  tm = tm * wMatrix::roll( toRad( cmd.get(9).asDouble() ) );
180  tm.w_pos = pos;
181  new PhySphere( radius, wctrl->world(), name, tm );
182  } else if ( objtype == "cylinder" ) {
183  // --- create a cylinder
184  real radius = 1.0;
185  real len = 1.0;
186  wMatrix tm = wMatrix::identity();
187  Value v = cmd.get(2);
188  if ( v.isNull() ) {
189  res.addString( "You must specify a name for the object" );
190  return res;
191  }
192  QString name = v.toString().c_str();
193  radius = cmd.get(3).asDouble();
194  len = cmd.get(4).asDouble();
195  if ( radius == 0 || len == 0 ) {
196  res.addString( "Dimension of the object must be greater than zero" );
197  return res;
198  }
199  wVector pos( cmd.get(5).asDouble(), cmd.get(6).asDouble(), cmd.get(7).asDouble() );
200  tm = tm * wMatrix::pitch( toRad(cmd.get(8).asDouble()) );
201  tm = tm * wMatrix::yaw( toRad(cmd.get(9).asDouble()) );
202  tm = tm * wMatrix::roll( toRad(cmd.get(10).asDouble()) );
203  tm.w_pos = pos;
204  new PhyCylinder( radius, len, wctrl->world(), name, tm );
205  } else if ( objtype == "icub" ) {
206  // --- create a iCub
207  wMatrix tm = wMatrix::identity();
208  Value v = cmd.get(2);
209  if ( v.isNull() ) {
210  res.addString( "You must specify a name for the object" );
211  return res;
212  }
213  QString name = v.toString().c_str();
214  wVector pos( cmd.get(3).asDouble(), cmd.get(4).asDouble(), cmd.get(5).asDouble() );
215  tm = tm * wMatrix::pitch( toRad(cmd.get(6).asDouble()) );
216  tm = tm * wMatrix::yaw( toRad(cmd.get(7).asDouble()) );
217  tm = tm * wMatrix::roll( toRad(cmd.get(8).asDouble()) );
218  tm.w_pos = pos;
219  PhyiCub* icub = new PhyiCub( wctrl->world(), name, tm );
220  icub->blockTorso0( true );
221  } else if ( objtype == "camera" ) {
222  // --- create a camera
223  wMatrix tm = wMatrix::identity();
224  Value v = cmd.get(2);
225  if ( v.isNull() ) {
226  res.addString( "You must specify a name for the object" );
227  return res;
228  }
229  QString name = v.toString().c_str();
230  wVector pos( cmd.get(3).asDouble(), cmd.get(4).asDouble(), cmd.get(5).asDouble() );
231  tm = tm * wMatrix::pitch( toRad(cmd.get(6).asDouble()) );
232  tm = tm * wMatrix::yaw( toRad(cmd.get(7).asDouble()) );
233  tm = tm * wMatrix::roll( toRad(cmd.get(8).asDouble()) );
234  tm.w_pos = pos;
235  unsigned int width = cmd.get(9).asInt();
236  unsigned int height = cmd.get(10).asInt();
237  if ( width == 0 || height == 0 ) {
238  res.addString( "Dimension of the frame must be greater than zero" );
239  return res;
240  }
241  new WCamera( wctrl->world(), name, width, height, tm );
242  }
243  res.addString("Make Command executed");
244  return res;
245 }
246 
247 yarp::os::Bottle ServerWorldController::setCmd( const yarp::os::Bottle& cmd ) {
248  // --- the set command is quite complex but essentialy the structure is the following
249  // set [object_name] [property_name] [parameters]
250  // if the object_name is "world" then it configure the world's properties
251  // property_name specify what you want to change and it can be one of the following:
252  // position : and three number of the new position of the object
253  // rotation : and three number specifing angle of rotation about X, Y and Z axes
254  // Only in the case of "world" there are the following property
255  // size : dimension of the world
256  // timestep : time interval of integration step
257  // threads : if more than one activate the multi-thread capability
258  // realtime : on or off
259  QString objname = cmd.get(1).toString().c_str();
260  if ( objname == "world" ) {
261  return setWorldCmd( cmd );
262  } else {
263  WObject* obj = wctrl->world()->getObject( objname );
264  if ( obj != NULL ) {
265  return setObjectCmd( cmd, obj );
266  }
267  }
268  Bottle res;
269  res.addString( "Object not found" );
270  return res;
271 }
272 
273 yarp::os::Bottle ServerWorldController::setWorldCmd( const yarp::os::Bottle& cmd ) {
274  //--- see setCmd comments for understand the behaviour
275  Bottle res;
276  QString propname = cmd.get(2).toString().c_str();
277  if ( propname == "size" ) {
278  real x_dim = fabs( cmd.get(3).asDouble()/2.0 );
279  real y_dim = fabs( cmd.get(4).asDouble()/2.0 );
280  real z_dim = fabs( cmd.get(5).asDouble() );
281  if ( x_dim == 0 || y_dim == 0 || z_dim == 0 ) {
282  res.addString( "Dimension of the world must be greater than zero" );
283  return res;
284  }
285  wctrl->world()->setSize( wVector( -x_dim, -y_dim, 0 ), wVector( +x_dim, +y_dim, +z_dim ) );
286  res.addString( "World Re-Sized" );
287  } else if ( propname == "timestep" ) {
288  real newtimestep = fabs( cmd.get(3).asDouble() );
289  if ( newtimestep == 0 ) {
290  res.addString( "TimeStep of the world must be greater than zero" );
291  return res;
292  }
293  wctrl->world()->setTimeStep( newtimestep );
294  res.addString( "New TimeStep setted" );
295  } else if ( propname == "threads" ) {
296  real numThreads = fabs( (float)(cmd.get(3).asInt()) );
297  if ( numThreads == 0 ) {
298  res.addString( "Threads of the world must be greater than zero" );
299  return res;
300  }
301  wctrl->world()->setMultiThread( numThreads );
302  res.addString( "Multi-Thread setted" );
303  } else if ( propname == "realtime" ) {
304  bool ison = ( QString(cmd.get(3).toString().c_str()) == "on" );
305  wctrl->world()->setIsRealTime( ison );
306  if ( ison ) {
307  res.addString( "RealTime Activated" );
308  } else {
309  res.addString( "RealTime De-Activated" );
310  }
311  }
312  return res;
313 }
314 
315 yarp::os::Bottle ServerWorldController::setObjectCmd( const yarp::os::Bottle& /*cmd*/, WObject* /*object*/ ) {
316  //--- see setCmd comments for understand the behaviour
317  Bottle res;
318  res.addString( "Not Yet Implemented" );
319  return res;
320 }
321 
323  : YarpObject( w, name ) {
324  inport = new Port();
325  outport = new Port();
326  inport->open( QString( "/%1/%2:i" ).arg( world()->name() ).arg( name ).toAscii().data() );
327  outport->open( QString( "/%1/%2:o" ).arg( world()->name() ).arg( name ).toAscii().data() );
328  w->pushObject( this );
329  srv = new ServerWorldController( this );
330  srv->start();
331 }
332 
334  srv->terminate();
335  inport->close();
336  outport->close();
337  delete srv;
338  //--- this delete blocks MAC application
339  //delete inport;
340  //delete outport;
341 }
342 
344  srv->applyQueuedCommands();
345 }
346 
347 } // end namespace farsa
348 
349 #endif //FARSA_USE_YARP_AND_ICUB