Skip to content
Snippets Groups Projects
Commit f15b8d7d authored by Elisabetta Pianori's avatar Elisabetta Pianori
Browse files

Merge branch 'dantrim_remove_obsolete_libs' into 'devel'

Remove ImageRec, Zaber, WaferProbe, WaveFormGen

See merge request !235
parents 0816fe80 23025c15
Branches
Tags
6 merge requests!308Bring main and devel back in sync,!300playing with fixing divergence between devel and main,!287Updates for Julabo Chiller,!285Julabo Chiller Added with Fixed Pipeline Compatibility,!269Merge devel into main: largest change is code formatting checker and enforcement in CI,!235Remove ImageRec, Zaber, WaferProbe, WaveFormGen
Pipeline #2608199 passed
Showing
with 0 additions and 1248 deletions
......@@ -13,6 +13,3 @@
[submodule "src/exts/json-schema-validator"]
path = src/exts/json-schema-validator
url = https://github.com/pboettch/json-schema-validator.git
[submodule "src/exts/zaber"]
path = src/exts/zaber
url = https://gitlab.com/zaber-core-libs/core-c.git
......@@ -78,9 +78,6 @@ that the user is responsible for installing them on their system if required.
| [libmpsse](https://github.com/l29ah/libmpsse) | Library that implements common communication protocols (I2C, SPI) using the MPSSE framework on FTDI chips | FTDICom | **NO** |
| [linux-gpib](https://linux-gpib.sourceforge.io/) | Support for GPIB hardware | [libPS](src/libPS) | **NO** |
| [Qt 5.9.2](https://www.qt.io/download-qt-for-application-development) | GUI fun in C++ | [Probe Station](src/libWaferProb) | **NO** |
| [OpenCV 3.3.1](https://docs.opencv.org/3.3.1/d7/d9f/tutorial_linux_install.html) | | [Probe Station](src/libWaferProb) | **NO** |
| [gclib](http://galilmc.com/sw/pub/all/doc/gclib/html/osx.html) ([Galil](https://www.galil.com/sw/pub/all/doc/gclib/html/rhel7.html)) | Installation instructions found [here](https://www.galil.com/sw/pub/all/doc/gclib/html/rhel7.html) | [Probe Station](src/libWaferProb) | **NO** |
| [zaber](https://gitlab.com/zaber-core-libs/core-c) | This is a deprecated library, with more up-to-date C++ library located [here](https://www.zaber.com/software/docs/motion-library/ascii/tutorials/install/cpp/) | | **NO** |
| [graphviz](https://graphviz.org/) | Requirement for `doxygen`, provides `dot` utility | | **NO** |
One can also refer to the [.gitlab-ci.yml](.gitlab-ci.yml) file for a complete listing
......
......@@ -72,14 +72,11 @@ add_subdirectory(libMeter)
add_subdirectory(libLoad)
add_subdirectory(libCom)
add_subdirectory(libDevCom)
add_subdirectory(libImageRec)
add_subdirectory(libScope)
add_subdirectory(libWaveFormGen)
add_subdirectory(libUtils)
add_subdirectory(libEquipConf)
add_subdirectory(libDataSink)
add_subdirectory(libChiller)
add_subdirectory(libWaferProb)
#
# Add binaries
......
......@@ -105,22 +105,3 @@ if (USE_PYTHON)
endif()
set(PYBIND_OK TRUE PARENT_SCOPE)
endif()
##
## Zaber
##
set(zaber_ok TRUE)
DIR_NOT_EMPTY(zaber zaber_ok)
if(${zaber_ok})
add_library(Zaber SHARED)
target_include_directories(Zaber PUBLIC zaber)
target_sources(Zaber
PRIVATE
zaber/za_serial.c
)
set(ZABER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/zaber PARENT_SCOPE)
set(ZABER_FOUND TRUE PARENT_SCOPE)
else()
message(STATUS "zaber directory is empty")
set(ZABER_FOUND FALSE PARENT_SCOPE)
endif()
Subproject commit e2e71cdc11fb5e2fb6e9147a7b9196944a18ef1b
# Check for OpenCV
find_package( OpenCV QUIET )
if ( ${OpenCV_FOUND} )
list(FIND OpenCV_LIB_COMPONENTS "opencv_xfeatures2d" OpenCV_xfeatures2d_FOUND)
if( ${OpenCV_xfeatures2d_FOUND} EQUAL -1 )
set(OpenCV_xfeatures2d_FOUND FALSE)
else()
set(OpenCV_xfeatures2d_FOUND TRUE)
endif()
else()
set(OpenCV_xfeatures2d_FOUND FALSE)
endif()
if ( ${OpenCV_FOUND} AND ${OpenCV_xfeatures2d_FOUND} )
add_library(ImageRec SHARED)
target_sources(ImageRec PRIVATE OpenCVHelper.cpp)
target_link_libraries(ImageRec ${OpenCV_LIBS})
# Tell rest of labRemote that the library exists
set(libImageRec_FOUND TRUE)
else()
message(STATUS "Disabling libImageRec due to missing dependencies:")
message(STATUS " OpenCV_FOUND = ${OpenCV_FOUND}")
message(STATUS " OpenCV-xfeatures2d = ${OpenCV_xfeatures2d_FOUND}")
set(libImageRec_FOUND FALSE)
endif()
#include "OpenCVHelper.h"
#include <iostream>
#include <vector>
#include "opencv2/calib3d/calib3d.hpp" // for findHomography
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/xfeatures2d.hpp"
#include "opencv2/xfeatures2d/nonfree.hpp"
using namespace cv;
using namespace cv::xfeatures2d;
using namespace std;
void OpenCVHelper::SIFT_obj_identify(const Mat& img1, const Mat& img2,
vector<Point2f>& matchedCorners) {
bool debug = false;
Ptr<SIFT> detector = SIFT::create();
// const int minHessian = 400;
// Ptr<SURF> detector = SURF::create(minHessian);
// Ptr<ORB> detector = ORB::create();
vector<KeyPoint> kp1, kp2;
Mat des1, des2;
detector->detectAndCompute(img1, noArray(), kp1, des1);
detector->detectAndCompute(img2, noArray(), kp2, des2);
if (debug) cout << "computed features" << endl;
const int checks = 50;
Ptr<flann::SearchParams> searchParams = new flann::SearchParams(checks);
Ptr<flann::KDTreeIndexParams> indexParams = new flann::KDTreeIndexParams(5);
auto flann = FlannBasedMatcher(indexParams, searchParams);
if (debug) cout << "created FLANN Matcher" << endl;
vector<vector<DMatch> > matches;
flann.knnMatch(des1, des2, matches, 2);
vector<DMatch> good_matches;
// perform a ratio test.
const float minRatio = 1. / 1.5;
for (int i = 0; i < (int)matches.size(); i++) {
const DMatch& bestMatch = matches[i][0];
const DMatch& betterMatch = matches[i][1];
float distanceRatio = bestMatch.distance / betterMatch.distance;
if (distanceRatio < minRatio) {
good_matches.push_back(bestMatch);
}
}
if (debug) cout << "found good matches" << endl;
const int min_match_count = 10;
if (good_matches.size() > min_match_count) {
vector<Point2f> src_pts;
vector<Point2f> dst_pts;
for (int i = 0; i < (int)good_matches.size(); i++) {
src_pts.push_back(kp1[good_matches[i].queryIdx].pt);
dst_pts.push_back(kp2[good_matches[i].trainIdx].pt);
}
if (debug) cout << "created source and destination points" << endl;
Mat H = findHomography(src_pts, dst_pts, cv::RANSAC, 5.0);
//-- Get the corners from the img1 (the object to be "detected")
vector<Point2f> obj_corners(4);
obj_corners[0] = cvPoint(0, 0);
obj_corners[1] = cvPoint(img1.cols, 0);
obj_corners[2] = cvPoint(img1.cols, img1.rows);
obj_corners[3] = cvPoint(0, img1.rows);
// vector<Point2f> scene_corners(4);
if (debug) cout << "before the transformation" << endl;
try {
perspectiveTransform(obj_corners, matchedCorners, H);
} catch (cv::Exception e) {
;
}
} else {
cout << "Found less than " << min_match_count << " matches" << endl;
}
if (debug) cout << "Finished" << endl;
return;
}
#ifndef __OpenCVHelper_H__
#define __OpenCVHelper_H__
#include "opencv2/core/core.hpp"
namespace OpenCVHelper {
void SIFT_obj_identify(const cv::Mat& img1, const cv::Mat& img2,
std::vector<cv::Point2f>& matchedCorners);
};
#endif
if(NOT ${ZABER_FOUND})
message(STATUS "Disabling libWaferProb due to missing dependency (ZABER_FOUND = ${ZABER_FOUND})")
set(libWaferProb_FOUND FALSE PARENT_SCOPE)
return()
endif()
if ( NOT "${LIBGCLIB_FOUND}") # OR NOT ${ZABER_FOUND})
message(STATUS "Disabling libWaferProb due to missing dependencies (LIBGCLIB_FOUND = ${LIBGCLIB_FOUND})")
set(libWaferProb_FOUND FALSE PARENT_SCOPE)
return()
endif()
add_library(WaferProb SHARED)
target_sources(WaferProb
PRIVATE
ControllerBase.cpp
ControllerGalil.cpp
ControllerZaber.cpp
Handler.cpp
Helper.cpp
MotionController.cpp
)
target_link_libraries(WaferProb Zaber ${LIBGCLIB_LIBRARIES})
# Tell rest of labRemote that the library exists
set(libWaferProb_FOUND TRUE PARENT_SCOPE)
#include "ControllerBase.h"
#include <stdio.h>
#include <sstream>
#include "Helper.h"
ControllerBase::ControllerBase() {
status = -1;
m_is_connected = false;
m_z_calibrated = true;
}
ControllerBase::~ControllerBase() {}
void ControllerBase::print_cmd() {
printf(
"MA X 10 --> move X-axis w.r.t home position 10 millimeter\n"
"MR X 10 --> move X-axis w.r.t current position 10 millimeter\n"
"SP X 10 --> set speed in x-axis direction by 10 millimeter/s\n"
"SH --> move to HOME\n"
"SM --> move to center\n"
"FZRANGE --> find maximum and minimum of Z-axis\n"
"FZMIN --> find minimum of Z-axis\n"
"CHECKZMIN --> check the minimum position of Z-axis\n"
"XY_PARK --> park the xy controller \n"
"XY_UNPARK --> unpark the xy controller \n"
"POLL_POS --> poll positions of controllers\n"
"----------------------------------------------------------\n");
}
int ControllerBase::run_cmd(const string& cmd) {
printf("HELLO??? %s\n", cmd.c_str());
int axis = -1;
if (cmd.empty()) {
return axis;
}
vector<string> raw_items;
WaferProb::tokenizeString(cmd, ' ', raw_items);
vector<string> items;
// convert commands to upper case.
for (auto& item : raw_items) {
items.push_back(WaferProb::toUpper(item));
}
const string& action(items[0]);
// Check each case..
if (action == "MA") {
if (items.size() != 3) {
printf(
"argument of MA is wrong\n"
"MA X/Y/Z 10\n");
return axis;
}
axis = WaferProb::axis_number(items[1]);
this->mv_abs(axis, atof(items[2].c_str()));
} else if (action == "MR") {
if (items.size() != 3) {
printf(
"argument of MR is wrong\n"
"MR X/Y/Z 10\n");
return axis;
}
axis = WaferProb::axis_number(items[1]);
this->mv_rel(axis, atof(items[2].c_str()));
} else if (action == "SH") {
this->set_home();
axis = 3;
} else if (action == "SM") {
this->set_center();
axis = 3;
} else if (action == "SP") {
if (items.size() != 3) {
printf(
"argument of SP is wrong\n"
"SP X/Y/Z 10000\n");
return axis;
}
axis = WaferProb::axis_number(items[1]);
this->set_speed(axis, atof(items[2].c_str()));
} else if (action == "FZRANGE") {
this->find_max_min();
} else if (action == "FZMIN") {
this->find_z_min();
} else if (action == "CHECKZMIN") {
this->check_z_min();
} else if (action == "XY_PARK") {
this->xy_park();
} else if (action == "XY_UNPARK") {
this->xy_unpark();
} else {
printf("%s not supported yet!\n", action.c_str());
print_cmd();
}
this->get_position();
return axis;
}
#ifndef __WaferProb_ControllerBase_H__
#define __WaferProb_ControllerBase_H__
/*
* Define a general interface for a controller.
* All length unit is in millimeter
*/
#include <string>
using namespace std;
class ControllerBase {
protected:
int status; // 0 is ok, non-zero indicates problems
bool m_is_connected;
// put it public so it's easy to access...
public:
float m_position[3];
bool m_z_calibrated;
public:
ControllerBase();
virtual ~ControllerBase();
int get_status() { return status; }
bool is_connected() { return m_is_connected; }
// command lines are interpreted by this function.
int run_cmd(const string& cmd);
void print_cmd();
virtual int connect() = 0;
virtual int disconnect() = 0;
virtual int write(const string& cmd) = 0; // send command to device
// unit of length: millimeter
virtual int set_speed(int axis, float value) = 0;
// move w.r.t home-position
virtual int mv_abs(int axis, float value) = 0;
// move w.r.t current-position
virtual int mv_rel(int axis, float value) = 0;
virtual int stop() = 0; // stop motion immediately
virtual int get_position() = 0;
virtual int set_home() = 0;
virtual int set_center() = 0;
virtual void find_max_min() { return; }
virtual void find_z_min() { return; }
virtual void check_z_min() { return; }
virtual bool is_z_calibrated() { return m_z_calibrated; }
virtual int xy_park() { return -1; }
virtual int xy_unpark() { return -1; }
};
#endif
#include "ControllerGalil.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <vector>
#include "Helper.h"
ControllerGalil::ControllerGalil(const char* device_name) {
char device[256];
sprintf(device, "%s --subscribe ALL", device_name);
dn = string(device);
port = 0;
m_position[0] = m_position[1] = m_position[2] = DEFAULT_GALIL_POS;
m_raw_position[0] = m_raw_position[1] = m_raw_position[2] =
DEFAULT_GALIL_POS;
// TO DO: to read in from the text file "z_range.txt"
m_ymax = 600000; // 765253;
m_ymin = -100000; //-364475;
}
ControllerGalil::~ControllerGalil() { disconnect(); }
int ControllerGalil::connect() {
if (m_is_connected) return 0;
printf("%s: connecting to device %s\n", __FUNCTION__, dn.c_str());
if (check(GOpen(dn.c_str(), &port))) {
printf("%s connected\n", dn.c_str());
get_position();
status = 0;
m_is_connected = true;
} else {
printf("%s not connected\n", dn.c_str());
status = 1;
}
return status;
}
int ControllerGalil::disconnect() {
if (port != 0) {
GClose(port);
port = 0;
}
return 0;
}
int ControllerGalil::write(const string& cmd) {
if (port == 0) {
printf("%s is not open\n", dn.c_str());
return -1;
}
char* trimmed;
if (!check(GCmdT(port, cmd.c_str(), buf, sizeof(buf), &trimmed))) {
printf("%s is not recognized\n", cmd.c_str());
return -2;
}
printf("Galil: %s --> %s\n", cmd.c_str(), buf);
poll_position();
return 0;
}
string* ControllerGalil::write_with_reply(const string& cmd) {
if (port == 0) {
printf("%s is not open\n", dn.c_str());
return NULL;
}
char* trimmed;
if (!check(GCmdT(port, cmd.c_str(), buf, sizeof(buf), &trimmed))) {
printf("%s is not recognized\n", cmd.c_str());
return NULL;
}
printf("Galil: %s --> %s\n", cmd.c_str(), buf);
string* result = new string(buf);
poll_position();
return result;
}
int ControllerGalil::stop() {
int status = write("AB");
get_position();
return status;
}
int ControllerGalil::set_speed(int axis, float sp) {
int steps = convert_mm_to_turns(sp);
string cmd = generate_cmd("SP", axis, steps);
return write(cmd);
}
int ControllerGalil::mv_abs(int axis, float value) {
int steps = convert_mm_to_turns(value - m_position[axis]);
string cmd = generate_cmd("PR", axis, steps);
write(cmd);
make_a_move(axis);
return 0;
}
int ControllerGalil::mv_rel(int axis, float value) {
int steps = convert_mm_to_turns(value);
string cmd = generate_cmd("PR", axis, steps);
printf("%s\n", cmd.c_str());
write(cmd);
make_a_move(axis);
return 0;
}
int ControllerGalil::get_position() {
if (port == 0) return -1;
char* trimmed;
GCmdT(port, "RP", buf, sizeof(buf), &trimmed);
string data(trimmed);
printf("Galic: RP --> %s\n", trimmed);
vector<string> raw_items;
WaferProb::tokenizeString(data, ',', raw_items);
for (int i = 0; i < 3; i++) {
float raw_pos = atof(raw_items.at(i).c_str());
m_raw_position[i] = raw_pos;
m_position[i] = convert_turns_to_mm(raw_pos);
}
return 0;
}
int ControllerGalil::set_home() { return 0; }
int ControllerGalil::set_center() { return 0; }
string ControllerGalil::generate_cmd(const char* cmd, int axis, int steps) {
char val_str[256];
sprintf(val_str, "%d", steps);
string cmd_val(",,");
cmd_val.insert(axis, val_str);
char res_str[256];
sprintf(res_str, "%s %s", cmd, cmd_val.c_str());
return string(res_str);
}
void ControllerGalil::make_a_move(int axis) {
if (axis == 2 && !m_z_calibrated) {
printf("ERROR, Z-axis is not calibrated!");
return;
}
char mv[256];
char axis_name = axis_index_to_name(axis);
sprintf(mv, "BG %c", axis_name);
write(mv);
// block until motion is complete.
GMotionComplete(port, string(1, axis_name).c_str());
get_position();
}
void ControllerGalil::find_max_min() {
m_z_calibrated = true;
int axis = 2;
set_speed(axis, 1); // second argument: mm per s
string cmd = generate_cmd("PA", axis, 1000000);
write(cmd);
make_a_move(axis);
get_position();
m_ymax = m_raw_position[2];
printf("HELLO: %.2f\n", m_ymax);
string cmd2 = generate_cmd("PA", axis, -1000000);
write(cmd2);
make_a_move(axis);
get_position();
m_ymin = m_raw_position[2];
printf("range of z-axis in turns: [%.2f, %.2f]\n", m_ymin, m_ymax);
// float quarter = (m_ymax - m_ymin)/4;
// if (quarter<0) quarter = -quarter;
// float quarter_up = m_ymin + quarter;
// Move quarter of the range up from the minimum
// string cmd3 = generate_cmd("PA", axis, quarter_up);
// write(cmd3);
// make_a_move(axis);
// get_position();
}
void ControllerGalil::find_z_min() {
m_z_calibrated = true;
int axis = 2;
set_speed(axis, 1);
string cmd = generate_cmd("PA", axis, -1000000);
write(cmd);
make_a_move(axis);
get_position();
m_ymin = m_raw_position[2];
printf("HELLO: %.2f\n", m_ymin);
}
void ControllerGalil::check_z_min() {
int axis = 2;
string cmd2 = generate_cmd("PA", axis, -1000000);
write(cmd2);
make_a_move(axis);
get_position();
if (m_position[2] != 0) m_z_calibrated = false;
}
void ControllerGalil::poll_position() {
string *reply, *last_reply;
reply = write_with_reply("TP");
sleep(1);
last_reply = write_with_reply("TP");
while (*last_reply != *reply) {
reply = write_with_reply("TP");
sleep(1);
last_reply = write_with_reply("TP");
}
}
#ifndef __WaferProb_ControllerGalil_H__
#define __WaferProb_ControllerGalil_H__
#ifndef I_7B02A40E_869B_4650_A5A8_859F0A6E3325
#define I_7B02A40E_869B_4650_A5A8_859F0A6E3325
#endif
#include "gclib.h"
#include "gclibo.h"
#define GALIL_EXAMPLE_OK G_NO_ERROR // return code for correct code execution
#define GALIL_EXAMPLE_ERROR -100 // return code for error in example code
#define DEFAULT_GALIL_POS -2
#include <string>
#include "ControllerBase.h"
using namespace std;
class ControllerGalil : public ControllerBase {
private:
GCon port; // port connected to Galil
string dn; // device name
public:
ControllerGalil(const char* device_name);
~ControllerGalil();
int connect();
int disconnect();
int write(const string& cmd);
string* write_with_reply(const string& cmd);
int set_speed(int axis, float sp);
int mv_abs(int axis, float value);
int mv_rel(int axis, float value);
int stop();
int get_position();
int get_speed();
int set_home();
int set_center();
void find_max_min();
void find_z_min();
void check_z_min();
void poll_position();
public:
// 14.2 mili-meter is the total distance the Z-axis can travel.
// project the absolute turns (or position) to the 14.2 mm length
// lowest position would be zero, while highest position is 14.2 mm.
float m_raw_position[3];
float m_ymax; // turns at the top, --> 14.2mm
float m_ymin; // turns at the bottom, --> 0
private:
inline bool check(GReturn rc) { return (rc == G_NO_ERROR); }
int convert_mm_to_turns(float value) {
// value is the relative distance.
return value * (m_ymax - m_ymin) / 14.2;
}
float convert_turns_to_mm(float turns) {
float res = 14.2 * (turns - m_ymin) / (m_ymax - m_ymin);
res = (int)(res * 1000) / 1000.;
return res;
}
char axis_index_to_name(int axis) {
// ABC is for XYZ!
// axis starts from 0 to 2;
return 'A' + axis;
}
string generate_cmd(const char* cmd, int axis, int steps);
void make_a_move(int axis);
char buf[1024];
};
#endif
#include "ControllerZaber.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include "Helper.h"
using namespace std;
ControllerZaber::ControllerZaber(const char* device_name)
: ControllerBase(), dn(device_name) {
port = -1;
m_position[0] = m_position[1] = DEFAULT_ZABER_POS;
}
int ControllerZaber::connect() {
if (m_is_connected) return 0;
printf("%s:connecting to device %s\n", __FUNCTION__, dn.c_str());
if (check(za_connect(&port, dn.c_str()))) {
printf("%s connected\n", dn.c_str());
status = 0;
m_is_connected = true;
unpark();
} else {
printf("%s not connected\n", dn.c_str());
status = 1;
}
return status;
}
ControllerZaber::~ControllerZaber() { disconnect(); }
int ControllerZaber::disconnect() {
if (port > 0) {
park();
za_disconnect(port);
port = -1;
}
return 0;
}
int ControllerZaber::write(const string& cmd) {
if (port < 0) {
printf("%s is not open!\n", dn.c_str());
return -1;
}
za_send(port, cmd.c_str());
char reply[256] = {0};
za_receive(port, reply, sizeof(reply));
printf("%s -> %s\n", cmd.c_str(), reply);
poll_until_idle();
return 0;
}
string* ControllerZaber::write_with_reply(const string& cmd) {
if (port < 0) {
printf("%s is not open!", dn.c_str());
return NULL;
}
char reply[256] = {0};
za_send(port, cmd.c_str());
za_receive(port, reply, sizeof(reply));
printf("%s -> %s\n", cmd.c_str(), reply);
string* result = new string(reply);
poll_until_idle();
return result;
}
int ControllerZaber::set_speed(int axis, float value) {
int steps = convert_mm_to_turns(value);
char cmd[256];
sprintf(cmd, "/1 %d set maxspeed %d\n", axis, steps);
return write(cmd);
}
int ControllerZaber::mv_abs(int axis, float value) {
int steps = convert_mm_to_turns(value);
char cmd[256];
sprintf(cmd, "/1 %d move abs %d\n", axis, steps);
return write(cmd);
}
int ControllerZaber::mv_rel(int axis, float value) {
int steps = convert_mm_to_turns(value);
char cmd[256];
sprintf(cmd, "/1 %d move rel %d\n", axis, steps);
return write(cmd);
}
int ControllerZaber::get_position() {
if (port < 0) {
return 1;
}
char cmd[256];
sprintf(cmd, "/1 get pos\n");
string* rpy = write_with_reply(cmd);
if (rpy == NULL) return 2;
// analyze the reply.
struct za_reply decoded_reply;
za_decode(&decoded_reply, const_cast<char*>(rpy->c_str()));
// analyze response data.
string data(decoded_reply.response_data);
if (strncmp(decoded_reply.response_data, "BADDATA", 7) == 0) {
m_position[0] = m_position[1] = DEFAULT_ZABER_POS;
} else {
vector<string> raw_items;
WaferProb::tokenizeString(data, ' ', raw_items);
for (int i = 0; i < (int)raw_items.size(); i++) {
m_position[i] =
(int)(convert_turns_to_mm(atof(raw_items.at(i).c_str())) *
1000) /
1000.;
}
}
return 0;
}
int ControllerZaber::set_home() { return write("/home\n"); }
int ControllerZaber::set_center() {
// 1952000/2. = 976000
return write("/move abs 976000\n");
}
int ControllerZaber::park() {
int status = write("/tools parking park\n");
if (status == 0) {
printf("%s is parked\n", dn.c_str());
}
return status;
}
int ControllerZaber::unpark() {
int status = write("/tools parking unpark\n");
if (status == 0) {
printf("%s is unparked\n", dn.c_str());
} else {
printf("%s cannot unparked\n", dn.c_str());
}
return status;
}
int ControllerZaber::stop() {
int status = write("/estop\n");
get_position();
return status;
}
int ControllerZaber::convert_mm_to_turns(float value) {
// value should be in millimeter.
// turns: 1952000 turns
// length: 305 millimeter
return value * 6400;
}
float ControllerZaber::convert_turns_to_mm(float turns) {
return turns * 305. / 1952000.;
}
void ControllerZaber::poll_until_idle() {
char reply[256] = {0};
char pos_reply[256] = {0};
struct za_reply decoded_reply;
const struct timespec ts = {0, 100000000}; /* 100mil nanosec = 100ms */
/* We use za_decode() to decode this string into more manageable parts,
* sorting them into the fields of a za_reply struct, then we test
* the device_status field. Possible values for device_status are "IDLE"
* and "BUSY". */
int count = 0;
for (;;) {
za_send(port, "/\n");
za_receive(port, reply, sizeof(reply));
za_decode(&decoded_reply, reply);
if (strncmp(decoded_reply.device_status, "BUSY", 4) == 0) {
nanosleep(&ts, NULL); /* If we're busy, wait then try again */
} else {
break;
}
za_send(port, "/get pos\n");
za_receive(port, pos_reply, sizeof(pos_reply));
printf(pos_reply);
printf("\n");
if (count > 1000) {
break;
} else {
count++;
}
}
}
const char* ControllerZaber::device_name() { return dn.c_str(); }
#ifndef __WaferProb_ControllerZaber_H__
#define __WaferProb_ControllerZaber_H__
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 199309L
#endif
#include <string>
#include "ControllerBase.h"
#include "za_serial.h" // Driver of Zaber
using namespace std;
class ControllerZaber : public ControllerBase {
private:
z_port port; // port connected to Zaber
string dn; // device name
public: // implement controller's interface
ControllerZaber(const char* device_name);
~ControllerZaber();
int connect();
int disconnect();
string* write_with_reply(const string& cmd);
int write(const string& cmd);
int set_speed(int axis, float sp);
int mv_abs(int axis, float value); // move w.r.t home-position
int mv_rel(int axis, float value); // move w.r.t current-position
int stop();
// get current position
int get_position();
int get_speed();
int set_home();
int set_center();
const char* device_name();
public:
// park the device: lock it so that when powered up,
// don't need to homed.
int park();
int unpark();
private:
// convert mili-meter to number of turns/steps
int convert_mm_to_turns(float value);
float convert_turns_to_mm(float turns);
inline bool check(int rc) {
// if(rc != Z_SUCCESS) throw rc;
return (rc == Z_SUCCESS);
}
void poll_until_idle();
};
#endif
#include "Handler.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // for sleep()
#include <vector>
#include "Helper.h"
Handler::Handler() {
ctrl = new MotionController("/dev/ttyACM0");
ctrl->connect();
}
Handler::~Handler() {
ctrl->disconnect();
delete ctrl;
}
void Handler::print_cmd() {
printf(
"MA X 10 --> move X-axis w.r.t home position 10 millimeter\n"
"MR X 10 --> move X-axis w.r.t current position 10 millimeter\n"
"SP X 10 --> set speed in x-axis direction by 10 millimeter/s\n"
"SH --> move to HOME\n"
"SM --> move to center\n"
"SZC --> set needles contact with chip\n"
"SZS --> set needles separate from chip\n"
"SZD 10 --> set distance in z-axis in order to separate needle and "
"chip.\n"
"TESTX --> move x from 0 to 305 with pre-defined steps\n"
"----------------------------------------------------------\n"
// "MVC X P --> move to positive x-axis direction, continuously\n"
// "MVC X N --> move to negative x-axis direction, continuously\n"
);
}
void Handler::write(const string& cmd) {
float unit_scale = 1000.;
if (cmd.empty()) {
return;
}
vector<string> raw_items;
WaferProb::tokenizeString(cmd, ' ', raw_items);
vector<string> items;
// convert commands to uppercase
for (auto& item : raw_items) {
items.push_back(WaferProb::toUpper(item));
}
const string& action(items[0]);
// Check each case..
if (action == "MA") {
if (items.size() != 3) {
printf(
"argument of MA is wrong\n"
"MA X/Y/Z 10\n");
return;
}
int axis = WaferProb::axis_number(items[1]);
ctrl->mv_abs(axis, unit_scale * atof(items[2].c_str()));
} else if (action == "MR") {
if (items.size() != 3) {
printf(
"argument of MR is wrong\n"
"MR X/Y/Z 10\n");
return;
}
int axis = WaferProb::axis_number(items[1]);
ctrl->mv_rel(axis, unit_scale * atof(items[2].c_str()));
} else if (action == "SH") {
ctrl->set_home();
} else if (action == "SM") {
ctrl->set_center();
} else if (action == "SP") {
if (items.size() != 3) {
printf(
"argument of SP is wrong\n"
"SP X/Y/Z 10000\n");
return;
}
int axis = WaferProb::axis_number(items[1]);
ctrl->set_speed(axis, unit_scale * atof(items[2].c_str()));
} else if (action == "TEST") {
vector<int> steps{20, 46, 73, 100, 126, 152, 179, 206, 226};
if (items.size() != 2) {
printf(
"argument of TEST is wrong\n"
"TEST X/Y \n");
return;
}
int axis = WaferProb::axis_number(items[1]);
for (int step : steps) {
ctrl->mv_abs(axis, unit_scale * step);
sleep(10);
}
} else {
printf("%s not supported yet!\n", action.c_str());
// print_cmd();
}
}
#ifndef __WaferProb_Handler_H_
#define __WaferProb_Handler_H_
/*
* A wrapper of all controls.
* define our own commands to control the station.
* Underlying implementations are taken care by MotionController
* example commands:
* MA X 10 // move X-axis w.r.t home position 10 micro-meter
* MR X 10 // move X-axis w.r.t current position 10 micro-meter
* SP X 10 // set speed in x-axis direction by 10 micro-meter/s
* SH // set current position as HOME
* SC // set needles contact with chip
* SS // set needles separate from chip
* SDZ 10 // set distance in z-axis in order to separate needle and chip.
*/
#include <string>
#include <vector>
#include "MotionController.h"
using namespace std;
class Handler {
private:
MotionController* ctrl;
// vector<string>* supported_actions;
public:
Handler();
~Handler();
void write(const string& cmd);
void print_cmd();
};
#endif
#include "Helper.h"
#include <locale>
#include <sstream>
namespace WaferProb {
void tokenizeString(const string& str, char delim, vector<string>& tokens) {
tokens.clear();
istringstream iss(str);
string token;
while (getline(iss, token, delim)) {
// boost::algorithm::trim(token);
tokens.push_back(token);
}
}
string toUpper(const string& str) {
std::locale loc;
string new_str(str);
for (string::size_type i = 0; i < str.length(); ++i) {
new_str[i] = std::toupper(str[i], loc);
}
return new_str;
}
int axis_number(const string& axis_str) {
// need to do better than this!
int axis = -1;
if (axis_str == "X" or axis_str == "x") {
axis = 0;
}
if (axis_str == "Y" or axis_str == "y") {
axis = 1;
}
if (axis_str == "Z" or axis_str == "z") {
axis = 2;
}
if (axis < 0) {
printf("Axis is wrong. Use X instead.");
axis = 0;
}
return axis;
}
} // namespace WaferProb
#ifndef _WaferProbe_helper_H_
#define _WaferProbe_helper_H_
#include <string>
#include <vector>
using namespace std;
// define some global code.
#define DEFAULT_ZABER_POS -3
namespace WaferProb {
void tokenizeString(const string& str, char delim, vector<string>& tokens);
string toUpper(const string& str);
int axis_number(const string& axis_str);
} // namespace WaferProb
#endif
#include "MotionController.h"
#include <stdio.h>
#include <unistd.h> // for sleep()
#include <sstream>
#include <string>
#include <vector>
#include "Helper.h"
using namespace std;
MotionController::MotionController(const char* dn_1) : ControllerBase() {
xy_ctrl = new ControllerZaber(dn_1);
z_ctrl = new ControllerGalil("192.168.1.30");
m_position[0] = m_position[1] = m_position[2] = -1;
}
MotionController::~MotionController() { disconnect(); }
int MotionController::connect() {
if (xy_ctrl->connect() != 0) {
return 1;
}
// connect z station
if (z_ctrl->connect() != 0) {
return 2;
}
this->get_position();
return 0;
}
int MotionController::disconnect() {
xy_ctrl->disconnect();
z_ctrl->disconnect();
return 0;
}
int MotionController::set_speed(int axis, float sp) {
if (axis == 0 || axis == 1) { // x-y-axis
xy_ctrl->set_speed(axis + 1, sp);
} else if (axis == 2) {
z_ctrl->set_speed(axis, sp);
} else {
;
}
return 0;
}
int MotionController::mv_abs(int axis, float value) {
if (axis == 0 || axis == 1) {
xy_ctrl->mv_abs(axis + 1, value);
} else if (axis == 2) {
z_ctrl->mv_abs(axis, value);
} else {
;
}
return 0;
}
int MotionController::mv_rel(int axis, float value) {
if (axis == 0 || axis == 1) {
xy_ctrl->mv_rel(axis + 1, value);
} else if (axis == 2) {
z_ctrl->mv_rel(axis, value);
} else {
}
return 0;
}
int MotionController::stop() {
xy_ctrl->stop();
z_ctrl->stop();
return 0;
}
int MotionController::get_position() {
get_pos_xy();
get_pos_z();
return 0;
}
int MotionController::get_pos_xy() {
xy_ctrl->get_position();
m_position[0] = xy_ctrl->m_position[0];
m_position[1] = xy_ctrl->m_position[1];
printf("xy position: %.2f, %.2f\n", m_position[0], m_position[1]);
return 0;
}
int MotionController::get_pos_z() {
z_ctrl->get_position();
m_position[2] = z_ctrl->m_position[2];
return 0;
}
int MotionController::get_position(int axis) {
get_position();
return m_position[axis];
}
int MotionController::write(int axis, const string& cmd) {
if (axis == 0 || axis == 1) {
xy_ctrl->write(cmd);
} else if (axis == 2) {
z_ctrl->write(cmd);
} else {
}
return 0;
}
int MotionController::set_home() { return xy_ctrl->set_home(); }
int MotionController::set_center() { return xy_ctrl->set_center(); }
void MotionController::find_max_min() { z_ctrl->find_max_min(); }
void MotionController::find_z_min() { z_ctrl->find_z_min(); }
void MotionController::check_z_min() { z_ctrl->check_z_min(); }
int MotionController::xy_park() { return xy_ctrl->park(); }
int MotionController::xy_unpark() { return xy_ctrl->unpark(); }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment