RBControl
Library for the RB3201-RBControl board with the ESP32 by RoboticsBrno.
lx16a.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <chrono>
4 #include <driver/uart.h>
5 #include <esp_log.h>
6 #include <soc/io_mux_reg.h>
7 #include <stdexcept>
8 #include <vector>
9 
10 #include "RBControl_angle.hpp"
11 
12 namespace lw {
13 
14 enum class Command {
19  SERVO_MOVE_START = 11,
43 };
44 
45 using Id = uint8_t;
46 
47 struct Packet {
48  Packet() = default;
49 
50  Packet(const uint8_t* data, int len) {
51  for (int i = 0; i < len; i++) {
52  _data.push_back(data[i]);
53  }
54  }
55 
56  template <typename... Args>
57  Packet(Id id, Command c, Args... data) {
58  _buildHeader();
59  _data.push_back(id);
60  _data.push_back(3);
61  _data.push_back(static_cast<uint8_t>(c));
62  _pushData(data...);
63  _data.push_back(_checksum(_data));
64  }
65 
66  static Packet move(Id id, uint16_t position, uint16_t time) {
68  position & 0xFF, position >> 8,
69  time & 0xFF, time >> 8);
70  }
71 
72  static Packet limitAngle(Id id, uint16_t low, uint16_t high) {
74  low & 0xFF, low >> 8, high & 0xFF, high >> 8);
75  }
76 
77  static Packet setId(Id id, Id newId) {
78  return Packet(id, Command::SERVO_ID_WRITE, newId);
79  }
80 
81  static Packet getId(Id id) {
82  return Packet(id, Command::SERVO_ID_READ);
83  }
84 
85  void _buildHeader() {
86  _data.push_back(0x55);
87  _data.push_back(0x55);
88  }
89 
90  void _pushData() {}
91 
92  template <typename... Args>
93  void _pushData(uint8_t d, Args... data) {
94  _data.push_back(d);
95  _data[3]++;
96  _pushData(data...);
97  }
98 
99  static uint8_t _checksum(const std::vector<uint8_t>& data,
100  int offset = 2, int end_offset = 0) {
101  uint8_t sum = 0;
102  for (int i = offset; i < data.size() - end_offset; i++)
103  sum += data[i];
104  return ~sum;
105  }
106 
107  int size() const {
108  if (_data.size() < 4)
109  return -1;
110  return _data[3];
111  }
112 
113  bool valid() const {
114  if (_data.size() < 6)
115  return false;
116  uint8_t c = _checksum(_data, 2, 1);
117  if (c != _data.back())
118  return false;
119  if (size() + 3 != _data.size())
120  return false;
121  return true;
122  }
123 
124  void dump() {
125  printf("[");
126  bool first = true;
127  for (auto x : _data) {
128  if (!first)
129  printf(", ");
130  first = false;
131  printf("%02X", (int)x);
132  }
133  printf("]\n");
134  }
135 
136  std::vector<uint8_t> _data;
137 };
138 
139 class Servo {
140 public:
141  static int posFromDeg(float angle) {
142  return angle * 1000 / 240;
143  }
144 
145  // Move servo to given position (in degree) in given time (in milliseconds)
146  static Packet move(Id id, rb::Angle pos, std::chrono::milliseconds t) {
147  float position = pos.deg();
148  int time = t.count();
149  if (position < 0 || position > 240)
150  ESP_LOGE("LX16A", "Position out of range");
151  if (time < 0)
152  ESP_LOGE("LX16A", "Time is negative");
153  if (time > 30000)
154  ESP_LOGE("LX16A", "Time is out of range");
155  auto p = Packet::move(id, Servo::posFromDeg(position), time);
156  return p;
157  }
158 
159  static Packet move(Id id, rb::Angle pos) {
160  float position = pos.deg();
161  if (position < 0 || position > 240)
162  ESP_LOGE("LX16A", "Position out of range");
163  auto p = Packet::move(id, Servo::posFromDeg(position), 0);
164  return p;
165  }
166 
167  // Set limits for the movement
168  static Packet limit(Id id, rb::Angle b, rb::Angle t) {
169  int bottom = b.deg();
170  int top = t.deg();
171  if (bottom < 0 || bottom > 240)
172  ESP_LOGE("LX16A", "Bottom limit out of range");
173  if (top < 0 || top > 240)
174  ESP_LOGE("LX16A", "Top limit out of range");
175  auto p = Packet::limitAngle(id, Servo::posFromDeg(bottom), Servo::posFromDeg(top));
176  return p;
177  }
178 
179  static Packet setId(Id oldId, Id newId) {
180  if (newId >= 254) {
181  ESP_LOGE("LX16A", "Invalid ID specified");
182  }
183  auto p = Packet::setId(oldId, newId);
184  return p;
185  }
186 };
187 
188 } // namespace lw
Definition: lx16a.hpp:139
static int posFromDeg(float angle)
Definition: lx16a.hpp:141
static Packet limit(Id id, rb::Angle b, rb::Angle t)
Definition: lx16a.hpp:168
static Packet move(Id id, rb::Angle pos, std::chrono::milliseconds t)
Definition: lx16a.hpp:146
static Packet move(Id id, rb::Angle pos)
Definition: lx16a.hpp:159
static Packet setId(Id oldId, Id newId)
Definition: lx16a.hpp:179
Definition: RBControl_angle.hpp:11
static Angle deg(_T d)
Definition: RBControl_angle.hpp:20
Definition: lx16a.hpp:12
Command
Definition: lx16a.hpp:14
@ SERVO_ANGLE_LIMIT_WRITE
@ SERVO_ANGLE_OFFSET_WRITE
@ SERVO_MOVE_TIME_READ
@ SERVO_MOVE_TIME_WAIT_WRITE
@ SERVO_LOAD_OR_UNLOAD_WRITE
@ SERVO_ANGLE_LIMIT_READ
@ SERVO_LED_ERROR_READ
@ SERVO_ANGLE_OFFSET_READ
@ SERVO_MOVE_TIME_WRITE
@ SERVO_TEMP_MAX_LIMIT_READ
@ SERVO_OR_MOTOR_MODE_WRITE
@ SERVO_VIN_LIMIT_READ
@ SERVO_MOVE_TIME_WAIT_READ
@ SERVO_ANGLE_OFFSET_ADJUST
@ SERVO_LED_ERROR_WRITE
@ SERVO_OR_MOTOR_MODE_READ
@ SERVO_LED_CTRL_WRITE
@ SERVO_VIN_LIMIT_WRITE
@ SERVO_TEMP_MAX_LIMIT_WRITE
@ SERVO_LOAD_OR_UNLOAD_READ
uint8_t Id
Definition: lx16a.hpp:45
Definition: lx16a.hpp:47
static Packet move(Id id, uint16_t position, uint16_t time)
Definition: lx16a.hpp:66
Packet(Id id, Command c, Args... data)
Definition: lx16a.hpp:57
static Packet limitAngle(Id id, uint16_t low, uint16_t high)
Definition: lx16a.hpp:72
void _pushData()
Definition: lx16a.hpp:90
static uint8_t _checksum(const std::vector< uint8_t > &data, int offset=2, int end_offset=0)
Definition: lx16a.hpp:99
Packet()=default
bool valid() const
Definition: lx16a.hpp:113
std::vector< uint8_t > _data
Definition: lx16a.hpp:136
Packet(const uint8_t *data, int len)
Definition: lx16a.hpp:50
static Packet setId(Id id, Id newId)
Definition: lx16a.hpp:77
int size() const
Definition: lx16a.hpp:107
static Packet getId(Id id)
Definition: lx16a.hpp:81
void _pushData(uint8_t d, Args... data)
Definition: lx16a.hpp:93
void dump()
Definition: lx16a.hpp:124
void _buildHeader()
Definition: lx16a.hpp:85