remotecontrolboard.cpp
来自「一个语言识别引擎」· C++ 代码 · 共 2,110 行 · 第 1/5 页
CPP
2,110 行
// -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*-
/*
* Copyright (C) 2006 Giorgio Metta
* CopyPolicy: Released under the terms of the GNU GPL v2.0.
*
*/
#include <ace/config.h>
#include <ace/OS.h>
#include <ace/Log_Msg.h>
#include <yarp/os/PortablePair.h>
#include <yarp/os/BufferedPort.h>
#include <yarp/os/Time.h>
#include <yarp/os/Network.h>
#include <yarp/os/Thread.h>
#include <yarp/os/Vocab.h>
#include <yarp/String.h>
#include <yarp/dev/ControlBoardInterfaces.h>
#include <yarp/dev/PolyDriver.h>
#include <yarp/dev/ControlBoardInterfacesImpl.h>
#include <yarp/sig/Vector.h>
using namespace yarp::os;
using namespace yarp::dev;
using namespace yarp::sig;
namespace yarp{
namespace dev {
class RemoteControlBoard;
class ServerControlBoard;
class CommandsHelper;
class ImplementCallbackHelper;
}
}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
/* the control command message type
* head is a Bottle which contains the specification of the message type
* body is a Vector which move the robot accordingly
*/
typedef PortablePair<Bottle, Vector> CommandMessage;
/**
* Helper object for reading config commands for the ServerControlBoard
* class.
*/
class yarp::dev::CommandsHelper : public PortReader {
protected:
yarp::dev::ServerControlBoard *caller;
yarp::dev::IPidControl *pid;
yarp::dev::IPositionControl *pos;
yarp::dev::IVelocityControl *vel;
yarp::dev::IEncoders *enc;
yarp::dev::IAmplifierControl *amp;
yarp::dev::IControlLimits *lim;
int nj;
public:
/**
* Constructor.
* @param x is the pointer to the instance of the object that uses the CommandsHelper.
* This is required to recover the pointers to the interfaces that implement the responses
* to the commands.
*/
CommandsHelper(yarp::dev::ServerControlBoard *x);
/**
* read from the connection.
* @param connection is a reference to a ConnectionReader object which encapsulates
* the current port connection.
* @return true on a successful read.
*/
virtual bool read(ConnectionReader& connection);
/**
* Initialize the internal data.
* @return true/false on success/failure
*/
virtual bool initialize();
};
/**
* Callback implementation after buffered input.
*/
class yarp::dev::ImplementCallbackHelper : public TypedReaderCallback<CommandMessage> {
protected:
IPositionControl *pos;
IVelocityControl *vel;
public:
/**
* Constructor.
* @param x is the instance of the container class using the callback.
*/
ImplementCallbackHelper(yarp::dev::ServerControlBoard *x);
/**
* Callback function.
* @param v is the Vector being received.
*/
virtual void onRead(CommandMessage& v);
};
#endif // DOXYGEN_SHOULD_SKIP_THIS
/**
* @ingroup dev_impl_wrapper
*
* Implement the server side of a remote
* control board device driver. The device contains three ports:
* - rpc_p handling the configuration interfaces of the robot
* - state_p streaming information about the current state of the robot
* - control_p receiving a stream of control commands (e.g. position)
*
* Missing:
* torque control, NOT IMPLEMENTED
* calibration, tentative implementation, to be improved
*
*/
class yarp::dev::ServerControlBoard :
public DeviceDriver,
public Thread,
public IPidControl,
public IPositionControl,
public IVelocityControl,
public IEncoders,
public IAmplifierControl,
public IControlLimits,
public IControlCalibration
// convenient to put these here just to make sure all
// methods get implemented
{
private:
bool spoke;
bool verb;
Port rpc_p; // RPC to configure the robot
Port state_p; // out port to read the state
Port control_p; // in port to command the robot
PortWriterBuffer<yarp::sig::Vector> state_buffer;
PortReaderBuffer<CommandMessage> control_buffer;
yarp::dev::ImplementCallbackHelper callback_impl;
yarp::dev::CommandsHelper command_reader;
PolyDriver poly;
PolyDriver polyCalib;
int nj;
int thread_period;
IPidControl *pid;
IPositionControl *pos;
IVelocityControl *vel;
IEncoders *enc;
IAmplifierControl *amp;
IControlLimits *lim;
IControlCalibration *calib;
// LATER: other interfaces here.
public:
/**
* Constructor.
*/
ServerControlBoard() : callback_impl(this), command_reader(this)
{
pid = NULL;
pos = NULL;
vel = NULL;
enc = NULL;
amp = NULL;
lim = NULL;
calib = NULL;
nj = 0;
thread_period = 20; // ms.
verb = false;
}
/**
* Return the value of the verbose flag.
* @return the verbose flag.
*/
bool verbose() const { return verb; }
/**
* Default open() method.
* @return always false since initialization requires certain parameters.
*/
virtual bool open() {
return false;
}
/**
* Close the device driver by deallocating all resources and closing ports.
* @return true if successful or false otherwise.
*/
virtual bool close() {
if (Thread::isRunning())
Thread::stop();
// close the port connections here!
rpc_p.close();
control_p.close();
state_p.close();
poly.close();
polyCalib.close();
return true;
}
/**
* Open the device driver.
* @param prop is a Searchable object which contains the parameters.
* Allowed parameters are:
* - verbose or v to print diagnostic information while running.
* - subdevice to specify the name of the wrapped device.
* - name to specify the predix of the port names.
* - calibrator to specify the name of the calibrator object (created through a PolyDriver).
* and all parameters required by the wrapped device driver.
*/
virtual bool open(Searchable& prop) {
// attach readers.
rpc_p.setReader(command_reader);
// attach buffers.
state_buffer.attach(state_p);
control_buffer.attach(control_p);
// attach callback.
control_buffer.useCallback(callback_impl);
verb = (prop.check("verbose") || prop.check("v"));
if (verb)
ACE_OS::printf("running with verbose output\n");
Value *name;
if (prop.check("subdevice",name)) {
ACE_OS::printf("Subdevice %s\n", name->toString().c_str());
if (name->isString()) {
// maybe user isn't doing nested configuration
Property p;
p.setMonitor(prop.getMonitor(),
"subdevice"); // pass on any monitoring
p.fromString(prop.toString());
p.put("device",name->toString());
poly.open(p);
} else {
poly.open(*name);
}
if (!poly.isValid()) {
ACE_OS::printf("cannot make <%s>\n", name->toString().c_str());
}
} else {
ACE_OS::printf("\"--subdevice <name>\" not set for server_controlboard\n");
return false;
}
if (prop.check("name",name)) {
String s((size_t)1024);
ACE_OS::sprintf(&s[0], "%s/rpc:i", name->asString().c_str());
rpc_p.open(s.c_str());
ACE_OS::sprintf(&s[0], "%s/command:i", name->asString().c_str());
control_p.open(s.c_str());
ACE_OS::sprintf(&s[0], "%s/state:o", name->asString().c_str());
state_p.open(s.c_str());
} else {
rpc_p.open("/controlboard/rpc:i");
control_p.open("/controlboard/command:i");
state_p.open("/controlboard/state:o");
}
if (prop.check("calibrator", name))
{
Property p;
p.fromString(prop.toString());
p.put("device",name->toString());
polyCalib.open(p);
}
if (poly.isValid()) {
poly.view(pid);
poly.view(pos);
poly.view(vel);
poly.view(enc);
poly.view(amp);
poly.view(lim);
poly.view(calib);
}
// set calibrator //
if (polyCalib.isValid())
{
ICalibrator *icalibrator;
polyCalib.view(icalibrator);
calib->setCalibrator(icalibrator);
}
if (pid != NULL &&
pos != NULL &&
vel != NULL &&
enc != NULL &&
amp != NULL &&
lim != NULL) {
if (!pos->getAxes(&nj)) {
ACE_OS::printf ("problems: controlling 0 axes\n");
return false;
}
// initialization.
command_reader.initialize();
start();
return true;
}
ACE_OS::printf("subdevice <%s> doesn't look like a control board (not all interfaces were acquired)\n",
name->toString().c_str());
return false;
}
/**
* The thread main loop deals with writing on ports here.
*/
virtual void run() {
ACE_OS::printf("Server control board starting\n");
double before, now;
while (!isStopping()) {
before = Time::now();
yarp::sig::Vector& v = state_buffer.get();
v.size(nj);
enc->getEncoders(&v[0]);
// bool ok = enc->getEncoders(&v[0]);
// LATER: deal with the ok == false.
state_buffer.write();
now = Time::now();
if ((now-before)*1000 < thread_period) {
const double k = double(thread_period)/1000.0-(now-before);
Time::delay(k);
}
else {
ACE_OS::printf("Can't comply with the %d ms period\n", thread_period);
}
}
ACE_OS::printf("Server control board stopping\n");
}
/* IPidControl */
/** Set new pid value for a joint axis.
* @param j joint number
* @param pid new pid value
* @return true/false on success/failure
*/
virtual bool setPid(int j, const Pid &p) {
if (pid)
return pid->setPid(j, p);
return false;
}
/** Set new pid value on multiple axes.
* @param pids pointer to a vector of pids
* @return true/false upon success/failure
*/
virtual bool setPids(const Pid *ps) {
if (pid)
return pid->setPids(ps);
return false;
}
/** Set the controller reference point for a given axis.
* Warning this method can result in very large torques
* and should be used carefully. If you do not understand
* this warning you should avoid using this method.
* Have a look at other interfaces (e.g. position control).
* @param j joint number
* @param ref new reference point
* @return true/false upon success/failure
*/
virtual bool setReference(int j, double ref) {
if (pid)
return pid->setReference(j, ref);
return false;
}
/** Set the controller reference points, multiple axes.
* Warning this method can result in very large torques
* and should be used carefully. If you do not understand
* this warning you should avoid using this method.
* Have a look at other interfaces (e.g. position control).
* @param refs pointer to the vector that contains the new reference points.
* @return true/false upon success/failure
*/
virtual bool setReferences(const double *refs) {
if (pid)
return pid->setReferences(refs);
return false;
}
/** Set the error limit for the controller on a specifi joint
* @param j joint number
* @param limit limit value
* @return true/false on success/failure
*/
virtual bool setErrorLimit(int j, double limit) {
if (pid)
return pid->setErrorLimit(j, limit);
return false;
}
/** Get the error limit for the controller on all joints.
* @param limits pointer to the vector with the new limits
* @return true/false on success/failure
*/
virtual bool setErrorLimits(const double *limits) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?