FORUM CTRLX AUTOMATION
ctrlX World Partner Apps for ctrlX AUTOMATION
10-09-2024 01:39 PM
Hello all,
I have been trying to jog the motors via the sdk. i have the x axis in the status standstill. So if i read the docummentation correctly its now ready to recieve move commands. The problem is that i dont know how i need to declare and implement the axisjogcmd. This is done true the axis commands not the kinematic group. I added the code below. It gives a error about MotionResult not being declared.
Thanks in advance
#include <functional>
#include <thread>
#include <limits>
#include "ctrlx_datalayer_helper.h"
#include "datalayerclient.h"
#include <stdio.h>
#include <iostream>
using namespace std;
static void printStringList(comm::datalayer::Variant& data)
{
if (data.getType() == comm::datalayer::VariantType::ARRAY_OF_STRING)
{
std::cout << "Node List: ";
const char** strArray = data;
for (uint32_t i = 0; i < data.getCount(); i++)
{
std::cout << strArray[i] << " ";
}
std::cout << std::endl;
}
}
static void printMetadata(comm::datalayer::Variant& data)
{
if (STATUS_FAILED(data.verifyFlatbuffers(comm::datalayer::VerifyMetadataBuffer)))
{
std::cout << "Invalid Flatbuffer: Not a MetadataBuffer";
return;
}
auto metadata = comm::datalayer::GetMetadata(data.getData());
std::cout << metadata->displayName()->c_str() << std::endl;
std::cout << metadata->displayFormat() << std::endl;
std::cout << metadata->description()->c_str() << std::endl;
std::cout << metadata->descriptionUrl()->c_str() << std::endl;
auto operations = metadata->operations();
std::cout << "AllowedOperations: read=" << operations->read() << " write:" << operations->write() << " create:" << operations->create() << " delete:" << operations->delete_() << std::endl;
auto references = metadata->references();
for (flatbuffers::uoffset_t i = 0; i < references->size(); i++)
{
std::cout << references->Get(i)->type()->c_str() << std::endl;
std::cout << references->Get(i)->targetAddress()->c_str() << std::endl;
}
}
DataLayerClient::DataLayerClient(const std::string& ip, const std::string& user, const std::string& password, int sslPort)
: m_ip(ip)
, m_user(user)
, m_password(password)
, m_sslPort(sslPort)
, m_client(nullptr)
{}
bool DataLayerClient::start()
{
std::cout << "m_datalayer.start(..)" << std::endl;
m_datalayerSystem.start(false);
m_client = getClient(m_datalayerSystem, m_ip, m_user, m_password, m_sslPort);
return m_client != nullptr && m_client->isConnected();
}
comm::datalayer::IClient::ResponseCallback DataLayerClient::responseCallback()
{
// [&] All needed symbols are provided per reference
// (...) Parameter provided by the calling site
return [&](comm::datalayer::DlResult result, const comm::datalayer::Variant* data)
{
m_resultAsync = result;
if (data != nullptr)
{
// data must not be nullptr otherwise the '=' operator crashes
m_dataAsync = *data;
if (m_dataAsync.getType() == comm::datalayer::VariantType::ARRAY_OF_STRING)
{
printStringList(m_dataAsync);
}
}
std::cout << "ResponseCallback: " << std::string(result.toString()) << std::endl;
};
}
bool DataLayerClient::waitForResponseCallback(int counter)
{
for (;;)
{
if (counter > 0)
{
counter--;
if (counter <= 0)
{
return false;
}
}
//sleep(1);
if (m_resultAsync != -1)
{
std::cout << "ResponseCallback finished: " << m_resultAsync.toString() << std::endl;
return true;
}
}
}
void DataLayerClient::ping()
{
std::cout << "ping" << std::endl;
m_result = m_client->pingSync();
std::cout << "m_client->pingSync() " << m_result.toString() << std::endl;
m_resultAsync = -1;
m_result = m_client->pingAsync(responseCallback());
waitForResponseCallback(10);
}
//"fieldbuses/ethercat/master/instances/ethercatmaster/realtime_data/input/data/ctrlX_DRIVE_XCS_SoE_X/AT.Position_feedback_value_1"
void DataLayerClient::readSync(const std::string& node)
{
std::string address = node;
m_result = m_client->readSync(address, &m_data);
// std::cout << ("readSync() " + address) << endl;
cout << int32_t(m_data) << endl;
}
void DataLayerClient::writeSync(const std::string& node)
{
auto address = "motion/kin/Kinematics/cmd/group-ena";
m_result = m_client->writeSync(address, &m_data);
cout << m_result.toString() << endl;
}
void DataLayerClient::write()
{
m_data.setValue(true);
writeSync("bool8");
m_data.setValue(-0.123456789f);
writeSync("float32");
m_data.setValue(-0.987654321);
writeSync("float64");
m_data.setValue((int8_t)-127);
writeSync("int8");
m_data.setValue((int16_t)-32767);
writeSync("int16");
m_data.setValue((int32_t)0x80000001);
writeSync("int32");
m_data.setValue((int64_t)0x8000000000000001);
writeSync("int64");
m_data.setValue("Changed by cpp ctrlX Data Layer Client");
writeSync("string");
}
void DataLayerClient::createSync(const std::string& node)
{
std::string address = node;
m_client->removeSync(address); // First remove - may be node exists
m_result = m_client->createSync(address, &m_data);
cout << m_result.toString() << endl;
}
void DataLayerClient::stop()
{
delete m_client;
m_client = nullptr;
}
int main() {
// builds object
DataLayerClient test;
// starts tcp
test.start();
//payload definition
int p;
// ping ctrl x core
test.ping();
//set power to true
test.m_data.setValue(true);
test.createSync("motion/axs/X/cmd/power");
// this is the command responsible for jog the x axis
virtual MotionResult axsPosCmd(const cmd::DataLayerClient::CmdSourceInfo & sourceInfo, const char* x, cmd::axs::AxsCmdType AXS_CMD_POS_ABS, double 400, const cmd::DynamicLimitsT & dynLim, bool true, uint64_t & cmdID) const = 0;
for ( p = 0; p < 100; p++) {
//cout << p << endl;
//read out x encoder 100 times
test.readSync("fieldbuses/ethercat/master/instances/ethercatmaster/realtime_data/input/data/ctrlX_DRIVE_XCS_SoE_X/AT.Position_feedback_value_1");
} //set power to false
//test.m_data.setValue(false);
//test.createSync("motion/axs/X/cmd/power");
//test.stop();
}
With kinde regards,
David
10-09-2024 02:45 PM
Hi David,
The command you posted here is from the Bundle-Interface of the Motion App. This command can only be used if you build your own RT-Bundle with our RT-SDK. Learn more about how to access the RT-SDK here: FAQ for SDK for ctrlX AUTOMATION
But to be able to command the axis, its not necessary to use the RT-SDK. You can just use another interface of the Motion App. For example the Data Layer interface or the Script interface. See the Motion App Application Manual for more information regarding the interfaces. What kind of application do you want to achieve? There are use cases for every interface of the motion app.
If you want to use the same command via the Data Layer interface for example, you can do a "create" with a DL-Client to the path "motion/axs/<axs_name>/cmd/pos-rel" or "/pos-abs" or "pos-add". This you can also try out via the Data Layer web interface:
See also the Motion App Manual on this command.
Best regards,
Nick
10-10-2024 09:08 AM
Hi Nick,
Thanks for the fast response. We are trying to operate the ctrl x core via are own windows application we tried before with the create function to the exact same path. Once we send the payload that was specefied in the documentation we got the error code DL_type_mismatch what i could find in the documentation, that this has to do with sending a wrong datatype. But its not specified what datatype it needs to be or maybe its somthing with the syntac? It only specified what needs to be in the payload in the documentation.
https://docs.automation.boschrexroth.com/doc/28483558/axsjogincr-incremental-axis-jogging/latest/en/
Best regards,
David
10-10-2024 03:43 PM
Hi David,
you have two Options:
1. Use the Data Layer functions and create a complex FlatBuffer Data Type
2. Or use a REST Client and do a post. Here you have to send the payload like you can see in the Docu.
Best regards,
Nick
10-15-2024 03:51 PM
Hello Nick,
Thanks for the reply.
I just had a meeting with our contact person from Bosch rexroth. She was able to do it via python with the create, problem that she did it in python. That offcourse has different syntac and is managed while c++ isnt. My specific qeustion is how do i send this payload via the sdk i assume thats the flatbuffer data type. and if so do you have an example.
10-15-2024 06:09 PM
Hi David,
I made a little test and succeded.
To create a flatbuffer data type you need to use the genearted-header files, which got created out of the FlatBuffer-schema (.fbs).
You can check, I think depending on the SDK Version you are using the _generated.h files of the motion-app data types are allready in the SDK (under the path /include). If they are not there then you can also generate them out of the .fbs files with the help of the flatc (flatbuffer compiler).
Here is how I have done it for the two flatbuffers I need for the pos-abs command:
If you include these headers in your .cpp you can use the "Create..."-functions like this:
// Synchronous create of a ctrlX Data Layer of the motion app to command the Axis "Axis_1" -----------------------------------------------------------
auto DataLayerAddress = "motion/axs/Axis_1/cmd/pos-abs";
comm::datalayer::Variant myCmdPositionData;
//create the flatbuffer data type with the help of the generated header
flatbuffers::FlatBufferBuilder builder;
auto limits = motion::core::fbtypes::CreateDynamicLimits(builder,1.0,1.0,1.0,0.0,0.0);
auto cmdData = motion::core::fbtypes::CreateAxsCmdPosData(builder,10.0,true,limits,motion::core::fbtypes::CmdPosAbsDir_SHORTEST_WAY);
builder.Finish(cmdData);
myCmdPositionData.shareFlatbuffers(builder);
std::cout << "INFO create " << DataLayerAddress << " synchronously..." << std::endl;
auto result = dataLayerClient->createSync(DataLayerAddress, &myCmdPositionData);
if (result != DL_OK)
{
std::cout << "WARN create " << DataLayerAddress << " failed with: " << result.toString() << std::endl;
}
else
{
std::cout << "Create to " << DataLayerAddress << " succeded: "<< result.toString()<< std::endl;
}
Best regards,
Nick
10-16-2024 11:56 AM
Hi nick,
This clearefice allot for me so thx, i know better understand how the sdk works. I do still have a couple of qeustions if thats oke with you.
The CmdPosAbsDir_shortest_way is not a member of motion::core::fbtypes. Because of this im not sending the complete package with de create. and because of that im getting the dl_mismatch.
again thanks for your help.
10-16-2024 11:57 AM
i forgot to mention that i included the header files. axsCmdPosData_generated.h and dynamicLimits_generated.h