我创建了一个仅限标题的库,其目的是封装有关我所拥有的机器人的所有姿势信息。该库还提供了重新计算存储在结构中的值的函数。我在库中使用了两个数组结构;一个指定每个关节与其连接的关节之间的关系,另一个指示跟踪每个关节的各种空间属性(例如角度等)。
第一个结构永远不会改变(因为你不能从机器人中添加/删除东西)并且可以被认为是静态的和恒定的。第二种结构可以被认为是静态的但不是常数,因为空间信息将取决于机器人的状态。
虽然我的实现工作正常,但我正在努力确定我是否已根据我的意图在C ++中正确实现了这一点。该库旨在在模块中本地使用(因此不会出现并发问题),并且我希望确保所使用的内存空间不会随着时间的推移而增长。因此我使用了静态分配数组。我想重用分配给每个Point3D对象的内存,即我想覆盖现有值而不是创建新对象。传感器读数在我的库中使用如下分配更新;
bodyPoints[bWorld].jointAngle.x = torsoRoll;
bodyPoints[bWorld].jointAngle.y = torsoPitch;
bodyPoints[bWorld].jointAngle.z = torsoYaw;
我还没有用C ++进行编程,并且非常感谢有经验的人评论我所做的事情。代码需要使用C ++ 03标准进行编译。
= - = - = - = - = - = - = - = - = - = - = - = - = - = - = -
我现有代码的每个部分的代码片段如下。
我创建了一个枚举来定义我需要管理的所有点和链接,这基本上是机器人的树形描述。以下是枚举定义的代码片段:
typedef enum BodyPoints { // The verticies
bWorld,
jNeck,
eCam1
jLShoulder
} BodyPoints;
typedef enum BodyLinks { // The edges
Torso = 0,
Head,
Cam1,
LUpperArm,
RUpperArm
} BodyLinks;
我使用描述连接信息的结构为BodyLinks(边缘)创建了一个映射数组:
struct BodyLinksMapping {
const BodyLinks name;
const BodyLinks parent;
const BodyPoints linkage;
const std::vector<BodyLinks> children;
};
static BodyLinksMapping bodyMap[59]=
{
{Torso, NROTBODYS, bWorld, {Head, LUpperArm, RUpperArm, LPelvis, RPelvis}},
{Head, Torso, jNeck, {Cam1}},
{Cam1, Head, eCam1, {}},
{LUpperArm, Torso, jLShoulder, {LLowerArm}},
...
}
使用存储空间信息的结构的BodyPoints(顶点)数组:
struct BodyPoint {
BodyPoints name;
Point3D<double> orientation;
Point3D<double> offset;
Point3D<double> jointAngle;
Point3D<double> rotated;
Point3D<double> translated;
};
static BodyPoint bodyPoints[53] =
// ///< -Orientation- > <---- Offset ---->
{ BodyPoint(bWorld, Point3D<double>( 0.0, 0.0, 0.0), Point3D<double>( 0.00, 0.00, 0.00), Point3D<double>(0,0,0), Point3D<double>(0,0,0), Point3D<double>(0,0,0) ),
BodyPoint(jNeck, Point3D<double>( 0.0, 0.0, 0.0), Point3D<double>( 0.00, 0.00, 126.50), Point3D<double>(0,0,0), Point3D<double>(0,0,0), Point3D<double>(0,0,0) ),
BodyPoint(eCam1, Point3D<double>( 0.0, 1.2, 0.0), Point3D<double>( 58.71, 0.00, 63.64), Point3D<double>(0,0,0), Point3D<double>(0,0,0), Point3D<double>(0,0,0) ),
BodyPoint(jLShoulder, Point3D<double>( 0.0, 0.0, 0.0), Point3D<double>( 0.00, 98.00, 100.00), Point3D<double>(0,0,0), Point3D<double>(0,0,0), Point3D<double>(0,0,0) ),
...
}
每个Point的方向和偏移是恒定的,但随着机器人姿势的变化,JointAngle,Rotated和Translated会发生变化。这些动态数据使用库提供的递归函数计算:
static inline void recalcRAD(BodyLinks body) {
...
}
参数表示正在考虑的当前链接。我在使用指针访问数组元素时使用链表方法。
Point3D类主要基于NIST implementation of vector3d,而我只使用了一小部分可用的类方法;
operator=
和operator+=
以及我已定义的一些3D转换方法。以下是Point3D类的摘要,显示了我使用的方法:
template <class TYPE>
class Point3D {
public:
///
/// The components of the vector
///
TYPE x,y,z;
/// Default class constructor
Point3D<TYPE>() {}
/// Assignment operator
Point3D<TYPE>& operator=(const Point3D<TYPE>& a)
{
x=a.x;
y=a.y;
z=a.z;
return *this;
}
/// Addition of vectors
Point3D<TYPE> operator+(const Point3D<TYPE>& a) const
{
return Point3D<TYPE>(x+a.x,y+a.y,z+a.z);
}
/// Addition of vectors
const Point3D<TYPE>& operator+=(const Point3D<TYPE>& a)
{
return *this = *this+a;
}
Point3D<TYPE> rotateZ_RAD(double theta) {
return Point3D<TYPE>(x*cos(theta) - y*sin(theta),
x*sin(theta) + y*cos(theta),
z);
}
Point3D<TYPE> rotate3D_RAD(const Point3D<double>& theta) {
// Davenport (Tait–Bryan) chained extrinsic rotations (YPR)
Point3D<TYPE> r = rotateZ_RAD(theta.z);
r=r.rotateY_RAD(theta.y);
r=r.rotateX_RAD(theta.x);
return r;
}
...
}