trajectory_follower.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017, 2018 Simon Rasmussen (refactor)
3  *
4  * Copyright 2015, 2016 Thomas Timm Andersen (original version)
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
20 #include <endian.h>
21 #include <ros/ros.h>
22 #include <cmath>
23 
24 static const int32_t MULT_JOINTSTATE_ = 1000000;
25 static const std::string JOINT_STATE_REPLACE("{{JOINT_STATE_REPLACE}}");
26 static const std::string SERVO_J_REPLACE("{{SERVO_J_REPLACE}}");
27 static const std::string SERVER_IP_REPLACE("{{SERVER_IP_REPLACE}}");
28 static const std::string SERVER_PORT_REPLACE("{{SERVER_PORT_REPLACE}}");
29 static const std::string POSITION_PROGRAM = R"(
30 def driverProg():
31  MULT_jointstate = {{JOINT_STATE_REPLACE}}
32 
33  SERVO_IDLE = 0
34  SERVO_RUNNING = 1
35  cmd_servo_state = SERVO_IDLE
36  cmd_servo_q = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
37 
38  def set_servo_setpoint(q):
39  enter_critical
40  cmd_servo_state = SERVO_RUNNING
41  cmd_servo_q = q
42  exit_critical
43  end
44 
45  thread servoThread():
46  state = SERVO_IDLE
47  while True:
48  enter_critical
49  q = cmd_servo_q
50  do_brake = False
51  if (state == SERVO_RUNNING) and (cmd_servo_state == SERVO_IDLE):
52  do_brake = True
53  end
54  state = cmd_servo_state
55  cmd_servo_state = SERVO_IDLE
56  exit_critical
57  if do_brake:
58  stopj(1.0)
59  sync()
60  elif state == SERVO_RUNNING:
61  servoj(q, {{SERVO_J_REPLACE}})
62  else:
63  sync()
64  end
65  end
66  end
67 
68  socket_open("{{SERVER_IP_REPLACE}}", {{SERVER_PORT_REPLACE}})
69 
70  thread_servo = run servoThread()
71  keepalive = 1
72  while keepalive > 0:
73  params_mult = socket_read_binary_integer(6+1)
74  if params_mult[0] > 0:
75  q = [params_mult[1] / MULT_jointstate, params_mult[2] / MULT_jointstate, params_mult[3] / MULT_jointstate, params_mult[4] / MULT_jointstate, params_mult[5] / MULT_jointstate, params_mult[6] / MULT_jointstate]
76  keepalive = params_mult[7]
77  set_servo_setpoint(q)
78  end
79  end
80  sleep(.1)
81  socket_close()
82  kill thread_servo
83 end
84 )";
85 
86 TrajectoryFollower::TrajectoryFollower(URCommander &commander, std::string &reverse_ip, int reverse_port,
87  bool version_3)
88  : running_(false)
89  , commander_(commander)
90  , server_(reverse_port)
91  , servoj_time_(0.008)
92  , servoj_lookahead_time_(0.03)
93  , servoj_gain_(300.)
94 {
95  ros::param::get("~servoj_time", servoj_time_);
96  ros::param::get("~servoj_lookahead_time", servoj_lookahead_time_);
97  ros::param::get("~servoj_gain", servoj_gain_);
98 
99  std::string res(POSITION_PROGRAM);
100  res.replace(res.find(JOINT_STATE_REPLACE), JOINT_STATE_REPLACE.length(), std::to_string(MULT_JOINTSTATE_));
101 
102  std::ostringstream out;
103  out << "t=" << std::fixed << std::setprecision(4) << servoj_time_;
104  if (version_3)
105  out << ", lookahead_time=" << servoj_lookahead_time_ << ", gain=" << servoj_gain_;
106 
107  res.replace(res.find(SERVO_J_REPLACE), SERVO_J_REPLACE.length(), out.str());
108  res.replace(res.find(SERVER_IP_REPLACE), SERVER_IP_REPLACE.length(), reverse_ip);
109  res.replace(res.find(SERVER_PORT_REPLACE), SERVER_PORT_REPLACE.length(), std::to_string(reverse_port));
110  program_ = res;
111 
112  if (!server_.bind())
113  {
114  LOG_ERROR("Failed to bind server, the port %d is likely already in use", reverse_port);
115  std::exit(-1);
116  }
117 }
118 
120 {
121  if (running_)
122  return true; // not sure
123 
124  LOG_INFO("Uploading trajectory program to robot");
125 
127  {
128  LOG_ERROR("Program upload failed!");
129  return false;
130  }
131 
132  LOG_DEBUG("Awaiting incoming robot connection");
133 
134  if (!server_.accept())
135  {
136  LOG_ERROR("Failed to accept incoming robot connection");
137  return false;
138  }
139 
140  LOG_DEBUG("Robot successfully connected");
141  return (running_ = true);
142 }
143 
144 bool TrajectoryFollower::execute(std::array<double, 6> &positions, bool keep_alive)
145 {
146  if (!running_)
147  return false;
148 
149  // LOG_INFO("servoj([%f,%f,%f,%f,%f,%f])", positions[0], positions[1], positions[2], positions[3], positions[4],
150  // positions[5]);
151 
152  last_positions_ = positions;
153 
154  uint8_t buf[sizeof(uint32_t) * 7];
155  uint8_t *idx = buf;
156 
157  for (auto const &pos : positions)
158  {
159  int32_t val = static_cast<int32_t>(pos * MULT_JOINTSTATE_);
160  val = htobe32(val);
161  idx += append(idx, val);
162  }
163 
164  int32_t val = htobe32(static_cast<int32_t>(keep_alive));
165  append(idx, val);
166 
167  size_t written;
168  return server_.write(buf, sizeof(buf), written);
169 }
170 
171 double TrajectoryFollower::interpolate(double t, double T, double p0_pos, double p1_pos, double p0_vel, double p1_vel)
172 {
173  using std::pow;
174  double a = p0_pos;
175  double b = p0_vel;
176  double c = (-3 * a + 3 * p1_pos - 2 * T * b - T * p1_vel) / pow(T, 2);
177  double d = (2 * a - 2 * p1_pos + T * b + T * p1_vel) / pow(T, 3);
178  return a + b * t + c * pow(t, 2) + d * pow(t, 3);
179 }
180 
181 bool TrajectoryFollower::execute(std::array<double, 6> &positions)
182 {
183  return execute(positions, true);
184 }
185 
186 bool TrajectoryFollower::execute(std::vector<TrajectoryPoint> &trajectory, std::atomic<bool> &interrupt)
187 {
188  if (!running_)
189  return false;
190 
191  using namespace std::chrono;
192  typedef duration<double> double_seconds;
193  typedef high_resolution_clock Clock;
194  typedef Clock::time_point Time;
195 
196  auto &last = trajectory[trajectory.size() - 1];
197  auto &prev = trajectory[0];
198 
199  Time t0 = Clock::now();
200  Time latest = t0;
201 
202  std::array<double, 6> positions;
203 
204  for (auto const &point : trajectory)
205  {
206  // skip t0
207  if (&point == &prev)
208  continue;
209 
210  if (interrupt)
211  break;
212 
213  auto duration = point.time_from_start - prev.time_from_start;
214  double d_s = duration_cast<double_seconds>(duration).count();
215 
216  // interpolation loop
217  while (!interrupt)
218  {
219  latest = Clock::now();
220  auto elapsed = latest - t0;
221 
222  if (point.time_from_start <= elapsed)
223  break;
224 
225  if (last.time_from_start <= elapsed)
226  return true;
227 
228  double elapsed_s = duration_cast<double_seconds>(elapsed - prev.time_from_start).count();
229  for (size_t j = 0; j < positions.size(); j++)
230  {
231  positions[j] =
232  interpolate(elapsed_s, d_s, prev.positions[j], point.positions[j], prev.velocities[j], point.velocities[j]);
233  }
234 
235  if (!execute(positions, true))
236  return false;
237 
238  std::this_thread::sleep_for(std::chrono::milliseconds((int)((servoj_time_ * 1000) / 4.)));
239  }
240 
241  prev = point;
242  }
243 
244  // In theory it's possible the last position won't be sent by
245  // the interpolation loop above but rather some position between
246  // t[N-1] and t[N] where N is the number of trajectory points.
247  // To make sure this does not happen the last position is sent
248  return execute(last.positions, true);
249 }
250 
252 {
253  if (!running_)
254  return;
255 
256  // std::array<double, 6> empty;
257  // execute(empty, false);
258 
260  running_ = false;
261 }
d
bool accept()
Definition: server.cpp:75
bool execute(std::array< double, 6 > &positions, bool keep_alive)
bool uploadProg(const std::string &s)
Definition: commander.cpp:41
static const std::string SERVER_PORT_REPLACE("{{SERVER_PORT_REPLACE}}")
static const int32_t MULT_JOINTSTATE_
#define LOG_DEBUG(format,...)
Definition: log.h:33
bool bind()
Definition: server.cpp:61
static const std::string SERVO_J_REPLACE("{{SERVO_J_REPLACE}}")
bool write(const uint8_t *buf, size_t buf_len, size_t &written)
Definition: server.cpp:105
ROSCPP_DECL bool get(const std::string &key, std::string &s)
#define LOG_INFO(format,...)
Definition: log.h:35
void disconnectClient()
Definition: server.cpp:97
URCommander & commander_
double interpolate(double t, double T, double p0_pos, double p1_pos, double p0_vel, double p1_vel)
INLINE Rall1d< T, V, S > pow(const Rall1d< T, V, S > &arg, double m)
size_t append(uint8_t *buffer, T &val)
static const std::string JOINT_STATE_REPLACE("{{JOINT_STATE_REPLACE}}")
std::atomic< bool > running_
std::array< double, 6 > last_positions_
#define LOG_ERROR(format,...)
Definition: log.h:36
TrajectoryFollower(URCommander &commander, std::string &reverse_ip, int reverse_port, bool version_3)
static const std::string SERVER_IP_REPLACE("{{SERVER_IP_REPLACE}}")
static const std::string POSITION_PROGRAM


ur_modern_driver
Author(s): Thomas Timm Andersen, Simon Rasmussen
autogenerated on Fri Jun 26 2020 03:37:01