下面,简要介绍一下程序各个类的功能。
Robot.h就是Robot类;Frame.h就是坐标系类,任务坐标系和世界坐标系都可以用类Frame定义。
关节坐标系由两个关节的转角theta1,theta2组成为JointFrame类;
Joint.h就是Joint类,注意的Joint类是与JointFrame类不同的,Joint类是真正的关节属性(包括转角,零点,转角范围等),而JointFrame强调的是整个机器人的所有关节(我们这只有2个关节);
Solver.h就是定义的求解器Slover类,用于机器手的正反运动学求解,Robot类中定义了一个Solver类对象作为成员变量,Robot的运动求解都交给Solver来做;
至于Coffee.h就是定义的coffee类,其中还包括子类杯子Cup(大小和放置位置属性)和需要增加的材料CoffeeAddMaterial(糖,奶,或者什么都不加)
在Robot类中:
class Robot { private: double length1,length2; Joint joint1,joint2; Frame WorldFrame; vector<Frame> fv; Solver solver; public: Robot(){} Robot(double l1,double l2,Joint jt1,Joint jt2,Frame WF): length1(l1),length2(l2),jt1(joint),jt2(joint2),WorldFrame(WF),solver(l1,l2,jt1.getthetamax(),jt1.getthetamin(),jt2.getthetamax(),jt2.getthetamin()){} void TaskFrameCreate(Frame &tf); void PTPMove(Frame &fr,Point &pt); void RobotShow(void); double getlength1(void); double getlength2(void); Joint getjoint1(void); Joint getjoint2(void); void setjoint1(Joint &jt); void setjoint2(Joint &jt); };
在该类中length1,length2分别代表两杆的长度,joint1,joint2分别代表在关节点1,2的关节坐标系,solver用来求解,PTPMove(Frame &fr,Point &pt)是对输入坐标系fr中的点pt,计算相应的关节角
Point类:
class Point { private: string name;//Point的名称 double x,y; public: Point(double xx=0,double yy=0):x(xx),y(yy){} //复制构造函数 Point(string nam,double xx=0,double yy=0):name(nam),x(xx),y(yy){} Point(Point &p):name(p.name),x(p.x),y(p.y){}//拷贝构造函数 void copyto(Point &p); double getx(void); double gety(void); string getname(void); };
Frame类的定义:
class Frame { private: string name;// frame的名字 Vector2d vector_X;//frame的x单位向量 Vector2d vector_Y;//frame的y单位向量 Point origin;// public: Frame() {}//默认构造函数 Frame(string nam,Vector2d &vx,Vector2d &vy,Point &oripoint):name(nam),origin(oripoint)//复制构造函数 { vector_X=vx/(sqrt(vx.transpose()*vx)); vector_Y=vy/(sqrt(vy.transpose()*vy)); } Frame(Frame &fr):name(fr.name),vector_X(fr.vector_X),vector_Y(fr.vector_Y),origin(fr.origin){}//拷贝构造函数 string getname(void); Vector2d getVector_X(void); Vector2d getVector_Y(void); Point getorigin(void); };
JointFrame类:
class JointFrame
{
private:
double theta1,theta2;//theta1,theta2分别代表关节角1,2的转角 public: JointFrame(double t1=0,double t2=0):theta1(t1),theta2(t2){}//复制构造函数 JointFrame(Jointpoint &p):theta1(p.theta1),theta2(p.theta2){}//拷贝构造函数 double gettheta1(void);
double gettheta2(void); };
Solver类的定义:
class Solver { private: double length1,length2; double theta1max,theta1min,theta2max,theta2min; public: Solver(){} Solver(double l1,double l2,double t1max,double t1min,double t2max,double t2min): length1(l1),length2(l2),theta1max(t1max),theta1min(t1min),theta2max(t2max),theta2min(t2min){} JointFrame ToJoint(Point &);//由点求得关节角
Point JointTo(JointFrame &);//由关节角求得点
void setlength1(double l1); void setlength2(double l2); void settheta1max(double t1max); void settheta1min(double t1min); void settheta2max(double t2max); void settheta2min(double t2min); };
反思:
1.在程序中,没有很好的利用继承,派生,多重派生以及虚函数等类的方法,如果能够合理的运用这些东西的话,可能就不需要再每个类中都定义相应的get函数了,
2.我觉得程序还是可以简化,比如合理的利用Eigen的向量的运算方式,这样可能就不需要定义Point类了,只需要定义Vector就可以了,而且还可以利用向量的运算法则 简化Solver中求解的算法,比如 vector v_frame1,vector v_frame2,vector origin_of_frame1_in_frame2,这样v_frame1=v_frame2+origin_of_frame1_in_frame2,这样大大简化了计算算法。
3.关于机械臂的实际运动而言,其实有一点是没有解决的,就是一般情况下一个点对应两组关节角,如果点的轨迹是连续的话,那相应的角的运动也应该是连续而不能突变,但是如果在两组关节角中取值呢?目前我们还没想到相应的方法。由于目前不需要考虑连续运动的情况,可能我们就按随意取了一组关节角。