UniversalRobotsVrepPlugin.hpp
Go to the documentation of this file.
1 #ifndef UniversalRobots_VREP_PLUGIN_HPP_
2 #define UniversalRobots_VREP_PLUGIN_HPP_
3 
4 #include <iostream>
5 #include <memory>
6 #include <array>
7 
8 #include <boost/range/algorithm/copy.hpp>
9 #include <boost/asio.hpp>
10 #include <boost/log/trivial.hpp>
11 #include <boost/exception/all.hpp>
12 #include <boost/algorithm/string.hpp>
13 #include <ur_modern_driver/ur_hardware_interface_standalone.h>
14 
15 #include "grl/vrep/Vrep.hpp"
17 
18 #include "v_repLib.h"
19 
20 /// @todo move elsewhere, because it will conflict with others' implementations of outputting vectors
21 template<typename T>
22 inline boost::log::formatting_ostream& operator<<(boost::log::formatting_ostream& out, std::vector<T>& v)
23 {
24  out << "[";
25  size_t last = v.size() - 1;
26  for(size_t i = 0; i < v.size(); ++i) {
27  out << v[i];
28  if (i != last)
29  out << ", ";
30  }
31  out << "]";
32  return out;
33 }
34 
35 namespace grl { namespace vrep {
36 
37 
38 
39 
40 /// Creates a complete vrep plugin object
41 /// usage:
42 /// @code
43 /// auto UniversalRobotsPluginPG = std::make_shared<grl::KukaVrepPlugin>();
44 /// kukaPluginPG->construct();
45 /// while(true) kukaPluginPG->run_one();
46 /// @endcode
47 ///
48 /// @todo this implementation is a bit hacky, redesign it
49 /// @todo separate out grl specific code from general kuka control code
50 /// @todo Template on robot driver and create a driver that just reads/writes to/from the simulation, then pass the two templates so the simulation and the real driver can be selected.
51 ///
52 class UniversalRobotsVrepPlugin : public std::enable_shared_from_this<UniversalRobotsVrepPlugin> {
53 public:
54 
55  enum ParamIndex {
75  };
76 
77  /// @todo allow default params
78  typedef std::tuple<
79  std::string,
80  std::string,
81  std::string,
82  std::string,
83  std::string,
84  std::string,
85  std::string,
86  std::string,
87  std::string,
88  std::string,
89  std::string,
90  std::string,
91  std::string,
92  std::string,
93  std::string,
94  std::string,
95  std::string,
96  std::string,
97  std::string
98  > Params;
99 
100 
101  static const Params defaultParams(){
102  return std::make_tuple(
103  "LBR_iiwa_14_R820_joint1" , // Joint1Handle,
104  "LBR_iiwa_14_R820_joint2" , // Joint2Handle,
105  "LBR_iiwa_14_R820_joint3" , // Joint3Handle,
106  "LBR_iiwa_14_R820_joint4" , // Joint4Handle,
107  "LBR_iiwa_14_R820_joint5" , // Joint5Handle,
108  "LBR_iiwa_14_R820_joint6" , // Joint6Handle,
109  "LBR_iiwa_14_R820_joint7" , // Joint7Handle,
110  "RobotFlangeTip" , // RobotFlangeTipHandle,
111  "RobotMillTip" , // RobotTipHandle,
112  "RobotMillTipTarget" , // RobotTargetHandle,
113  "Robotiiwa" , // RobotTargetBaseHandle,
114  "tcp://0.0.0.0:30010" , // LocalZMQAddress
115  "tcp://172.31.1.147:30010", // RemoteZMQAddress
116  "192.170.10.100" , // LocalHostUniversalRobotsKoniUDPAddress,
117  "30200" , // LocalHostUniversalRobotsKoniUDPPort,
118  "192.170.10.2" , // RemoteHostUniversalRobotsKoniUDPAddress,
119  "30200" , // RemoteHostUniversalRobotsKoniUDPPort
120  "JAVA" , // UniversalRobotsCommandMode (options are FRI, JAVA)
121  "IK_Group1_iiwa"
122  );
123  }
124 
125 
126 
127 
128 
129 /// @todo allow UniversalRobotsFRIThreadSeparator parameters to be updated
130 /// @param params a tuple containing all of the parameter strings needed to configure the device.
131 ///
132 /// The UniversalRobotsCommandMode parameters supports the options "FRI" and "JAVA". This configures how commands will
133 /// be sent to the arm itself. "FRI" mode is via a direct "Fast Robot Interface" "UniversalRobots KONI"
134 /// ethernet connection which provides substantially higher performance and response time,
135 // but is extremely sensitive to delays, and any delay will halt the robot and require a manual reset.
136 // "JAVA" mode sends the command to the Java application installed on the UniversalRobots robot, which then submits
137 // it to the arm itself to execute. This is a much more forgiving mode of communication, but it is subject to delays.
139  :
140  params_(params)
141 {
142 }
143 
144 void construct(){construct(params_);}
145 
146 /// construct() function completes initialization of the plugin
147 /// @todo move this into the actual constructor, but need to correctly handle or attach vrep shared libraries for unit tests.
148 void construct(Params params){
149  params_ = params;
150  // keep driver threads from exiting immediately after creation, because they have work to do!
151  device_driver_workP_.reset(new boost::asio::io_service::work(device_driver_io_service));
152 
153 
154  UniversalRobotsDriverP_.reset(new ur::UrHardwareInterfaceStandalone(std::string(std::get<LocalHostUniversalRobotsKoniUDPAddress > (params))));
155  initHandles();
156 }
157 
158 
159 void run_one(){
160 
161  if(!allHandlesSet) BOOST_THROW_EXCEPTION(std::runtime_error("UniversalRobotsVrepPlugin: Handles have not been initialized, cannot run updates."));
162  getRealUniversalRobotsAngles();
163  bool isError = getStateFromVrep(); // true if there is an error
164  allHandlesSet = !isError;
165  /// @todo re-enable simulation feedback based on actual UniversalRobots state
166  //updateVrepFromUniversalRobots();
167  sendSimulatedJointAnglesToUniversalRobots();
168 
169 }
170 
171 
173  device_driver_workP_.reset();
174 
175  if(driver_threadP){
176  device_driver_io_service.stop();
177  driver_threadP->join();
178  }
179 }
180 
181 private:
182 
183 
184 
185 void initHandles() {
186 
187  vrepRobotArmDriverP_ = std::make_shared<VrepRobotArmDriver>
188  (
189  std::make_tuple(
190  std::vector<std::string>
191  {
192  std::get<Joint1Name> (params_),
193  std::get<Joint2Name> (params_),
194  std::get<Joint3Name> (params_),
195  std::get<Joint4Name> (params_),
196  std::get<Joint5Name> (params_),
197  std::get<Joint6Name> (params_),
198  std::get<Joint7Name> (params_)
199  },
200  std::get<RobotFlangeTipName> (params_),
201  std::get<RobotTipName> (params_),
202  std::get<RobotTargetName> (params_),
203  std::get<RobotTargetBaseName> (params_),
204  std::get<RobotIKGroup> (params_)
205  )
206  );
207  vrepRobotArmDriverP_->construct();
208  /// @todo remove this assumption
209  allHandlesSet = true;
210 }
211 
212 void getRealUniversalRobotsAngles() {
213  /// @todo m_haveReceivedRealData = true is a DANGEROUS HACK!!!! REMOVE ME AFTER DEBUGGING
214  m_haveReceivedRealData = true;
215  if(UniversalRobotsDriverP_)
216  {
217  std::vector<double> vals;
218  UniversalRobotsDriverP_->read_joint_position(vals);
219  realJointPosition.clear();
220  boost::copy(vals,std::back_inserter(realJointPosition));
221 
222  UniversalRobotsDriverP_->read_joint_velocity(vals);
223  realJointPosition.clear();
224  boost::copy(vals,std::back_inserter(realJointVelocity));
225  }
226 
227 #if BOOST_VERSION < 105900
228  // here we expect the simulation to be slightly ahead of the arm
229  // so we get the simulation based joint angles and update the arm
230  BOOST_LOG_TRIVIAL(trace) << "Real joint angles from FRI: " << realJointPosition << "\n";
231 #endif
232 
233 }
234 
235 void sendSimulatedJointAnglesToUniversalRobots(){
236 
237  if(!allHandlesSet || !m_haveReceivedRealData) return;
238 
239 /// @todo make this handled by template driver implementations/extensions
240 
241  if( UniversalRobotsDriverP_)
242  {
243  std::vector<double> dpos;
244  boost::copy(simJointPosition,std::back_inserter(dpos));
245  UniversalRobotsDriverP_->write_joint_position(dpos);
246  }
247 
248 }
249 
250 /// @todo if there aren't real limits set via the UniversalRobots model already then implement me
251 void setArmLimits(){
252  //simSetJointInterval(simInt objectHandle,simBool cyclic,const simFloat* interval); //Sets the interval parameters of a joint (i.e. range values)
253  //simSetJointMode(simInt jointHandle,simInt jointMode,simInt options); //Sets the operation mode of a joint. Might have as side-effect the change of additional properties of the joint
254 
255 }
256 
257 /// @return isError - true if there is an error, false if there is no Error
258 bool getStateFromVrep(){
259  if(!allHandlesSet || !vrepRobotArmDriverP_) return false;
260 
261  VrepRobotArmDriver::State armState;
262 
263  bool isError = vrepRobotArmDriverP_->getState(armState);
264 
265  if(isError) return isError;
266 
267  simJointPosition = std::get<VrepRobotArmDriver::JointPosition> (armState);
268  simJointForce = std::get<VrepRobotArmDriver::JointForce> (armState);
269  simJointTargetPosition = std::get<VrepRobotArmDriver::JointTargetPosition>(armState);
270  simJointTransformationMatrix = std::get<VrepRobotArmDriver::JointMatrix> (armState);
271 
272  return false;
273 }
274 
275 /// @todo reenable this component
276 bool updateVrepFromUniversalRobots() {
277  // Step 1
278  ////////////////////////////////////////////////////
279  // call the functions here and just print joint angles out
280  // or display something on the screens
281 
282  ///////////////////
283  // call our object to get the latest real UniversalRobots state
284  // then use the functions below to set the simulation state
285  // to match
286 
287  /////////////////// assuming given real joint position (angles), forces, target position and target velocity
288 
289 
290  // setting the simulation variables to data from real robot (here they have been assumed given)
291 
292  for (int i=0 ; i < 7 ; i++)
293  {
294  //simSetJointPosition(jointHandle[i],realJointPosition[i]); //Sets the intrinsic position of a joint. May have no effect depending on the joint mode
295 
296 
297  //simSetJointTargetPosition(jointHandle[i],realJointTargetPosition[i]); //Sets the target position of a joint if the joint is in torque/force mode (also make sure that the joint's motor and position control are enabled
298 
299  //simSetJointForce(jointHandle[i],realJointForce[i]); //Sets the maximum force or torque that a joint can exert. This function has no effect when the joint is not dynamically enabled
300 
301 
302  //simSetJointTargetVelocity(jointHandle[i],realJointTargetVelocity[i]); //Sets the intrinsic target velocity of a non-spherical joint. This command makes only sense when the joint mode is: (a) motion mode: the joint's motion handling feature must be enabled (simHandleJoint must be called (is called by default in the main script), and the joint motion properties must be set in the joint settings dialog), (b) torque/force mode: the dynamics functionality and the joint motor have to be enabled (position control should however be disabled)
303  }
304 
305  return false;
306 }
307 
308 volatile bool allHandlesSet = false;
309 volatile bool m_haveReceivedRealData = false;
310 
311 boost::asio::io_service device_driver_io_service;
312 std::unique_ptr<boost::asio::io_service::work> device_driver_workP_;
313 std::unique_ptr<std::thread> driver_threadP;
314 std::unique_ptr<ur::UrHardwareInterfaceStandalone> UniversalRobotsDriverP_;
315 std::shared_ptr<VrepRobotArmDriver> vrepRobotArmDriverP_;
316 //boost::asio::deadline_timer sendToJavaDelay;
317 
318 /// @todo replace all these simJoint elements with simple VrepRobotArmDriver::State
319 std::vector<float> simJointPosition = {0.0,0.0,0.0,0.0,0.0,0.0,0.0};
320 // std::vector<float> simJointVelocity = {0.0,0.0,0.0,0.0,0.0,0.0,0.0}; no velocity yet
321 std::vector<float> simJointForce = {0.0,0.0,0.0,0.0,0.0,0.0,0.0};
322 std::vector<float> simJointTargetPosition = {0.0,0.0,0.0,0.0,0.0,0.0,0.0};
323 VrepRobotArmDriver::TransformationMatrices simJointTransformationMatrix;
324 
325 /// @note loss of precision! UniversalRobots sends double values, if you write custom code don't use these float values. Vrep uses floats internally which is why they are used here.
326 std::vector<float> realJointPosition = { 0, 0, 0, 0, 0, 0, 0 };
327 // does not exist
328 // std::vector<float> realJointTargetPosition = { 0, 0, 0, 0, 0, 0, 0 };
329 std::vector<float> realJointForce = { 0, 0, 0, 0, 0, 0, 0 };
330 std::vector<float> realJointVelocity = { 0, 0, 0, 0, 0, 0, 0 };
331 // does not exist yet
332 //std::vector<float> realJointTargetVelocity = { 0, 0, 0, 0, 0, 0, 0 };
333 
334 private:
335 Params params_;
336 };
337 
338 }} // grl::vrep
339 
340 #endif
OutputIterator copy(std::string model, OutputIterator it, grl::revolute_joint_velocity_open_chain_state_constraint_tag)
copy vector of joint velocity limits in radians/s
Definition: Kuka.hpp:131
UniversalRobotsVrepPlugin(Params params=defaultParams())
std::vector< TransformationMatrix > TransformationMatrices
std::tuple< std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string > Params
std::tuple< JointScalar, JointScalar, JointScalar, JointScalar, JointScalar, TransformationMatrices, JointStateTag, JointScalar > State