34 #include <visp3/core/vpConfig.h>
37 #if defined(VISP_HAVE_POLOLU) && defined(VISP_HAVE_THREADS)
42 #include <RPMSerialInterface.h>
44 #include <visp3/robot/vpRobot.h>
45 #include <visp3/robot/vpRobotException.h>
46 #include <visp3/robot/vpPololu.h>
48 std::chrono::milliseconds millis(1);
51 RPMSerialInterface *vpPololu::m_interface =
nullptr;
52 int vpPololu::m_nb_servo = 0;
55 : m_channel(0), m_apply_velocity_cmd(false), m_stop_velocity_cmd_thread(false),
56 m_vel_speed(1), m_vel_target_position(0), m_vel_speed_prev(1), m_vel_target_position_prev(0), m_mutex_velocity_cmd(), m_verbose(verbose)
60 : m_channel(channel), m_apply_velocity_cmd(false), m_stop_velocity_cmd_thread(false),
61 m_vel_speed(1), m_vel_target_position(0), m_vel_speed_prev(1), m_vel_target_position_prev(0), m_mutex_velocity_cmd(), m_verbose(verbose)
63 connect(device, baudrate, channel);
68 std::string error_msg;
74 std::cout <<
"Creating serial interface '" << device <<
"' at " << baudrate <<
" bauds" << std::endl;
76 m_interface = RPMSerialInterface::createSerialInterface(device, baudrate, &error_msg);
78 if (m_interface ==
nullptr) {
80 "Cannot connect to pololu board with serial port %s at baudrate %d.\n%s",
81 device.c_str(), baudrate, error_msg.c_str()));
86 std::thread t(&vpPololu::VelocityCmdThread,
this);
93 m_stop_velocity_cmd_thread =
true;
94 if (m_nb_servo == 1) {
96 std::cout <<
"Deleting serial interface" << std::endl;
106 ret = m_interface->setTargetMSSCP(m_channel, 0);
110 std::this_thread::sleep_for(std::chrono::milliseconds(2000));
113 ret = m_interface->setTargetMSSCP(m_channel, 254);
117 std::this_thread::sleep_for(std::chrono::milliseconds(2000));
123 float a = m_range_pwm / m_range_angle;
124 float b = m_min_pwm - m_min_angle * a;
126 return static_cast<unsigned short>(a * angle + b);
131 if (!m_interface->isOpen()) {
133 std::cout <<
"Serial Communication Failed!\n";
142 return static_cast<short>((speed_rad_s / 100.f) * (m_range_pwm / m_range_angle));
147 unsigned short position_pwm;
151 for (
int i = 0; i < nb_attempt && ret ==
false; i++) {
152 ret = m_interface->getPositionCP(m_channel, position_pwm);
154 std::this_thread::sleep_for(std::chrono::milliseconds(wait_ms));
156 std::cout <<
"Failed to get position, new attempt: " << i << std::endl;
169 float position_angle =
pwmToRad(position_pwm);
171 return position_angle;
176 minAngle = m_min_angle;
177 maxAngle = m_max_angle;
188 float a = m_range_angle / m_range_pwm;
189 float b = m_min_angle - m_min_pwm * a;
191 return (a * pwm + b);
196 if ((m_min_angle <= pos_rad) && (pos_rad <= m_max_angle)) {
197 unsigned short pos_pwm =
radToPwm(pos_rad);
198 unsigned short pos_speed =
static_cast<unsigned short>(std::fabs(
radSToSpeed(vel_rad_s)));
200 if (pos_speed == 0) {
207 "Given position: %d is outside of the servo range. You can check the range using the method getRangeAngles()", pos_rad));
214 if ((m_min_pwm <= pos_pwm) && (pos_pwm <= m_max_pwm)) {
215 if (speed_pwm <= 1000) {
216 ret = m_interface->setSpeedCP(m_channel, speed_pwm);
223 "Given speed (pwm): %d is outside of the servo speed range. range is from 0 to 1000", speed_pwm));
226 std::cout <<
"Channel " << m_channel <<
" set position (pwm): " << pos_pwm <<
" with speed: " << speed_pwm << std::endl;
228 ret = m_interface->setTargetCP(m_channel, pos_pwm);
235 "Given position (pwm): %d is outside servo range. You can check the range using the method getRangePwm()", pos_pwm));
248 else if (vel_rad_s < 0) {
257 unsigned short vel_speed;
258 unsigned short vel_target_position;
259 if (pwm_vel <= 1000) {
260 vel_speed =
static_cast<unsigned short>(std::abs(pwm_vel));
262 vel_target_position = m_max_pwm;
264 else if (pwm_vel < 0) {
265 vel_target_position = m_min_pwm;
271 m_mutex_velocity_cmd.lock();
272 m_vel_speed = vel_speed;
273 m_vel_target_position = vel_target_position;
274 m_apply_velocity_cmd =
true;
275 m_mutex_velocity_cmd.unlock();
279 "Given pwm velocity %d is outside of the servo velocity range. Range is from 0 to 1000", pwm_vel));
285 return (speed_pwm * 100) * (m_range_angle / m_range_pwm);
291 std::cout <<
"Stoping vel cmd channel: " << m_channel << std::endl;
294 m_mutex_velocity_cmd.lock();
295 m_apply_velocity_cmd =
false;
296 m_mutex_velocity_cmd.unlock();
301 std::cout <<
"Stoping channel " << m_channel <<
" at position " << pos_pwm << std::endl;
306 void vpPololu::VelocityCmdThread()
309 std::cout <<
"Create Velocity command thread" << std::endl;
311 unsigned short vel_speed;
312 unsigned short vel_target_position;
313 bool apply_velocity_cmd;
315 while (!m_stop_velocity_cmd_thread) {
316 m_mutex_velocity_cmd.lock();
317 vel_speed = m_vel_speed;
318 vel_target_position = m_vel_target_position;
319 apply_velocity_cmd = m_apply_velocity_cmd;
320 m_mutex_velocity_cmd.unlock();
321 if (apply_velocity_cmd) {
324 if (m_vel_speed_prev != vel_speed || m_vel_target_position_prev != vel_target_position) {
328 m_vel_speed_prev = vel_speed;
329 m_vel_target_position_prev = vel_target_position;
332 std::this_thread::sleep_for(20 * millis);
336 #elif !defined(VISP_BUILD_SHARED_LIBS)
338 void dummy_vpPololu() { };
error that can be emitted by ViSP classes.
short radSToSpeed(float speed_rad_s) const
unsigned short radToPwm(float angle) const
void getRangePwm(unsigned short &min, unsigned short &max)
unsigned short getPwmPosition() const
void calibrate(unsigned short &pwm_min, unsigned short &pwm_max)
float speedToRadS(short speed) const
void setAngularVelocity(float vel_rad_s)
vpPololu(bool verbose=false)
float pwmToRad(unsigned short pwm) const
void connect(const std::string &device, int baudrate, int channel)
float getAngularPosition() const
void setPwmPosition(unsigned short pos_pwm, unsigned short speed_pwm=0)
void setAngularPosition(float pos_rad, float vel_rad_s=0.f)
void getRangeAngles(float &minAngle, float &maxAngle) const
void setPwmVelocity(short pwm_vel)
Error that can be emitted by the vpRobot class and its derivatives.
@ constructionError
Error from constructor.
@ positionOutOfRangeError
Position is out of range.