AnimatLab  2
Test
RobotIOControl.cpp
Go to the documentation of this file.
1 
7 #include "StdAfx.h"
8 #include "IMovableItemCallback.h"
9 #include "ISimGUICallback.h"
10 #include "IMotorizedJoint.h"
11 #include "AnimatBase.h"
12 
13 #include "Node.h"
14 #include "Link.h"
15 #include "IPhysicsMovableItem.h"
16 #include "IPhysicsBody.h"
17 #include "BoundingBox.h"
18 #include "MovableItem.h"
19 #include "BodyPart.h"
20 #include "Joint.h"
21 #include "ReceptiveField.h"
22 #include "ContactSensor.h"
23 #include "RigidBody.h"
24 #include "Structure.h"
25 #include "NeuralModule.h"
26 #include "Adapter.h"
27 #include "NervousSystem.h"
28 #include "Organism.h"
29 #include "ActivatedItem.h"
30 #include "ActivatedItemMgr.h"
31 #include "DataChartMgr.h"
32 #include "ExternalStimuliMgr.h"
33 #include "KeyFrame.h"
34 #include "SimulationRecorder.h"
35 #include "OdorType.h"
36 #include "Odor.h"
37 #include "Light.h"
38 #include "LightManager.h"
39 #include "Simulator.h"
40 
41 #include "RobotInterface.h"
42 #include "RobotIOControl.h"
43 #include "RobotPartInterface.h"
44 
45 namespace AnimatSim
46 {
47  namespace Robotics
48  {
49 
57 {
58  m_lpParentInterface = NULL;
59  m_bSetupStarted = false;
60  m_bSetupComplete = false; // flag so we setup when its ready, you don't need to touch this :)
61  m_bStopIO = false;
62  m_bIOThreadProcessing = false;
64  m_iCyclePartIdx = 0;
66  m_bPauseIO = false;
67  m_bIOPaused = false;
69 }
70 
71 
79 {
80 try
81 {
82  m_aryParts.RemoveAll();
83 }
84 catch(...)
85 {Std_TraceMsg(0, "Caught Error in desctructor of RobotIOControl\r\n", "", -1, false, true);}
86 }
87 
97 
107 
116 void RobotIOControl::PauseIO(bool bVal)
117 {
118  m_bPauseIO = bVal;
119  m_bIOPaused = false;
120 }
121 
122 bool RobotIOControl::PauseIO() {return m_bPauseIO;}
123 
124 bool RobotIOControl::IOPaused() {return m_bIOPaused;}
125 
134 CStdPtrArray<RobotPartInterface> *RobotIOControl::Parts() {return &m_aryParts;}
135 
145 
146 #pragma region DataAccesMethods
147 
148 float *RobotIOControl::GetDataPointer(const std::string &strDataType)
149 {
150  std::string strType = Std_CheckString(strDataType);
151 
152  if(strType == "STEPIODURATION")
153  return &m_fltStepIODuration;
154  else
155  THROW_TEXT_ERROR(Al_Err_lInvalidDataType, Al_Err_strInvalidDataType, "Robot Interface ID: " + STR(m_strName) + " DataType: " + strDataType);
156 
157  return NULL;
158 }
159 
160 bool RobotIOControl::SetData(const std::string &strDataType, const std::string &strValue, bool bThrowError)
161 {
162  std::string strType = Std_CheckString(strDataType);
163 
164  if(AnimatBase::SetData(strType, strValue, false))
165  return true;
166 
167  if(strType == "ENABLED")
168  {
169  Enabled(Std_ToBool(strValue));
170  return true;
171  }
172 
173  //If it was not one of those above then we have a problem.
174  if(bThrowError)
175  THROW_PARAM_ERROR(Al_Err_lInvalidDataType, Al_Err_strInvalidDataType, "Data Type", strDataType);
176 
177  return false;
178 }
179 
180 void RobotIOControl::QueryProperties(CStdPtrArray<TypeProperty> &aryProperties)
181 {
182  AnimatBase::QueryProperties(aryProperties);
183 
184  aryProperties.Add(new TypeProperty("StepIODuration", AnimatPropertyType::Float, AnimatPropertyDirection::Get));
185 }
186 
187 bool RobotIOControl::AddItem(const std::string &strItemType, const std::string &strXml, bool bThrowError, bool bDoNotInit)
188 {
189  std::string strType = Std_CheckString(strItemType);
190 
191  if(strType == "ROBOTPARTINTERFACE")
192  {
193  AddPartInterface(strXml);
194  return true;
195  }
196 
197  //If it was not one of those above then we have a problem.
198  if(bThrowError)
199  THROW_PARAM_ERROR(Al_Err_lInvalidItemType, Al_Err_strInvalidItemType, "Item Type", strItemType);
200 
201  return false;
202 }
203 
204 bool RobotIOControl::RemoveItem(const std::string &strItemType, const std::string &strID, bool bThrowError)
205 {
206  std::string strType = Std_CheckString(strItemType);
207 
208  if(strType == "ROBOTPARTINTERFACE")
209  {
210  RemovePartInterface(strID);
211  return true;
212  }
213 
214  //If it was not one of those above then we have a problem.
215  if(bThrowError)
216  THROW_PARAM_ERROR(Al_Err_lInvalidItemType, Al_Err_strInvalidItemType, "Item Type", strItemType);
217 
218  return false;
219 }
220 
230 {
231  CStdXml oXml;
232  oXml.Deserialize(strXml);
233  oXml.FindElement("Root");
234  oXml.FindChildElement("RobotPartInterface");
235 
236  RobotPartInterface *lpPart = LoadPartInterface(oXml);
237 
238  lpPart->Initialize();
239 
240  return lpPart;
241 }
242 
253 void RobotIOControl::RemovePartInterface(std::string strID, bool bThrowError)
254 {
255  int iPos = FindChildListPos(strID, bThrowError);
256 
257  RobotPartInterface *lpPart = m_aryParts[iPos];
258 
259  m_aryParts.RemoveAt(iPos);
260 }
261 
262 
276 int RobotIOControl::FindChildListPos(std::string strID, bool bThrowError)
277 {
278  std::string sID = Std_ToUpper(Std_Trim(strID));
279 
280  int iCount = m_aryParts.GetSize();
281  for(int iIndex=0; iIndex<iCount; iIndex++)
282  if(m_aryParts[iIndex]->ID() == sID)
283  return iIndex;
284 
285  if(bThrowError)
286  THROW_PARAM_ERROR(Al_Err_lPartInterfaceIDNotFound, Al_Err_strPartInterfaceIDNotFound, "ID", strID);
287 
288  return -1;
289 }
290 
291 #pragma endregion
292 
293 void RobotIOControl::StartIOThread()
294 {
295  int iWaitTime = 30;
296 #ifdef _DEBUG
297  iWaitTime = 200;
298 #endif
299 
300  boost::posix_time::ptime pt = boost::posix_time::microsec_clock::universal_time() + boost::posix_time::seconds(iWaitTime);
301 
302  boost::interprocess::scoped_lock<boost::interprocess::interprocess_mutex> lock(m_WaitForIOSetupMutex);
303 
305  m_ioThread = boost::thread(&RobotIOControl::ProcessIO, this);
306 
307  std::cout << "Waiting for IO thread return\r\n";
309  bool bWaitRet = m_WaitForIOSetupCond.timed_wait(lock, pt);
310 
311  if(!bWaitRet)
312  {
313  std::cout << "IO thread Timed out\r\n";
314  ShutdownIO();
315  THROW_ERROR(Al_Err_lErrorSettingUpIOThread, Al_Err_strErrorSettingUpIOThread);
316  }
317 
318  std::cout << "IO thread returned\r\n";
319 }
320 
321 void RobotIOControl::WaitForThreadNotifyReady()
322 {
323  //Wait to fire the signal until we get notification that it is waiting.
325  boost::this_thread::sleep(boost::posix_time::microseconds(500));
326 }
327 
328 void RobotIOControl::ProcessIO()
329 {
330  try
331  {
332  m_bIOThreadProcessing = true;
333 
334  SetupIO();
335 
336  m_bSetupComplete = true;
337 
338  WaitForThreadNotifyReady();
339 
340  //Notify it back that we are ready.
341  m_WaitForIOSetupCond.notify_all();
342 
343  while(!m_bStopIO)
344  {
345  if(m_bPauseIO || m_lpSim->Paused())
346  {
347  m_bIOPaused = true;
348  boost::this_thread::sleep(boost::posix_time::microseconds(1000));
349  }
350  else
351  {
352  m_bIOPaused = false;
353  StepIO();
354  }
355  }
356  }
357  catch(CStdErrorInfo oError)
358  {
359  m_bIOThreadProcessing = false;
360  }
361  catch(...)
362  {
363  m_bIOThreadProcessing = false;
364  }
365 
366  m_bIOThreadProcessing = false;
367 }
368 
369 void RobotIOControl::ExitIOThread()
370 {
371  TRACE_DEBUG("ExitIOThread.");
372 
374  {
375  //Close the comm channel.
376  CloseIO();
377 
378  //Tell the IO thread to shutdown
379  m_bStopIO = true;
380 
381  TRACE_DEBUG("Joint Thread.\r\n");
382 
383  bool bTryJoin = false;
384 #if (BOOST_VERSION >= 105000)
385  bTryJoin = m_ioThread.try_join_for(boost::chrono::seconds(30));
386 #else
387  m_ioThread.join();
388 #endif
389  }
390 }
391 
404 {
405  if(m_bEnabled)
406  {
407  m_iCyclePartCount = 0;
408  int iCount = m_aryParts.GetSize();
409  for(int iIndex=0; iIndex<iCount; iIndex++)
410  if(m_aryParts[iIndex]->Enabled())
411  {
412  if(m_aryParts[iIndex]->IncludeInPartsCycle())
414 
415  m_aryParts[iIndex]->SetupIO();
416 
417  //Give it just smidge of time to finish processing the last set of data so we do not overload the arduino's buffer and so it has time to process the requests.
418  boost::this_thread::sleep(boost::posix_time::microseconds(1000));
419  }
420  }
421  else
422  //Give the wait thread a chance to start waiting if we are not enabled.
423  boost::this_thread::sleep(boost::posix_time::microseconds(1000));
424 }
425 
434 {
435  if(m_bEnabled)
436  {
437  unsigned long long lStepStartTick = m_lpSim->GetTimerTick();
438 
439  int iCount = m_aryParts.GetSize();
440  for(int iIndex=0; iIndex<iCount; iIndex++)
441  if(m_aryParts[iIndex]->Enabled())
442  m_aryParts[iIndex]->StepIO(m_iCyclePartIdx);
443 
444  unsigned long long lEndStartTick = m_lpSim->GetTimerTick();
445  m_fltStepIODuration = m_lpSim->TimerDiff_m(lStepStartTick, lEndStartTick);
446 
447  m_iCyclePartIdx++;
449  m_iCyclePartIdx = 0;
450  }
451 }
452 
461 {
462  m_bIOPaused = true;
463  while(m_bPauseIO)
464  boost::this_thread::sleep(boost::posix_time::microseconds(1000));
465  m_bIOPaused = false;
466 }
467 
476 {
477  while(!m_bIOPaused)
478  boost::this_thread::sleep(boost::posix_time::microseconds(1000));
479 }
480 
489 {
490  m_bPauseIO = true;
491 
492  if(!m_bEnabled || (m_lpSim->InSimulation() && m_lpSim->Paused()))
493  m_bIOPaused = true;
494 
495  while(!m_bIOPaused)
496  boost::this_thread::sleep(boost::posix_time::microseconds(1000));
497 }
498 
507 {
508  m_bPauseIO = false;
509 
510  if(!m_bEnabled || (m_lpSim->InSimulation() && m_lpSim->Paused()))
511  m_bIOPaused = false;
512 
513  while(m_bIOPaused)
514  boost::this_thread::sleep(boost::posix_time::microseconds(1000));
515 }
516 
526 {
527  //Prevent any more attempts to write to the comm channel.
529  {
530  StartPause();
531  WaitTillPaused();
532  }
533 
534  if(m_bEnabled)
535  {
536  int iCount = m_aryParts.GetSize();
537  for(int iIndex=0; iIndex<iCount; iIndex++)
538  if(m_aryParts[iIndex]->Enabled())
539  {
540  TRACE_DEBUG("Shutting down IO: " + m_aryParts[iIndex]->Name());
541  m_aryParts[iIndex]->ShutdownIO();
542  }
543  }
544 
545  ExitIOThread();
546 }
547 
549 {
550  if(m_bEnabled)
551  {
552  // Open device. Do this before calling the Initialize on the parts so they can have communications.
553  if(!m_lpSim->InSimulation())
554  {
555  OpenIO();
556 
557  StartIOThread();
558  }
559 
560  int iCount = m_aryParts.GetSize();
561  for(int iIndex=0; iIndex<iCount; iIndex++)
562  m_aryParts[iIndex]->Initialize();
563  }
564 }
565 
567 {
569 
570  if(m_bEnabled)
571  {
572  m_iCyclePartIdx = 0;
573  int iCount = m_aryParts.GetSize();
574  for(int iIndex=0; iIndex<iCount; iIndex++)
575  m_aryParts[iIndex]->ResetSimulation();
576  }
577 }
578 
580 {
582 
583  if(m_bEnabled)
584  {
585  int iCount = m_aryParts.GetSize();
586  for(int iIndex=0; iIndex<iCount; iIndex++)
587  m_aryParts[iIndex]->AfterResetSimulation();
588  }
589 }
590 
592 {
594 
595  ShutdownIO();
596 }
597 
599 {
600  if(m_bEnabled)
601  {
603 
604  int iCount = m_aryParts.GetSize();
605  for(int iIndex=0; iIndex<iCount; iIndex++)
606  if(m_aryParts[iIndex]->Enabled())
607  m_aryParts[iIndex]->StepSimulation();
608  }
609 }
610 
611 void RobotIOControl::Load(CStdXml &oXml)
612 {
613  AnimatBase::Load(oXml);
614 
615  oXml.IntoElem(); //Into RigidBody Element
616 
617  if(oXml.FindChildElement("Parts", false))
618  {
619  oXml.IntoElem(); //Into ChildBodies Element
620  int iChildCount = oXml.NumberOfChildren();
621 
622  for(int iIndex=0; iIndex<iChildCount; iIndex++)
623  {
624  oXml.FindChildByIndex(iIndex);
625  LoadPartInterface(oXml);
626  }
627  oXml.OutOfElem(); //OutOf ChildBodies Element
628  }
629 
630  oXml.OutOfElem(); //OutOf RigidBody Element
631 }
632 
645 {
646  RobotPartInterface *lpChild = NULL;
647  std::string strType;
648 
649 try
650 {
651  oXml.IntoElem(); //Into Child Element
652  std::string strModule = oXml.GetChildString("ModuleName", "");
653  strType = oXml.GetChildString("Type");
654  oXml.OutOfElem(); //OutOf Child Element
655 
656  lpChild = dynamic_cast<RobotPartInterface *>(m_lpSim->CreateObject(strModule, "RobotPartInterface", strType));
657  if(!lpChild)
658  THROW_TEXT_ERROR(Al_Err_lConvertingClassToType, Al_Err_strConvertingClassToType, "RobotPartInterface");
659 
660  lpChild->ParentIOControl(this);
661  lpChild->SetSystemPointers(m_lpSim, m_lpStructure, NULL, NULL, true);
662 
663  lpChild->Load(oXml);
664 
665  m_aryParts.Add(lpChild);
666 
667  return lpChild;
668 }
669 catch(CStdErrorInfo oError)
670 {
671  if(lpChild) delete lpChild;
672  RELAY_ERROR(oError);
673  return NULL;
674 }
675 catch(...)
676 {
677  if(lpChild) delete lpChild;
678  THROW_ERROR(Std_Err_lUnspecifiedError, Std_Err_strUnspecifiedError);
679  return NULL;
680 }
681 }
682 
683 
684  }
685 }
virtual void ResetSimulation()
Resets the simulation back to time 0.
Definition: AnimatBase.cpp:587
virtual void Deserialize(std::string &strXml)
Deserializes a string into an xml document.
Definition: StdXml.cpp:162
Base class file for all Animat simulation objects.
Declares the nervous system class.
Declares the simulation recorder class.
Declares the Robot IO control interface base class.
virtual void SetSystemPointers(Simulator *lpSim, Structure *lpStructure, NeuralModule *lpModule, Node *lpNode, bool bVerify)
Sets the system pointers.
virtual bool FindChildElement(std::string strElementName, bool fThrowError=true)
Finds a child element by name.
Definition: StdXml.cpp:256
virtual bool InSimulation()
Used to determine if we are running in a simulation, or in a real control mode.
Definition: Simulator.cpp:1673
Root namespace for the base simulation library for AnimatLab.
virtual void QueryProperties(CStdPtrArray< TypeProperty > &aryProperties)
Queries this object for a list of properties that can be changed using SetData.
virtual void Initialize()
Initializes this object.
Declares the body part class.
RobotIOControl(void)
Default constructor.
virtual void StepSimulation()
Step the simulation for this object.
virtual bool FindElement(std::string strElementName, bool fThrowError=true)
Finds an element with the specified name.
Definition: StdXml.cpp:179
Simulator * m_lpSim
The pointer to a Simulation.
Definition: AnimatBase.h:43
virtual bool Paused()
Gets whether the Simulation is paused.
Definition: Simulator.cpp:347
Information about the standard error.
Definition: StdErrorInfo.h:19
virtual std::string ID()
Gets the unique GUID ID of this object.
Definition: AnimatBase.cpp:167
virtual bool IntoElem()
Goes into the next element where the cursor is located.
Definition: StdXml.cpp:42
boost::interprocess::interprocess_condition m_WaitForIOSetupCond
Condition used to determine when the IO is setup.
virtual void Initialize()
Initializes this object.
virtual CStdPtrArray< RobotPartInterface > * Parts()
Gets the array of IO controls.
Class that stores information about types for QueryProperty information.
Definition: TypeProperty.h:35
bool m_bStopIO
Flags the thread processing loop to exit.
virtual void AfterResetSimulation()
Called after a simulation reset for some objects.
Definition: AnimatBase.cpp:598
Declares the key frame class.
virtual void ExitPause()
This method is waits until the m_bIOPaused flag is set back to false.
virtual bool SetData(const std::string &strDataType, const std::string &strValue, bool bThrowError=true)
Set a variable based on a string data type name.
virtual ~RobotIOControl(void)
Destructor.
Declares the joint class.
Declares the organism class.
bool m_bWaitingForThreadNotify
Used to signal to the IO thread that we are waiting for their return signal.
virtual void StepIO()
This method is called from within the IO thread. It calls StepIO for each part.
AnimatSim::Environment::Structure * m_lpStructure
The pointer to this items parent Structure. If this is not relevant for this object then this is NULL...
Definition: AnimatBase.h:46
virtual void ShutdownIO()
This method is called just before the IO thread is closed down. It gives the IO objects a chance to d...
std::string Std_Trim(std::string strVal)
Trims a string.
Declares a light object.
boost::thread m_ioThread
Thread responsible for doing IO processing.
Declares the activated item class.
virtual CStdSerialize * CreateObject(std::string strModule, std::string strClassName, std::string strType, bool bThrowError=true)
Creates an object using a class factory.
Definition: Simulator.cpp:3440
virtual RobotPartInterface * LoadPartInterface(CStdXml &oXml)
Loads a child IO Control.
virtual float * GetDataPointer(const std::string &strDataType)
Returns a float pointer to a data item of interest in this object.
Declares a light manager object.
RobotInterface * m_lpParentInterface
Pointer to the parent robot interface.
Declares the bounding box class.
virtual std::string Name()
Gets the name of this object.
Definition: AnimatBase.cpp:195
virtual bool Enabled()
Tells whether this item is enabled or not. This is not actually used for all objects, only specific ones. I am putting it in the base class though to prevent numerous duplications.
Definition: AnimatBase.cpp:113
A standard xml manipulation class.
Definition: StdXml.h:19
virtual void WaitTillPaused()
This method is waits until the m_bIOPaused flag is set to true.
virtual void StepSimulation()
Step the simulation for this object.
Definition: AnimatBase.cpp:643
Declares the node class.
virtual RobotPartInterface * AddPartInterface(std::string strXml)
Creates and adds a robot IO control.
virtual void SimStopping()
Called just before the simulation stops.
virtual void QueryProperties(CStdPtrArray< TypeProperty > &aryProperties)
Queries this object for a list of properties that can be changed using SetData.
Definition: AnimatBase.cpp:447
virtual std::string GetChildString(std::string strElementName)
Gets a string value from the element with the specified name.
Definition: StdXml.cpp:307
virtual void ResetSimulation()
Resets the simulation back to time 0.
bool m_bIOPaused
Is set to true once the IO loop is paused.
bool Std_ToBool(int iVal)
Converts a value toa bool.
virtual void Load(StdUtils::CStdXml &oXml)
Loads the item using an XML data packet.
Definition: AnimatBase.cpp:771
void Std_TraceMsg(const int iLevel, std::string strMessage, std::string strSourceFile, int iSourceLine, bool bLogToFile, bool bPrintHeader)
Traces a message to the debugger window.
CStdPtrArray< RobotPartInterface > m_aryParts
bool m_bEnabled
Tells if this item is enabled or not. If it is not enabled then it is not run.
Definition: AnimatBase.h:40
virtual int NumberOfChildren()
Gets the number of children of the current element.
Definition: StdXml.cpp:202
bool m_bPauseIO
Set to true to pause the IO processing. Set back to false to resume it.
virtual bool OutOfElem()
Goes out of the element where the cursor is located.
Definition: StdXml.cpp:56
int m_iCyclePartIdx
The index of the part that should be processed on the current step.
virtual int FindChildListPos(std::string strID, bool bThrowError=true)
Finds the array index for the child part with the specified ID.
Declares the data chart manager class.
virtual void SetupIO()
This method is called after all connections to whatever control board have been made. It calls each parts SetupIO method. For example, We connect to a Firmata microcontroller like an Arduino, and then do a setup that could take some time. We should not attempt to setup any of the pins until after the board itself has been setup. After that we need to loop through and setup all the parts.
int m_iCyclePartCount
The total number of parts that are part of any round robin cycle of updates.
Declares the rigid body class.
boost::interprocess::interprocess_mutex m_WaitForIOSetupMutex
Mutex responsible for waiting until the IO is finished setting up.
virtual void AfterResetSimulation()
Called after a simulation reset for some objects.
std::string Std_CheckString(std::string strVal)
Converts a string to upper case and trims it.
virtual void SimStopping()
Called just before the simulation stops.
Definition: AnimatBase.cpp:676
Declares the structure class.
float m_fltStepIODuration
The time it takes to perform a step of the IO for all parts in this control.
Declares the odor type class.
virtual void RemovePartInterface(std::string strID, bool bThrowError=true)
Removes the rigid body with the specified ID.
bool m_bIOThreadProcessing
True while the io thread processing loop is going on.
virtual bool RemoveItem(const std::string &strItemType, const std::string &strID, bool bThrowError=true)
Removes a child item from this parent.
bool m_bSetupComplete
Set to true once the IO is setup correctly.
virtual RobotInterface * ParentInterface()
Gets the parent robot interface pointer.
Declares the robotics inerface for animatlab.
Declares the odor class.
Declares the simulator class.
Declares the neural module class.
virtual bool FindChildByIndex(int iIndex, bool bThrowError=true)
Finds a child element by index.
Definition: StdXml.cpp:225
std::string Std_ToUpper(std::string strVal)
Converts a string to upper case.
Declares the activated item manager class.
Declares the contact sensor class.
Declares the external stimuli manager class.
virtual bool SetData(const std::string &strDataType, const std::string &strValue, bool bThrowError=true)
Set a variable based on a string data type name.
Definition: AnimatBase.cpp:371
virtual float StepIODuration()
Gets the time duration required to perform one step of the IO for all parts in this control...
virtual void WaitWhilePaused()
This method is waits until the m_bPauseIO flag is set back to false.
virtual void StartPause()
This method is waits until the m_bIOPaused flag is set to true.
virtual bool AddItem(const std::string &strItemType, const std::string &strXml, bool bThrowError=true, bool bDoNotInit=false)
Adds a new object to this parent.
Declares the receptive field class.
The Robotics interface configures a simulation to run on a microcontroller board. ...
std::string m_strName
The name for this object.
Definition: AnimatBase.h:61
bool m_bSetupStarted
Set to true once the IO begins its setup.