17 #include <asm/ioctls.h> 18 #include <linux/serial.h> 19 #include <sys/ioctl.h> 34 const std::uint32_t& baudRate)
38 , usbFileDescriptor_{ -1 }
70 std::this_thread::sleep_for(std::chrono::microseconds(3000000));
75 ROS_ERROR(
"[%s] Could not establish connection with device. Start-up failed.",
name_.c_str());
80 ROS_ERROR(
"[%s] Could not bring device to INIT mode.",
name_.c_str());
105 ROS_INFO(
"[%s] Driver will attempt to shut-down",
name_.c_str());
125 ROS_INFO(
"[%s] Closing Serial Communication",
name_.c_str());
194 uint8_t possible_header;
196 usbStreamIn_.read((
char*)&possible_header,
sizeof(possible_header));
200 usbStreamIn_.read((
char*)&frame.
bytes[
sizeof(frame.header)],
sizeof(frame) -
sizeof(frame.header));
228 catch (std::exception& e)
230 ROS_ERROR(
"[%s] Error while reading a packet, %s",
name_.c_str(), e.what());
242 ROS_WARN(
"[%s] Reached max syncing errors. Disconnecting sensor.",
name_.c_str());
251 uint16_t crc_received = frame.crc16_ccitt;
253 if (crc_received != crc_computed)
256 ROS_WARN(
"[%s] CRC missmatch received: 0x%04x calculated: 0x%04x",
name_.c_str(), crc_received, crc_computed);
260 catch (std::exception& e)
262 ROS_ERROR(
"[%s] Error while reading a packet, %s",
name_.c_str(), e.what());
267 if (frame.data.status.app_took_too_long)
269 ROS_WARN(
"[%s] Warning force sensor is skipping measurements, Increase sinc length",
name_.c_str());
271 if (frame.data.status.overrange)
273 ROS_WARN(
"[%s] Warning measuring range exceeded",
name_.c_str());
275 if (frame.data.status.invalid_measurements)
277 ROS_ERROR(
"[%s] Warning force torque measurements are invalid, Permanent damage may occur",
name_.c_str());
279 if (frame.data.status.raw_measurements)
325 return std::string{
"No Error" };
328 return std::string{
"Offset Error" };
331 return std::string{
"Calibration Error" };
334 return std::string{
"Packet Reading Error" };
337 return std::string{
"Sync Error" };
340 return std::string{
"Undefined" };
343 return std::string{
"No Error" };
356 std::this_thread::sleep_for(std::chrono::microseconds(100000));
357 }
while (
isRunning_ && keepConnecting && !connected);
436 ROS_ERROR(
"[%s] Baud rate %u is not supported\n",
name_.c_str(), baudRate);
444 struct serial_struct ser_info;
454 ROS_ERROR(
"[%s] Failed to open serial-port: '%s'",
name_.c_str(), port.c_str());
461 ROS_ERROR(
"[%s] Failed to get connection attributes.",
name_.c_str());
467 if (baud_rate_definition != 0)
469 cfsetispeed(&newtio, baud_rate_definition);
470 cfsetospeed(&newtio, baud_rate_definition);
481 ROS_ERROR(
"[%s] Failed to set connection attributes.",
name_.c_str());
488 ROS_ERROR(
"[%s] Failed to flush the input and output streams.",
name_.c_str());
494 ser_info.flags |= ASYNC_LOW_LATENCY;
500 ROS_ERROR(
"[%s] Failed to set the descriptor flags.",
name_.c_str());
514 std::this_thread::sleep_for(std::chrono::seconds(1));
520 uint16_t crc = 0xFFFF;
528 #define lo8(x) ((x)&0xFF) 529 #define hi8(x) (((x) >> 8) & 0xFF) 533 return ((((uint16_t)data << 8) |
hi8(crc)) ^ (uint8_t)(data >> 4) ^ ((uint16_t)data << 3));
546 params.sched_priority = priority;
547 if (sched_setscheduler(getpid(), SCHED_FIFO, ¶ms) != 0)
549 ROS_WARN(
"[%s] Failed to set thread priority to %d: %s.",
name_.c_str(), priority, std::strerror(errno));
562 double time_stamp = 0.0;
565 timespec t_current, t_previous, t_cycle, t_loop;
567 bool run_processing =
true;
568 unsigned long loop_counter = 0;
574 t_cycle.tv_sec =
static_cast<uint64_t
>(int_part);
575 clock_gettime(CLOCK_MONOTONIC_RAW, &t_current);
580 t_previous = t_current;
581 clock_gettime(CLOCK_MONOTONIC_RAW, &t_current);
582 time_delta =
diffSec(t_previous, t_current);
586 ROS_WARN(
"[%s] Polling is out of sync! TimeDelta=%f",
name_.c_str(), time_delta);
591 std::unique_lock<std::recursive_mutex> lock(
serialMutex_);
592 (this->
readDevice(frame)) ? (run_processing =
true) : (run_processing =
false);
602 time_stamp = (double)frame.data.timestamp * 1e-6;
617 clock_nanosleep(CLOCK_MONOTONIC_RAW, TIMER_ABSTIME, &t_loop,
nullptr);
624 ROS_WARN(
"[%s] Sensor polling thread error report:",
name_.c_str());
625 ROS_WARN(
"[%s] Total iterations: %lu",
name_.c_str(), loop_counter);
667 std::unique_lock<std::recursive_mutex> lock(
serialMutex_);
670 if (!config_command.formatCommand(str))
672 ROS_ERROR(
"[%s] Could not format the config command",
name_.c_str());
686 std::this_thread::sleep_for(std::chrono::microseconds(1500000));
703 std::unique_lock<std::recursive_mutex> lock(
serialMutex_);
706 if (!run_command.formatCommand(str))
708 ROS_ERROR(
"[%s] Could not format the run command",
name_.c_str());
725 std::unique_lock<std::recursive_mutex> lock(
serialMutex_);
728 if (!hard_reset_command.formatCommand(str))
730 ROS_ERROR(
"[%s] Could not format the hardware reset command",
name_.c_str());
740 std::unique_lock<std::recursive_mutex> lock(
serialMutex_);
743 if (!soft_reset_command.formatCommand(str))
745 ROS_ERROR(
"[%s] Could not format the software reset command",
name_.c_str());
759 std::this_thread::sleep_for(std::chrono::microseconds(500000));
789 if (!filter_command.formatCommand(str))
791 ROS_ERROR(
"[%s] Could not format the filter command",
name_.c_str());
794 std::unique_lock<std::recursive_mutex> lock(
serialMutex_);
807 ROS_DEBUG_STREAM(
"[" <<
name_.c_str() <<
"] Setting Force/Torque offset: " << forceTorqueOffset << std::endl);
810 if (!offset_command.formatCommand(str))
812 ROS_ERROR(
"[%s] Could not format the force torque offset command",
name_.c_str());
815 std::unique_lock<std::recursive_mutex> lock(
serialMutex_);
829 for (uint32_t row = 0; row < 6; row++)
836 if (!sensor_calibration_row_command.formatCommand(str))
838 ROS_ERROR(
"[%s] Could not format the calibration matrix command",
name_.c_str());
841 ROS_DEBUG_STREAM(
"[" <<
name_.c_str() <<
"] Calibration matrix line is: " << str <<
". Size is " << str.size());
842 std::unique_lock<std::recursive_mutex> lock(
serialMutex_);
845 memset(buffer, 0,
sizeof(buffer));
847 std::this_thread::sleep_for(std::chrono::microseconds(10000));
861 uint8_t data_format = 0;
865 const uint8_t& dataFormat,
const uint32_t& baudRate)
887 ROS_ERROR(
"[%s] The baud rate %u is not supported\n",
name_.c_str(), baudRate);
892 if (!comm_setup.formatCommand(str))
894 ROS_ERROR(
"[%s] Could not format the communication setup command",
name_.c_str());
897 std::unique_lock<std::recursive_mutex> lock(
serialMutex_);
911 if (!save_config.formatCommand(str))
913 ROS_ERROR(
"[%s] Could not format the save config command",
name_.c_str());
916 std::unique_lock<std::recursive_mutex> lock(
serialMutex_);
929 if (!load_config.formatCommand(str))
931 ROS_ERROR(
"[%s] Could not format the load config command",
name_.c_str());
934 std::unique_lock<std::recursive_mutex> lock(
serialMutex_);
947 if (!print_config.formatCommand(str))
949 ROS_ERROR(
"[%s] Could not format the print config command",
name_.c_str());
952 std::unique_lock<std::recursive_mutex> lock(
serialMutex_);
960 uint64_t timespec_diff_ns;
962 clock_gettime(CLOCK_MONOTONIC_RAW, &tnow);
965 ROS_INFO(
"[%s] Printing user configuration:",
name_.c_str());
975 clock_gettime(CLOCK_MONOTONIC_RAW, &t_loop);
976 timespec_diff_ns = (t_loop.tv_sec - tnow.tv_sec) * 1e9 + (t_loop.tv_nsec - tnow.tv_nsec);
977 }
while (timespec_diff_ns < 1e9);
989 ROS_WARN(
"[%s] String's length exceeds permittable limit (64)",
name_.c_str());
992 ROS_DEBUG(
"[%s] Number of chars: %zu",
name_.c_str(), str.size());
997 char cstr[str.size() + 1];
998 strcpy(cstr, str.c_str());
999 for (uint8_t i = 0; i < str.size(); i++)
1002 std::this_thread::sleep_for(std::chrono::microseconds(5000));
1007 ROS_WARN(
"[%s] Serial Write or Read failed",
name_.c_str());
1017 catch (
const std::exception& e)
1030 std::unique_lock<std::recursive_mutex> lock(
serialMutex_);
1037 ROS_ERROR(
"Could not fork, error occured");
1043 ROS_DEBUG(
"Child process, pid = %u\n", getpid());
1045 char path_argument[filePath.size() + 15];
1046 int ret = sprintf(path_argument,
"-Uflash:w:%s:i", filePath.c_str());
1053 char port_argument[
port_.size() + 2];
1054 ret = sprintf(port_argument,
"-P%s",
port_.c_str());
1065 const char* argv_list[9] = {
"avrdude",
"-v",
"-patmega328p",
"-carduino", port_argument,
1066 "-b230400",
"-D", path_argument,
nullptr };
1067 ROS_DEBUG(
"Complete command for avrdude:");
1068 for (std::size_t i = 0; i <
sizeof(argv_list); i++)
1074 ret = execvp(argv_list[0], const_cast<char* const*>(argv_list));
1077 ROS_ERROR(
"[%s] Execution of avrdude failed: %s",
name_.c_str(), strerror(errno));
1078 kill(getpid(), SIGKILL);
1091 if (waitpid(pid, &status, WUNTRACED) > 0)
1093 if (WIFEXITED(status) && !WEXITSTATUS(status))
1095 ROS_INFO(
"[%s] avrdude returned successfully",
name_.c_str());
1099 else if (WIFEXITED(status) && WEXITSTATUS(status))
1101 if (WEXITSTATUS(status) == 127)
1110 ROS_ERROR(
"[%s] program terminated normally," 1111 " but returned a non-zero status",
1121 ROS_ERROR(
"[%s] program didn't terminate normally",
name_.c_str());
uint8_t getChopEnable() const
boost::atomic< bool > frameSync_
Flag that indicates if the frame is synced.
void connectionWorker()
Worker threads for managing sensor connections.
ConnectionState getConnectionState() const
Retreive sensor state/status.
bool readDevice(RxFrame &frame)
Reads a raw measurement frame from the serial-port.
bool startup()
This method starts up communication with the device.
bool initSerialPort(const std::string &port)
Sets up and initializes the serial port for communication.
std::ifstream usbStreamIn_
Input stream for the USB file descriptor.
ErrorState getErrorState() const
Gets the current error status.
#define ROS_WARN_THROTTLE(rate,...)
const WrenchType & getWrench() const
bool isConnecting() const
Checks if device is already in the process of connecting.
bool init()
This method initializes internal variables and the device for communication. It connects to the seria...
boost::atomic< ModeState > modeState_
Mode state of the sensor.
bool setSensorConfiguration(const configuration::SensorConfiguration &sensorConfiguration)
Sets a sensor configuration to the device.
double timespecToSec(timespec t)
Converts a timespec to seconds.
bool writeSerial(const std::string &str)
Writes an Ascii string to the serial device.
unsigned long frameCrcErrorCounter_
Counter for frames with CRC errors.
bool setSensorCalibration(const calibration::SensorCalibration &sensorCalibration)
Sets a sensor calibration to the device.
bool printUserConfig()
Prints all the user configurable parameters.
static const uint64_t NSEC_PER_SEC
unsigned long frameReceivedCounter_
Received frame counter.
bool setConfigMode()
Sets the device in config mode.
double pollingThreadTimeStep_
If setup, the sensor polling thread will poll at this rate.
bool setInitMode()
Triggers a software reset of the sensor bringing it to a known state.
bool isConnected() const
Quick sensor/state testers.
boost::atomic< bool > isRunning_
Internal flags/indicators.
uint16_t calcCrc16X25(uint8_t *data, int len)
uint16_t crcCcittUpdate(uint16_t crc, uint8_t data)
Implementation function of the CRC16 X25 checksum for the input data.
std::recursive_mutex readingMutex_
Mutex prohibiting simultaneous access the internal Reading variable.
unsigned long frameSuccessCounter_
Correct frames counter.
Reading serialImplReading_
The internal reading variable. It's used for providing to client code the sensor readings, through the getReading () function.
std::uint32_t getBaudRateDefinition(const uint32_t &baudRate)
Returns the system definition for the given baudRate.
bool loadConfig()
Loads the configuration of the device.
bool initSensorCommunication(bool keepConnecting)
Initializatin-time helper functions.
std::string getErrorString() const
Retrieves detailed error indication.
bool useDeviceTimeStamps_
Flag to indicate whether time-stamps should be generated using sensor or system time.
std::string port_
The serial port to connect to.
bool firmwareUpdate(const std::string &filePath)
Updates the firmware of the device.
uint8_t getFastEnable() const
uint8_t getSkipEnable() const
bool isInConfigMode() const
Checks if the ModeState is Config Mode.
unsigned int frameSyncErrorCounter_
Frame sync errors.
bool setForceTorqueFilter(const configuration::ForceTorqueFilter &filter)
Sets a force torque filter to the device.
RokubiminiSerialImpl()=delete
Default constructor is deleted.
timespec timespecAdd(timespec a, timespec b)
Calculates the sum of two timespecs.
void shutdown()
Shuts down the device. It automatically shuts-down threads and disconnects from serial-port.
RxFrame frame_
The internal variable for the receiving frame. This variable represents the raw data received from th...
bool setRunMode()
Sets the device in run mode.
std::ofstream usbStreamOut_
Output stream for the USB file descriptor.
#define ROS_DEBUG_STREAM(args)
bool saveConfigParameter()
Saves the current configuration to the device.
bool hasError() const
Checks the connection has errors.
bool runInThreadedMode_
Flag to indicate whether the driver should setup worker threads at startup.
The frame transmitted and received via the serial bus.
void getReading(rokubimini::Reading &reading)
Gets the internal reading variable.
unsigned int maxFrameSyncErrorCounts_
Maximum acceptable frame sync errors.
bool setForceTorqueOffset(const Eigen::Matrix< double, 6, 1 > &forceTorqueOffset)
Sets a force torque offset to the device.
uint16_t getSincFilterSize() const
bool setCommunicationSetup(const configuration::SensorConfiguration &sensorConfiguration, const uint8_t &dataFormat, const uint32_t &baudRate)
Sets communication setup for the device. This includes setting the temperature compensation, the matrix calibration, the data format and the baud rate.
void pollingWorker()
Worker threads for polling the sensors.
const TempType & getTemperature() const
boost::atomic< ConnectionState > connectionState_
Internal connection state.
unsigned long pollingSyncErrorCounter_
Internal statistics and error counters.
boost::atomic< ErrorState > errorState_
Internal error state.
std::recursive_mutex serialMutex_
Mutex prohibiting simultaneous access to Serial device.
bool setHardwareReset()
Triggers a hardware reset of the sensor.
double diffSec(timespec a, timespec b)
Calculates the difference (b-a) of two timespecs in seconds.
std::string name_
Name of the sensor.
const Eigen::Matrix< double, 6, 6 > & getCalibrationMatrix() const
bool connect()
Connects to the Serial-over-USB port.
double timeStampSecs_
Sample time-stamp.
boost::thread connectionThread_
Connection thread handle.
uint8_t frameHeader
The frame header value.
boost::atomic< int > usbFileDescriptor_
The USB file descriptor.
std::uint32_t baudRate_
The baud rate of the serial communication.
bool startPollingThread()
This method starts up the polling thread.
boost::thread pollingThread_
Polling thread handle.