1 #ifndef _KUKA_FRI_DRIVER 2 #define _KUKA_FRI_DRIVER 4 #include <boost/asio.hpp> 5 #include <boost/circular_buffer.hpp> 6 #include <boost/config.hpp> 7 #include <boost/exception/all.hpp> 13 #include <boost/math/special_functions/sign.hpp> 14 #include <boost/range/algorithm/copy.hpp> 15 #include <boost/range/algorithm/transform.hpp> 17 #ifdef BOOST_NO_CXX11_ATOMIC_SMART_PTR 18 #include <boost/thread.hpp> 22 #include "friClientData.h" 23 #include "friClientIf.h" 33 template <
typename T,
size_t N>
35 const boost::container::static_vector<T, N> &v) {
37 size_t last = v.size() - 1;
38 for (
size_t i = 0; i < v.size(); ++i) {
56 void decode(KUKA::FRI::ClientData &friData, std::size_t msg_size) {
58 if (!friData.decoder.decode(friData.receiveBuffer, msg_size)) {
59 BOOST_THROW_EXCEPTION(std::runtime_error(
"Error decoding received data"));
63 if (friData.expectedMonitorMsgID !=
64 friData.monitoringMsg.header.messageIdentifier) {
65 BOOST_THROW_EXCEPTION(std::invalid_argument(
66 std::string(
"KukaFRI.hpp: Problem reading buffer, id code: ") +
67 boost::lexical_cast<std::string>(
68 static_cast<int>(friData.monitoringMsg.header.messageIdentifier)) +
69 std::string(
" does not match expected id code: ") +
70 boost::lexical_cast<std::string>(
71 static_cast<int>(friData.expectedMonitorMsgID)) +
91 : armState(armState_),
92 goal_position_command_time_duration_remaining(
93 armState_.goal_position_command_time_duration) {
98 template <
typename ArmDataType,
typename CommandModeType>
105 template <
typename ArmData>
118 double rcurrentJointPos[7];
119 double rcommandedGoal[7];
120 double rdiffToGoal[7];
121 double ramountToMove[7];
122 double rcommandToSend[7];
123 double rvelocity_limits[7];
130 std::back_inserter(currentJointPos),
132 boost::copy(currentJointPos, &rcurrentJointPos[0]);
137 double thisTimeStepS = (
static_cast<double>(thisTimeStepMS) / 1000);
143 double fractionOfDistanceToTraverse =
144 static_cast<double>(thisTimeStepMS) /
145 static_cast<double>(goal_position_command_time_duration_remaining);
152 std::back_inserter(diffToGoal),
153 [&](
double commanded_angle,
double current_angle) {
154 return (commanded_angle - current_angle) *
155 fractionOfDistanceToTraverse;
160 goal_position_command_time_duration_remaining -= thisTimeStepMS;
175 velocity_limits.push_back(1.483529864195);
176 velocity_limits.push_back(1.483529864195);
177 velocity_limits.push_back(1.745329251994);
178 velocity_limits.push_back(1.308996938996);
179 velocity_limits.push_back(2.268928027593);
180 velocity_limits.push_back(2.356194490192);
181 velocity_limits.push_back(2.356194490192);
183 boost::copy(velocity_limits, &rvelocity_limits[0]);
187 diffToGoal, velocity_limits, std::back_inserter(amountToMove),
188 [&](
double diff,
double maxvel) {
189 return boost::math::copysign(std::min(std::abs(diff), maxvel), diff);
196 boost::transform(currentJointPos, amountToMove,
197 std::back_inserter(commandToSend), std::plus<double>());
202 grl::robot::arm::set(friData.commandMsg, commandToSend,
210 template <
typename ArmData>
226 template <
typename ArmData>
230 grl::robot::arm::set(friData.commandMsg,
240 return goal_position_command_time_duration_remaining > 0;
252 double goal_position_command_time_duration_remaining;
261 template <
typename LowLevelStepAlgorithmType = LinearInterpolation>
262 std::size_t
encode(LowLevelStepAlgorithmType &step_alg,
263 KUKA::FRI::ClientData &friData,
264 boost::system::error_code &ec) {
266 friData.lastSendCounter = 0;
269 friData.commandMsg.header.sequenceCounter = friData.sequenceCounter++;
270 friData.commandMsg.header.reflectedSequenceCounter =
271 friData.monitoringMsg.header.sequenceCounter;
276 if ((step_alg.hasCommandData() &&
277 (sessionState == KUKA::FRI::COMMANDING_WAIT ||
278 sessionState == KUKA::FRI::COMMANDING_ACTIVE))) {
281 switch (commandMode) {
282 case ClientCommandMode_POSITION:
285 case ClientCommandMode_WRENCH:
288 case ClientCommandMode_TORQUE:
302 }
else if (!(friData.commandMsg.has_commandData &&
303 step_alg.hasCommandData() &&
304 (sessionState == KUKA::FRI::COMMANDING_WAIT ||
305 sessionState == KUKA::FRI::COMMANDING_ACTIVE))) {
312 std::vector<double> msg;
313 copy(friData.monitoringMsg, std::back_inserter(msg),
316 set(friData.commandMsg, msg,
320 int buffersize = KUKA::FRI::FRI_COMMAND_MSG_MAX_SIZE;
321 if (!friData.encoder.encode(friData.sendBuffer, buffersize)) {
324 ec = boost::system::errc::make_error_code(boost::system::errc::bad_message);
340 template <
typename LowLevelStepAlgorithmType = LinearInterpolation>
342 LowLevelStepAlgorithmType &step_alg,
343 KUKA::FRI::ClientData &friData,
344 boost::system::error_code &receive_ec,
345 std::size_t &receive_bytes_transferred,
346 boost::system::error_code &send_ec,
347 std::size_t &send_bytes_transferred,
348 boost::asio::ip::udp::endpoint sender_endpoint =
349 boost::asio::ip::udp::endpoint()) {
351 static const int message_flags = 0;
352 receive_bytes_transferred = socket.receive_from(
353 boost::asio::buffer(friData.receiveBuffer,
354 KUKA::FRI::FRI_MONITOR_MSG_MAX_SIZE),
355 sender_endpoint, message_flags, receive_ec);
356 decode(friData, receive_bytes_transferred);
358 friData.lastSendCounter++;
360 if (friData.lastSendCounter >=
361 friData.monitoringMsg.connectionInfo.receiveMultiplier) {
362 send_bytes_transferred =
encode(step_alg, friData, send_ec);
365 socket.send(boost::asio::buffer(friData.sendBuffer, send_bytes_transferred),
366 message_flags, send_ec);
377 copy(monitoringMsg, std::back_inserter(state.
torque),
420 template <
typename LowLevelStepAlgorithmType = LinearInterpolation>
422 :
public std::enable_shared_from_this<
423 KukaFRIClientDataDriver<LowLevelStepAlgorithmType>>,
433 Params params = defaultParams())
434 : params_(params), m_shouldStop(false), isConnectionEstablished_(false),
444 : params_(params), m_shouldStop(false), isConnectionEstablished_(false),
445 optional_internal_io_service_P(new
boost::asio::io_service),
446 io_service_(*optional_internal_io_service_P)
460 latestStateForUser_ = make_valid_LatestState();
461 spareStates_.emplace_back(std::move(make_valid_LatestState()));
462 spareStates_.emplace_back(std::move(make_valid_LatestState()));
465 if (std::get<is_running_automatically>(params)) {
466 driver_threadP_.reset(
new std::thread([&] { update(); }));
469 }
catch (boost::exception &e) {
470 add_details_to_connection_error(e, params);
515 std::shared_ptr<KUKA::FRI::ClientData> &friData,
516 boost::system::error_code &receive_ec,
517 std::size_t &receive_bytes_transferred,
518 boost::system::error_code &send_ec,
519 std::size_t &send_bytes_transferred) {
524 std::rethrow_exception(exceptionPtr);
527 bool haveNewData =
false;
529 if (!isConnectionEstablished_ ||
530 !std::get<latest_receive_monitor_state>(latestStateForUser_)) {
532 std::tie(friData, receive_ec, receive_bytes_transferred, send_ec,
533 send_bytes_transferred) = make_LatestState(friData);
541 auto validFriDataLatestState = make_valid_LatestState(friData);
545 boost::lock_guard<boost::mutex> lock(ptrMutex_);
549 step_alg_ = step_alg;
553 if (std::get<latest_receive_monitor_state>(validFriDataLatestState)
554 ->commandMsg.has_commandData) {
555 std::swap(validFriDataLatestState, newCommandForDriver_);
559 if (spareStates_.size() < spareStates_.capacity() &&
560 std::get<latest_receive_monitor_state>(validFriDataLatestState)) {
561 spareStates_.emplace_back(std::move(validFriDataLatestState));
564 if (std::get<latest_receive_monitor_state>(latestStateForUser_)) {
566 std::tie(friData, receive_ec, receive_bytes_transferred, send_ec,
567 send_bytes_transferred) = std::move(latestStateForUser_);
569 }
else if (std::get<latest_receive_monitor_state>(
570 validFriDataLatestState)) {
572 std::tie(friData, receive_ec, receive_bytes_transferred, send_ec,
573 send_bytes_transferred) = validFriDataLatestState;
578 return !haveNewData || receive_bytes_transferred == 0 || receive_ec ||
584 if (driver_threadP_) {
585 driver_threadP_->join();
595 bool is_active() {
return !exceptionPtr && isConnectionEstablished_; }
608 LatestState nextState = make_valid_LatestState();
609 LatestState latestCommandBackup = make_valid_LatestState();
611 boost::asio::ip::udp::endpoint sender_endpoint;
612 boost::asio::ip::udp::socket socket(
613 connect(params_, io_service_, sender_endpoint));
619 while (!m_shouldStop) {
624 BOOST_VERIFY(std::get<latest_receive_monitor_state>(nextState));
626 std::get<latest_receive_monitor_state>(latestCommandBackup));
629 std::get<latest_receive_monitor_state>(nextState)
636 *std::get<latest_receive_monitor_state>(nextState),
637 std::get<latest_receive_ec>(nextState),
638 std::get<latest_receive_bytes_transferred>(nextState),
639 std::get<latest_send_ec>(nextState),
640 std::get<latest_send_bytes_transferred>(nextState));
646 if (ptrMutex_.try_lock()) {
666 std::swap(latestStateForUser_, nextState);
670 if (std::get<latest_receive_monitor_state>(newCommandForDriver_)) {
674 std::swap(latestCommandBackup, newCommandForDriver_);
677 if (!std::get<latest_receive_monitor_state>(nextState)) {
678 nextState = std::move(newCommandForDriver_);
679 }
else if (!(spareStates_.size() == spareStates_.capacity())) {
680 spareStates_.emplace_back(std::move(newCommandForDriver_));
682 std::get<latest_receive_monitor_state>(newCommandForDriver_)
692 BOOST_VERIFY(spareStates_.size() > 0);
694 if (!std::get<latest_receive_monitor_state>(nextState) &&
695 spareStates_.size()) {
697 nextState = std::move(*(spareStates_.end() - 1));
698 spareStates_.pop_back();
701 BOOST_VERIFY(std::get<latest_receive_monitor_state>(nextState));
703 KUKA::FRI::ClientData &nextClientData =
704 *std::get<latest_receive_monitor_state>(nextState);
705 KUKA::FRI::ClientData &latestClientData =
706 *std::get<latest_receive_monitor_state>(latestStateForUser_);
709 nextClientData.lastState = latestClientData.lastState;
710 nextClientData.sequenceCounter = latestClientData.sequenceCounter;
711 nextClientData.lastSendCounter = latestClientData.lastSendCounter;
712 nextClientData.expectedMonitorMsgID =
713 latestClientData.expectedMonitorMsgID;
717 KUKA::FRI::ClientData &latestCommandBackupClientData =
718 *std::get<latest_receive_monitor_state>(latestCommandBackup);
719 set(nextClientData.commandMsg,
720 latestCommandBackupClientData.commandMsg);
725 if (!std::get<latest_receive_ec>(nextState) &&
726 !std::get<latest_send_ec>(nextState) &&
727 std::get<latest_receive_bytes_transferred>(nextState)) {
728 isConnectionEstablished_ =
true;
737 exceptionPtr = std::current_exception();
739 isConnectionEstablished_ =
false;
742 isConnectionEstablished_ =
false;
745 enum LatestStateIndex {
746 latest_receive_monitor_state,
748 latest_receive_bytes_transferred,
750 latest_send_bytes_transferred
753 typedef std::tuple<std::shared_ptr<KUKA::FRI::ClientData>,
754 boost::system::error_code, std::size_t,
755 boost::system::error_code, std::size_t>
760 make_LatestState(std::shared_ptr<KUKA::FRI::ClientData> &clientData) {
761 return std::make_tuple(clientData, boost::system::error_code(),
762 std::size_t(), boost::system::error_code(),
769 static std::shared_ptr<KUKA::FRI::ClientData> make_shared_valid_ClientData(
770 std::shared_ptr<KUKA::FRI::ClientData> &friData) {
771 if (friData.get() ==
nullptr) {
775 friData->resetCommandMessage();
781 static std::shared_ptr<KUKA::FRI::ClientData> make_shared_valid_ClientData() {
782 std::shared_ptr<KUKA::FRI::ClientData> friData;
783 return make_shared_valid_ClientData(friData);
789 make_valid_LatestState(std::shared_ptr<KUKA::FRI::ClientData> &friData) {
791 friData = make_shared_valid_ClientData();
793 return make_LatestState(friData);
796 static LatestState make_valid_LatestState() {
797 std::shared_ptr<KUKA::FRI::ClientData> friData;
798 return make_valid_LatestState(friData);
805 LatestState latestStateForUser_;
806 LatestState newCommandForDriver_;
809 boost::container::static_vector<LatestState, 2> spareStates_;
811 std::atomic<bool> m_shouldStop;
812 std::exception_ptr exceptionPtr;
813 std::atomic<bool> isConnectionEstablished_;
817 std::unique_ptr<boost::asio::io_service> optional_internal_io_service_P;
823 boost::asio::io_service &io_service_;
824 std::unique_ptr<std::thread> driver_threadP_;
825 boost::mutex ptrMutex_;
827 LowLevelStepAlgorithmType step_alg_;
869 template <
typename LowLevelStepAlgorithmType = LinearInterpolation>
871 KukaFRIdriver<LowLevelStepAlgorithmType>>,
900 device_driver_workP_.reset(
901 new boost::asio::io_service::work(device_driver_io_service));
903 kukaFRIClientDataDriverP_.reset(
905 device_driver_io_service,
906 std::make_tuple(std::string(std::get<RobotModel>(params)),
907 std::string(std::get<localhost>(params)),
908 std::string(std::get<localport>(params)),
909 std::string(std::get<remotehost>(params)),
910 std::string(std::get<remoteport>(params)),
912 LowLevelStepAlgorithmType>::run_automatically))
920 device_driver_workP_.reset();
922 if (driver_threadP) {
923 device_driver_io_service.stop();
924 driver_threadP->join();
931 return std::chrono::duration_cast<std::chrono::seconds>(
942 copy(std::get<RobotModel>(params_), std::back_inserter(maxVel),
948 maxVel, maxVel.begin(),
949 std::bind2nd(std::multiplies<KukaState::joint_state::value_type>(),
950 getSecondsPerTick()));
965 BOOST_VERIFY(kukaFRIClientDataDriverP_.get() !=
nullptr);
971 bool haveNewData =
false;
973 static const std::size_t minimumConsecutiveSuccessesBeforeSendingCommands =
976 std::unique_ptr<LinearInterpolation> lowLevelStepAlgorithmP;
979 armState.velocity_limits.clear();
980 armState.velocity_limits = getMaxVel();
985 if (this->m_haveReceivedRealDataCount >
986 minimumConsecutiveSuccessesBeforeSendingCommands) {
987 boost::lock_guard<boost::mutex> lock(jt_mutex);
1002 BOOST_VERIFY(lowLevelStepAlgorithmP !=
nullptr);
1003 boost::system::error_code send_ec, recv_ec;
1004 std::size_t send_bytes, recv_bytes;
1006 haveNewData = !kukaFRIClientDataDriverP_->update_state(
1007 *lowLevelStepAlgorithmP, friData_, recv_ec, recv_bytes, send_ec,
1009 m_attemptedCommunicationCount++;
1012 boost::lock_guard<boost::mutex> lock(jt_mutex);
1031 m_attemptedCommunicationConsecutiveSuccessCount++;
1032 this->m_attemptedCommunicationConsecutiveFailureCount = 0;
1033 this->m_haveReceivedRealDataCount++;
1037 armState.position.clear();
1039 std::back_inserter(armState.position),
1042 armState.torque.clear();
1044 std::back_inserter(armState.torque),
1047 armState.externalTorque.clear();
1049 friData_->monitoringMsg, std::back_inserter(armState.externalTorque),
1052 armState.externalForce.clear();
1054 std::back_inserter(armState.externalForce),
1057 armState.ipoJointPosition.clear();
1059 friData_->monitoringMsg,
1060 std::back_inserter(armState.ipoJointPosition),
1063 armState.sendPeriod = std::chrono::milliseconds(
1087 m_attemptedCommunicationConsecutiveFailureCount++;
1088 std::cerr <<
"No new FRI data available, is an FRI application running " 1089 "on the Kuka arm? \n Total sucessful transfers: " 1090 << this->m_haveReceivedRealDataCount
1091 <<
"\n Total attempts: " << m_attemptedCommunicationCount
1092 <<
"\n Consecutive Failures: " 1093 << m_attemptedCommunicationConsecutiveFailureCount
1094 <<
"\n Consecutive Successes: " 1095 << m_attemptedCommunicationConsecutiveSuccessCount <<
"\n";
1096 m_attemptedCommunicationConsecutiveSuccessCount = 0;
1130 template <
typename Range>
1132 boost::lock_guard<boost::mutex> lock(jt_mutex);
1133 armState.clearCommands();
1134 boost::copy(range, std::back_inserter(armState.commandedPosition));
1135 boost::copy(range, std::back_inserter(armState.commandedPosition_goal));
1159 boost::lock_guard<boost::mutex> lock(jt_mutex);
1160 armState.goal_position_command_time_duration = duration_to_goal_command;
1173 boost::lock_guard<boost::mutex> lock(jt_mutex);
1174 return armState.timestamp;
1190 template <
typename Range>
1192 boost::lock_guard<boost::mutex> lock(jt_mutex);
1193 armState.clearCommands();
1222 template <
typename Range>
1224 boost::lock_guard<boost::mutex> lock(jt_mutex);
1225 armState.clearCommands();
1226 std::copy(range, armState.commandedCartesianWrenchFeedForward);
1231 boost::lock_guard<boost::mutex> lock(jt_mutex);
1238 volatile std::size_t m_haveReceivedRealDataCount = 0;
1243 volatile std::size_t m_attemptedCommunicationCount = 0;
1246 volatile std::size_t m_attemptedCommunicationConsecutiveFailureCount = 0;
1249 volatile std::size_t m_attemptedCommunicationConsecutiveSuccessCount = 0;
1260 boost::mutex jt_mutex;
1263 std::shared_ptr<KUKA::FRI::ClientData> friData_;
1269 typename Range,
typename T>
1271 Range &&range, T t) {
1272 state.set(range, t);
const Params & getParams()
joint_state velocity_limits
void decode(KUKA::FRI::ClientData &friData, std::size_t msg_size)
internal function to decode KUKA FRI message buffer (using nanopb decoder) for the KUKA FRI ...
void construct(Params params)
void copy(const FRIMonitoringMessage &monitoringMsg, KukaState &state)
don't use this
std::tuple< std::string, std::string, std::string, std::string, std::string, ThreadingRunMode > Params
joint velocity constraint (ex: max velocity)
void operator()(ArmData &friData, revolute_joint_torque_open_chain_command_tag)
flatbuffer::ESafetyState safetyState
joint_state commandedPosition
std::ostream & operator<<(std::ostream &out, const boost::container::static_vector< T, N > &v)
void operator()(ArmDataType &, CommandModeType &)
boost::asio::io_service device_driver_io_service
Default LowLevelStepAlgorithmType This algorithm is designed to be changed out.
Internal implementation class for driver use only, stores all the kuka state data in a simple object...
std::chrono::time_point< std::chrono::high_resolution_clock > time_point_type
std::unique_ptr< boost::asio::io_service::work > device_driver_workP_
KukaFRIClientDataDriver(Params params=defaultParams())
Simple low level driver to communicate over the Kuka iiwa FRI interface using KUKA::FRI::ClientData s...
KUKA::FRI::ESafetyState get(const FRIMonitoringMessage &monitoringMsg, const KUKA::FRI::ESafetyState)
external joint torque, i.e. torques applied to an arm excluding those caused by the mass of the arm i...
cartesian_state commandedCartesianWrenchFeedForward
Primary Kuka FRI driver, only talks over realtime network FRI KONI ethernet port. ...
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
joint_state ipoJointPosition
void construct(Params params=defaultParams())
Call this to initialize the object after the constructor has been called.
std::unique_ptr< std::thread > driver_threadP
flatbuffer::EOperationMode operationMode
std::shared_ptr< grl::robot::arm::KukaFRIClientDataDriver< LowLevelStepAlgorithmType > > kukaFRIClientDataDriverP_
the time duration over which a command should be completed
KukaState::joint_state getMaxVel()
joint_state commandedPosition_goal
we need to mind arm constraints, so we set a goal then work towards it
const int LBRMONITORMESSAGEID
void operator()(ArmData &friData, cartesian_wrench_command_tag)
void run()
blocking call to communicate with the robot continuously
~KukaFRIClientDataDriver()
flatbuffer::EDriveState driveState
LinearInterpolation(const KukaState &armState_)
std::size_t encode(LowLevelStepAlgorithmType &step_alg, KUKA::FRI::ClientData &friData, boost::system::error_code &ec)
encode data in the class KUKA::FRI::ClientData into the send buffer for the KUKA FRI. this preps the information for transport over the network
std::tuple< std::string, std::string, std::string, std::string, std::string, ThreadingRunMode > Params
bool update_state(LowLevelStepAlgorithmType &step_alg, std::shared_ptr< KUKA::FRI::ClientData > &friData, boost::system::error_code &receive_ec, std::size_t &receive_bytes_transferred, boost::system::error_code &send_ec, std::size_t &send_bytes_transferred)
Updates the passed friData shared pointer to a pointer to newly updated data, plus any errors that oc...
time step between measurements
void update_state(boost::asio::ip::udp::socket &socket, LowLevelStepAlgorithmType &step_alg, KUKA::FRI::ClientData &friData, boost::system::error_code &receive_ec, std::size_t &receive_bytes_transferred, boost::system::error_code &send_ec, std::size_t &send_bytes_transferred, boost::asio::ip::udp::endpoint sender_endpoint=boost::asio::ip::udp::endpoint())
Actually talk over the network to receive an update and send out a new KUKA FRI command.
boost::container::static_vector< double, KUKA::LBRState::NUM_DOF > joint_state
KukaFRIdriver(Params params=defaultParams())
external forces, i.e. forces applied to an arm excluding those caused by the mass of the arm itself a...
flatbuffer::ESessionState sessionState
double getSecondsPerTick()
std::tuple< std::string, std::string, std::string, std::string, std::string, ThreadingRunMode > Params
EClientCommandMode
Type of command being sent to the arm (Dimensonal units)
flatbuffer::EConnectionQuality connectionQuality
joint_state commandedTorque
static const Params defaultParams()
single point in time relative to some start point
Internal class, defines some default status variables.
KukaFRIClientDataDriver(boost::asio::io_service &ios, Params params=defaultParams())
void operator()(ArmData &friData, revolute_joint_angle_open_chain_command_tag)