-
Notifications
You must be signed in to change notification settings - Fork 31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[NOT FOR MERGE] Feature/coe parametrization #12
base: master
Are you sure you want to change the base?
Conversation
* add soem_master_types.hpp * add the "parameter" type to soem_master * add the "ec_state" type to soem_master * minor bugfix: state of the slaves properly updated
Conflicts: soem_master/soem_master_component.cpp soem_master/soem_master_component.h soem_master/soem_master_types.hpp
* add soem_master_types.hpp * updated files containing features * minor space canges in soem_driver.h * tab alignment fix in soem_master_component * white spaces fixing * fixing marked issues for pr * fix for pr
Conflicts: soem_master/soem_master_component.cpp soem_master/soem_master_component.h soem_master/soem_master_types.hpp
ptal @adolfo-rt, @mvukov |
in soem_master_component.cpp I introduced a bug: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
90% of comments are style and nits.
It would be good that someone with good EtherCAT-fu takes a pass as well.
@@ -52,10 +52,29 @@ SoemMasterComponent::SoemMasterComponent(const std::string& name) : | |||
"Second (redundant) interface to which the ethercat device is connected"); | |||
this->addProperty("redundant", prop_redundant=false).doc( | |||
"Whether to use a redundant nic"); | |||
this->addProperty("slavesCoeParameters",parameters).doc( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: space after comma, here and for added operations below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
"send a CoE SDO read (blocking: not to be done while slaves are in OP)"); | ||
|
||
RTT::types::GlobalsRepository::shared_ptr globals = RTT::types::GlobalsRepository::Instance(); | ||
globals->setValue( new Constant<ec_state>("EC_STATE_INIT",EC_STATE_INIT) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: No space after ( nor before ), add space after comma. Here and below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
||
RTT::types::Types()->addType(new ec_stateTypeInfo()); | ||
RTT::types::Types()->addType(new parameterTypeInfo()); | ||
RTT::types::Types()->addType(new types::SequenceTypeInfo< std::vector<rtt_soem::Parameter> >("std.vector<Parameter>")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: wrap line at 80 cols. Applies to other long lines in the diff. No need to fix existing code violating this, but new code should strive to comply with our style guide.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
@@ -91,8 +110,38 @@ bool SoemMasterComponent::configureHook() | |||
<< endlog(); | |||
ec_slave[0].state = EC_STATE_PRE_OP; | |||
ec_writestate(0); | |||
// wait for all slaves to reach PRE_OP state | |||
ec_statecheck(0, EC_STATE_PRE_OP, EC_TIMEOUTSTATE); | |||
//Wait for all slaves to reach PRE_OP state |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Space after //
, here and in other comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
tmp.index = parameters[i].index; | ||
tmp.sub_index = parameters[i].sub_index; | ||
|
||
if(ec_slave[tmp.slave_position].mbx_proto & ECT_MBXPROT_COE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: space after if
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -50,6 +58,11 @@ class SoemMasterComponent: public RTT::TaskContext | |||
bool prop_redundant; | |||
char m_IOmap[4096]; | |||
std::vector<SoemDriver*> m_drivers; | |||
std::vector <rtt_soem::Parameter> parameters; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: No space after std::vector.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
} | ||
|
||
}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Only one newline at end.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -45,6 +45,8 @@ extern "C" | |||
|
|||
#include <sstream> | |||
|
|||
#include "soem_master_types.hpp" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not needed in this header? but in soem_master_component.h
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
/** Index of the CoE object */ | ||
int index; | ||
/** Subindex of the CoE object */ | ||
int sub_index; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are different types used here and in the AddressInfo
struct? int vs unsigned int vs char.
Here implicit conversions are taking place, and here the char sub_index is being cast to int. If possible, it would be best to use types that need no casting, implicit or explicit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, it this was because I wasn't sure.
In fact there are thresholds that these members should respect
- for slave_position : max 65535 maximum theoretical number of slaves addressed by a single
- for index: max 65535 because of the limit in the object dictionary entries
- for sub_index: max 255
In fact in the soem header ethercoe.h
ec_SDOwrite(uint16 Slave, uint16 Index, uint8 SubIndex, ...)
So my doubt are:
- use the right number of bytes as soem does?
- keep it simple and use an int?
Opinions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep it consistent above all: soem types and no casts, or ints and explicit casts when calling soem, but not a mix. The value ranges for each member can also be documented.
Notice that with default compiler flags, you can still assign -1 to an unsigned int and get an overflow, so no protection from out-of-range values. Adding -Wconversion -Werror
(in gcc) enables additional compiler checks that would generate a compile error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK,
setting the members of the Parameter structure to be SOEM types would lead to some errors while parsing soem.cpf such as:
"[ ERROR ][TinyDemarshaller] Unknown type "uint16" for for tag simple"
and at the moment I do not know how to fix that, so I keep these members as "int" while an explicit cast is done to the SOEM type while saving in "AddressInfo" structure.
PS
The "AddressInfo" structure has been introduced because I had compilation error calling "this->addOperation("writeCoeSdo,..." for a function with more than 5 arguments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll probable need the stdint typekit to resolve this? Can you try and see if these errors disappear if you load this typekit. (https://github.com/orocos-toolchain/stdint_typekit)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well what was already done (not committed yet) was:
In soem_master_types.hpp
#include <rtt/typekit/StdTypeInfo.hpp>
In soem_master_component.cpp:
// To teach RTT SOEM fixed length types
RTT::types::Types()->addType(new types::StdTypeInfo<uint8_t>("uint8"));
RTT::types::Types()->addType(new types::StdTypeInfo<uint16_t>("uint16"));
RTT::types::Types()->addType(new types::StdTypeInfo<uint32_t>("uint32"));
But even doing that I could't load uin16 from the soem.cpf.
Maybe I have to add something else...when you write load you mean something different?
}; | ||
} | ||
|
||
//################################################################ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Remove these comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@MagnaboscoL, to correctly display checkboxes in the description, the syntax is:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@adolfo-rt already made comments about style, I have more ECAT relevant questions/remarks.
|
||
if(wkc == 0) | ||
{ | ||
log(Error) << "Slave_" << ec_slave[tmp.slave_position].configadr <<" SDOwrite{index["<< tmp.index |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, in this case you should return false
.
@@ -269,4 +270,96 @@ void SoemMasterComponent::cleanupHook() | |||
//stop SOEM, close socket | |||
ec_close(); | |||
} | |||
|
|||
int SoemMasterComponent::writeCoeSdo(const AddressInfo& address, bool complete_access, int size, void* data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we discussed offline:
- If this is blocking call, this method and corresponding read method should check the state: if operational, the call should not be made. The rationale: once operational, the communication enters cyclic mode. Thus, read/write of SDOs would possibly postpone PDOs.
- The function should return bool: true on success, false otherwise.
- However, as @MagnaboscoL indicated, SDOs are sometimes useful in operational state to handle emergency situations. Therefore, another solution here may be to make those functions protected.
@smits What do you think about this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would clearly indicate the behavior in the documentation of the function. I agree that the user should be allowed to to SDO writes when he feels like it, given that he knows what he's doing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok,
for the moment I have modified the functions so that:
- if at least a slave is in operational state they simply return false without trying to send an SDO.
- return true in case it succeeded, false otherwise
Notes:
- from the wireshark record I have seen that an SDO write can take up to 80 ms to be completed but it really depends on the slave. Since the procedure is completed only when the slave confirmed that the SDO has peen processed or when too much time has elapsed.
- as far as I know SDO are allowed by the EtherCAT standard in the states preop, safeop and operational.
- in my opinion an SDO can be used in operational at least in the following cases:
- if a drives notify a fault using its PDO mapped statusword it can be useful to know which kind of fault it is and that could be done reading the proper object. Usually the standard object for this purpose is index: 0x1003 (subindex: 0 = fault count, other subindices = fault code)
- if a drive controls also the brake motor, it can be useful to open the brake even if the drive is not enabled just to be able to move the axis by hand. This is usually done by SDO for Ds402 drives even though it would be possible to manage it mapping the needed object to a PDO
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't see the comment on time :)
ok so the functions could be called in operational too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work, it will however not be ABI backwards compatible, so we'll need to bump the minor version number as well with this change.
|
||
if(wkc == 0) | ||
{ | ||
log(Error) << "Slave_" << ec_slave[tmp.slave_position].configadr <<" SDOwrite{index["<< tmp.index |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 on returning false here, we're still configuring, if things go wrong here, don't expect anything to work.
@@ -142,6 +191,7 @@ bool SoemMasterComponent::configureHook() | |||
else | |||
{ | |||
log(Error) << "Configuration of slaves failed!!!" << endlog(); | |||
log(Error) << "The NIC currently used for EtherCAT is "<< prop_ifname1.c_str() << " . Another could be chosen by editing soem.cpf." << endlog(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
80-char wrapping.
} | ||
//return false; | ||
} | ||
checkNetworkState(EC_STATE_SAFE_OP, EC_TIMEOUTSTATE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would additionally replace Network with Slave --> updateSlaveStates or something similar.
@@ -269,4 +270,96 @@ void SoemMasterComponent::cleanupHook() | |||
//stop SOEM, close socket | |||
ec_close(); | |||
} | |||
|
|||
int SoemMasterComponent::writeCoeSdo(const AddressInfo& address, bool complete_access, int size, void* data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would clearly indicate the behavior in the documentation of the function. I agree that the user should be allowed to to SDO writes when he feels like it, given that he knows what he's doing.
/** Index of the CoE object */ | ||
int index; | ||
/** Subindex of the CoE object */ | ||
int sub_index; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll probable need the stdint typekit to resolve this? Can you try and see if these errors disappear if you load this typekit. (https://github.com/orocos-toolchain/stdint_typekit)
OK I just pushed a commit that:
|
TODO before merging: