#include <iostream>
#include <visp3/core/vpImageConvert.h>
#include <visp3/core/vpMutex.h>
#include <visp3/core/vpThread.h>
#include <visp3/core/vpTime.h>
#include <visp3/gui/vpDisplayX.h>
#include <visp3/gui/vpPlot.h>
#include <visp3/robot/vpRobotViper850.h>
#include <visp3/sensor/vpV4l2Grabber.h>
#include <visp3/ustk_core/usImagePostScan2D.h>
#include <visp3/ustk_core/usPixelMeterConversion.h>
#include <visp3/ustk_template_tracking/usDenseTracker2D.h>
#if defined(VISP_HAVE_V4L2) && defined(VISP_HAVE_PTHREAD) && defined(VISP_HAVE_VIPER850)
typedef enum { capture_waiting, capture_started, capture_stopped } t_CaptureState;
t_CaptureState s_capture_state = capture_waiting;
vpImage<unsigned char> s_frame;
vpMutex s_mutex_capture;
bool s_robotIsRunning;
vpMutex s_mutex_control_velocity;
vpColVector s_controlVelocity(6, 0.);
vpThread::Return captureFunction(vpThread::Args args)
{
vpV4l2Grabber cap = *((vpV4l2Grabber *)args);
vpImage<unsigned char> frame_;
bool stop_capture_ = false;
cap.open(frame_);
vpRect roi(vpImagePoint(55, 70), vpImagePoint(410, 555));
while (!stop_capture_) {
cap.acquire(frame_, roi);
{
vpMutex::vpScopedLock lock(s_mutex_capture);
if (s_capture_state == capture_stopped)
stop_capture_ = true;
else
s_capture_state = capture_started;
s_frame = frame_;
}
}
{
vpMutex::vpScopedLock lock(s_mutex_capture);
s_capture_state = capture_stopped;
}
std::cout << "End of capture thread" << std::endl;
return 0;
}
vpThread::Return displayFunction(vpThread::Args args)
{
(void)args;
vpRectOriented rectangle;
t_CaptureState capture_state_;
bool display_initialized_ = false;
#if defined(VISP_HAVE_X11)
vpDisplayX *dpost_scan_ = NULL;
#endif
vpPlot plot(1);
plot.initGraph(0, 1);
plot.initRange(0, 0, 10, -0.01, 0.01);
plot.setTitle(0, "X target error");
plot.setUnitY(0, "error(meters)");
plot.setLegend(0, 0, "time");
double xtarget;
double ytarget;
bool firstLoopCycle = true;
double startTime = vpTime::measureTimeMs();
do {
s_mutex_capture.lock();
capture_state_ = s_capture_state;
s_mutex_capture.unlock();
if (capture_state_ == capture_started) {
{
vpMutex::vpScopedLock lock(s_mutex_capture);
postScan_.getHeight());
postScan_.getHeight());
}
if (firstLoopCycle) {
rectangle.setCenter(vpImagePoint(postScan_.getHeight() / 2, postScan_.getWidth() / 2));
rectangle.setSize(50, 30);
rectangle.setOrientation(0);
tracker.
init(postScan_, rectangle);
}
ytarget);
std::cout << "Center i = " << rectangle.getCenter().get_i() << ", j = " << rectangle.getCenter().get_j()
<< std::endl;
std::cout << "xtarget = " << xtarget << ", ytarget = " << ytarget << std::endl;
double time = (vpTime::measureTimeMs() - startTime) / 1000.0;
plot.plot(0, 0, time, xtarget);
{
vpMutex::vpScopedLock lock(s_mutex_capture);
s_controlVelocity = 0.0;
s_controlVelocity[1] = -1 * xtarget;
}
if (!display_initialized_) {
#if defined(VISP_HAVE_X11)
unsigned int xpos = 10;
dpost_scan_ = new vpDisplayX(postScan_, xpos, 10, "post-scan");
display_initialized_ = true;
#endif
}
vpDisplay::display(postScan_);
vpDisplay::displayLine(postScan_, static_cast<int>(rectangle.getTopLeft().get_i()),
static_cast<int>(rectangle.getTopLeft().get_j()),
static_cast<int>(rectangle.getBottomLeft().get_i()),
static_cast<int>(rectangle.getBottomLeft().get_j()), vpColor::red);
vpDisplay::displayLine(postScan_, static_cast<int>(rectangle.getBottomLeft().get_i()),
static_cast<int>(rectangle.getBottomLeft().get_j()),
static_cast<int>(rectangle.getBottomRight().get_i()),
static_cast<int>(rectangle.getBottomRight().get_j()), vpColor::red);
vpDisplay::displayLine(postScan_, static_cast<int>(rectangle.getBottomRight().get_i()),
static_cast<int>(rectangle.getBottomRight().get_j()),
static_cast<int>(rectangle.getTopRight().get_i()),
static_cast<int>(rectangle.getTopRight().get_j()), vpColor::red);
vpDisplay::displayLine(postScan_, static_cast<int>(rectangle.getTopRight().get_i()),
static_cast<int>(rectangle.getTopRight().get_j()),
static_cast<int>(rectangle.getTopLeft().get_i()),
static_cast<int>(rectangle.getTopLeft().get_j()), vpColor::red);
vpDisplay::displayText(postScan_, 10, 10, "Click to exit...", vpColor::red);
if (vpDisplay::getClick(postScan_, false)) {
vpMutex::vpScopedLock lock(s_mutex_capture);
s_capture_state = capture_stopped;
}
vpDisplay::flush(postScan_);
firstLoopCycle = false;
} else {
vpTime::wait(2);
}
} while (capture_state_ != capture_stopped);
#if defined(VISP_HAVE_X11)
delete dpost_scan_;
#endif
std::cout << "End of display thread" << std::endl;
return 0;
}
vpThread::Return controlFunction(vpThread::Args args)
{
(void)args;
vpRobotViper850 robot;
vpMatrix eJe;
vpHomogeneousMatrix eMs;
eMs[2][3] = -0.062;
vpHomogeneousMatrix sMp;
vpHomogeneousMatrix sMe;
eMs.inverse(sMe);
vpVelocityTwistMatrix sVe;
sVe.buildFrom(sMe);
vpColVector sHs(6);
vpColVector sHs_star(6);
vpColVector pHp_star(6);
vpColVector gHg(6);
vpMatrix lambda(6, 6);
vpTranslationVector stg;
vpColVector sHs_bias(6);
vpColVector v_s(6);
vpColVector q_dot(6);
lambda = 0;
for (int i = 0; i < 3; i++)
lambda[i][i] = 0.02 / 6;
for (int i = 3; i < 6; i++)
lambda[i][i] = 1. / 2;
pHp_star = 0;
pHp_star[2] = 3;
sMp[2][3] = 0.262;
gHg[2] = -(0.696 + 0.476) * 9.81;
stg[0] = 0;
stg[1] = 0;
stg[2] = 0.088;
vpRotationMatrix sRp;
sMp.extract(sRp);
vpTranslationVector stp;
sMp.extract(stp);
vpHomogeneousMatrix eMp = eMs * sMp;
vpVelocityTwistMatrix eVp(eMp);
vpColVector q;
vpHomogeneousMatrix fMe;
vpHomogeneousMatrix fMs;
vpRotationMatrix sRf;
robot.getPosition(vpRobot::ARTICULAR_FRAME, q);
robot.get_fMe(q, fMe);
fMs = fMe * eMs;
vpHomogeneousMatrix sMf;
fMs.inverse(sMf);
sMf.extract(sRf);
vpForceTwistMatrix sFg(sMf);
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
sFg[i + 3][j] = (stg.skew() * sRf)[i][j];
vpForceTwistMatrix sFp(sMp);
std::cout << "\nBias the force/torque sensor...\n " << std::endl;
robot.biasForceTorqueSensor();
robot.setRobotState(vpRobot::STATE_VELOCITY_CONTROL);
int iter = 0;
t_CaptureState capture_state_;
std::cout << "Starting control loop..." << std::endl;
do {
s_mutex_capture.lock();
capture_state_ = s_capture_state;
s_mutex_capture.unlock();
if (capture_state_ == capture_started) {
sHs = robot.getForceTorque();
sHs *= -1;
robot.getPosition(vpRobot::ARTICULAR_FRAME, q);
robot.get_fMe(q, fMe);
fMs = fMe * eMs;
fMs.inverse(sMf);
sMf.extract(sRf);
sFg.buildFrom(sMf);
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
sFg[i + 3][j] = (stg.skew() * sRf)[i][j];
if (iter == 0) {
sHs_bias = sHs - sFg * gHg;
}
vpColVector v_p;
{
vpMutex::vpScopedLock lock(s_mutex_capture);
v_p = s_controlVelocity;
}
v_p[0] = 0;
v_p[2] = 0;
v_p[3] = 0;
v_p[4] = 0;
v_p[5] = 0;
v_s = lambda * (sFp * pHp_star - (sHs - sFg * gHg - sHs_bias));
v_s[0] = 0.0;
v_s[1] = 0.0;
v_s[3] = 0.0;
v_s[4] = 0.0;
v_s[5] = 0.0;
vpVelocityTwistMatrix eVs;
sVe.inverse(eVs);
vpColVector v_e = eVs * v_s + eVp * v_p;
robot.get_eJe(eJe);
q_dot = eJe.pseudoInverse() * v_e;
robot.setVelocity(vpRobot::ARTICULAR_FRAME, q_dot);
iter++;
}
vpTime::wait(1);
} while (capture_state_ != capture_stopped);
std::cout << "End of control thread" << std::endl;
return 0;
}
int main(int argc, const char *argv[])
{
unsigned int opt_input = 1;
for (int i = 0; i < argc; i++) {
if (std::string(argv[i]) == "--input")
opt_input = (unsigned int)atoi(argv[i + 1]);
else if (std::string(argv[i]) == "--help") {
std::cout << "Usage: " << argv[0] << " [--input <number>] [--help]" << std::endl;
return 0;
}
}
vpV4l2Grabber g;
g.setInput(opt_input);
g.setScale(1);
s_robotIsRunning = false;
s_controlVelocity = vpColVector(6, 0);
vpThread thread_capture((vpThread::Fn)captureFunction, (vpThread::Args)&g);
vpThread thread_display((vpThread::Fn)displayFunction);
vpThread thread_control((vpThread::Fn)controlFunction);
thread_capture.join();
thread_display.join();
thread_control.join();
return 0;
}
#else
int main()
{
#ifndef VISP_HAVE_V4L2
std::cout << "You should enable V4L2 to make this example working..." << std::endl;
#elif !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))
std::cout << "You should enable pthread usage and rebuild ViSP..." << std::endl;
#else
std::cout << "Multi-threading seems not supported on this platform" << std::endl;
#endif
#ifndef VISP_HAVE_VIPER850
std::cout << "You need viper 850 robot to run this example" << std::endl;
#endif
}
#endif
void update(const vpImage< unsigned char > &I)
Tracking method, to call at every new frame to track.
void init(const vpImage< unsigned char > &I, const vpRectOriented &R)
Initialisation of the tracker : to call to set the region to track (R) in the image (I) before starti...
vpRectOriented getTarget() const
To call after update() at each new frame, to get the position of the ROI in the last acquired frame.
void setHeightResolution(double heightResolution)
void setData(const vpImage< Type > &image)
double getHeightResolution() const
void setWidthResolution(double widthResolution)
double getWidthResolution() const
static void convert(const usImagePostScan2D< unsigned char > &image, const double &u, const double &v, double &x, double &y)
Conversion for 2D post-scan images.
void setFieldOfView(double fieldOfView)
void setTransducerConvexity(const bool isTransducerConvex)
double getFieldOfView() const
void setDepth(double depth)
void setProbeName(std::string probeName)
void setTransducerRadius(const double transducerRadius)
double getTransducerRadius() const
void setScanLineNumber(unsigned int scanLineNumber)