implement probing, and plane definition and z offset calculation
authorJim Morris <morris@wolfman.com>
Thu, 31 Jul 2014 06:48:31 +0000 (23:48 -0700)
committerJim Morris <morris@wolfman.com>
Thu, 31 Jul 2014 06:48:31 +0000 (23:48 -0700)
src/libs/Vector3.cpp
src/libs/Vector3.h
src/modules/tools/zprobe/Plane3D.cpp [new file with mode: 0644]
src/modules/tools/zprobe/Plane3D.h [new file with mode: 0644]
src/modules/tools/zprobe/ThreePointStrategy.cpp
src/modules/tools/zprobe/ThreePointStrategy.h
src/modules/tools/zprobe/ZProbe.cpp
src/modules/tools/zprobe/ZProbe.h

index bc9cda5..3129893 100644 (file)
@@ -17,6 +17,23 @@ Vector3::Vector3(float a, float b, float c)
     elem[2] = c;
 }
 
+Vector3::Vector3(const Vector3 &to_copy)
+{
+    elem[0] = to_copy.elem[0];
+    elem[1] = to_copy.elem[1];
+    elem[2] = to_copy.elem[2];
+}
+
+Vector3& Vector3::operator= (const Vector3 &to_copy)
+{
+    if( this != &to_copy ) {
+        elem[0] = to_copy.elem[0];
+        elem[1] = to_copy.elem[1];
+        elem[2] = to_copy.elem[2];
+    }
+    return *this;
+}
+
 float Vector3::operator[](int i) const
 {
     if (i >= 0 && i <= 2)
@@ -24,6 +41,13 @@ float Vector3::operator[](int i) const
     return nan;
 }
 
+void Vector3::set(float a, float b, float c)
+{
+    elem[0] = a;
+    elem[1] = b;
+    elem[2] = c;
+}
+
 Vector3 Vector3::cross(const Vector3 &vec) const
 {
     Vector3 out;
index 6ebb9e2..3ea5852 100644 (file)
@@ -6,9 +6,11 @@ class Vector3
 public:
     Vector3();
     Vector3(float, float, float);
+    Vector3(const Vector3& to_copy);
+    Vector3& operator= (const Vector3& to_copy);
 
     float    operator[](int) const;
-
+    void     set(float a, float b, float c);
     Vector3  cross(const Vector3&) const;
 
     float    dot(const Vector3&) const;
diff --git a/src/modules/tools/zprobe/Plane3D.cpp b/src/modules/tools/zprobe/Plane3D.cpp
new file mode 100644 (file)
index 0000000..cbe3211
--- /dev/null
@@ -0,0 +1,28 @@
+#include "Plane3D.h"
+
+Plane3D::Plane3D(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3)
+{
+    // get the normal of the plane
+    Vector3 ab = v1.sub(v2);
+    Vector3 ac = v1.sub(v3);
+
+    Vector3 cp = ab.cross(ac);
+    normal = cp.unit();
+
+    // ax+by+cz+d=0
+    // solve for d
+    Vector3 dv = normal.mul(v1);
+    d = -dv[0] - dv[1] - dv[2];
+}
+
+// solve for z given x and y
+// z= (-ax - by - d)/c
+float Plane3D::getz(float x, float y)
+{
+    return ((-normal[0] * x) - (normal[1] * y) - d) / normal[2];
+}
+
+Vector3 Plane3D::getNormal() const
+{
+    return normal;
+}
diff --git a/src/modules/tools/zprobe/Plane3D.h b/src/modules/tools/zprobe/Plane3D.h
new file mode 100644 (file)
index 0000000..f77d591
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __PLANE3D_H
+#define __PLANE3D_H
+
+#include "Vector3.h"
+
+// define a plane given three points
+class Plane3D
+{
+private:
+    Vector3 normal;
+    float d;
+
+public:
+    Plane3D(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3);
+    float getz(float x, float y);
+    Vector3 getNormal() const;
+};
+
+#endif
index 4916e8e..16361c0 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <string>
 #include <algorithm>
+#include <cstdlib>
 
 #define probe_point_1_checksum       CHECKSUM("point1")
 #define probe_point_2_checksum       CHECKSUM("point2")
 
 bool ThreePointStrategy::handleConfig()
 {
-    for (int i = 0; i < 3; ++i) {
-        std::string s= THEKERNEL->config->value(leveling_strategy_checksum, three_point_leveling_strategy_checksum, probe_point_1_checksum)->by_default("")->as_string();
-        if(s.empty()) break;
-        // format is xxx,yyy
-
-
-    }
+    // format is xxx,yyy for the probe points
+    std::string p1= THEKERNEL->config->value(leveling_strategy_checksum, three_point_leveling_strategy_checksum, probe_point_1_checksum)->by_default("")->as_string();
+    std::string p2= THEKERNEL->config->value(leveling_strategy_checksum, three_point_leveling_strategy_checksum, probe_point_2_checksum)->by_default("")->as_string();
+    std::string p3= THEKERNEL->config->value(leveling_strategy_checksum, three_point_leveling_strategy_checksum, probe_point_3_checksum)->by_default("")->as_string();
+    if(!p1.empty()) probe_points[0]= parseXY(p1.c_str());
+    if(!p2.empty()) probe_points[1]= parseXY(p2.c_str());
+    if(!p3.empty()) probe_points[2]= parseXY(p3.c_str());
     return true;
 }
 
@@ -38,15 +39,91 @@ bool ThreePointStrategy::handleGcode(Gcode *gcode)
         if( gcode->g == 32 ) { // three point probe
             // first wait for an empty queue i.e. no moves left
             THEKERNEL->conveyor->wait_for_empty_queue();
-
+            if(!doProbing(gcode->stream)) {
+                gcode->stream->printf("Probe failed to complete, probe not triggered\n");
+            }else{
+                gcode->stream->printf("Probe completed, bed plane defined\n");
+            }
             return true;
         }
 
     } else if(gcode->has_m) {
-        // handle mcodes
+        if(gcode->m == 557) { // M557 - set probe points eg M557 P0 X30 Y40.5  where P is 0,1,2
+            int idx= 0;
+            float x= NAN, y= NAN;
+            if(gcode->has_letter('P')) idx= gcode->get_value('P');
+            if(gcode->has_letter('X')) x= gcode->get_value('X');
+            if(gcode->has_letter('Y')) y= gcode->get_value('Y');
+            if(idx >= 0 && idx <= 2) {
+                probe_points[idx]= std::make_tuple(x, y);
+            }
+            return true;
+
+        }else if(gcode->m == 503) {
+            gcode->stream->printf(";Probe points:\n");
+            for (int i = 0; i < 3; ++i) {
+                float x, y;
+                std::tie(x, y) = probe_points[i];
+                gcode->stream->printf("M557 P%d X%1.5f Y%1.5f\n", i, x, y);
+            }
+            return true;
+        }
     }
 
     return false;
 }
 
+bool ThreePointStrategy::doProbing(StreamOutput *stream)
+{
+    float x, y;
+    // check the probe points have been defined
+    for (int i = 0; i < 3; ++i) {
+        std::tie(x, y) = probe_points[i];
+        if(isnan(x) || isnan(y)) {
+             stream->printf("Probe point P%d has not been defined, use M557 P%d Xnnn Ynnn to define it\n", i, i);
+             return false;
+        }
+    }
+
+    // home presuming a cartesian homing to 0,0,0
+    zprobe->home();
+
+    // move to start position and probe from there
+    zprobe->coordinated_move(NAN, NAN, zprobe->getProbeHeight(), zprobe->getFastFeedrate(), true); // do a relative move from home to the point above the bed
+
+    // probe the three points
+    Vector3 v[3];
+    for (int i = 0; i < 3; ++i) {
+        std::tie(x, y) = probe_points[i];
+        float z= zprobe->probeDistance(x, y) - zprobe->getProbeHeight(); // relative distance between the probe points
+        if(isnan(z)) return false; // probe failed
+        stream->printf("DEBUG: P%d:%1.4f\n", i, z);
+        v[i].set(x, y, z);
+    }
+
+    // define the plane
+    delete this->plane;
+    this->plane= new Plane3D(v[0], v[1], v[2]);
+
+    stream->printf("DEBUG: plane normal= %f, %f, %f\n", plane->getNormal()[0], plane->getNormal()[1], plane->getNormal()[2]);
+
+    return true;
+}
+
+// find the Z offset for the point on the plane at x, y
+float ThreePointStrategy::getZOffset(float x, float y)
+{
+    if(plane == nullptr) return NAN;
+    return plane->getz(x, y);
+}
 
+// parse a "X,Y" string return x,y
+std::tuple<float, float> ThreePointStrategy::parseXY(const char *str){
+    float x=NAN, y=NAN;
+    char *p;
+    x= strtof(str, &p);
+    if(p+1 < str+strlen(str)) {
+        y= strtof(p+1, nullptr);
+    }
+    return std::make_tuple(x, y);
+}
index 79aab18..2dc9871 100644 (file)
@@ -2,8 +2,11 @@
 #define _THREEPOINTSTRATEGY
 
 #include "LevelingStrategy.h"
+#include "Plane3D.h"
 
 #include <string.h>
+#include <tuple>
+#include <cmath>
 
 #define three_point_leveling_strategy_checksum CHECKSUM("three-point-leveling")
 
@@ -12,13 +15,18 @@ class StreamOutput;
 class ThreePointStrategy : public LevelingStrategy
 {
 public:
-    ThreePointStrategy(ZProbe *zprobe) : LevelingStrategy(zprobe){ memset(probe_points, 0, sizeof probe_points); }
-    ~ThreePointStrategy(){}
+    ThreePointStrategy(ZProbe *zprobe) : LevelingStrategy(zprobe){ for (int i = 0; i < 3; ++i) {probe_points[i]= std::make_tuple(NAN,NAN);}; plane= nullptr; }
+    ~ThreePointStrategy(){ delete plane; }
     bool handleGcode(Gcode* gcode);
     bool handleConfig();
+    float getZOffset(float x, float y);
 
 private:
-    float probe_points[3][2];
+    bool doProbing(StreamOutput *stream);
+    std::tuple<float, float> parseXY(const char *str);
+
+    std::tuple<float, float> probe_points[3];
+    Plane3D *plane;
 };
 
 #endif
index 502113f..5bd5171 100644 (file)
@@ -215,6 +215,13 @@ bool ZProbe::doProbeAt(int &steps, float x, float y)
     return true;
 }
 
+float ZProbe::probeDistance(float x, float y)
+{
+    int s;
+    if(!doProbeAt(s, x, y)) return NAN;
+    return zsteps_to_mm(s);
+}
+
 void ZProbe::on_gcode_received(void *argument)
 {
     Gcode *gcode = static_cast<Gcode *>(argument);
index 2c706ec..7b773e0 100644 (file)
@@ -35,6 +35,7 @@ public:
     bool run_probe(int& steps, bool fast= false);
     bool return_probe(int steps);
     bool doProbeAt(int &steps, float x, float y);
+    float probeDistance(float x, float y);
 
     void coordinated_move(float x, float y, float z, float feedrate, bool relative=false);
     void home();