icub-test
TorqueControlAccuracy.cpp
1 /*
2  * iCub Robot Unit Tests (Robot Testing Framework)
3  *
4  * Copyright (C) 2015-2019 Istituto Italiano di Tecnologia (IIT)
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <math.h>
22 #include <robottestingframework/TestAssert.h>
23 #include <robottestingframework/dll/Plugin.h>
24 #include <yarp/os/Time.h>
25 #include <yarp/os/Property.h>
26 #include <fstream>
27 #include <algorithm>
28 #include <cstdlib>
29 
30 #include "TorqueControlAccuracy.h"
31 
32 using namespace robottestingframework;
33 using namespace yarp::os;
34 using namespace yarp::dev;
35 
36 // prepare the plugin
37 ROBOTTESTINGFRAMEWORK_PREPARE_PLUGIN(TorqueControlAccuracy)
38 
39 TorqueControlAccuracy::TorqueControlAccuracy() : yarp::robottestingframework::TestCase("TorqueControlAccuracy") {
40  m_jointsList = 0;
41  m_encoders = 0;
42  m_torques = 0;
43  m_zeros = 0;
44  dd=0;
45  ipos=0;
46  icmd=0;
47  iimd=0;
48  ienc=0;
49  itrq=0;
50 }
51 
52 TorqueControlAccuracy::~TorqueControlAccuracy() { }
53 
54 bool TorqueControlAccuracy::setup(yarp::os::Property& property) {
55 
56  //updating the test name
57  if(property.check("name"))
58  setName(property.find("name").asString());
59 
60  // updating parameters
61  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF(property.check("robot"), "The robot name must be given as the test parameter!");
62  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF(property.check("part"), "The part name must be given as the test parameter!");
63  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF(property.check("joints"), "The joints list must be given as the test parameter!");
64  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF(property.check("zeros"), "The zero position list must be given as the test parameter!");
65  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF(property.check("cycles"), "The number of cycles of the control signal must be given as the test parameter!");
66  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF(property.check("step"), "The amplitude of the step reference signal expressed in Nm!");
67  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF(property.check("sampleTime"), "The sampleTime of the control signal must be given as the test parameter!");
68 
69  m_robotName = property.find("robot").asString();
70  m_partName = property.find("part").asString();
71 
72  Bottle* jointsBottle = property.find("joints").asList();
73  Bottle* zerosBottle = property.find("zeros").asList();
74 
75  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF(jointsBottle!=0,"unable to parse joints parameter");
76  m_n_cmd_joints = jointsBottle->size();
77  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF(m_n_cmd_joints>0, "invalid number of joints, it must be >0");
78 
79  m_step = property.find("step").asFloat64();
80 
81  m_cycles = property.find("cycles").asInt32();
82  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF(m_cycles>0, "invalid cycles");
83 
84  m_sampleTime = property.find("sampleTime").asFloat64();
85  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF(m_sampleTime>0, "invalid sampleTime");
86 
87  Property options;
88  options.put("device", "remote_controlboard");
89  options.put("remote", "/" + m_robotName + "/" + m_partName);
90  options.put("local", "/TorqueControlAccuracyTest/" + m_robotName + "/" + m_partName);
91 
92  dd = new PolyDriver(options);
93  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF(dd->isValid(),"Unable to open device driver");
94  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF(dd->view(itrq),"Unable to open torque control interface");
95  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF(dd->view(ienc),"Unable to open encoders interface");
96  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF(dd->view(ipos),"Unable to open position interface");
97  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF(dd->view(icmd),"Unable to open control mode interface");
98  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF(dd->view(iimd),"Unable to open interaction mode interface");
99 
100  if (!ienc->getAxes(&m_n_part_joints))
101  {
102  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR("unable to get the number of joints of the part");
103  }
104 
105  m_zeros = new double[m_n_part_joints];
106  m_encoders = new double[m_n_part_joints];
107  m_jointsList = new int[m_n_cmd_joints];
108  m_torques = new double[m_n_part_joints];
109  for (int i = 0; i <m_n_cmd_joints; i++) m_jointsList[i] = jointsBottle->get(i).asInt32();
110  for (int i = 0; i <m_n_cmd_joints; i++) m_zeros[i] = zerosBottle->get(i).asFloat64();
111 
112  return true;
113 }
114 
115 void TorqueControlAccuracy::tearDown()
116 {
117  if (m_jointsList) { delete [] m_jointsList; m_jointsList = 0; }
118  if (m_zeros) { delete [] m_zeros; m_zeros = 0; }
119  if (m_torques) { delete [] m_torques; m_torques = 0; }
120  if (m_encoders) { delete [] m_encoders; m_encoders = 0; }
121  if (dd) {delete dd; dd =0;}
122 }
123 
124 void TorqueControlAccuracy::setMode(int desired_mode)
125 {
126  for (int i = 0; i<m_n_cmd_joints; i++)
127  {
128  icmd->setControlMode(m_jointsList[i], desired_mode);
129  iimd->setInteractionMode(m_jointsList[i], VOCAB_IM_STIFF);
130  yarp::os::Time::delay(0.010);
131  }
132 
133  int cmode;
134  yarp::dev::InteractionModeEnum imode;
135  int timeout = 0;
136 
137  while (1)
138  {
139  int ok=0;
140  for (int i = 0; i<m_n_cmd_joints; i++)
141  {
142  icmd->getControlMode(m_jointsList[i], &cmode);
143  iimd->getInteractionMode(m_jointsList[i], &imode);
144  if (cmode==desired_mode && imode==VOCAB_IM_STIFF) ok++;
145  }
146  if (ok == m_n_cmd_joints) break;
147  if (timeout>100)
148  {
149  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR("Unable to set control mode/interaction mode");
150  }
151  yarp::os::Time::delay(0.2);
152  timeout++;
153  }
154 }
155 
156 bool TorqueControlAccuracy::goHome()
157 {
158  for (int i = 0; i<m_n_cmd_joints; i++)
159  {
160  ipos->setRefSpeed(m_jointsList[i], 20.0);
161  ipos->positionMove(m_jointsList[i], m_zeros[i]);
162  }
163 
164  int timeout = 0;
165  while (1)
166  {
167  int in_position=0;
168  for (int i = 0; i<m_n_cmd_joints; i++)
169  {
170  ienc->getEncoder(m_jointsList[i], &m_encoders[m_jointsList[i]]);
171  if (fabs(m_encoders[m_jointsList[i]] - m_zeros[i])<0.5) in_position++;
172  }
173  if (in_position == m_n_cmd_joints) break;
174  if (timeout>100)
175  {
176  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR("Timeout while reaching zero position");
177  return false;
178  }
179  yarp::os::Time::delay(0.2);
180  timeout++;
181  }
182  //sleep some additional time to complete movement from 0.5 to 0
183  yarp::os::Time::delay(0.5);
184  return true;
185 }
186 
187 void TorqueControlAccuracy::run()
188 {
189  for (int i = 0; i < m_n_cmd_joints; i++)
190  {
191  for (int cycle = 0; cycle < m_cycles; cycle++)
192  {
193  setMode(VOCAB_CM_POSITION);
194  if (goHome() == false)
195  {
196  ROBOTTESTINGFRAMEWORK_ASSERT_FAIL("Test stopped");
197  };
198  setMode(VOCAB_CM_TORQUE);
199  double start_time = yarp::os::Time::now();
200 
201  std::string buff = "Testing Joint: " + std::to_string(i) + " cycle: " + std::to_string(cycle);
202  ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
203 
204  double time_zero = 0;
205  yarp::os::Bottle dataToPlotRaw;
206  yarp::os::Bottle dataToPlotSync;
207 
208  while (1)
209  {
210  double curr_time = yarp::os::Time::now();
211  double elapsed = curr_time - start_time;
212 
213  if (elapsed <= 1.0)
214  {
215  m_cmd_single = 0.0;
216  }
217  else if (elapsed > 1.0 && elapsed <= 4.0)
218  {
219  m_cmd_single = m_zeros[i] + m_step;
220  if (time_zero == 0) time_zero = elapsed;
221  }
222  else
223  {
224  break;
225  }
226 
227  ienc->getEncoders(m_encoders);
228  itrq->getTorques(m_torques);
229  itrq->setRefTorque(m_jointsList[i], m_cmd_single);
230 
231  Bottle& b1 = dataToPlotRaw.addList();
232  b1.addInt32(cycle);
233  b1.addFloat64(elapsed);
234  b1.addFloat64(m_torques[m_jointsList[i]]);
235  b1.addFloat64(m_cmd_single);
236  yarp::os::Time::delay(m_sampleTime);
237  }
238 
239  //reorder data
240  for (int t = 0; t < dataToPlotRaw.size(); t++)
241  {
242  int cycle = dataToPlotRaw.get(t).asList()->get(0).asInt32();
243  double time = dataToPlotRaw.get(t).asList()->get(1).asFloat64();
244  double val = dataToPlotRaw.get(t).asList()->get(2).asFloat64();
245  double cmd = dataToPlotRaw.get(t).asList()->get(3).asFloat64();
246  Bottle& b1 = dataToPlotSync.addList();
247  b1.addInt32(cycle);
248  b1.addFloat64(time - time_zero);
249  b1.addFloat64(val);
250  b1.addFloat64(cmd);
251  }
252 
253  m_dataToSave.append(dataToPlotSync);
254  } //cycle loop
255 
256  //save data
257  std::string filename = "torqueControlAccuracy_plot_";
258  filename += m_partName;
259  filename += std::to_string(i);
260  filename += ".txt";
261  saveToFile(filename, m_dataToSave);
262  } //joint loop
263 
264  //data acquisition ends here
265  setMode(VOCAB_CM_POSITION);
266  goHome();
267  ROBOTTESTINGFRAMEWORK_TEST_REPORT("Data acquisition complete");
268 
269  //plot data
270  /*for (int i = 0; i < m_n_cmd_joints; i++)
271  {
272  std::string filename = "torqueControlAccuracy_plot_";
273  filename += m_partName;
274  filename += std::to_string(i);
275  filename += ".txt";
276  char plotstring[1000];
277  sprintf(plotstring, "gnuplot -e \" unset key; plot for [col=1:%d] '%s' using col with lines \" -persist", m_n_cmd_joints, filename.c_str());
278  system(plotstring);
279  }*/
280 }
281 
282 void TorqueControlAccuracy::saveToFile(std::string filename, yarp::os::Bottle &b)
283 {
284  std::fstream fs;
285  fs.open(filename.c_str(), std::fstream::out);
286 
287  for (int i = 0; i<b.size(); i++)
288  {
289  std::string s = b.get(i).toString();
290  std::replace(s.begin(), s.end(), '(', ' ');
291  std::replace(s.begin(), s.end(), ')', ' ');
292  fs << s << std::endl;
293  }
294 
295  fs.close();
296 }
This tests checks the a torque PID response, sending a step reference signal with a setRefTorque comm...