ati_force_torque_hw_rs485.cpp
Go to the documentation of this file.
1 /****************************************************************
2  *
3  * Copyright 2016 Intelligent Industrial Robotics (IIROB) Group,
4  * Institute for Anthropomatics and Robotics (IAR) -
5  * Intelligent Process Control and Robotics (IPR),
6  * Karlsruhe Institute of Technology
7  *
8  * Author: Florian Aumann
9  * Maintainer: Denis Štogl, email: denis.stogl@kit.edu
10  *
11  * Date of update: 2014-2018
12  *
13  * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
14  *
15  * Copyright (c) 2010
16  *
17  * Fraunhofer Institute for Manufacturing Engineering
18  * and Automation (IPA)
19  *
20  * Date of creation: June 2010
21  *
22  * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
23  *
24  * Redistribution and use in source and binary forms, with or without
25  * modification, are permitted provided that the following conditions are met:
26  *
27  * * Redistributions of source code must retain the above copyright
28  * notice, this list of conditions and the following disclaimer.
29  * * Redistributions in binary form must reproduce the above copyright
30  * notice, this list of conditions and the following disclaimer in the
31  * documentation and/or other materials provided with the distribution.
32  * * Neither the name of the copyright holder nor the names of its
33  * contributors may be used to endorse or promote products derived from
34  * this software without specific prior written permission.
35  *
36  * This program is free software: you can redistribute it and/or modify
37  * it under the terms of the GNU Lesser General Public License LGPL as
38  * published by the Free Software Foundation, either version 3 of the
39  * License, or (at your option) any later version.
40  *
41  * This program is distributed in the hope that it will be useful,
42  * but WITHOUT ANY WARRANTY; without even the implied warranty of
43  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44  * GNU Lesser General Public License LGPL for more details.
45  *
46  * You should have received a copy of the GNU Lesser General Public
47  * License LGPL along with this program.
48  * If not, see <http://www.gnu.org/licenses/>.
49  *
50  ****************************************************************/
51 
52 #define DEBUG 0
53 
54 // general includes
56 
58 
59 #include <unistd.h>
60 #include <iostream>
61 #include <sstream>
62 #include <fcntl.h>
63 #include <string>
64 
65 #include <stropts.h>
66 #include <sys/ioctl.h>
67 #include <linux/serial.h>
68 #include <termios.h>
69 #include <unistd.h>
70 #include <arpa/inet.h>
71 
72 
74 : m_modbusCtrl(0),
75  m_rs485(0)
76 {
77  // for baudrates see:
78  // https://www.ati-ia.com/app_content/documents/9620-05-Digital%20FT.pdf
79  m_RS485Device = "/dev/ttyUSB0";
80  m_ModbusBaseIdentifier = 0xA; //ID of the ATI sensor is always set to 10 (As specified in 8.3)
82 }
83 
84 ATIForceTorqueSensorHWRS485::ATIForceTorqueSensorHWRS485(std::string device_path, int device_baudrate, int base_identifier)
85 : m_modbusCtrl(0),
86  m_rs485(0)
87 {
88  // for types and baudrates see:
89  m_RS485Device = device_path;
90  m_ModbusBaudrate = device_baudrate;
91  m_ModbusBaseIdentifier = base_identifier;
92 }
93 
95 {
96  if (m_modbusCtrl != NULL)
97  {
98  if (m_isStreaming)
99  {
100  StopStreaming();
101  }
102  Close();
103  }
104 }
105 
106 bool ATIForceTorqueSensorHWRS485::initCommunication(int type, std::string path, int baudrate, int base_identifier)
107 {
108  std::cout << "ATIForceTorqueSensorHWRS485::initCommunication" << std::endl;
109  if (baudrate != MODBUSBAUD_1250K && baudrate != MODBUSBAUD_115200 && baudrate != MODBUSBAUD_19200)
110  {
111  #if DEBUG
112  std::cout << "Baudrate " << baudrate << " is not supported!" << std::endl;
113  #endif
114  return false;
115  }
116 
117  // for types and baudrates see:
118  m_RS485Device = path;
119  m_ModbusBaudrate = baudrate;
120  m_ModbusBaseIdentifier = base_identifier;
121  return true;
122 }
123 
125 {
126 #if DEBUG
127  std::cout << "ATIForceTorqueSensorHWRS485::init" << std::endl;
128 #endif
129  m_isStreaming = false;
130  if (initRS485())
131  {
132  int tries = 0;
133  while (!ReadFTCalibrationData(1) && tries < 10) {
134  tries++;
135  usleep(100000);
136  }
137  // This is a way of testing if communication is successful
138  if (tries >= 10)
139  {
140  std::cout << "Can not read Calibration Data from FTS!" << std::endl;
141  return false;
142  }
143 
144  //Set active gain and offset from the calibration data
145  if (!SetStorageLock(false))
146  {
147  return false;
148  }
150  {
151  return false;
152  }
153 
155  {
156  return false;
157  }
158 
159  if (!SetStorageLock(true))
160  {
161  return false;
162  }
163 
165  }
166  else
167  {
168  std::cout << "RS485 initialization unsuccessful!" << std::endl;
169  return false;
170  }
171 
172  return true;
173 }
174 
176 {
177 #if DEBUG
178  std::cout << "ATIForceTorqueSensorHWRS485::initRS485" << std::endl;
179 #endif
180  if (m_modbusCtrl)
181  {
182  Close(); //Close existing modbus connection before opening a new one
183  }
184 
185 
186 #if DEBUG
187  std::cout << "Opening new modbus connection to " << m_RS485Device.c_str() << " with baudrate " << m_ModbusBaudrate << std::endl;
188 #endif
189  m_ModbusBaseIdentifier = 0x0A;
190 
191  int tries = 0;
192  bool gotStatusWord = false;
193  while (!gotStatusWord && tries < 10) {
194  m_modbusCtrl = modbus_new_rtu(m_RS485Device.c_str(), m_ModbusBaudrate, 'E', 8, 1); //As specified in 8.1., the sensor uses 8 data bits and one bit for 'Even' parity
195  if (!m_modbusCtrl)
196  {
197  std::cout << "Could not initialize modbus connection" << std::endl;
198  tries++;
199  continue;
200  }
201  //#if DEBUG
202  // modbus_set_debug(m_modbusCtrl, true);
203  //#endif
204  #if DEBUG
205  std::cout << "Setting slave to " << m_ModbusBaseIdentifier << std::endl;
206  #endif
208  if (rc == -1)
209  {
210  std::cout << "Could not set slave ID" << std::endl;
211  Close();
212  tries++;
213  continue;
214  }
215 
217  if (rc == -1)
218  {
219  std::cout << "Could not connect" << std::endl;
220  Close();
221  tries++;
222  continue;
223  }
224  // This is a way of testing if communication is successful
225  gotStatusWord = ReadStatusWord();
226  if(!gotStatusWord)
227  {
228  Close();
229  //Send stop sequence when starting a new connection, to make sure the sensor is not in streaming mode
230  if (!OpenRawConnection())
231  {
232  tries++;
233  continue;
234  }
236  usleep(500000);
237  }
238  tries++;
239  }
240 
241  if (!gotStatusWord)
242  {
243  std::cout << "Could not read status word!" << std::endl;
244  return false;
245  }
246  m_isStreaming = false;
247  return true;
248 }
249 
250 bool ATIForceTorqueSensorHWRS485::ReadFTCalibrationData(const unsigned int calibrationNumber)
251 {
252 #if DEBUG
253  std::cout << "\n\n*********FTSerialNumber**********" << std::endl;
254 #endif
255  if (calibrationNumber < 1 || calibrationNumber > 16)
256  {
257  std::cout << "Invalid calibration number" << std::endl;
258  return false;
259  }
260 
261  uint16_t tab_reg[168];
262  unsigned int registerOffset = (calibrationNumber - 1) * 192;
263  uint8_t dest;
264 
265  int failure = false;
266  failure |= (modbus_read_registers(m_modbusCtrl, 0x00e3 + registerOffset, 64, tab_reg) == -1);
267  failure |= (modbus_read_registers(m_modbusCtrl, 0x00e3 + registerOffset + 64, 64, &tab_reg[64]) == -1);
268  failure |= (modbus_read_registers(m_modbusCtrl, 0x00e3 + registerOffset + 128, 40, &tab_reg[128]) == -1);
269 
270  if (failure)
271  {
272  std::cout << "Reading Calibration Data failed" << std::endl;
273  fprintf(stderr, "%s\n", modbus_strerror(errno));
274  return false;
275  }
276 
277  std::string calibSerialNumber;
278  for (unsigned int i = 0; i < 4; i++)
279  {
280  calibSerialNumber += (char)MODBUS_GET_HIGH_BYTE(tab_reg[i]);
281  calibSerialNumber += (char)MODBUS_GET_LOW_BYTE(tab_reg[i]);
282  }
283  m_calibrationData.calibSerialNumber = calibSerialNumber;
284  #if DEBUG
285  std::cout << "Serial Number is " << m_calibrationData.calibSerialNumber << std::endl;
286 #endif
287  std::string calibPartNumber;
288  for (unsigned int i = 4; i < 20; i++)
289  {
290  calibPartNumber += (char)MODBUS_GET_HIGH_BYTE(tab_reg[i]);
291  calibPartNumber += (char)MODBUS_GET_LOW_BYTE(tab_reg[i]);
292  }
293  m_calibrationData.calibPartNumberNumber = calibPartNumber;
294 
295 #if DEBUG
296  std::cout << "Part Number is " << m_calibrationData.calibPartNumberNumber << std::endl;
297 #endif
298  std::string calibFamilyID;
299  for (unsigned int i = 20; i < 22; i++)
300  {
301  calibFamilyID += (char)MODBUS_GET_HIGH_BYTE(tab_reg[i]);
302  calibFamilyID += (char)MODBUS_GET_LOW_BYTE(tab_reg[i]);
303  }
304  m_calibrationData.calibFamilyID = calibFamilyID;
305 
306 #if DEBUG
307  std::cout << "Calib Family ID is " << m_calibrationData.calibFamilyID << std::endl;
308 #endif
309  std::string calibTime;
310  for (unsigned int i = 22; i < 32; i++)
311  {
312  calibTime += (char)MODBUS_GET_HIGH_BYTE(tab_reg[i]);
313  calibTime += (char)MODBUS_GET_LOW_BYTE(tab_reg[i]);
314  }
315 
316  m_calibrationData.calibTime = calibTime;
317 #if DEBUG
318  std::cout << "Calib Time is " << m_calibrationData.calibTime << std::endl;
319 #endif
320  std::cout << "Calibration Matrix:" << std::endl;
321  for (unsigned int i = 0; i < 6; i++)
322  {
323  for (unsigned int j = 0; j < 6; j++)
324  {
325  unsigned int index = 32+(i*6+j)*2;
326  uint32_t temp;
327  temp = (MODBUS_GET_HIGH_BYTE(tab_reg[index]) << 24) | (MODBUS_GET_LOW_BYTE(tab_reg[index]) << 16) | (MODBUS_GET_HIGH_BYTE(tab_reg[index+1]) << 8) | (MODBUS_GET_LOW_BYTE(tab_reg[index+1]));
328  memcpy(&m_calibrationData.basicMatrix[i][j], &temp, sizeof(float));
329  std::cout << m_calibrationData.basicMatrix[i][j] << ", ";
330  }
331  std::cout << std::endl;
332  }
333 
334  m_calibrationData.forceUnitsInt = static_cast<ForceUnit>(MODBUS_GET_HIGH_BYTE(tab_reg[104]));
335 #if DEBUG
336  std::cout << "Force Units are ";
338  {
340  std::cout << "Pound" << std::endl;
341  break;
343  std::cout << "Newton" << std::endl;
344  break;
346  std::cout << "Kilopound" << std::endl;
347  break;
349  std::cout << "KiloNewton" << std::endl;
350  break;
352  std::cout << "Kilogram-equivalent force" << std::endl;
353  break;
355  std::cout << "Gram-equivalent force" << std::endl;
356  break;
357  default:
358  std::cout << "Unknown!" << std::endl;
359  break;
360  }
361 #endif
363 
364  m_calibrationData.torqueUnitsInt = static_cast<TorqueUnit>(MODBUS_GET_LOW_BYTE(tab_reg[104]));
365 #if DEBUG
366  std::cout << "Torque Units are ";
368  {
370  std::cout << "Pound-inch" << std::endl;
371  break;
373  std::cout << "Pound-foot" << std::endl;
374  break;
376  std::cout << "Newton-meter" << std::endl;
377  break;
379  std::cout << "Newton-millimeter" << std::endl;
380  break;
382  std::cout << "Kilogram(-equivalent)-centimeter" << std::endl;
383  break;
384  default:
385  std::cout << "Unknown!" << std::endl;
386  break;
387  }
388 #endif
390 
391  for (unsigned int i = 0; i < 6; i++)
392  {
393  unsigned int index = 105 +i*2;
394  int32_t temp;
395  temp = (((int32_t)tab_reg[index]) << 16) | tab_reg[index+1];
396  memcpy(&m_calibrationData.maxRating[i], &temp, sizeof(float));
397  }
399 #if DEBUG
400  std::cout << "Counts per force are " << m_calibrationData.countsPerForce << std::endl;
401 #endif
403 #if DEBUG
404  std::cout << "Counts per torque " << m_calibrationData.countsPerTorque << std::endl;
405 #endif
406  for (unsigned int i = 0; i < 6; i++)
407  {
408  m_calibrationData.gageGain[i] = (MODBUS_GET_HIGH_BYTE(tab_reg[121 + i]) << 8) | (MODBUS_GET_LOW_BYTE(tab_reg[121 + i]));
409 #if DEBUG
410  std::cout << "Gage gain " << i << " is " << m_calibrationData.gageGain[i] << std::endl;
411 #endif
412  }
413  for (unsigned int i = 0; i < 6; i++)
414  {
415  m_calibrationData.gageOffset[i] = (MODBUS_GET_HIGH_BYTE(tab_reg[127 + i]) << 8) | (MODBUS_GET_LOW_BYTE(tab_reg[127 + i]));
416 #if DEBUG
417  std::cout << "Gage offset " << i << " is " << m_calibrationData.gageOffset[i] << std::endl;
418 #endif
419  }
420 
421  return true;
422 }
423 
425 {
426  uint8_t lockCode;
427  if (lock)
428  {
429  lockCode = 0x18;
430  }
431  else
432  {
433  lockCode = 0xaa;
434  }
435 
436  uint8_t raw_req[] = { m_ModbusBaseIdentifier, 0x6a, lockCode }; //OpCode is 0x6a = 104, Data is 0x18 (to lock) or 0xaa (to unlock) as specified in 8.3.1.
438  int req_length = modbus_send_raw_request(m_modbusCtrl, raw_req, 3 * sizeof(uint8_t));
440 
441  if (len == -1)
442  {
443  std::cout << "Could not set storage lock. No confirmation received." << std::endl;
444  return false;
445  }
446  if (rsp[2] != 1)
447  {
448  std::cout << "Could not set storage lock. Invalid answer." << std::endl;
449  return false;
450  }
451 #if DEBUG
452  std::cout << "Setting storage lock was successful" << std::endl;
453 #endif
454 
455  return true;
456 }
457 
458 
459 bool ATIForceTorqueSensorHWRS485::SetActiveGain(const uint16_t ag0, const uint16_t ag1, const uint16_t ag2, const uint16_t ag3, const uint16_t ag4, const uint16_t ag5) const
460 {
461 #if DEBUG
462  std::cout << "Setting active gain to " << ag0 << ", " << ag1 << ", " << ag2 << ", " << ag3 << ", " << ag4 << ", " << ag5 << std::endl;
463 #endif
464  uint16_t activeGain[6] = {ag0, ag1, ag2, ag3, ag4, ag5};
465  int rc = modbus_write_registers(m_modbusCtrl, 0x0000, 6, activeGain);
466  if (rc == -1)
467  {
468  std::cout << "Setting active gain failed with status " << rc << std::endl;
469  fprintf(stderr, "%s\n", modbus_strerror(errno));
470  return false;
471  }
472  return true;
473 }
474 
475 
476 bool ATIForceTorqueSensorHWRS485::SetActiveOffset(const uint16_t ao0, const uint16_t ao1, const uint16_t ao2, const uint16_t ao3, const uint16_t ao4, const uint16_t ao5) const
477 {
478 #if DEBUG
479  std::cout << "Setting active offset to " << ao0 << ", " << ao1 << ", " << ao2 << ", " << ao3 << ", " << ao4 << ", " << ao5 << std::endl;
480 #endif
481  uint16_t activeOffset[6] = {ao0, ao1, ao2, ao3, ao4, ao5};
482  int rc = modbus_write_registers(m_modbusCtrl, 0x0006, 6, activeOffset);
483  if (rc == -1)
484  {
485  std::cout << "Setting active offset failed with status " << rc << std::endl;
486  fprintf(stderr, "%s\n", modbus_strerror(errno));
487  return false;
488  }
489  return true;
490 }
491 
493 {
494 #if DEBUG
495  std::cout << "\n\n*********FTStatusWord**********" << std::endl;
496 #endif
497  uint16_t tab_reg[1];
498 
499  int rc = modbus_read_registers(m_modbusCtrl, 0x001D, 1, tab_reg);
500  if (rc == -1)
501  {
502  std::cout << "Reading Status Word failed with status " << rc << std::endl;
503  fprintf(stderr, "%s\n", modbus_strerror(errno));
504  return false;
505  }
506  bool statusGood = true;
507  if (tab_reg[0] == 0)
508  {
509 #if DEBUG
510  std::cout << "Status is good." << std::endl;
511 #endif
512  return true;
513  }
514 
515  if (tab_reg[0] & ST_WATCHDOG_RESET)
516  {
517  std::cout << "Watchdog reset - the analog board was reset by the watchdog timer." << std::endl;
518  }
519  if (tab_reg[0] & ST_EXC_VOLTAGE_HIGH)
520  {
521  std::cout << "Excitation voltage too high." << std::endl;
522  }
523  if (tab_reg[0] & ST_EXC_VOLTAGE_LOW)
524  {
525  std::cout << "Excitation voltage too low." << std::endl;
526  }
527  if (tab_reg[0] & ST_ART_ANALOG_GRND_OOR)
528  {
529  std::cout << "Artificial analog ground out of range." << std::endl;
530  }
531  if (tab_reg[0] & ST_PWR_HIGH)
532  {
533  std::cout << "Power supply too high." << std::endl;
534  }
535  if (tab_reg[0] & ST_PWR_LOW)
536  {
537  std::cout << "Power supply too low." << std::endl;
538  }
539  if (tab_reg[0] & ST_EEPROM_ERR)
540  {
541  std::cout << "Error accessing stored settings in EEPROM." << std::endl;
542  }
543  if (tab_reg[0] & ST_INV_CONF_DATA)
544  {
545  std::cout << "Invalid configuration data." << std::endl;
546  }
547  if (tab_reg[0] & ST_STRAIN_GAGE_SUPPLY_HIGH)
548  {
549  std::cout << "Strain gage bridge supply current too high." << std::endl;
550  }
551  if (tab_reg[0] & ST_STRAIN_GAGE_SUPPLY_LOW)
552  {
553  std::cout << "Strain gage bridge supply current too low." << std::endl;
554  }
555  if (tab_reg[0] & ST_THERMISTOR_HIGH)
556  {
557  std::cout << "Thermistor too high." << std::endl;
558  }
559  if (tab_reg[0] & ST_THERMISTOR_LOW)
560  {
561  std::cout << "Thermistor too low." << std::endl;
562  }
563  if (tab_reg[0] & ST_DAC_READING_OOR)
564  {
565  std::cout << "DAC reading out of range." << std::endl;
566  }
567  return false;
568 }
569 
570 bool ATIForceTorqueSensorHWRS485::SetBaudRate(const int value, const bool setVolatile)
571 {
572 #if DEBUG
573  std::cout << "\n\n*******Setting Baud Rate value to: " << value << "********" << std::endl;
574 #endif
575  uint16_t baudrateIndex = 0;
576  if (value == MODBUSBAUD_1250K)
577  {
578  baudrateIndex = 0;
579  }
580  else if (value == MODBUSBAUD_115200)
581  {
582  baudrateIndex = 2;
583  }
584  else if (value == MODBUSBAUD_19200)
585  {
586  baudrateIndex = 1;
587  }
588  else //Baudrate not supported
589  {
590  fprintf(stderr, "Baudrate %i is not supported \n", value);
591  return false;
592  }
593 
594  //If Baudrate should be set non-volatile, the 0x001E flag has to be set first (According to 8.3.2 of the sensors user manual)
595  if(!setVolatile)
596  {
597  uint16_t tab_reg[1] = {1};
598 
599  int rc = modbus_write_registers(m_modbusCtrl, 0x001E, 1, tab_reg);
600  if (rc == -1)
601  {
602  std::cout << "Setting non-volatile baud rate flag failed with status " << rc << std::endl;
603  fprintf(stderr, "%s\n", modbus_strerror(errno));
604  return false;
605  }
606  }
607 
608  uint16_t tab_reg[1] = {baudrateIndex};
609 
610  int rc = modbus_write_registers(m_modbusCtrl, 0x001F, 1, tab_reg);
611  if (rc == -1)
612  {
613  std::cout << "Setting baudrate failed with status " << rc << std::endl;
614  fprintf(stderr, "%s\n", modbus_strerror(errno));
615  return false;
616  }
617  m_ModbusBaudrate = value;
618  //Reset connection here
619  Reset();
620 
621  return true;
622 }
623 
625 {
626 #if DEBUG
627  std::cout << "\n\n******* Reseting the RS485 Interface ********" << std::endl;
628 #endif
629  if (!Close())
630  {
631  return false;
632  }
633  if (!init())
634  {
635  return false;
636  }
637  return true;
638 }
639 
641 {
644 
645  return true;
646 }
647 
648 bool ATIForceTorqueSensorHWRS485::SetSessionID(const uint16_t sessionID)
649 {
650 #if DEBUG
651  std::cout << "\n\n*******Setting Session ID value to HEX : " << std::hex << sessionID << " ********" << std::endl;
652 #endif
653  uint16_t tab_reg[1] = {sessionID};
654 
655  int rc = modbus_write_registers(m_modbusCtrl, 0x000C, 1, tab_reg);
656  if (rc == -1)
657  {
658  #if DEBUG
659  std::cout << "Setting Session ID failed with status " << rc << std::endl;
660  #endif
661  fprintf(stderr, "%s\n", modbus_strerror(errno));
662  return false;
663  }
664  return true;
665 }
666 
667 bool ATIForceTorqueSensorHWRS485::ReadSessionID(uint16_t &sessionID) const
668 {
669 #if DEBUG
670  std::cout << "\n\n*******Reading Session ID"<< " ********"
671  << std::endl;
672 #endif
673  uint16_t tab_reg[1];
674 
675  int rc = modbus_read_registers(m_modbusCtrl, 0x000C, 1, tab_reg);
676  if (rc == -1)
677  {
678  #if DEBUG
679  std::cout << "Reading Session ID failed with status " << rc << std::endl;
680  #endif
681  fprintf(stderr, "%s\n", modbus_strerror(errno));
682  return false;
683  }
684  sessionID = tab_reg[0];
685  return true;
686 }
687 
688 
689 bool ATIForceTorqueSensorHWRS485::readFTData(int statusCode, double& Fx, double& Fy, double& Fz, double& Tx, double& Ty, double& Tz)
690 {
691  int sg0 = 0, sg1 = 0, sg2 = 0, sg3 = 0, sg4 = 0, sg5 = 0;
692  if (!m_isStreaming)
693  {
694  if (!StartStreaming())
695  {
696  return false;
697  }
698  }
699 
700  m_buffer_mutex.lock();
701  long unsigned int timeSinceLastInput = (ros::Time::now()-m_buffer.timestamp).toNSec();
702  if (timeSinceLastInput > m_bufferTimeout)
703  {
704  std::cout << "Buffer timestamp is too far in the past! Data might be deprecated and will be ignored. (" << timeSinceLastInput << ")" << std::endl;
705  m_buffer_mutex.unlock();
706  return false;
707  }
708  sg0 = m_buffer.gageData[0];
709  sg1 = m_buffer.gageData[1];
710  sg2 = m_buffer.gageData[2];
711  sg3 = m_buffer.gageData[3];
712  sg4 = m_buffer.gageData[4];
713  sg5 = m_buffer.gageData[5];
714  m_buffer_mutex.unlock();
715 
716  StrainGaugeToForce(sg0, sg1, sg2, sg3, sg4, sg5);
717  Fx = m_vForceData(0);
718  Fy = m_vForceData(1);
719  Fz = m_vForceData(2);
720  Tx = m_vForceData(3);
721  Ty = m_vForceData(4);
722  Tz = m_vForceData(5);
723 // std::cout << "Strain Gauge is: " << sg0 << ", " << sg1 << ", " << sg2 << ", " << sg3 << ", " << sg4 << ", " << sg5 << ", Force data is: " << Fx << " " << forceUnitStr << ", " << Fy << " " << forceUnitStr << ", "
724 // << Fz << " " << forceUnitStr << ", Torque data is: " << Tx << " " << torqueUnitStr << ", " << Ty << " " << torqueUnitStr << ", " << Tz << " " << torqueUnitStr << std::endl;
725 
726  return true;
727 
728 }
729 
731 {
732 #if DEBUG
733  std::cout << "Trying to start stream" << std::endl;
734 #endif
735  if (!m_isStreaming)
736  {
737  uint8_t raw_req[] = { m_ModbusBaseIdentifier, 0x46, 0x55 }; //OpCode is 0x46 = 70, Data is 0x55 as specified in 8.3.1.
739  int req_length = modbus_send_raw_request(m_modbusCtrl, raw_req, 3 * sizeof(uint8_t));
741 
742  if (len == -1)
743  {
744  std::cout << "Could not start data streaming. No confirmation received." << std::endl;
745  return false;
746  }
747  else if (rsp[2] == 1)
748  {
749  if (!OpenRawConnection())
750  {
751  return false;
752  }
753  m_isStreaming = true;
754  }
755  else
756  {
757  std::cout << "Could not start data streaming. Invalid answer." << std::endl;
758  return false;
759  }
760  bytesRead = 0;
761  std::cout << "Started streaming." << std::endl;
763  bufferSize = 0;
765  m_readThread.detach();
766  }
767  return true;
768 }
769 
771 {
772  //Confirmed
773  /* Open File Descriptor: The connection have read/write access and it should be blocking */
774  m_rs485 = open( m_RS485Device.c_str(), O_RDWR | O_NOCTTY | O_EXCL );
775 
776  /* Error Handling */
777  if ( m_rs485 == 0 )
778  {
779  std::cout << "Error " << errno << " opening " << m_RS485Device << ": " << strerror (errno) << std::endl;
780  return false;
781  }
782  //Flush serial buffer
783  tcflush(m_rs485,TCIOFLUSH);
784 
785  struct serial_struct ss;
786  ioctl(m_rs485, TIOCGSERIAL, &ss);
787  ss.flags = (ss.flags & ~ASYNC_SPD_MASK) | ASYNC_SPD_CUST;
788  ss.custom_divisor = (ss.baud_base + (m_ModbusBaudrate/ 2)) / m_ModbusBaudrate;
789  int closestSpeed = ss.baud_base / ss.custom_divisor;
790 
791  if (closestSpeed < m_ModbusBaudrate * 98 / 100 || closestSpeed > m_ModbusBaudrate * 102 / 100) {
792  fprintf(stderr, "Cannot set serial port speed to. Closest possible is %i\n", closestSpeed);
793  return false;
794  }
795  ioctl(m_rs485, TIOCSSERIAL, &ss);
796  struct termios tios;
797  memset(&tios, 0, sizeof(struct termios));
798  speed_t speed;
799  speed = B38400;
800  cfsetispeed(&tios, B38400);
801  cfsetospeed(&tios, B38400);
802  /* Set the baud rate */
803  if ((cfsetispeed(&tios, speed) < 0) ||
804  (cfsetospeed(&tios, speed) < 0)) {
805  close(m_rs485);
806  m_rs485 = 0;
807  std::cout << "Could not set speed" << std::endl;
808  return false;
809 
810  }
811  ioctl(m_rs485, TIOCSSERIAL, &ss);
812  /* Software flow control is disabled */
813  tios.c_iflag &= ~(IXON | IXOFF | IXANY);
814  /* Raw ouput */
815  tios.c_oflag &=~ OPOST;
816  tios.c_cflag &= ~CSIZE;
817  tios.c_cflag |= CS8;
818  tios.c_cflag &=~ CSTOPB;
819  tios.c_cflag |= PARENB;
820  tios.c_cflag &=~ PARODD;
821  tios.c_iflag |= INPCK;
822  tios.c_cflag |= (CREAD | CLOCAL); //enable receiver
823  tios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
824  tios.c_cc[VMIN] = 39; /* Read 10 characters */
825  tios.c_cc[VTIME] = 0; /* Wait indefinitely */
826  if (tcsetattr(m_rs485, TCSANOW, &tios) < 0)
827  {
828  return false;
829  }
830  return true;
831 }
832 
834 {
835  while (m_isStreaming)
836  {
837  if (ReadData())
838  {
840  }
841  else if ((ros::Time::now() - lastValidTimeStamp).toSec() > 2)
842  {
843  std::cout << "Error while reading: Timeout. " << std::endl;
845  std::this_thread::sleep_for(std::chrono::milliseconds(1000));
846  ReadStatusWord();
847  m_isStreaming = false;
848  return;
849  }
850  }
851 }
852 
854 {
855  if (m_isStreaming)
856  {
857 #if DEBUG
859 #endif
860  /* *** READ *** */
861  int n = read( m_rs485, &streamBuf + bufferSize , sizeof(streamBuf) - bufferSize );
862  /* Error Handling */
863  if (n < 0)
864  {
865  std::cout << "Error reading: " << strerror(errno) << std::endl;
866  std::chrono::microseconds sleepTime = std::chrono::microseconds(5000);
867  return false;
868  }
869  else if (n == 0) {
870  //No data received
871  std::cout << "No data received!" << std::endl;
872  std::chrono::microseconds sleepTime = std::chrono::microseconds(5000);
873  return false;
874  }
875  else if (n + bufferSize != sizeof(streamBuf)) {
876  //The received package was incomplete, therefore we need to read the missing data in the next call
877  std::cout << "Data truncated. n: " << n << " bufferSize: " << bufferSize << std::endl;
878  bufferSize = (n + bufferSize) % sizeof(streamBuf);
879  bytesRead += n;
880  return false;
881  }
882  bytesRead += sizeof(streamBuf);
883  bufferSize = 0;
884  //Validate the read data (if invalid, exit)
886  {
887  return false;
888  }
889  GageVector tmp;
890  //The data package from the sensor contains the data clustered together by each axis (as specified in 8.4.2)
891  //Therefore, the data has to be rearranged when saving it
892  tmp.gageData[0] = streamBuf[1] | (streamBuf[0] << 8);
893  tmp.gageData[1] = streamBuf[7] | (streamBuf[6] << 8);
894  tmp.gageData[2] = streamBuf[3] | (streamBuf[2] << 8);
895  tmp.gageData[3] = streamBuf[9] | (streamBuf[8] << 8);
896  tmp.gageData[4] = streamBuf[5] | (streamBuf[4] << 8);
897  tmp.gageData[5] = streamBuf[11] | (streamBuf[10] << 8);
898  tmp.timestamp = ros::Time::now();
899  if (m_buffer_mutex.try_lock())
900  {
901  m_buffer = tmp;
902  m_buffer_mutex.unlock();
903  }
904 #if DEBUG
905  std::cout << "Read took " << (ros::Time::now()-readStart).toNSec() << " nanoseconds" << std::endl;
906 #endif
907 
908  }
909  return true;
910 }
911 
913 {
914  uint8_t check = buf[12];
915 
916  if (((check >> 7) & 0x01)) //Check status bit
917  {
918  //If it is set to 1, an error occurred -> Stop streaming
919  std::cout << bytesRead << "Invalid status bit" << std::endl;
920  return false;
921  }
922  uint8_t checksum = check & 0x7F;
923 
924  int compareChecksum = 0;
925  for (unsigned int i = 0; i < 12; i++)
926  {
927  compareChecksum += buf[i];
928  }
929  if ((compareChecksum & 0x7F) != checksum)
930  {
931  std::cout << bytesRead << "Package has invalid checksum! Ignoring data... ";
932  return false;
933  }
934  return true;
935 }
936 
937 
939 {
940  if (m_isStreaming)
941  {
942  if (m_readThread.joinable())
943  {
944  m_readThread.join();
945  }
946  m_isStreaming = false;
947  return SendStopSequence();
948  }
949  return false;
950 }
951 
953 {
954  if (m_isStreaming)
955  {
956  unsigned char stopCmd[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //Send jamming sequence of 14 bytes to stop streaming
957  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
958  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
959  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
960  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
961  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
962  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
963  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
964  int n_written = write( m_rs485, stopCmd, sizeof(stopCmd));
965  return true;
966  }
967  return false;
968 }
969 
970 void ATIForceTorqueSensorHWRS485::StrainGaugeToForce(const int &sg0, const int &sg1, const int &sg2, const int &sg3, const int &sg4, const int &sg5)
971 {
972  Eigen::VectorXf v6SG(6);
973  Eigen::VectorXf tmp(6);
974 
975  v6SG[0] = sg0;
976  v6SG[1] = sg1;
977  v6SG[2] = sg2;
978  v6SG[3] = sg3;
979  v6SG[4] = sg4;
980  v6SG[5] = sg5;
981  tmp = m_mXCalibMatrix * v6SG;
982  //Scale the force/torque values according to calibration
983  tmp[0] = tmp[0] / m_calibrationData.countsPerForce;
984  tmp[1] = tmp[1] / m_calibrationData.countsPerForce;
985  tmp[2] = tmp[2] / m_calibrationData.countsPerForce;
986  tmp[3] = tmp[3] / m_calibrationData.countsPerTorque;
987  tmp[4] = tmp[4] / m_calibrationData.countsPerTorque;
988  tmp[5] = tmp[5] / m_calibrationData.countsPerTorque;
989  m_vForceData = tmp;
990 }
991 
992 void ATIForceTorqueSensorHWRS485::SetCalibMatrix(const float (&matrix)[6][6])
993 {
994  Eigen::MatrixXf tmp(6, 6);
995  for (unsigned int i = 0; i < 6; i++)
996  {
997  for (unsigned int j = 0; j < 6; j++)
998  {
999  tmp(i,j) = matrix[i][j];
1000  }
1001  }
1002 
1003  m_mXCalibMatrix = tmp;
1004 }
1005 
#define MODBUS_GET_LOW_BYTE(data)
#define ST_THERMISTOR_HIGH
int modbus_send_raw_request(modbus_t *ctx, uint8_t *raw_req, int raw_req_length)
#define ST_DAC_READING_OOR
ROSCPP_DECL bool check()
#define ST_EXC_VOLTAGE_LOW
int modbus_set_slave(modbus_t *ctx, int slave)
int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest)
#define ST_STRAIN_GAGE_SUPPLY_HIGH
#define MODBUSBAUD_19200
#define MODBUS_RTU_MAX_ADU_LENGTH
virtual bool readFTData(int statusCode, double &Fx, double &Fy, double &Fz, double &Tx, double &Ty, double &Tz)
bool ReadSessionID(uint16_t &sessionID) const
#define ST_STRAIN_GAGE_SUPPLY_LOW
int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src)
#define ST_WATCHDOG_RESET
bool ReadFTCalibrationData(const unsigned int calibrationNumber=1)
const std::string TorqueUnitNames[]
#define MODBUSBAUD_115200
void StrainGaugeToForce(const int &sg0, const int &sg1, const int &sg2, const int &sg3, const int &sg4, const int &sg5)
#define MODBUSBAUD_1250K
void SetCalibMatrix(const float(&matrix)[6][6])
const char * modbus_strerror(int errnum)
stderr
#define MODBUS_GET_INT32_FROM_INT16(tab_int16, index)
#define MODBUS_GET_HIGH_BYTE(data)
#define ST_PWR_HIGH
bool SetSessionID(const uint16_t sessionID)
const std::string ForceUnitNames[]
unsigned char uint8_t
bool SetStorageLock(const bool lock) const
#define ST_ART_ANALOG_GRND_OOR
#define ST_PWR_LOW
bool SetBaudRate(const int value, const bool setVolatile=true)
#define ST_THERMISTOR_LOW
static Time now()
bool ValidateFTData(const uint8_t(&buf)[26]) const
virtual bool initCommunication(int type, std::string path, int baudrate, int base_identifier)
int modbus_receive_confirmation(modbus_t *ctx, uint8_t *rsp)
void modbus_close(modbus_t *ctx)
bool SetActiveOffset(const uint16_t ao0, const uint16_t ao1, const uint16_t ao2, const uint16_t ao3, const uint16_t ao4, const uint16_t ao5) const
modbus_t * modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop_bit)
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
#define ST_EEPROM_ERR
#define ST_INV_CONF_DATA
void modbus_free(modbus_t *ctx)
int modbus_connect(modbus_t *ctx)
#define ST_EXC_VOLTAGE_HIGH
bool SetActiveGain(const uint16_t ag0, const uint16_t ag1, const uint16_t ag2, const uint16_t ag3, const uint16_t ag4, const uint16_t ag5) const


ati_force_torque
Author(s): Denis Štogl, Alexander Bubeck
autogenerated on Thu Sep 17 2020 03:18:35