Hier werden die Unterschiede zwischen zwei Versionen gezeigt.
Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
mechatronik:sose24:remote-plotter:code [2024/07/26 00:55] Paul-Hoeft |
mechatronik:sose24:remote-plotter:code [2024/07/31 10:29] (aktuell) TPfoch [Backend] |
||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
======Code====== | ======Code====== | ||
Falls Github spinnt :) | Falls Github spinnt :) | ||
- | =====Arduino===== | + | =====Backend===== |
- | <file C++ mlzrobo.ino> | + | <file C++ main.cpp> |
- | #include "Motor.hpp" | + | #include "DrawRobot.hpp" |
- | //#define PI 3.14159265358979 | + | |
- | template<typename T1, typename T2> | + | #define cm |
- | struct Pair | + | |
- | { | + | |
- | T1 a; | + | |
- | T2 b; | + | |
- | }; | + | |
- | struct Point | + | DrawRobot<Arm> robot; |
- | { | + | |
- | double x,y; | + | |
- | Point(double ix, double iy): x(ix), y(iy) | + | |
- | {} | + | |
- | Point operator-(Point other) | + | |
- | { | + | |
- | return Point(x-other.x, y-other.y); | + | |
- | } | + | |
- | + | ||
- | Point operator+(Point other) | + | |
- | { | + | |
- | return Point(x+other.x, y+other.y); | + | |
- | } | + | |
- | Point operator*(double div) | + | void setup() |
- | { | + | |
- | return Point(x*div, y*div); | + | |
- | } | + | |
- | Point operator/(double div) | + | |
- | { | + | |
- | return Point(x/div, y/div); | + | |
- | } | + | |
- | }; | + | |
- | // std::ostream& operator<<(std::ostream &os, Point p) | + | |
- | // { | + | |
- | // os << '[' << p.x << ' ' << p.y<<']'; | + | |
- | + | ||
- | // return os; | + | |
- | // } | + | |
- | class Arm | + | |
{ | { | ||
- | double l1,l2; | + | Serial.begin(115200); |
- | Point current; | + | |
- | Motor *m1,*m2; | + | |
- | public: | + | Motor root(AccelStepper(8,4,6,5,7), 4076); |
- | //arm with the two sections l1,l2. At start both facing upwards | + | Motor ext(AccelStepper(8,8,9,10,11), 4076); |
- | template<typename M1, typename M2> | + | |
- | Arm(double ll1, double ll2, M1 &&m1, M2 &&m2): | + | |
- | l1(ll1), l2(ll2), current(0,l1+l2), m1(new M1(m1)), m2(new M2(m2)) | + | |
- | {} | + | |
- | //calculates the angles of the two sections so the end of the second is at point p | + | robot = { |
- | Pair<double, double> angles(Point p) | + | .axies = Arm(11 cm, 11.5 cm, root, ext), |
- | { | + | .gantry = Gantry(6, 7) |
- | double ph2= acos( | + | }; |
- | (p.x*p.x+p.y*p.y-l1*l1-l2*l2)/ | + | |
- | (2*l1*l2)); | + | |
- | double phi1 = atan2(p.y,p.x) | + | |
- | -atan2(l2*sin(ph2), | + | |
- | (l1+l2*cos(ph2))); | + | |
- | return Pair<double,double>{phi1/PI*180, ph2/PI*180}; | + | // robot.axies.moveTo({22.5,0}); |
- | } | + | robot.axies.moveTo({11,11.5}); |
- | //goes form current position to point b in a "straight" line by dividing it in s Sections | + | } |
- | void straightline(Point b, int s) | + | void loop() |
- | { | + | { |
- | Point delta=(b-current)/s; | + | int cmd = Serial.parseInt(); |
- | //std::cout<< delta<<std::endl; | + | switch(cmd){ |
- | for(int i=0;i<s;i++) | + | case 0:{ |
- | { | + | int x = Serial.parseInt(); |
- | gotoP(current+delta); | + | int y = Serial.parseInt(); |
- | } | + | robot.axies.moveTo({x,y}); |
+ | break; | ||
} | } | ||
- | | + | case 1: { |
- | //goes form current to point b | + | int tool = Serial.parseInt(); |
- | void gotoP(Point b) | + | robot.gantry.setTool(tool); // ist tool |
- | { | + | |
- | current=b; | + | |
- | auto a = angles(current); | + | |
- | m1->setAngle(a.a); | + | |
- | m2->setAngle(a.b); | + | |
- | | + | |
} | } | ||
- | //lift/dops the pen on/off the canvas | ||
- | void shiftPen() | ||
- | { | ||
- | | ||
- | } | ||
- | |||
- | }; | ||
- | |||
- | |||
- | void setup() | ||
- | { | ||
- | // Serial.begin(115200); | ||
- | // Arm a(1,2, | ||
- | // MotorStepper(8,9,10,11, 4096), | ||
- | // MotorServo(A1)); | ||
- | // Point goal(3,0); | ||
- | // a.straightline(goal, 3); | ||
- | Serial.begin(115200); | ||
- | SmallMotor a(8,9,10,11,2048, 5); | ||
- | a.setAngle(180); | ||
- | AccelMotor b(3,2, 300); | ||
- | b.setAngle(180); | ||
- | for(int i=0; i<1000;i++){ | ||
- | a.update(1000); | ||
- | b.update(1000); | ||
- | // delay(100); | ||
} | } | ||
} | } | ||
- | void loop() | ||
- | { | ||
- | delay(1000); | ||
- | } | ||
- | |||
- | // int main() | ||
- | // { | ||
- | // Arm a(2,1); | ||
- | // Point b(3,0); | ||
- | // a.straightline(b,10); | ||
- | // //auto [phi1, phi2] = a.angles(Point{1,2}); | ||
- | // //std::cout << phi1 << " " << phi2 << std::endl; | ||
- | // } | ||
</file> | </file> | ||
- | =====Motor===== | + | ====Axies==== |
- | <file C++ motor_mtrobo.cpp> | + | <file C++ Axies.hpp> |
#pragma once | #pragma once | ||
- | #include <math.h> | + | #include "AccelStepper.h" |
+ | #include "MultiStepper.h" | ||
#ifndef PI | #ifndef PI | ||
#define PI 3.14159265358979 | #define PI 3.14159265358979 | ||
#endif | #endif | ||
- | class Motor{ | + | |
+ | struct Point {double x,y;}; | ||
+ | struct Angles {double root, ext;}; | ||
+ | |||
+ | class Axies | ||
+ | { | ||
public: | public: | ||
- | // return inaccuarrcy | + | virtual void moveTo(Point p)=0; |
- | virtual double setAngle(double angle)=0; | + | |
- | virtual double update(int steps)=0; | + | |
}; | }; | ||
- | class StepperMotor : public Motor | + | struct Motor |
{ | { | ||
- | double partial=0; | + | AccelStepper stepper; |
- | int speed, | + | int stepsPerRev=-1; |
- | stepsPerRev; | + | Motor(AccelStepper stepper, int stepsPerRev, int speed=4000): |
- | double target=0; | + | stepper(stepper), stepsPerRev(stepsPerRev) |
- | int current=0; | + | { |
- | public: | + | this->stepper.setAcceleration(1000); |
- | StepperMotor(int stepsPerRev, int speed=5) | + | this->stepper.setMaxSpeed(speed); |
- | : speed(speed), stepsPerRev(stepsPerRev) | + | this->stepper.setSpeed(speed); |
- | {} | + | } |
- | // return inaccuarrcy | + | |
- | double setAngle(double angle) override | + | long getSteps(double deg) |
- | { | + | { |
- | target = angle*stepsPerRev/360.0; | + | return deg/360.0*stepsPerRev; |
- | } | + | } |
- | double update(int steps) override | + | |
- | { | + | |
- | double delta = target/steps+partial; | + | |
- | partial = delta-(int)delta; | + | |
- | current+=delta; | + | |
- | stepBy(delta); | + | |
- | return 0; | + | |
- | } | + | |
- | private: | + | |
- | virtual void stepBy(int delta) =0; | + | |
}; | }; | ||
- | #include "Stepper.h" | ||
- | class SmallMotor : public StepperMotor { | ||
- | Stepper s; | ||
+ | class Arm | ||
+ | { | ||
+ | double rootLen, extLen; | ||
+ | Motor root, ext; | ||
+ | MultiStepper ms; | ||
public: | public: | ||
- | SmallMotor(int in1, int in2, int in3, int in4, int stepsPerRev, int speed=5) | + | Arm(double rootLen, double extLen, Motor root, Motor ext); |
- | : s(stepsPerRev, in1, in2, in3, in4), StepperMotor(stepsPerRev, speed) | + | void moveTo(Point p); |
- | { | + | |
- | s.setSpeed(speed); | + | |
- | } | + | |
private: | private: | ||
- | void stepBy(int delta) override | + | //calculates the angles of the two sections so the end of the second is at point p |
- | { | + | Angles pointToAngles(Point p); |
- | Serial.println(delta); | + | |
- | s.step(delta); | + | |
- | } | + | |
}; | }; | ||
+ | </file> | ||
+ | <file C++ Axies.cpp> | ||
+ | #include "Axies.hpp" | ||
- | #include "AccelStepper.h" | + | Arm::Arm(double rootLen, double extLen, Motor root, Motor ext) : |
+ | rootLen(rootLen), extLen(extLen), ms(), root(root), ext(ext) | ||
+ | { | ||
+ | ms.addStepper(root.stepper); | ||
+ | ms.addStepper(ext.stepper); | ||
+ | } | ||
+ | |||
+ | |||
+ | void Arm::moveTo(Point p) | ||
+ | { | ||
+ | Angles angle = pointToAngles(p); // 0-360 | ||
+ | Serial.println("Root: " + String(angle.root) + "°->" + String(root.getSteps(angle.root))); | ||
+ | Serial.println("Ext: " + String(angle.ext) + "°->" + String(ext.getSteps(angle.root))); | ||
+ | long pos[2] = {root.getSteps(angle.root), ext.getSteps(angle.ext)}; | ||
+ | ms.moveTo(pos); | ||
+ | ms.runSpeedToPosition(); | ||
+ | } | ||
+ | |||
+ | Angles Arm::pointToAngles(Point p) | ||
+ | { | ||
+ | double ph2= acos( | ||
+ | (p.x*p.x+p.y*p.y-rootLen*rootLen-extLen*extLen)/ | ||
+ | (2*rootLen*extLen)); | ||
+ | |||
+ | double phi1 = atan2(p.y,p.x) | ||
+ | -atan2(extLen*sin(ph2), | ||
+ | (rootLen+extLen*cos(ph2))); | ||
+ | |||
+ | return {phi1/PI*180, ph2/PI*180}; | ||
+ | } | ||
+ | </file> | ||
+ | ====Gantry==== | ||
+ | <file C++ Gantry.hpp> | ||
+ | #pragma once | ||
+ | #include <Servo.h> | ||
+ | |||
+ | class Gantry | ||
+ | { | ||
+ | Servo use, // servo for lowering tool | ||
+ | select;// Servo to switch between tools | ||
+ | // ^ currently unused | ||
- | class AccelMotor : public StepperMotor { | ||
- | AccelStepper stepper; | ||
public: | public: | ||
- | AccelMotor(int stepPin, int dirPin, int stepsPerRev, int speed=1000) | + | Gantry(int usePin, int selectPin) |
- | : stepper(1, stepPin, dirPin), StepperMotor(stepsPerRev, speed) | + | |
{ | { | ||
- | stepper.setCurrentPosition(0); | + | use.attach(usePin); |
- | stepper.setMaxSpeed(10000); | + | select.attach(selectPin); |
- | stepper.setAcceleration(500); | + | |
- | stepper.setSpeed(500); | + | |
} | } | ||
+ | enum Tool { | ||
+ | NONE, | ||
+ | PEN | ||
+ | }; | ||
+ | void setTool(Tool tool); | ||
- | // double update() override | ||
- | // { | ||
- | // if(stepper.currentPosition() < target) | ||
- | // { | ||
- | // stepper.setSpeed(speed); | ||
- | // stepper.runSpeed(); | ||
- | // } | ||
- | // else if(stepper.currentPosition() > target) | ||
- | // { | ||
- | // stepper.setSpeed(-speed); | ||
- | // stepper.runSpeed(); | ||
- | // } else { | ||
- | // stepper.setSpeed(0); | ||
- | // stepper.runSpeed(); | ||
- | // } | ||
- | // } | ||
- | private: | ||
- | void stepBy(int delta) override | ||
- | { | ||
- | stepper.moveTo(stepper.currentPosition()+delta); | ||
- | stepper.runToPosition(); | ||
- | } | ||
}; | }; | ||
+ | </file> | ||
+ | <file C++ Gantry.cpp> | ||
+ | #include "Gantry.hpp" | ||
- | #include <Servo.h> | + | void Gantry::setTool(Tool tool) |
+ | { | ||
+ | // maybe second servo for tool switch | ||
- | class MotorServo : public Motor { | + | // dummy implementation |
- | Servo s; | + | use.write(180*(tool==PEN)); |
- | uint8_t pin; | + | } |
- | double currentAngle=0, | + | |
- | speed; | + | |
- | public: | + | |
- | MotorServo(uint8_t pin, double speed=100) : pin(pin), speed(speed) | + | |
- | { | + | |
- | s.attach(pin); | + | |
- | } | + | |
- | double setAngle(double angle) override | + | |
- | { | + | |
- | double dAngle = angle - currentAngle; | + | |
- | Serial.println(dAngle); | + | |
- | s.write(angle); | + | |
- | delay(1000/speed*dAngle); | + | |
- | currentAngle=angle; | + | |
- | return 0; | + | |
- | } | + | |
- | double update() {}; | + | |
- | }; | + | |
</file> | </file> | ||
+ | |||
+ | |||
=====Frontend===== | =====Frontend===== | ||
Dieses Programm ist mithilfe des Tkinter-Moduls geschrieben. Hiermt hat man eine Zeichenoberfläche, welche die aktuelle Zeichnung speichern kann als auch die Koordinaten der Zeichnung während Laufzeit ausgibt und an den Arduino schicken kann.(?) | Dieses Programm ist mithilfe des Tkinter-Moduls geschrieben. Hiermt hat man eine Zeichenoberfläche, welche die aktuelle Zeichnung speichern kann als auch die Koordinaten der Zeichnung während Laufzeit ausgibt und an den Arduino schicken kann.(?) |