-
Notifications
You must be signed in to change notification settings - Fork 52
Description
Hi! I have a myCobot 280 (for Arduino) and I am using an FT232 to control the robot directly from my laptop.
I was benchmarking the function get_angles() and was surprised to see that it takes at least 20 ms for it to return.
I updated the ATOM firmware from v6.5 to v7.2 and that did make a small difference: the mean time has decreased by about 3 ms.
I spent some time digging further and implementing my own serial implementation of the protocol to understand if this could be an issue with the pymycobot serial implementation, but my investigation seems to suggest that the delay is not due to some issue with the Python implementation. Instead, it seems that the delay has to do with the processing happening on the ATOM — I measured the elapsed time between writing the raw frame request (for getting the joint angles) and reading the raw bytes containing the response frame; this confirmed that the delay is coming from the ATOM firmware implementation.
Is it possible to optimise the implementation of the ATOM firmware?
20 ms feels quite slow, and I don't think we're hitting the bottleneck of the serial communication for the 1M baudrate. 20 ms for getting the joint angles means that, right now, a simple for loop to read only the joint positions of the robot (not even sending any other commands for controlling the arm) would be limited to a max frequency of about 50 Hz...
Thanks in advance!
Benchmark Results for get_angles()
ATOM v6.5
- Samples: 100
- Mean: 23.54 ± 1.82 ms
- Range: 21.33 - 27.26 ms
Raw timings (ms): ['23.59', '26.56', '25.96', '22.09', '21.83', '26.55', '21.51', '21.83', '25.88', '24.95', '24.74', '24.87', '25.52', '26.69', '21.86', '22.06', '22.83', '22.63', '25.22', '21.52', '22.05', '24.54', '24.94', '26.53', '22.02', '22.51', '25.97', '21.87', '24.12', '23.79', '27.26', '22.00', '21.82', '26.55', '21.88', '21.96', '24.03', '22.91', '23.13', '24.05', '21.81', '21.88', '25.49', '21.89', '25.46', '22.10', '21.74', '26.21', '22.06', '24.56', '22.48', '21.48', '25.83', '23.15', '22.18', '23.36', '27.06', '21.33', '22.06', '22.42', '25.02', '21.94', '23.17', '22.85', '23.44', '22.07', '22.25', '22.31', '23.15', '26.47', '21.64', '22.05', '23.93', '21.82', '21.98', '22.44', '24.31', '21.64', '21.83', '21.83', '22.03', '25.45', '26.68', '24.36', '23.44', '21.96', '22.19', '21.89', '26.18', '22.09', '21.38', '25.66', '26.96', '24.29', '25.60', '22.93', '27.00', '21.55', '26.55', '22.72']
ATOM v7.2
- Samples: 100
- Mean: 20.62 ± 0.60 ms
- Range: 19.81 - 24.30 ms
Raw timings (ms): ['20.81', '20.99', '20.94', '21.33', '21.16', '20.50', '21.19', '20.78', '20.08', '20.03', '20.10', '20.04', '20.29', '20.26', '20.56', '20.65', '19.98', '20.07', '20.27', '20.14', '20.16', '19.90', '20.03', '20.06', '20.18', '20.15', '19.92', '20.57', '19.88', '20.38', '21.52', '20.95', '20.69', '21.06', '21.48', '21.55', '20.73', '21.11', '21.32', '21.25', '21.53', '21.40', '21.08', '20.69', '21.52', '20.58', '20.51', '20.79', '20.43', '21.80', '20.26', '21.09', '20.86', '21.13', '20.26', '20.99', '21.41', '20.88', '24.30', '20.41', '20.83', '20.56', '20.55', '20.09', '21.23', '20.71', '20.96', '21.00', '20.21', '20.81', '19.97', '20.47', '20.06', '20.47', '20.58', '20.54', '20.33', '20.08', '20.83', '20.02', '20.98', '20.52', '20.63', '20.17', '20.49', '19.93', '20.33', '20.54', '19.96', '20.34', '19.95', '20.12', '19.81', '20.09', '20.13', '20.45', '20.69', '20.36', '20.61', '20.54']
Source code used for benchmarking the function
import statistics
import time
from pymycobot import MyCobot280
mycobot = MyCobot280("/dev/tty.usbserial-B00033ZX", baudrate=1000000)
def benchmark_get_angles(mycobot, n_samples=10, warmup=3):
"""Run timing benchmark for get_angles() with statistics."""
timings = []
# Warmup phase (discard initial unstable measurements)
for _ in range(warmup):
mycobot.get_angles()
time.sleep(0.1) # Short pause between calls
# Timed samples
for _ in range(n_samples):
start = time.perf_counter()
angles = mycobot.get_angles() # Actual measurement we care about
elapsed = time.perf_counter() - start
timings.append(elapsed * 1000) # Convert to milliseconds
time.sleep(0.05) # Prevent serial buffer overflow
# Calculate statistics
mean = statistics.mean(timings)
stdev = statistics.stdev(timings) if n_samples > 1 else 0
# GitHub-friendly output
print(f"## MyCobot get_angles() Benchmark Results")
print(f"- Samples: {n_samples}")
print(f"- Mean: {mean:.2f} ± {stdev:.2f} ms")
print(f"- Range: {min(timings):.2f} - {max(timings):.2f} ms\n")
print("Raw timings (ms):", [f"{t:.2f}" for t in timings])
benchmark_get_angles(mycobot, n_samples=100)