-
Notifications
You must be signed in to change notification settings - Fork 58
Wishlist: As I am converting from using Dynamixel SDK... #23
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
Comments
Hi, @KurtE
The examples are pin definitions only on the premise of using DynamixelShield.
I'll add one more API that takes a pointer parameter. Thank you for your good feedback.
The initial design of the APIs was designed only considering the basic circuit of Dynamixel.
In the case of the Master class, just like the SerialPortHandler class, you can inherit from the PortHandler class to create a new class.
I'll add this too. When I update(PR) the above, I will add you as a reviewer. |
I have created and updated a branch for some of the issues above. There are still points to consider or think about more. I added an example with respect to the custom SerialPortHandler. I hope this example helps you. +Update: @KurtE, I hope you'll give a review to #24. Would you please? |
Hi @OpusK, Will take a look at the new branch: On examples: My understanding from before is that for the Dynamixel Shield, there is already a different library which is a subclass of this library (DynamixelShield), so obviously those examples should be centered around the shield. However if this library is supposed to be a better light weight library to use for embedded stuff using the OpenCM... then personally think the examples should include this board. (But that is just my $.02 worth)... A couple of other things I have or will run into.
Will fail to compile, likewise:
Something about C++ when a derived class has a member function with same name as base class, the base class ones are not usable... I have hacked up a version that compiles, (but I have not tried running yet. |
Forgot to ask, should I do more comments here about changes and/or part of the PR? Memory(OpenCM) - I understand memory is limited (20K? ) So obviously can not go totally wild on using memory. So again, the question comes up with what is a valid default size for DXL_MAX_NODE and what does changing that impact and does it make sense to maybe change this separate some of these limitations? Currently for openCM board I believe this now takes: 4 bytes per item (as unpacked) so 64 bytes, and if you for example increased this to 32 instead of 16 128 bytes... Could again reduce this by allowing the structure to be packed, example using pragma packed. Or could go whole hog and allow all 256(or 253) ids and make it a simple array of Model numbers indexed by ID... And/Or could instead of storing whole ModelNumbers could convert these maybe to a 1 byte value of something like ModelIndex so you don't have to do large case statements for each usage. b) Ping: again above you could have a default MAX number allowed to be pinged, which again assuming you call the XEL version forms of ping, then you gave me an out, of simply defining my own array to pass in, which solves that... In fact personally I don't see the need to have one with the hard coded max size... c) SyncWrite (and likewise syncRead probably bulk ones as well). But the main one I currently use is SYncWrite as it was there for Protocol 1... Personally I don't like the current APIS. Example suppose again suppose I edit DXL_MAX_NODE to just handle the default hexapod with lets say 20 servos. In order to use the SyncWrite to output the new positions for the servos.
And currently DXL_MAX_NODE_BUFFER_SIZE is 16. And in order for you to actually send out the data, you have to then pack the data up and you reserved a buffer in the DxlPacket to handle this (sort of), and you have two of those structures as part of dxl as well. So will be looking to see if I can do the packing myself, and avoiding double packing. Side note: currently if by the real off chance that someone tries to send 16 bytes of data to all 16 max servos, your packet buffer won't be large enough as you need an extra byte per servo for the id. Now back to experimenting |
@OpusK - On the ping issue above, I think the fix for it is to add a using statement in Dynamixel2Arduino.h
I put it just above the new ping member here, but probably could be in any location within the public: Edit: Note: several methods in Dynamixel2Arduino.h comments mention getLastErrorCode() which I don't think exists. But instead in master.h is: getLastLibErrCode Edit: I have a version of the find all servos OpenCM_Find_Servos which is not that different than yours, although I was experimenting with different versions of ping and the like. |
Thanks for your feedback :)
Anyway, an important concept is that Dynamixel2Arduino's API should be easy to use for Arduino novice users. I and our team had a lot of trouble with this, but now we're just designing the API to this level. With the feedback you gave me, I will think about it and leave an additional reply. |
The following has been updated so far.
In addition, the issues related to memory management (Model Index, etc.) need more discussion and consideration. |
@OpusK, Memory usage and ease of use stuff, always a good thing to discuss... You can save a byte per servo, by packing the IdAndModelNum structure, like:
Or you can maybe decrease this in half by instead of model_num, you use an uint8_t model index, which could either refer to a actual model number in some table in const memory or could use memory to keep a table of model numbers used... Or could remove limitation of how many servos you map (but restrict how many unique model numbers to example can only use 15 servo model numbers...
This would take up More memory but would remove limitations... And we could reduce this, by for example max 8 servo types. Which only need 3 bits. (96 bytes). Code to map to bits would be slightly more complex. As for SyncWrite like operations, I have some thoughts which I will try to setup in a sketch or the like, which would be a lot easier than trying to type it into this issue... |
Here is a modified version of the sync_read_write_raw or some such name, that I have two other files included in sketch that so far defines a possible sync write object... It won't run yet as I am not sure how to call something like: |
Quick update: I hacked up your current version of library (master.h and Master.cpp) and added:
And edited the send method of the class I defined in the above zip file:
It builds, but I have not yet tried it... |
Hi @OpusK, I had a chance to play around some more with the Sync Read/Write code I mentioned yesterday and made them into classes. These classes allow you to have them allocate memory for them by default or you can pre allocate memory and pass in the buffer to use. I have update the a version of the sync read/write sketch to do simply set servo goal positions and query back current positions. The above sketch is also in my github project I mentioned earlier: https://github.com/KurtE/Open_CM_CR_Arduino_Sketches/tree/Dynamixel2Arduino It required a few changes to master.h and master.cpp to allow external libraries/code to be able to call functions to send and receive packets:
And in Master.cpp:
Currently the sketch is moving I think 12 servos to 2048+-256. If you get a chance you might take a look and see what you think. Also still personally I think it would be great if you hid some of the special case code for OpenCM board to make simple code for Seria1 work without needing user code to do something special.
With the code in the #if defined added... |
Hi, @KurtE Thanks for your feedback and contribution. First of all, Master Class should be modified to change the APIs of Sync and Bulk. Therefore, if we need to modify the API anyway, I would like to modify the API a lot for the following purposes:
Of course, the functions of the Dynamixel2Arduino class will not change. However, if the Master is partially changed and the Sync and Bulk classes are created as you suggested, the related advanced examples will inevitably be modified. If you have any ideas or opinions as you have been, please tell me. +Update: In addition, Dynamixel2Arduino currently crashes with the Dynamixel SDK (MACRO and PortHandler, Model Name, etc..) Therefore, this part will be modified, and the function name will be changed. I think it's not a major version of the library yet, so I think I need to change it fast now. +Update: The expected code layer structure is shown below.
|
Thanks for merging all of this stuff into the library. Wonder if we should continue on this issue or startup a new one... Personally I don't see a need to convert to C, especially with things like PortHandler... As if you wish to support multiple handlers with function pointers, you are now just emulating c++ without the compile type checking. I understand there are some C programmers out there that may wish to do DXL programming. For example: over the last year or so, with the Teensy stuff for the new T4, I sort of reversed some of these versus the T3.x branch. Example HardwareSerial class with T3.x the code was developed like for Serial1, there may have been a c function like: int serial1_available(), which would return the count and the C++ class was simply HardwareSerial1::available() {return serial1_available();} Now with T4 code we have HardwareSerial::available() doing the work, and a Serial wrappers file (in c++) do something like:
Again side note: But on T4 code base did some additional things to minimize memory usage with this. With this for example: HardwareSerial1.cpp is setup to define Serial1 object, plus all of the default buffers it uses. I also put hooks into the main code that before might look something like:
That instead of explicitly calling the SerialX.available()... functions I instead call on static member of HardwareSerial, where I keep a list of which SerialX.begin() methods have been called. The begins set a function pointer to call as part of their begin. Note: their weak linked function like Serial1Event if called, sets the function pointer back to NULL to not call again... Why this and why mentioning here? By doing the above, that when you build a sketch that for example does not user Serial2-Serial7, these objects and any necessary buffers are not allocated in that sketch, nor is the overhead then of calling their event code. Although the main reason for indirect calling of the SerialX.available... was to not have any explicit reference to the object which would always bring everything in... So if you are reworking some of the things like the Master class, you may want to look at what things are tightly coupled into the object, especially if they bring in any additional things like buffers... Example I have never used the Bulk Read and Write stuff. More back to this library and: Support multi-platform (Arduino, bare-metal, OS, etc) What may turn into an interest challenge is things like which of these platforms support big endian versus little endian? This is another reason why I was migrating over to using methods (functions) to move data in and out of SyncRead/SyncWrite. Example code like this out of sync_read_write_raw I have not fixed that yet in my class I posted, where instead I do something like: Note: My method also has optional parameters for offset within the data to write as well as size to copy. So if I wish to handle this properly I could add one or more ways to do this. Could do maybe something like explicitly say it is a 4 byte field: I still wish/want/need support for > 16 servos on OpenCM hopefully by default. Personally I recommend maybe slightly decoupling of MAX_NODE and MAX_NODE_BUFFER_SIZE from DXL_BUF_LENGTH and/or turn things upside down a little... That is in config.h where you have something like:
Wish maybe it was more like:
Probably enough rambling for this round... |
Forgot to mention, it looks like there is no implementation for: Should probably be added to master.cpp at about line 714 like:
|
I think it's a good idea to discuss the task of converting to c, memory issues, multiplatform support, etc. in a new thread.
Oh, my mistake. I'll fix it.
I understand your opinion, but can you tell me why each buffer length is the same as above? I understand 16 and 171 (16 * 10 + 11), but I want to know what standard you did this way. (eg. 16 and 203, That is, a comment is required)
Apart from the Arduino, we want to convert the code to c in case the user wants to use c only (c compiler only) on other platforms. |
@OpusK As for the changes of defines like I mentioned. Some of it is just my gut reaction about what things are driving what things... That is currently the DXL_BUF_LENGTH is defined to in theory to handle the maximum operation like Sync Write or Sync Read. And it is assumed that all the servos that you may have will be part of that sync write... Again as I think I sort of mentioned earlier is also not 100% correct. That is for Sync_Write, your data structures are:
The current defined buffer size is: Where current actual define is 267 And it is even worse for bulk write as you have ID, addr, length plus data for each node... So again my comments were just more of a gut reaction. Would more likely change definitions to maybe have MAX IDs separate than number of ids in Sync or bulk operations... As there may be lots of apps who play with servo who never use Sync or Bulk.... But again just rambling Again I was trying to semi decouple the BUFFER sizes from the off chance you are going to do a |
Maybe should be on new Issue or Forum or email or ??? If you are interested, for the fun of it, with the sketch I had with potential C++ Sync read and write code, I wrote another version of Sync Read in C. There are two new files that are part of that sketch, and the INO file calls these as well. Again this is only a test looks like it may be sort of working, obviously if it were real for library would need cleanup and ... It is up at: https://github.com/KurtE/Open_CM_CR_Arduino_Sketches/tree/Dynamixel2Arduino/Dynamixel2Arduino_sync_read_write I will probably won't do anything else over the weekend or so... But the nice thing is, I can do all of this external from library. So only issue left in library is for the default number of IDs that it can map ID to model number... Hope you have a good weekend Edit: I updated the test sketch, and I think the C version of sync read it is working a lot better now. |
I think it would be nice to proceed on GitHub issue.
Thanks for sharing! |
@OpusK - I am back from a mini vacation and now recovering ;) For now I will probably not do much more with the Sync Read/Write, other than keep it in the back of my mind that it is easily doable to not need to use up so much memory on these operations. So I might now look at how to increase the number of servos supported without killing memory. Then I may hack up a version of SerialPort - that supports other boards, with or without using Hardware Buffer chips. My exercise in converting the C++ SyncRead into a C version reminded me several reasons why I don't do straight C anymore. Note: I am not one to use C++ bells ans whistles like the STD libraries, or templates, or dynamic casting, or ... But some things I do find come in handy: VTables - In the old days I did do things like, your data structure would contain either a set of member variables or pointer to table of pointers, that you would call. So If you wanted a sub class, you new you had to update the 4th pointer to point to your method... Again all you are doing is emulating C++ here. Optional/default Arguments on functions: That is these days, I might do something like: But in C there is no such thing as default arguments. Overloading of functions, in C++ I can have two different call signatures by the same name. A simple case is you go well maybe I could do the begin above, by making a couple of versions of it:
But that again is not allowed. So I am keeping my fingers crossed that you won't completely sacrifice the C++ stuff for C. I am still sort of curious on what platform/setup that people are requiring only C? I know that on many platforms they use GCC compilers, so should also have both compilers... But I understand, you got to do, what you got to do. Good luck |
Quick question - I again would like to remove constraint on how many servos that can be handled by different processors. If we disregard the SyncRead/Write likewise Bulk... One of the main things is a table that gets used to map an ID to a Model number, and my quick look through you are not really interested in the model number. What instead is used is to differentiate some action depending on the type of servo and mostly this is within groups of servos: And if you go to where these are actually used, they boil down to be used in different switch statements with groups of cases... I sort gathered all of these and for each these I sort of marked groupings of the cases...
So far the biggest distinguishing list is the getControlTableIntemInfo, which appears to have 13 unique tables, now what I have not yet done is to see if some of the other tables conflict. LIke some servo being in one grouping in one operation and a different grouping in a different operation... What I am wondering is instead of keeping the model number for each servo, we could keep a grouping index number. If it turns out less < 16 could save this info in 4 bits... So to hold information for 254 servos would take 127 bytes. Reserve value 0 maybe as unknown/not in list... This could allow for much faster mapping. If you want to know which type servo 23 is, you don't have to linear search a list to see if it is in the list and then grab value. Instead you simply compute that this is in byte 12... and grab it... Also the places that use this like setOperatingMode or the functions that use getControlTableItemInfo would have a much short list of items to use in switch statement and/or could have simple array to load data from... But before I consider trying this out, does this sound reasonable to you and/or other issues you can think of. Thanks |
Hi, @KurtE I've been on a short vacation last Friday. First of all, when it comes to converting c++ to c, I thought about it because there was a request from the company. I agree with many of the things you mentioned. This work is in progress in the branch below. (I think protocol.c is done) I used this to rewrite master and slave. And, for packet buffer allocation, I applied your dynamic allocation. Anyway, could you please review the changes? For your second article, I will read and understand it more and then reply to you. Thanks again for your contribution! |
I've considered this before, but I've put it on hold for scalability.
Even if we can reduce it to 4 bits, if we can't reasonably use the additional 4 bits, it looks good to use all 8 bits. BTW, it would be nice to use an 8-bit index for model numbers represented in 16-bit.
It also looks good with arrays instead of switch statements. |
Hi @OpusK, I meant to reply yesterday, but it was lost... So will try again. Will take a look at your new branch hopefully in the next few days. I am doing some stuff with Teensy, and was going through and updating some of my current code to use this library, to get ideas of stuff, that I like or don't like. Have another branch of my fork (https://github.com/KurtE/Dynamixel2Arduino/tree/develop_allow_all_ids) that I was doing some hacking on to allow all IDS... So far it keeps a const PROGMEM table of all currently defined dynamixel types and uses an array of indexes to access these tables. So currently taking 254 bytes of storage, plus program space of Servos: Am thinking about maybe modifying to either: b) instead of keeping list of model numbers, we simply define model_groupings, and keep index like above. If we can reduce again down to 15 groups can use same type of calculations and cut in half. Side note: we could use different number of bits per index other than 4 or 8, it can make the calculations a little more complex although in some cases we can waste a little memory and make it easier still. Like if 15 is too tight, so we wish to go up to 31 groupings. (8 bit)Again currently I have: 254 bytes for a byte index (max 255 types) The 5 bit math is not quite as easy but in logic it would be:
Again we could do it and save the extra few wasted bits, but maybe not worth it... Got to run... Again will try to take look through your current stuff soon. Kurt |
@OpusK, Just started to take a look through some of the protocol.h/c stuff. Wondering: if about if you should or want some form of standardized naming convention for structures and functions? That is with C++ you can and were using the namespace feature to help make sure that whatever you define should not conflict with other sub-systems... Looks like you sort of have one with: most of your functions ending with: _dxl_packet and likewise for many of your structures end with: DXLPacket_t Although all of your error enumeration ones start of with the name DXL... Wondering (thinking out laud) if all of the structures and maybe functions: maybe should start with DXL? Also I am still unsure of your audience for C version. With some of your other libraries like Dynamixel Workbench I am/was assuming ones who are likely to use ROS. With ROS they have a standard coding standard. Example with ROS, there is a standard for capitalization and underscores in Class Names, method names, member variables... Wonder if there is also a standard for C versions? Again sorry for my initial ramblings here. Luckily so far I am noticing much, as the Protocol stuff is pretty well self contained and only one version of it... (actually 2 but you have them as two separate things)... Now it will be more interesting for PORT, as I personally want the ability to support other platforms, and your stuff you put in earlier sample sketch allows you to sub-class the SerialPortHandler object. Part of the ability to sub-class the Port handler code may only be needed for maybe three virtual things (or set-able callback functions): That is all for now |
Hi @OpusK, As I mentioned I was playing with the sketch I had the C++ sync read and write classes in, which are running fine on current code_layer_redesign code base. So I thought I would try implementing the C version, and since I was doing C version, I thought I would start off with your ideas earlier on. But mainly ran into questions on what your thoughts were on it. Again like:
What is expected for each of these arguments: Things like that. Then the next half (or question) was about ok Now if I am going to implement the function syncRead, and I have this data? How to I get it out to the Serial port...
Are you thinking of doing something like that as well? Likewise a C wrapper to do the RX? Some of the other stuff was more a global question on handling big versus little endian. As one can not assume doing the logical of:
Will work on different platforms, as the byte ordering may be opposite... Edit: and then how does this impact the users code for the Sync read and write... again Suppose the user of an XL430... servo wishes to do a SyncRead of (present load, velocity and position), that they might use for example to detect when the leg hits the ground. So they call the api, with Register 126 length 10, so I have 18 servos, so I pass in a buffer that is at least as long as 18*11 198. Now what does the user code need to do, to extract the data from this 198 bytes? Likewise for the Sync Write... |
Another quick update on playing with C version.
This is in diff format. Basically added 2 #ifdef __cplusplus Could be done with one #ifdef also could/should also be done, by maybe updating each of the header files includes to only include the C++ stuff when in C++ mode... Next back to SyncRead: Going in: const uint8_t *p_param, uint16_t param_len, uint8_t id_cnt So what is param_len? Is it the size of the initialized data in p_param? or how many bytes per servo? Again assuming param_len is the actual size of data passed in, than id_cnt is redundant, as it should simply be param_len-4. Received data Example: do we save away the data in the order we receive it. Or does this retrieved data have a specific slot in memory where it should be stored? That is suppose, we query 10 bytes from 18 servos like my previous example: Suppose we request the data from, the ID list: And suppose suppose one leg stops working and I don't receive data from servos 2, 4, 6. If Slot 6, then we don't need to store away the servo ID in the results and helper functions like I mentioned might work off of slot # instead of ID... There may be a helper function to convert ID to slot... Again assuming we wish to keep the err_idx for servos. Do we keep this data spread out in the table, or for example we store them as the first N bytes in the retrieve data. In either case maybe we initialize these slots to some invalid setting, like maybe 0xff to say that servo did not respond... So again we can see which servos did not respond without walking the list... Again lots of options :D Not sure which ways make more sense to you? |
Hi, @KurtE Sorry. I was late because of other tasks.
I think that the parameters of the API that I declare arbitrarily can cause user confusion. /* Easy functions for Sync Read */
bool beginSyncRead(uint16_t addr, uint16_t addr_len);
bool addSyncReadID(uint8_t id);
bool sendSyncRead(uint8_t *p_recv_buf, uint16_t recv_buf_capacity);
/* Easy functions for Sync Write */
bool beginSyncWrite(uint16_t addr, uint16_t addr_len);
bool addSyncWriteData(uint8_t id, uint8_t *p_data, uint16_t data_len);
bool sendSyncWrite();
As I said before, I'm not thinking of making it c except protocol.c. Are you using the Sync feature with the code you created below? +Update:
I know what you mean. However, for general and stable operation I have created the same API as now. For example, if you are using DMA, you do not need to use flush and can automatically set the dir pin. In this case, if you |
@OpusK , I can imagine you have lots of stuff going on. Will take a look at your Easy functions. Not sure if you are expecting that there will only be one set of Sync reads, and Sync write active at any one time... That is do you see in a loop that the user will always do something like:
Especially if they have multiple ones... Or can the do the begin and the adds in setup, and just call sendSyncRead() in loop? As for SyncWrite, still an issue of memory. Do you see that the API will malloc or the like buffers as needed? If so, potentially could add another parameter to both beginMethods, like maybe, something like max number of IDS that it will support? Maybe also for those who do not want any heap stuff, maybe add method, like to set buffers? Something like:
Will try changing to some of this over the weekend. Yes that is the link to where several test apps have been. I have not pushed up the most recent of this conversation as it does not compile... But hopefully by Monday... |
Yes, it is possible due to the API structure of the current protocol.
I was considering this function as well. Of course, I'm wondering if it's better to add this to the Master class or use a separate class as you created. |
Yesterday I did hack in a version of syncRead along the line of your APIs as part of the one test sketch and update the main sketch to call it. It builds, but I have not tested it yet... But I did push it up the github project in case you wanted a look. So far I have not put in any of the set Buffers, but did add some query functions to extract the data retrieved from the buffer. Currently I have the buffer encoded with data sort of like:
Will hopefully test later today. |
I created and used an API to change the buffer as shown below, but in the end, it seemed better to manage it as a separate class to support querying on received data. (Changing the buffer, there was no problem communicating.) typedef struct InfoSyncBulkInst{
uint8_t* p_packet_buf;
uint16_t packet_buf_capacity;
uint16_t packet_length;
uint8_t id_cnt;
bool is_complete_packet;
uint16_t addr_len;
} InfoSyncBulkInst_t;
bool beginSyncRead(uint16_t addr, uint16_t addr_len, InfoSyncBulkInst_t *p_sync_info = nullptr);
bool addSyncReadID(uint8_t id, InfoSyncBulkInst_t *p_sync_info = nullptr, bool flag_end_add = false);
uint16_t sendSyncRead(uint8_t *p_recv_buf, uint16_t recv_buf_capacity, InfoSyncBulkInst_t *p_sync_info = nullptr);
bool beginSyncWrite(uint16_t addr, uint16_t addr_len, InfoSyncBulkInst_t *p_sync_info = nullptr);
bool addSyncWriteData(uint8_t id, uint8_t *p_data, InfoSyncBulkInst_t *p_sync_info = nullptr, bool flag_end_add = false);
bool sendSyncWrite(InfoSyncBulkInst_t *p_sync_info = nullptr); Below is a simple example.
I would like your suggestions too. |
Hi Again, Will take a look at the above. I just had a chance to get my earlier sketch to work, with a C version of SyncRead. Pushed up current stuff, will take a look in the next day or two at your newer stuff. Kurt |
@OpusK , I synced up to your branch again and took a look at your example, which looks like you are getting there. A few comments. Not sure if better on addSyncReadID to have the 3rd parameter or simply have another method, like in the method: sendSyncRead(), you are assuming that all of the servos in the list will respond and in the order in which they are in the list. But what happens if one of the servos does not respond?
The data in your buffers you passed in , will probably write in the first 4 elements of it, for servos: 1, 2, 4, 6 And your test app will assume that for example index 2 is for Servo #3, and there is no way to verify which one it is actually for? As the loop above does not check IDS. There are at least a few options here? a) Save the IDs as part of the user array... So they can loop through and know which ID they are looking at... b) Have the loop code above verify the ID, matches, the expected one, if not, move the data down to where it should be in the array to the index expected, and probably clear out the data for the one missed? Some error value? Also again not sure if you wish to worry about, but you are also not keeping the ERR values from the received servos, so for example if a servo has hardware issue, like it detected a low voltage, you will not get that information through the Sync Read. Also it will be interesting to see if all of the boards you wish to support all use little endian? If not examples like the one that assumes that the 10 bytes are stored in the same format as what your servos expect and/or receive could mess up. |
Quick message/suggestion: In the SerialPortHandler
I think it might be beneficial if your new begin(baud) method was virtual. Sort of for example how you have code added in the default specific to OpenCM or OpenCR... |
Hi, @KurtE I'm sorry for late reply. Can I leave an answer for the sync function later? |
Thanks, sounds good. As for Sync functions and the like, no worry, no hurry... |
Hi, @KurtE
I also worried about this a lot. As you comment I may need to modify the names of the functions somewhat. beginSetupSyncRead
addSyncReadID
endSetupSyncRead
doSyncRead
Yes. This is my mistake for(uint8_t i=0; i<p_info->id_cnt; i++)
{
if(rxStatusPacket(&p_recv_buf[i*p_info->addr_len],
recv_buf_capacity-i*p_info->addr_len, 3) != nullptr){
recv_cnt++;
}else{
break;
}
}
In fact, this example assumes that the user enters the ID correctly. By the way, when I try to create such a class, do I need to create these raw APIs? // raw APIs
bool txInstPacket(uint8_t id, uint8_t inst_idx, uint8_t *p_param, uint16_t param_len);
const InfoToParseDXLPacket_t* rxStatusPacket(uint8_t* p_param_buf, uint16_t param_buf_cap, uint32_t timeout_ms = 10);
The same seems to be the case.
Currently, I am writing only a little endian. However, I think it's a good idea to allow endian users to choose and use it in the future. +Update: |
Hi, @KurtE I gave up several levels of rawAPI and changed back to the previous structure parameterized API. (Struct member changed) Based on this, I plan to create a separate class and provide it like a class you create or a class method in the SDK and the workbench. +Update: |
I simply created template classes. What do you think about this? |
Hi @OpusK Happy new years (actually the day before)... I will take a look soon, been sidetracked with some other stuff, but hope to get back to it later this week or maybe early next. |
Hi, @KurtE Happy new year! :) I am always grateful for your contribution. |
Hi, @KurtE I have released a modified version of this issue. But I didn't implement it in Class form (this still seems to be a concern). I used struct parameters just like before, splitting them up into new ways of dynamic allocation and legacy support. In other words, only raw API is currently supported. |
Will have to take a look and get back to porting my code over. Always too many distractions ;) Most of which I create for myself. |
This issue has been closed as there weren't recent activities. Please feel free to reopen this thread if there's any opinion to throw. Thanks. |
Hi @OpusK,
I am trying to get myself going again on the updating of some of Hexapod code base, to now use this library instead of Dynamixel SDK. The main board that I believe Trossen Robotics will use, is the OpenCM9.04... But I would also for my own usage like for it to work well with Teensy boards by PJRC (with my own carrier boards). As I do some of this conversions, I run into different things and or wish things were ... So not sure if this is best place to ask/mention these. Would you prefer that each by separate, so can easily close off as answered?
So far some of the things I have seen include:
a) Wish more (all) of the examples had more complete options for different boards. Example the scan_dynamixel sketch does not have any example of how to configure up to run on OpenCM or OpenCR boards. I did see OpenCM stuff in read_write_ControlTableItem.ino.
b) Wish you would automatically handle somethings like:
#define DXL_SERIAL Serial3 //OpenCM9.04 EXP Board's DXL port Serial. (To use the DXL port on the OpenCM 9.04 board, you must use Serial1 for Serial. And because of the OpenCM 9.04 driver code, you must call Serial1.setDxlMode(true); before dxl.begin();.)
That is maybe on first call to dxl.begin() if compiled for OpenCM and Serial port is Serial1, do the setDXLMode(True)... Or could test again pin 28 in this case...
c) Wishing for some of the member functions including some of the constructors, you allowed pass by pointer as well as by reference. Including ones like:
Interesting you have a getPort which returns a pointer, but not a way to then use it to set it back...
Not sure if this would work or not:
SerialPortHandler::SerialPorthandler - WIsh I could pass in HardwareSerial port by pointer...)
Dynamixel2Arduino::Dynamixel2Arduino - maybe should allow to pass in port by address and default to nullptr? If I going to setup more than one HardwareSerial objects to pass in a different times, then maybe should be able to initially just be able to declare the main object like:
Dynamixel2Arduino dxl;
And when I am ready to use it do something like:
dxl.setPort(port_list[index_port_list]);
Likewise for AVR boards, like Trossen Robotics has the Arbotix boards, which don't use a buffer chip or the like but again toggle states of enable RX or TX pin depending on direction. Obviously I think I could write my own full subclass of the port object to handle this for me, or wonder if ether some of this should be built into default SerialPortHandler and/or setup to easily sub-class...
d) keywords.txt needs a pass through to update with all of the member names like:
setPortProtocolVersionUsingIndex
That is all for now...
The text was updated successfully, but these errors were encountered: