PDA

View Full Version : [Question(s)] Controlling dynamical together



vassilissa
04-24-2014, 12:19 AM
Hello, I'm currently having trouble controlling my dynamixels ax-12a with my arbotix. The thing is I have to control 4 ax (out of 12) together in wheel mode so that they move at the same time. I know that there is a sync write command but isn't that to control all of the 12 ax i have? An example code would be helpful.
Also I'm planning to control my dynamixel so that for example after id 1 get to 45degree, it will trigger id 2 to move. But the id 1 will still continue to move, just triggering the id 2 to move and so on. Is that possible?

siempre.aprendiendo
04-24-2014, 02:16 AM
To the syncwrite command you sould provide the id of the Dynamixel to be used (among others parameters).

The manual page for Dynamixel commands:
http://support.robotis.com/en/product/dynamixel/communication/dxl_instruction.htm

Yes, it's possible. Which programming tool do you will use?

KurtEck
04-24-2014, 08:13 AM
Note in questions like this, it would help to know what code base or the like you are using. My assumption here is you are using the Bioloid libraries.

There are several ways you can do these tasks.

Move 4 servo together - I would probably first try by simply outputting the individual commands to the servos and see if it is good enough. If not, I would do the syncwrite. No, you don't have to do all servos. With the Sync write command you tell it which register you wish to start outputting values for and how many bytes. Then the actual data you output per servo, is the servo number you wish to control followed by the register bytes for that servo.

Example code: This is an extract from the Phoenix code base when I was experimenting with some stuff:

// Need to first output the header for the Sync Write
int length = 4 + (NUMSERVOS * 5); // 5 = id + pos(2byte) + speed(2 bytes)
int checksum = 254 + length + AX_SYNC_WRITE + 4 + AX_GOAL_POSITION_L;
word wSpeed;
setTXall();
ax12write(0xFF);
ax12write(0xFF);
ax12write(0xFE);
ax12write(length);
ax12write(AX_SYNC_WRITE);
ax12write(AX_GOAL_POSITION_L);
ax12write(4); // number of bytes per servo (plus the ID...)
for (int i = 0; i < NUMSERVOS; i++) {
wSpeed = CalculateAX12MoveSpeed(g_awCurAXPos[i], g_awGoalAXPos[i], wMoveTime); // What order should we store these values?
byte id = pgm_read_byte(&cPinTable[i]);
checksum += id + (g_awGoalAXPos[i]&0xff) + (g_awGoalAXPos[i]>>8) + (wSpeed>>8) + (wSpeed & 0xff);
ax12write(id);
ax12write(g_awGoalAXPos[i]&0xff);
ax12write(g_awGoalAXPos[i]>>8);
ax12write(wSpeed&0xff);
ax12write(wSpeed>>8);

}
ax12write(0xff - (checksum % 256));
setRX(0);


Note the functions was outputting 4 register bytes per servo. Position and Speed... It uses the helper functions in the Bioloid libraries... In this example I did output for all of the servos. But did not have to. I have other code bases that with my version of the USB2AX firmware I only output to those servos that are still moving.

Another approach which I have never tried, would be to use the REG WRITE commands to output all of the commands to the individual servos and then use the ACTION command to tell them all to do it Again I have not tried this one.

2nd question. A couple of approaches.
Again not fully sure of your complete question. Are you moving Servo 1 to a goal position or are you in continuous rotation mode?

You could calculate how much time it should take for servo 1 to make it to the position (45 degrees) and simply start up the 2nd servo at that time.

If using goal positions, and using Bioloid library, In your loop calling off to bioloid library with the method getCurPose for that servo, and when it gets to 45 degrees (need to calculate what value that is), you start up the 2nd servo. Or probably you could also ask the actual servo position: ax12GetRegister(1,AX_PRESENT_POSITION_L,2)

Good luck

vassilissa
04-24-2014, 09:35 AM
hi, thank you for your answer siempre and KurtEck. currently i'm using arduino IDE to program my arbotix. For sync write it is written there setTXall() which send commands to all the servo. the thing is I don't know how to set it only for several servo out of all. Can you please give me a simple code for controlling only some of them together with sync write?
for my second question, I want ID 1 to move from 150 degree as initial position to 60 degree clockwise and then go counterclockwise until 240 degree in servo mode, but when it reaches 45 degree clockwise, it triggers ID 2 to start moving clockwise from 150 degree to 90 degree and go counterclockwise to 240 degree. What function should i use for this, is it better to calculate it with time or by position of the trigger?

jwatte
04-24-2014, 11:15 AM
It is quite possible that just sending the commands to each of the wheels separately will be good enough. Sending a command does not take very many microseconds.

There are two different "write lots" commands:
Sending a single command to the "broadcast ID" will make each servo act on that command (but not respond on the bus.)
Sending a command through the SYNC_WRITE mechanism will make each servo named in the SYNC_WRITE data respond -- the ID is part of the data chunk. The address ID field of the SYNC_WRITE command is the broadcast ID.

Here's an example from the documentation:

http://support.robotis.com/en/images/product/dynamixel/communication/inst05.png


More here: http://support.robotis.com/en/product/dynamixel/communication/dxl_instruction.htm

KurtEck
04-24-2014, 12:25 PM
For sync write it is written there setTXall() which send commands to all the servo. the thing is I don't know how to set it only for several servo out of all. Can you please give me a simple code for controlling only some of them together with sync write?
Note: without knowing the whole context here, it may be difficult to give a complete answer. Example So you wish to tell these four servos to do something what about the other servos? Are they being controlled by the BioloidController and doing stuff. But for now I will take it that this is an instant output to only those N servos. First thing setTXall() does not output stuff to the servos. The AX servos are connected using a half duplex serial protocol, so you can only either output on the buss or input on the buss. So this API simply says tell all of my AX Busses to go into write mode (in this case there is only one). SetRX(0), says set the specific buss into read mode, which depending on your AX library may simply wait a bit and then change the port registers, or like mine waits until the port actually completes the last output and then change the port registers.

Example of only partial ones being output is pretty straight forward from the above. Something like:
(Note typing on fly, so probably issues.


void SeServoPositions(uint8_t cServos, uint8_t *aIDs, uint16_t *awPos)
{
// Need to first output the header for the Sync Write
int length = 4 + (cServos* 3); // 3 = id + pos(2byte)
int checksum = 254 + length + AX_SYNC_WRITE + 2 + AX_GOAL_POSITION_L;
setTXall();
ax12write(0xFF);
ax12write(0xFF);
ax12write(0xFE);
ax12write(length);
ax12write(AX_SYNC_WRITE);
ax12write(AX_GOAL_POSITION_L);
ax12write(2); // number of bytes per servo (plus the ID...)
for (int i = 0; i < cServos; i++) {
checksum += *aIDs+ (*awPos&0xff) + (*awPos>>8);
ax12write(aIDs++);
ax12write(*g_awPos&0xff);
ax12write(*awPos++>>8);
}
ax12write(0xff - (checksum % 256));
setRX(0);
}

for my second question, I want ID 1 to move from 150 degree as initial position to 60 degree clockwise and then go counterclockwise until 240 degree in servo mode, but when it reaches 45 degree clockwise, it triggers ID 2 to start moving clockwise from 150 degree to 90 degree and go counterclockwise to 240 degree. What function should i use for this, is it better to calculate it with time or by position of the trigger?
Again this gets tricky. What are all of your other servos doing? Are you using the the Bioloid library? Are you attempting to manage the servos moving from position X to Position Y yourself? Are you attempting to use the Speed values of the servos or are you using the Interpolation stuff that is part of the BioloidController library. What is difficult is that the library is not really setup to do multiple different movements. It is setup to do a Pose, go through that Pose and when it completes go to the next Pose.

But if you are just worried about those two servos, you can for example set the posesize (Look at header files for actual variable names and methods). You could set the pose size to 2, do a read to have it know where the current servos are, set the first one to the first location, where maybe it is you wish to start servo 2, calculate how much time you wish this part of the move to take, then do an InterpolateSetup, and then loop while Interpolating and call InterpolateStep. Once this completes you set the desired position for each of the two servos and calculate where each servo should be when you wish to change something else, set the values and do the Interpolate stuff again ... Which may not be pretty...

Alternatively you could try to extend the library to allow new partial interpolate setups. That is where only a subset of the servos change, but still allow any other servos that are still interpolating to continue their interpolation. Not hard to do, but would take a little work.

Good Luck

Freyzor
04-25-2014, 10:41 AM
Incidentally I just solved this in my own project recently :P I base my solution on the NUKE code but have re-factored it quite heavily since. I used a separate BioloidsController from the arbotix/bioloids lib to control the coxa servos while in wheel mode and another that controls all 12 servos for quadruped walking. Just don't use them at the same time and re read the pose when switching to prime the internal values again :) I also use the default constructor to not have the ax lib primed twice and to control the actual number of servos used. You can take a look at the code here:

https://github.com/freyzor/stikklar/blob/master/StikklarMk3/wheel_engine.cpp