Skip to content

Instantly share code, notes, and snippets.

@machmotioncommunity
Created September 6, 2019 16:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save machmotioncommunity/169248a95c2213458cb1d9ca9d26e9e6 to your computer and use it in GitHub Desktop.
Save machmotioncommunity/169248a95c2213458cb1d9ca9d26e9e6 to your computer and use it in GitHub Desktop.
proof-of-concept of homing; tweaking parameters for RSI API
//
// Attempt to home to an arbitrary I/O.
// Everything in this proof-of-concept is hardcoded (upstairs test station)
//
#include <iostream>
#include <iomanip>
#include <string>
#include <cstdint>
#include <sstream>
#include <chrono>
#include <thread>
#include <cmath>
// convenience for string/object-stringified concatenation.
template<typename T>
void __cat(std::stringstream& tgt, const T& only) {
tgt << only;
}
// recursive function
template<typename T, typename... R>
void __cat(std::stringstream& tgt, const T& first, R... rest) {
tgt << first;
__cat(tgt, rest...);
}
// entry point for recursive call.
template<typename... R>
std::string _cat(R... rest) {
std::stringstream t;
__cat(t, rest...);
return t.str();
}
inline std::string _cat() { return std::string(); }
#define FIXED(d,p,w) _cat(std::setw(w),std::setprecision(p),std::fixed,d)
#define PTR_ADDR(p) _cat("0x",std::hex,(void*)p)
#define RSIAPP
// (20190827;8.1.3) rsi.h generates warnings (needless "typedef" before an enum).
#pragma warning( push )
#pragma warning( disable : 4091 )
#include <rsi.h>
#pragma warning( pop )
namespace r = RSI::RapidCode; // Don't hide the namespace, just abbreviate it.
#pragma comment(lib,"rsiqvc.lib")
#define CONTEXT() _cat("; [" , __FUNCTION__ , "] [" , __FILE__ , ":" , __LINE__ , "]")
#define EXCEPTION(...) std::exception(_cat(__VA_ARGS__,"; ",CONTEXT()).c_str())
inline std::string as_hex_string( const void* bytes, size_t size ) {
std::stringstream buf;
for (size_t i=0; i<size; i++)
buf << std::hex << std::setw(2) << std::setfill('0') << (uint16_t)(((const char*)bytes)[i]);
return buf.str();
}
const int TARGET_AXIS_IDX = 0; // drive to home
const double AXIS_COUNTS_PER_UNIT = 1<<17; // 1 PUU = 1 revolution
const int TARGET_IO_NODE_IDX = 2; // node hosting I/O
const int TARGET_IO_INPUT_IDX = 6; // (general) I/O index on node
// just for comparison (host/FW addrs)
const int TARGET_IO_NETWORK_IDX = 44;
const int TARGET_IO_NETWORK_BIT_INDEX = 1;
const r::RSIHomeMethod HOMING_METHOD = r::RSIHomeMethodRISING_HOME;
//const r::RSIHomeMethod HOMING_METHOD = r::RSIHomeMethodNEGATIVE_LIMIT;
//const r::RSIHomeMethod HOMING_METHOD = r::RSIHomeMethodPOSITIVE_LIMIT;
//const r::RSIHomeMethod HOMING_METHOD = r::RSIHomeMethodPOSITIVE_LIMIT_THEN_LEFT_INDEX;
//const r::RSIHomeMethod HOMING_METHOD = r::RSIHomeMethodRISING_HOME_POSITIVE_START;
const double HOME_OFFSET = 0.0;
const double HOME_VELOCITY = 1; // 60 RPM -> rev/sec
const double HOME_ACCEL = 1; // 60 RPM/sec -> rev/sec
const double HOME_DECEL = HOME_ACCEL; // same for now
const double HOME_JERK_PCT = 100.0;
const r::RSIAction HOME_ACTION = r::RSIActionSTOP; // default
// I don't want to use this.
const double HOME_TRAVEL_DISTANCE = -100.0; // 0; // 1000.0;
const bool HOME_MOVE_TO_ZERO = true; // default
#define DO_TRACE_HOME
//#define USE_DEPRECATED
void run_test() {
const char* rsi_val = getenv("RSI");
if (rsi_val == NULL) {
throw EXCEPTION("The environment variable RSI must be defined.\n");
}
r::MotionController* mc;
try {
mc = r::MotionController::CreateFromSoftware(const_cast<char*>(rsi_val));
}
catch ( const std::exception& e ) {
throw EXCEPTION("Error instantiating MotionController object: ",e.what(),"\n");
}
// Network:Operational
try {
size_t attempts = 0;
size_t max_attempts = 3;
while (mc->NetworkStateGet() != r::RSINetworkStateOPERATIONAL) {
if (attempts > max_attempts) {
throw EXCEPTION("Maximum # attempts (",max_attempts,") to start the network failed. Aborting...\n");
}
mc->NetworkStart();
}
}
catch ( const std::exception& e ) {
throw EXCEPTION("Exception raised attempting to start the EtherCAT network: ",e.what(),"\n");
}
auto axis_count = mc->AxisCountGet();
if (axis_count < 1) {
throw EXCEPTION("No axes found on the network: ",axis_count,"\n");
}
// axis to home
r::Axis* axis = mc->AxisGet(TARGET_AXIS_IDX);
std::cout << "Axis #" << axis->DriveIndexGet() << "\n "
<< axis->NetworkNode->NameGet() << ": " << axis->NetworkNode->VendorIdGet() << "/" << axis->NetworkNode->ProductCodeGet() << "\n";
#ifdef DO_TRACE_HOME
axis->TraceFileSet("RapidCodeHomeTrace.txt");
axis->TraceMaskOffSet(r::RSITraceALL);
axis->Trace(true);
#endif // DO_TRACE_HOME
axis->UserUnitsSet(AXIS_COUNTS_PER_UNIT);
double puu = axis->UserUnitsGet();
std::cout << " PUU: " << puu << "\n";
// I/O
r::IO* io_node = mc->IOGet(TARGET_IO_NODE_IDX);
r::IOPoint* io_point = r::IOPoint::CreateDigitalInput(io_node,TARGET_IO_INPUT_IDX);
//
// Configure Homing
// parameters: method, speed/accel, ...
//
axis->HomeMethodSet(HOMING_METHOD);
std::cout << " Homing Method: " << static_cast<int32_t>(axis->HomeMethodGet()) << "\n";
axis->HomeOffsetSet(HOME_OFFSET);
std::cout << " Home Offset: " << axis->HomeOffsetGet() << "\n";
// There may be multiple velocities to set for some homing methonds.
// virtual void HomeVelocitySet(RSIHomeStage homeStage, double velocity) = 0 ;
//
// RSIHomeStageSTAGE_ONE = 0, ///< Searching Move to Find Limit. (ie Home Active)
// RSIHomeStageSTAGE_TWO = 1, ///< Searching Move from Limit Active to Limit Edge. (ie Returning to Home Edge)
// RSIHomeStageSTAGE_THREE = 2, ///< Searching Move from Edge to Index.
// RSIHomeStageSTAGE_FOUR = 3, ///< Covers motion to Zero after HomeOffsetSet has been used.
#ifdef USE_DEPRECATED
std::cout << "Using Deprecated APIs...\n";
axis->HomeVelocitySet(HOME_VELOCITY);
std::cout << " Home Velocity: " << axis->HomeVelocityGet() << " (PUU/sec)\n";
axis->HomeSlowVelocitySet(HOME_VELOCITY);
std::cout << " Home Slow Velocity: " << axis->HomeSlowVelocityGet() << " (PUU/sec)\n";
axis->HomeAccelerationSet(HOME_ACCEL);
std::cout << " Home Acceleration: " << axis->HomeAccelerationGet() << " (PUU/sec/sec)\n";
axis->HomeDecelerationSet(HOME_DECEL);
std::cout << " Home Deceleration: " << axis->HomeDecelerationGet() << " (PUU/sec/sec)\n";
axis->HomeJerkPercentSet(HOME_JERK_PCT);
std::cout << " Home Jerk Percent: " << axis->HomeJerkPercentGet() << " %\n";
#else // USE_DEPRECATED
std::cout << "Using New APIs...\n";
for (auto& stage : std::vector<r::RSIHomeStage>{r::RSIHomeStageSTAGE_ONE, r::RSIHomeStageSTAGE_TWO,
r::RSIHomeStageSTAGE_THREE, r::RSIHomeStageSTAGE_FOUR}) {
std::cout << " Homing Stage " << stage << ":\n";
axis->HomeVelocitySet(stage,HOME_VELOCITY);
std::cout << " Home Velocity: " << axis->HomeVelocityGet(stage) << " (PUU/sec)\n";
axis->HomeAccelerationSet(stage,HOME_ACCEL);
std::cout << " Home Acceleration: " << axis->HomeAccelerationGet(stage) << " (PUU/sec/sec)\n";
axis->HomeDecelerationSet(stage,HOME_DECEL);
std::cout << " Home Deceleration: " << axis->HomeDecelerationGet(stage) << " (PUU/sec/sec)\n";
axis->HomeJerkPercentSet(stage,HOME_JERK_PCT);
std::cout << " Home Jerk Percent: " << axis->HomeJerkPercentGet(stage) << " %\n";
axis->HomeTravelDistanceSet(stage, HOME_TRAVEL_DISTANCE);
std::cout << " (using) Home Travel Distance: " << HOME_TRAVEL_DISTANCE << " (PUU)\n";
}
#endif // USE_DEPRECATED
//axis->HomeBehaviorSet(HOME_ACTION);
//std::cout << " Home Behavior: " << axis->HomeBehaviorGet() << "\n"; // 2: stop
// I don't think these will be used for this test.
axis->HomeActionSet(HOME_ACTION);
std::cout << " Home Action: " << axis->HomeActionGet() << "\n";
//axis->HardwareNegLimitActionSet(HOME_ACTION);
//std::cout << " Neg Limit Action: " << axis->HardwareNegLimitActionGet() << "\n";
//axis->HardwarePosLimitActionSet(HOME_ACTION);
//std::cout << " Pos Limit Action: " << axis->HardwarePosLimitActionGet() << "\n";
axis->ErrorLimitActionSet(r::RSIActionNONE);
std::cout << " Position Error Action: " << axis->ErrorLimitActionGet() << "\n";
// limits of travel
// I/O used for home switch
int32_t iopoint_bit_num = static_cast<int32_t>(floor((log(io_point->MaskGet()) / log(2)) + .5));
auto use_addr = io_point->AddressGet();
int32_t use_bit_num = iopoint_bit_num;
// use network I/O
//use_addr = mc->NetworkInputAddressGet(TARGET_IO_NETWORK_IDX);
//use_bit_num = 0;
std::cout << "\nHome Switch I/O: "
<< io_node->NetworkNode->NameGet() << ": " << io_node->NetworkNode->VendorIdGet() << "/" << io_node->NetworkNode->ProductCodeGet()
<< " #" << TARGET_IO_INPUT_IDX << "/Bit-" << iopoint_bit_num << "\n"
" Host(" << PTR_ADDR(io_point->AddressGet()) << ")"
" F/W(" << PTR_ADDR(mc->FirmwareAddressGet(io_point->AddressGet())) << ")\n"
<< " Mask(" << PTR_ADDR(io_point->MaskGet()) << ") Digital?(" << io_point->IsDigital() << ") IsOutput?(" << io_point->IsOutput() << ")\n"
<< " State: " << (io_point->Get()?"SET":"clear")
<< "\n"
<< " (-~-> Node) " << "Host(" << PTR_ADDR(io_node->NetworkNode->DigitalInAddressGet(TARGET_IO_INPUT_IDX)) << ")"
" F/W(" << PTR_ADDR(mc->FirmwareAddressGet(io_node->NetworkNode->DigitalInAddressGet(TARGET_IO_INPUT_IDX))) << ")"
" Mask(" << PTR_ADDR(io_node->NetworkNode->DigitalInMaskGet(TARGET_IO_INPUT_IDX)) << ")"
<< "\n"
<< " (-~-> NetworkInput) " << " Host(" << PTR_ADDR(mc->NetworkInputAddressGet(TARGET_IO_NETWORK_IDX)) << ")"
" F/W(" << PTR_ADDR(mc->FirmwareAddressGet(mc->NetworkInputAddressGet(TARGET_IO_NETWORK_IDX))) << ")"
<< "\n"
<< " Using: Host(" << PTR_ADDR(use_addr) << ") F/W(" << PTR_ADDR(mc->FirmwareAddressGet(use_addr)) << "), Bit #" << use_bit_num << "\n"
;
axis->HomeLimitCustomConfigSet(use_addr,use_bit_num);
// prepare for homing
axis->Abort();
axis->ClearFaults();
axis->AmpEnableSet(true);
// Home the axis.
std::cout << "\n\nHoming...\n";
std::cout.flush();
double home_start_pos = axis->ActualPositionGet(); // PUU
auto home_started_time = std::chrono::high_resolution_clock::now();
try {
// Axis::Home() is synchronous. We want to monitor things while it's taking place.
bool abort = false;
std::thread homer([axis,&abort](){
try {
std::cout << " -->\n";
std::cout.flush();
axis->Home(HOME_MOVE_TO_ZERO);
}
catch (const std::exception& e) {
std::cerr << "Exception raised in homing: " << e.what() << "\n";
abort = true;
}
});
// status: monitor distance moved, velocity, position
std::string prev;
while (! axis->HomeStateGet() && ! abort) {
// progress indicator
double curr_pos = axis->ActualPositionGet();
double home_traveled = curr_pos - home_start_pos;
auto status = _cat("D:",FIXED(home_traveled,2,8),
" V:",FIXED(axis->ActualVelocityGet(),2,8),
" IO:",(io_point->Get()?"ON":"off"));
if (prev.size() > 0) {
std::cout << std::string(prev.size(),'\b');
}
std::cout << status;
std::cout.flush();
prev = status;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
auto home_finished_time = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(home_finished_time-home_started_time).count()/1000.0;
if (!abort)
std::cout << "Homed: " << FIXED(elapsed,3,0) << " seconds.\n";
else
std::cout << "Homing ended. " << FIXED(elapsed,3,0) << " seconds.\n";
// cleanup
homer.join();
}
catch ( const std::exception& e ) {
auto elapsed = std::chrono::high_resolution_clock::now() - home_started_time;
throw EXCEPTION("Error during homing: ",e.what(),"\n"
" +",(std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count()/1000.0)," sec");
}
#ifdef DO_TRACE_HOME
axis->Trace(false);
#endif // DO_TRACE_HOME
}
int main( int argc, const char** argv ) {
try {
run_test();
}
catch ( const std::exception& e ) {
std::cerr << "Exception raised running test: " << e.what() << "\n";
return 1;
}
std::cout << "Finished!\n";
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment