Enumerating a MultiAxis

Is there a correct way to enumerate a multi axis (i.e. list the axes mapped to it)? Both flavors of RapidSetup are able to do it, but when I try from C++, it doesn’t seem to work.

  1. The MultiAxis indices are in the range [ MotionController::AxisCountGet(), MotionController::MotionCountGet() )
  2. The number of axes mapped to that multi axis come from MultiAxis::AxisCountGet().
  3. Each mapped axis is obtained using an index that goes from 0 to the result of #2 via MultiAxis::AxisGet(...).

Am I correct so far?

When I do this, the axis count is always 0.

Here’s some C++ code that behaves this way for me.

char* rsi_path = getenv("RSI");
if (rsi_path == NULL)
	throw std::exception("RSI not defined in the environment.");

std::cout << "Using RSI directory: " << rsi_path << "\n";
auto mc = r::MotionController::CreateFromSoftware(rsi_path);
if (mc == NULL)
	throw std::exception("Error creating motion controller object!");
if (mc->ErrorLogCountGet() > 0)
	throw *(mc->ErrorLogGet());

auto network_state = mc->NetworkStateGet();
if (network_state != r::RSINetworkState::RSINetworkStateOPERATIONAL) {
	std::cout << "  Starting network...\n";
	std::cout.flush();
	mc->NetworkStart();
}
network_state = mc->NetworkStateGet();
if (network_state != r::RSINetworkState::RSINetworkStateOPERATIONAL) {
	std::stringstream buf;
	buf << "  Network start failed! state(" << (int)network_state << ")\n";
	auto msg_count = mc->NetworkLogMessageCountGet();
	for (auto msg_idx=0; msg_idx<msg_count; msg_idx++)
		buf << "    " << mc->NetworkLogMessageGet(msg_idx) << "\n";
	throw std::exception(buf.str().c_str());
}

mc->Refresh();

auto axis_count = mc->AxisCountGet();
auto motion_count = mc->MotionCountGet();
std::cout << "Axis Count: " << axis_count << "\n"
	         "Motion Count: " << motion_count << "\n"
	;

for (auto ma_idx=axis_count; ma_idx<motion_count; ma_idx++) {
	auto ma = mc->MultiAxisGet(ma_idx);
	std::string label = ma->UserLabelGet();
	std::cout << "\nMultiAxis #" << ma->NumberGet() << " (" << label << ")\n";
	auto ma_axis_count = ma->AxisCountGet();
	std::cout << "    Axis Count: " << ma_axis_count << "\n";
}

FWIW, I get the same behavior from Python, which is what I use most of the time for quick inspection/verification tools. I have to assume I’m doing something incorrectly.

Here’s the output I get.

Axis Count: 7
Motion Count: 9

MultiAxis #7 (MG-0)
    Axis Count: 0

MultiAxis #8 (Util-0)
    Axis Count: 0

The labels for the MultiAxis objects are correct, so I conclude that I’m retrieving the correct MultiAxis object. When I try to get the axes (regardless of the result of AxisCountGet(), I get NULL back from AxisGet().

I get the same behavior if I use MultiAxis::AxisMapCountGet().

can you try MotionController::LoadExistingMultiAxis(…)?

1 Like

Bingo.
How long has that been around?

…and also, are you confirming that MotionController::MultiAxisGet(...) behaves fundamentally differently than MotionController::AxisGet(...) WRT recreating/initializing the returned object?

I was under the impression that I could call MotionController::AxisGet(0) all day long and always get back the same Axis object.

The method has been around a long time, at least a decade.

MultiAxisGet(…) does not attempt to read the axis mapping from the RMP firmware, so it always starts out with an empty Axis list internally.

LoadExistingMultiAxis() does read the axis mapping from the RMP and fills in its internal Axis list based on what it finds on the RMP.

Your AxisGet() assumption is correct.
I think you are correct to assume the utility of MultiAxis “Load” is much greater than “Get”, and we’d change the default API behavior if we weren’t so strict trying to maintain backwards combability. You make a strong case for even better documentation, like pointing “Get” users to “Load.”

1 Like

One final question: How would I know when it’s appropriate to use LoadExistingMultiAxis(...)?

If the MultiAxis has just been “created” (via MotionCountSet(...)), is getting the MultiAxis via “load” just as valid as getting it via “get?”

Yes, you could use LoadExistingMultiAxis(...) in all cases.