motor_node.cc
Go to the documentation of this file.
1 
31 #include <dynamic_reconfigure/server.h>
32 #include <ros/ros.h>
33 #include <time.h>
34 #include <ubiquity_motor/PIDConfig.h>
38 #include <boost/thread.hpp>
39 #include <string>
41 
42 static const double BILLION = 1000000000.0;
43 
47 
48 // Dynamic reconfiguration callback for setting ROS parameters dynamically
49 void PID_update_callback(const ubiquity_motor::PIDConfig& config,
50  uint32_t level) {
51  if (level == 0xFFFFFFFF) {
52  return;
53  }
54 
55  if (level == 1) {
56  firmware_params.pid_proportional = config.PID_P;
57  } else if (level == 2) {
58  firmware_params.pid_integral = config.PID_I;
59  } else if (level == 4) {
60  firmware_params.pid_derivative = config.PID_D;
61  } else if (level == 8) {
62  firmware_params.pid_denominator = config.PID_C;
63  } else if (level == 16) {
64  firmware_params.pid_moving_buffer_size = config.PID_W;
65  } else if (level == 32) {
66  firmware_params.pid_velocity = config.PID_V;
67  } else {
68  ROS_ERROR("Unsupported dynamic_reconfigure level %u", level);
69  }
70 }
71 
72 int main(int argc, char* argv[]) {
73  ros::init(argc, argv, "motor_node");
74  ros::NodeHandle nh;
75 
76  firmware_params = FirmwareParams(nh);
77  serial_params = CommsParams(nh);
78  node_params = NodeParams(nh);
79 
80  ros::Rate ctrlLoopDelay(node_params.controller_loop_rate);
81 
82  std::unique_ptr<MotorHardware> robot = nullptr;
83  // Keep trying to open serial
84  {
85  int times = 0;
86  while (ros::ok() && robot.get() == nullptr) {
87  try {
88  robot.reset(new MotorHardware(nh, serial_params, firmware_params));
89  }
90  catch (const serial::IOException& e) {
91  if (times % 30 == 0)
92  ROS_FATAL("Error opening serial port %s, trying again", serial_params.serial_port.c_str());
93  }
94  ctrlLoopDelay.sleep();
95  times++;
96  }
97  }
98 
99  controller_manager::ControllerManager cm(robot.get(), nh);
100 
102  spinner.start();
103 
104  dynamic_reconfigure::Server<ubiquity_motor::PIDConfig> server;
105  dynamic_reconfigure::Server<ubiquity_motor::PIDConfig>::CallbackType f;
106 
107  f = boost::bind(&PID_update_callback, _1, _2);
108  server.setCallback(f);
109 
110  robot->setParams(firmware_params);
111  robot->requestFirmwareVersion();
112 
113  // wait for reply then we know firmware version
114  ctrlLoopDelay.sleep(); // Allow controller to process command
115 
116  if (robot->firmware_version >= MIN_FW_FIRMWARE_DATE) {
117  ROS_INFO("Request the firmware daycode");
118  robot->requestFirmwareDate();
119  }
120 
121  // Make sure firmware is listening
122  {
123  robot->diag_updater.broadcast(0, "Establishing communication with motors");
124  // Start times counter at 1 to prevent false error print (0 % n = 0)
125  int times = 1;
126  while (ros::ok() && robot->firmware_version == 0) {
127  if (times % 30 == 0)
128  ROS_ERROR("The Firmware not reporting its version");
129  robot->requestFirmwareVersion();
130  robot->readInputs();
131  ctrlLoopDelay.sleep(); // Allow controller to process command
132  times++;
133  }
134  }
135 
136  if (robot->firmware_version >= MIN_FW_FIRMWARE_DATE) {
137  // If supported by firmware also request date code for this version
138  robot->requestFirmwareDate();
139  }
140 
141  // Tell the controller board firmware what version the hardware is at this time.
142  // TODO: Read from I2C. At this time we only allow setting the version from ros parameters
143  if (robot->firmware_version >= MIN_FW_HW_VERSION_SET) {
144  ROS_DEBUG("Firmware is version %d. Setting Controller board version to %d",
145  robot->firmware_version, firmware_params.controller_board_version);
146  robot->setHardwareVersion(firmware_params.controller_board_version);
147  ROS_DEBUG("Controller board version has been set to %d",
148  firmware_params.controller_board_version);
149  ctrlLoopDelay.sleep(); // Allow controller to process command
150  }
151 
152  // Setup other firmware parameters that could come from ROS parameters
153  if (robot->firmware_version >= MIN_FW_ESTOP_SUPPORT) {
154  robot->setEstopPidThreshold(firmware_params.estop_pid_threshold);
155  ctrlLoopDelay.sleep(); // Allow controller to process command
156  robot->setEstopDetection(firmware_params.estop_detection);
157  ctrlLoopDelay.sleep(); // Allow controller to process command
158  }
159 
160  if (robot->firmware_version >= MIN_FW_MAX_SPEED_AND_PWM) {
161  robot->setMaxFwdSpeed(firmware_params.max_speed_fwd);
162  ctrlLoopDelay.sleep(); // Allow controller to process command
163  robot->setMaxRevSpeed(firmware_params.max_speed_rev);
164  ctrlLoopDelay.sleep(); // Allow controller to process command
165  robot->setMaxPwm(firmware_params.max_pwm);
166  ctrlLoopDelay.sleep(); // Allow controller to process command
167  }
168 
169  if (robot->firmware_version >= MIN_FW_DEADZONE) {
170  robot->setDeadzoneEnable(firmware_params.deadzone_enable);
171  ctrlLoopDelay.sleep(); // Allow controller to process command
172  }
173 
174  ros::Time last_time;
175  ros::Time current_time;
176  ros::Duration elapsed;
177 
178  for (int i = 0; i < 5; i++) {
179  ctrlLoopDelay.sleep(); // Allow controller to process command
180  robot->sendParams();
181  }
182  float expectedCycleTime = ctrlLoopDelay.expectedCycleTime().toSec();
183  float minCycleTime = 0.75 * expectedCycleTime;
184  float maxCycleTime = 1.25 * expectedCycleTime;
185 
186  // Clear any commands the robot has at this time
187  robot->clearCommands();
188 
189  last_time = ros::Time::now();
190  ROS_WARN("Starting motor control node now");
191 
192  // Implement a speed reset while ESTOP is active and a delay after release
193  double estopReleaseDeadtime = 0.8;
194  double estopReleaseDelay = 0.0;
195  while (ros::ok()) {
196  current_time = ros::Time::now();
197  elapsed = current_time - last_time;
198  last_time = current_time;
199  robot->readInputs();
200  float elapsedSecs = elapsed.toSec();
201  if (minCycleTime < elapsedSecs && elapsedSecs < maxCycleTime) {
202  cm.update(current_time, elapsed);
203  }
204  else {
205  ROS_WARN("Resetting controller due to time jump %f seconds",
206  elapsedSecs);
207  cm.update(current_time, ctrlLoopDelay.expectedCycleTime(), true);
208  robot->clearCommands();
209  }
210  robot->setParams(firmware_params);
211  robot->sendParams();
212 
213  // Update motor controller speeds.
214  if (robot->getEstopState()) {
215  robot->writeSpeedsInRadians(0.0, 0.0); // We send zero velocity when estop is active
216  estopReleaseDelay = estopReleaseDeadtime;
217  } else {
218  if (estopReleaseDelay > 0.0) {
219  // Implement a delay after estop release where velocity remains zero
220  estopReleaseDelay -= (1.0/node_params.controller_loop_rate);
221  robot->writeSpeedsInRadians(0.0, 0.0);
222  } else {
223  robot->writeSpeeds(); // Normal operation using current system speeds
224  }
225  }
226 
227  robot->diag_updater.update();
228  ctrlLoopDelay.sleep(); // Allow controller to process command
229  }
230 
231  return 0;
232 }
int32_t pid_proportional
int32_t pid_velocity
#define MIN_FW_FIRMWARE_DATE
Definition: motor_message.h:48
#define ROS_FATAL(...)
f
double controller_loop_rate
int32_t pid_denominator
#define MIN_FW_DEADZONE
Definition: motor_message.h:49
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
#define MIN_FW_HW_VERSION_SET
Definition: motor_message.h:45
int32_t pid_moving_buffer_size
#define MIN_FW_MAX_SPEED_AND_PWM
Definition: motor_message.h:46
#define ROS_WARN(...)
void spinner()
static FirmwareParams firmware_params
Definition: motor_node.cc:44
int32_t controller_board_version
int32_t pid_integral
#define ROS_INFO(...)
int32_t pid_derivative
int32_t estop_pid_threshold
#define MIN_FW_ESTOP_SUPPORT
Definition: motor_message.h:44
ROSCPP_DECL bool ok()
int32_t deadzone_enable
int32_t max_speed_rev
void PID_update_callback(const ubiquity_motor::PIDConfig &config, uint32_t level)
Definition: motor_node.cc:49
bool sleep()
static CommsParams serial_params
Definition: motor_node.cc:45
static NodeParams node_params
Definition: motor_node.cc:46
int32_t max_speed_fwd
static Time now()
std::string serial_port
int main(int argc, char *argv[])
Definition: motor_node.cc:72
static const double BILLION
Definition: motor_node.cc:42
#define ROS_ERROR(...)
int32_t estop_detection
Duration expectedCycleTime() const
#define ROS_DEBUG(...)


ubiquity_motor
Author(s):
autogenerated on Mon Feb 28 2022 23:57:06