Flexiv RDK APIs  1.6.0
test_loop_latency.cpp
1 
10 #include <flexiv/rdk/robot.hpp>
11 #include <flexiv/rdk/scheduler.hpp>
12 #include <flexiv/rdk/utility.hpp>
13 #include <spdlog/spdlog.h>
14 
15 #include <iostream>
16 #include <thread>
17 #include <string.h>
18 #include <atomic>
19 
20 // Standard input/output definitions
21 #include <stdio.h>
22 // UNIX standard function definitions
23 #include <unistd.h>
24 // File control definitions
25 #include <fcntl.h>
26 // Error number definitions
27 #include <errno.h>
28 // POSIX terminal control definitions
29 #include <termios.h>
30 
31 namespace {
33 int g_fd = 0;
34 
36 std::atomic<bool> g_stop_sched = {false};
37 }
38 
39 // callback function for realtime periodic task
40 void PeriodicTask(flexiv::rdk::Robot& robot)
41 {
42  // Loop counter
43  static unsigned int loop_counter = 0;
44 
45  try {
46  // Monitor fault on the connected robot
47  if (robot.fault()) {
48  throw std::runtime_error(
49  "PeriodicTask: Fault occurred on the connected robot, exiting ...");
50  }
51 
52  // send signal at 1Hz
53  switch (loop_counter % 1000) {
54  case 0: {
55  spdlog::info(
56  "Sending benchmark signal to both workstation PC's serial "
57  "port and robot server's digital out port[0]");
58  break;
59  }
60  case 1: {
61  // signal robot server's digital out port
62  robot.SetDigitalOutputs(std::vector<unsigned int> {0}, std::vector<bool> {true});
63 
64  // signal workstation PC's serial port
65  auto n = write(g_fd, "0", 1);
66  if (n < 0) {
67  spdlog::error("Failed to write to serial port");
68  }
69 
70  break;
71  }
72  case 900: {
73  // reset digital out after a few seconds
74  robot.SetDigitalOutputs(std::vector<unsigned int> {0}, std::vector<bool> {false});
75  break;
76  }
77  default:
78  break;
79  }
80  loop_counter++;
81 
82  } catch (const std::exception& e) {
83  spdlog::error(e.what());
84  g_stop_sched = true;
85  }
86 }
87 
88 void PrintHelp()
89 {
90  // clang-format off
91  std::cout << "Required arguments: [robot_sn] [serial_port_name]" << std::endl;
92  std::cout << " robot_sn: Serial number of the robot to connect. Remove any space, e.g. Rizon4s-123456" << std::endl;
93  std::cout << " serial_port_name: /dev/ttyS0 for COM1, /dev/ttyS1 for COM2, /dev/ttyUSB0 for USB-serial converter" << std::endl;
94  std::cout << "Optional arguments: None" << std::endl;
95  std::cout << std::endl;
96  // clang-format on
97 }
98 
99 int main(int argc, char* argv[])
100 {
101  // Parse Parameters
102  //=============================================================================
103  if (argc < 3 || flexiv::rdk::utility::ProgramArgsExistAny(argc, argv, {"-h", "--help"})) {
104  PrintHelp();
105  return 1;
106  }
107 
108  // Serial number of the robot to connect to. Remove any space, for example: Rizon4s-123456
109  std::string robot_sn = argv[1];
110 
111  // serial port name
112  std::string serial_port = argv[2];
113 
114  try {
115  // RDK Initialization
116  //=============================================================================
117  // Instantiate robot interface
118  flexiv::rdk::Robot robot(robot_sn);
119 
120  // Clear fault on the connected robot if any
121  if (robot.fault()) {
122  spdlog::warn("Fault occurred on the connected robot, trying to clear ...");
123  // Try to clear the fault
124  if (!robot.ClearFault()) {
125  spdlog::error("Fault cannot be cleared, exiting ...");
126  return 1;
127  }
128  spdlog::info("Fault on the connected robot is cleared");
129  }
130 
131  // enable the robot, make sure the E-stop is released before enabling
132  spdlog::info("Enabling robot ...");
133  robot.Enable();
134 
135  // Wait for the robot to become operational
136  while (!robot.operational()) {
137  std::this_thread::sleep_for(std::chrono::seconds(1));
138  }
139  spdlog::info("Robot is now operational");
140 
141  // Benchmark Signal
142  //=============================================================================
143  // get workstation PC's serial port ready,
144  g_fd = open(serial_port.c_str(), O_RDWR | O_NOCTTY | O_NDELAY | O_EXCL | O_CLOEXEC);
145 
146  if (g_fd == -1) {
147  spdlog::error("Unable to open serial port [{}]", serial_port);
148  }
149 
150  // print messages
151  spdlog::warn("Benchmark signal will be sent every 1 second");
152 
153  // Periodic Tasks
154  //=============================================================================
155  flexiv::rdk::Scheduler scheduler;
156  // Add periodic task with 1ms interval and highest applicable priority
157  scheduler.AddTask(
158  std::bind(PeriodicTask, std::ref(robot)), "HP periodic", 1, scheduler.max_priority());
159  // Start all added tasks
160  scheduler.Start();
161 
162  // Block and wait for signal to stop scheduler tasks
163  while (!g_stop_sched) {
164  std::this_thread::sleep_for(std::chrono::milliseconds(1));
165  }
166  // Received signal to stop scheduler tasks
167  scheduler.Stop();
168 
169  } catch (const std::exception& e) {
170  spdlog::error(e.what());
171  return 1;
172  }
173 
174  return 0;
175 }
Main interface with the robot, containing several function categories and background services.
Definition: robot.hpp:25
void SetDigitalOutputs(const std::vector< unsigned int > &port_idx, const std::vector< bool > &values)
[Blocking] Set one or more digital output ports, including 16 on the control box plus 2 inside the wr...
bool operational(bool verbose=true) const
[Non-blocking] Whether the robot is ready to be operated, which requires the following conditions to ...
void Enable()
[Blocking] Enable the robot, if E-stop is released and there's no fault, the robot will release brake...
bool fault() const
[Non-blocking] Whether the robot is in fault state.
bool ClearFault(unsigned int timeout_sec=30)
[Blocking] Try to clear minor or critical fault of the robot without a power cycle.
Real-time scheduler that can simultaneously run multiple periodic tasks. Parameters for each task are...
Definition: scheduler.hpp:22
int max_priority() const
[Non-blocking] Get maximum available priority for user tasks.
void AddTask(std::function< void(void)> &&callback, const std::string &task_name, int interval, int priority, int cpu_affinity=-1)
[Non-blocking] Add a new periodic task to the scheduler's task pool. Each task in the pool is assigne...
void Stop()
[Blocking] Stop all added tasks. The periodic execution will stop and all task threads will be closed...
void Start()
[Blocking] Start all added tasks. A dedicated thread will be created for each added task and the peri...