AnimatLab  2
Test
RbFirmataController.cpp
1 // RbFirmataController.cpp: implementation of the RbFirmataController class.
2 //
4 
5 #include "StdAfx.h"
6 #include <stdarg.h>
7 #include "RbMovableItem.h"
8 #include "RbBody.h"
9 #include "RbJoint.h"
10 #include "RbMotorizedJoint.h"
11 #include "RbHingeLimit.h"
12 #include "RbHinge.h"
13 #include "RbRigidBody.h"
14 #include "RbStructure.h"
15 #include "RbFirmataPart.h"
16 #include "RbFirmataController.h"
17 
18 namespace RoboticsAnimatSim
19 {
20  namespace Robotics
21  {
22  namespace RobotIOControls
23  {
24  namespace Firmata
25  {
26 
28 // Construction/Destruction
30 
31 RbFirmataController::RbFirmataController()
32 {
33  m_strComPort = "COM4";
34  m_iBaudRate = 115200;
37 
38  // listen for EInitialized notification. this indicates that
39  // the arduino is ready to receive commands and it is safe to
40  // call setupArduino()
41  m_EInitializedConnection = this->EInitialized.connect(boost::bind(&RbFirmataController::setupArduino, this, _1));
42 
43 }
44 
45 RbFirmataController::~RbFirmataController()
46 {
47  try
48  {
49  }
50  catch(...)
51  {Std_TraceMsg(0, "Caught Error in desctructor of RbFirmataController\r\n", "", -1, false, true);}
52 }
53 
54 void RbFirmataController::ComPort(std::string strPort)
55 {
56  if(Std_IsBlank(strPort))
57  THROW_PARAM_ERROR(Rb_Err_lInvalidPort, Rb_Err_strInvalidPort, "ComPort", strPort);
58 
59  m_strComPort = strPort;
60 }
61 
62 std::string RbFirmataController::ComPort() {return m_strComPort;}
63 
64 void RbFirmataController::BaudRate(int iRate)
65 {
66  if( iRate <= 0 )
67  THROW_PARAM_ERROR(Rb_Err_lInvalidBaudRate, Rb_Err_strInvalidBaudRate, "Baud rate", iRate);
68  m_iBaudRate = iRate;
69 }
70 
71 int RbFirmataController::BaudRate() {return m_iBaudRate;}
72 
73 #pragma region DataAccesMethods
74 
75 float *RbFirmataController::GetDataPointer(const std::string &strDataType)
76 {
77  std::string strType = Std_CheckString(strDataType);
78 
79  if(strType == "MOTORSENDTIME")
80  return &m_fltMotorSendTime;
81  else
82  return RobotIOControl::GetDataPointer(strDataType);
83 }
84 
85 bool RbFirmataController::SetData(const std::string &strDataType, const std::string &strValue, bool bThrowError)
86 {
87  std::string strType = Std_CheckString(strDataType);
88 
89  if(RobotIOControl::SetData(strDataType, strValue, false))
90  return true;
91 
92  if(strType == "COMPORT")
93  {
94  ComPort(strValue);
95  return true;
96  }
97  else if(strType == "BAUDRATE")
98  {
99  BaudRate((int) atoi(strValue.c_str()));
100  return true;
101  }
102 
103  //If it was not one of those above then we have a problem.
104  if(bThrowError)
105  THROW_PARAM_ERROR(Al_Err_lInvalidDataType, Al_Err_strInvalidDataType, "Data Type", strDataType);
106 
107  return false;
108 }
109 
110 void RbFirmataController::QueryProperties(CStdPtrArray<TypeProperty> &aryProperties)
111 {
112  RobotIOControl::QueryProperties(aryProperties);
113 
114  aryProperties.Add(new TypeProperty("ComPort", AnimatPropertyType::Integer, AnimatPropertyDirection::Set));
115  aryProperties.Add(new TypeProperty("BaudRate", AnimatPropertyType::Integer, AnimatPropertyDirection::Set));
116 }
117 
118 #pragma endregion
119 
121 {
122  RobotIOControl::ResetSimulation();
123 
124  m_fltMotorSendTime = 0;
125  m_lMotorSendStart = 0;
126 }
127 
128 bool RbFirmataController::OpenIO()
129 {
130  //Try to connect to the arduino board.
131  if(!connect(m_strComPort, m_iBaudRate))
132  THROW_PARAM_ERROR(Rb_Err_lErrorConnectingToArduino, Rb_Err_strErrorConnectingToArduino, "ComPort", m_strComPort);
133 
134  return true;
135 }
136 
137 void RbFirmataController::CloseIO()
138 {
139  _port.close();
140 }
141 
142 void RbFirmataController::ProcessIO()
143 {
144  try
145  {
146  m_bIOThreadProcessing = true;
147 
148  std::cout << "Sending firmware version request\r\n";
149 
150  //First lets flush the buffer.
151  _port.flush();
152 
153  //First reset firmata
154  sendReset();
155  boost::this_thread::sleep(boost::posix_time::microseconds(10));
156 
157  sendFirmwareVersionRequest();
158 
159  //Loop through to do the innitial setup
160  int iSendFirmwareCount=0;
161  while(!(m_bStopIO || m_bSetupComplete))
162  {
163  if(!_firmwareReceived)
164  {
165  update();
166 
167  //if(iSendFirmwareCount <= 0 && !_firmwareReceived)
168  //{
169  // //Then need to do this to init the pins, get the firmware version, and call setupArduino.
170  // //Will stay in update loop looking for signal. When it arrives Setup will be called
171  // //and we can start processing.
172  // iSendFirmwareCount = 1000;
173  //}
174 
175  //iSendFirmwareCount--;
176  boost::this_thread::sleep(boost::posix_time::microseconds(300));
177  }
178  }
179 
180  //Start the timer to measure motor send timing.
181  m_lMotorSendStart = GetSimulator()->GetTimerTick();
182 
183  //Now that setup has compled lets do our main loop
184  while(!m_bStopIO)
185  {
186  if(m_bPauseIO || m_lpSim->Paused())
187  {
188  m_bIOPaused = true;
189  boost::this_thread::sleep(boost::posix_time::microseconds(1000));
190  }
191  else
192  {
193  m_bIOPaused = false;
194 
195  //Update the firmata IO.
196  update();
197 
198  //Do not try and step IO until it has been setup correctly.
199  StepIO();
200 
201  if(_dynamixelMoveAdds > 0)
202  {
203  //Get the motor send time
204  m_fltMotorSendTime = GetSimulator()->TimerDiff_m(m_lMotorSendStart, GetSimulator()->GetTimerTick());
205 
206  //Execute any synch moves that were setup for this IO loop in StepIO
207  //If none were setup it will ignore this call.
208  sendDynamixelSynchMoveExecute();
209 
210  //Star the timer again.
211  m_lMotorSendStart = GetSimulator()->GetTimerTick();
212  }
213  }
214  }
215  }
216  catch(CStdErrorInfo oError)
217  {
218  m_bIOThreadProcessing = false;
219  }
220  catch(...)
221  {
222  m_bIOThreadProcessing = false;
223  }
224 
225  m_bIOThreadProcessing = false;
226 }
227 
228 
229 void RbFirmataController::setupArduino(const int & version)
230 {
231  m_EInitializedConnection.disconnect();
232 
233  //Only do setup once. This is in case it gets called.
234  if(m_bSetupStarted)
235  return;
236 
237  //Signal that we are starting setup.
238  m_bSetupStarted = true;
239 
240  // print firmware name and version to the console
241  //std::cout << this->getFirmwareName();
242  //std::cout << "firmata v" << this->getMajorFirmwareVersion() << "." << this->getMinorFirmwareVersion() << "\r\n";
243 
244  SetupIO();
245 
246  // it is now safe to send commands to the Arduino
247  m_bSetupComplete = true;
248 
249  //
250  // // Note: pins A0 - A5 can be used as digital input and output.
251  // // Refer to them as pins 14 - 19 if using StandardFirmata from Arduino 1.0.
252  // // If using Arduino 0022 or older, then use 16 - 21.
253  // // Firmata pin numbering changed in version 2.3 (which is included in Arduino 1.0)
254  //
255  // // set pins D2 and A5 to digital input
256  // this->sendDigitalPinMode(2, ARD_INPUT);
257 
258  // // set pin A0 to analog input
259  // this->sendAnalogPinReporting(0, ARD_ANALOG);
260  //
261  // // set pin D13 as digital output
262  //this->sendDigitalPinMode(13, ARD_OUTPUT);
263  // // set pin A4 as digital output
264  // this->sendDigitalPinMode(18, ARD_OUTPUT); // pin 20 if using StandardFirmata from Arduino 0022 or older
265 
266  // // set pin D11 as PWM (analog output)
267  //this->sendDigitalPinMode(11, ARD_PWM);
268  //
269  // // attach a servo to pin D9
270  // // servo motors can only be attached to pin D3, D5, D6, D9, D10, or D11
271  // this->sendServoAttach(9);
272  //this->sendServo(9, 0, true);
273 
274  // Listen for changes on the digital and analog pins
275  //m_EDigitalPinChanged = this->EDigitalPinChanged.connect(boost::bind(&RbFirmataController::digitalPinChanged, this, _1));
276  //m_EAnalogPinChanged = this->EAnalogPinChanged.connect(boost::bind(&RbFirmataController::analogPinChanged, this, _1));
277 
278  m_WaitForIOSetupCond.notify_all();
279 }
280 
281 // digital pin event handler, called whenever a digital pin value has changed
282 // note: if an analog pin has been set as a digital pin, it will be handled
283 // by the digitalPinChanged function rather than the analogPinChanged function.
284 
285 //--------------------------------------------------------------
286 void RbFirmataController::digitalPinChanged(const int & pinNum)
287 {
288  // // do something with the digital input. here we're simply going to print the pin number and
289  // // value to the screen each time it changes
290  //int iVal = this->getDigital(pinNum);
291  //std::cout << "digital pin: " << pinNum << " = " << iVal << "\r\n";
292 
293  //this->sendDigital(13, iVal);
294 }
295 
296 // analog pin event handler, called whenever an analog pin value has changed
297 
298 //--------------------------------------------------------------
299 void RbFirmataController::analogPinChanged(const int & pinNum)
300 {
301  // // do something with the analog input. here we're simply going to print the pin number and
302  // // value to the screen each time it changes
303  //int iVal = this->getAnalog(pinNum);
304  // std::cout << "analog pin: " << pinNum << " = " << iVal << "\r\n";
305 }
306 
308 {
309  RobotIOControl::Load(oXml);
310 
311  oXml.IntoElem();
312  ComPort(oXml.GetChildString("ComPort", m_strComPort));
313  BaudRate(oXml.GetChildInt("BaudRate", m_iBaudRate));
314  oXml.OutOfElem();
315 }
316 
317 
318  } //Firmata
319  } //RobotIOControls
320  } // Robotics
321 } //RoboticsAnimatSim
322 
virtual void ResetSimulation()
Resets the simulation back to time 0.
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
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.
bool m_bStopIO
Flags the thread processing loop to exit.
virtual Simulator * GetSimulator()
Gets the simulator pointer.
Definition: AnimatBase.cpp:123
virtual int GetChildInt(std::string strElementName)
Gets an integer value from the element with the specified name.
Definition: StdXml.cpp:456
virtual void StepIO()
This method is called from within the IO thread. It calls StepIO for each part.
Declares the vortex structure class.
virtual float * GetDataPointer(const std::string &strDataType)
Returns a float pointer to a data item of interest in this object.
Declares the vortex hinge class.
A standard xml manipulation class.
Definition: StdXml.h:19
virtual std::string GetChildString(std::string strElementName)
Gets a string value from the element with the specified name.
Definition: StdXml.cpp:307
bool m_bIOPaused
Is set to true once the IO loop is paused.
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.
virtual bool SetData(const std::string &strDataType, const std::string &strValue, bool bThrowError=true)
Set a variable based on a string data type name.
unsigned long long m_lMotorSendStart
Tick to measure the the timing for sending motor commands.
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
virtual void Load(StdUtils::CStdXml &oXml)
Loads the item using an XML data packet.
float m_fltMotorSendTime
The time between when synchronous motor commands are sent.
bool Std_IsBlank(std::string strVal)
Trims a string and tests if a string is blank.
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.
std::string Std_CheckString(std::string strVal)
Converts a string to upper case and trims it.
std::string m_strComPort
Com port for the connection to the Arduino.
bool m_bIOThreadProcessing
True while the io thread processing loop is going on.
bool m_bSetupComplete
Set to true once the IO is setup correctly.
Classes for implementing the cm-labs vortex physics engine for AnimatLab.
bool m_bSetupStarted
Set to true once the IO begins its setup.