PDA

View Full Version : Detecting motion in an AX-12+ servo



Pi Robot
07-07-2010, 11:19 AM
OK, this has been driving me nuts for a few days: I am trying to detect movement in a Dynamixel AX-12+ servo so I know when a given motion is complete. I am using the Forest Moon Dynamixel library and it has a method for checking if a servo is moving. If I am reading the source code correctly, this method reads register 0x2E (46) which according to the AX-12+ manual is "Set to 1 when the Dynamixel actuator is moving by its own power. " However, I'm beginning to wonder if this is actually correct. What *seems* to be happening is that the register is actually set to 1 if the current position != the goal position. However, given that there is some slop, I almost never get back a 0 or "False" from register 0x2E. So I have resorted to checking to see if the current position and goal position are within 10 units of each other (5 seems too small) to determine when the servo has stopped moving.

Anyway, has anyone else experienced a similar problem?

Thanks!
patrick

Adam
07-07-2010, 01:06 PM
I don't have that problem. The Forest Moon code reads the register.



private void synchMove()
{
dynNet.Synchronize();
while (dynNet.Moving())
{
Thread.Sleep(20);
}
}

Pi Robot
07-07-2010, 04:13 PM
Thanks Adam. Sounds like it is my code then--I'm doing some multi-threaded access on the servos and chances are I'm screwing up. BTW, did you copy-and-paste that code sample or type it in? I ask because I don't see a Moving() method on the dynNet object itself, just the individual servos.

--patrick

Adam
07-07-2010, 08:39 PM
It looks like I wrote a method... just a for loop over the Dynamixels. It works.

Pi Robot
07-08-2010, 08:28 AM
OK, I finally found the problem. It turns out if that you write to the GoalPosition or MovingSpeed register it also sets the Moving register to 1 even if the servo is not actually moving. Try this loop:


while (true)
{
DynaNet.Synchronize();
Console.WriteLine(TestServo.Moving);
TestServo.GoalPosition = 512;
}or


while (true)
{
DynaNet.Synchronize();
Console.WriteLine(TestServo.Moving);
TestServo.MovingSpeed = 50;
}On my setup using a USB2Dynamixel controller in TTL mode and a bus of 11 AX-12 servos, these two loops always print "True" for TestServo.Moving, even after it has stopped. So I looked at the Forest Moon source for the Dynamixel library and in the file Dynamixel.cs, this is the block for getting back the value for Moving from register 46:


public bool Moving
{
get { return Changed || DynNet.ReadRegister(_Id, Register.Moving) != 0; }
}As you can see, Moving returns True if the Moving register value is 1 OR the variable Changed is True. So I thought I had the answer and took out the dependency on Changed so I have this:


public bool Moving
{
get
{
Console.WriteLine("REG 46: " + DynNet.ReadRegister(_Id, Register.Moving));
return DynNet.ReadRegister(_Id, Register.Moving) != 0;
}
}Rebuilding the DLL and trying it out I found that Register 46 is set to 1 by my test loops above all on its own! In other words, it seems that the AX-12+ itself sets the Moving register to 1 whenever the GoalPosition or MovingSpeed registers are set--even if they are set to the same value they already have.

Assuming I haven't missed something, I will now just use a test in my loop to only set the GoalPosition or MovingSpeed if they are different from what the servo already thinks they are. For example:


while (true)
{
DynaNet.Synchronize();
Console.WriteLine(TestServo.Moving);
if (TestServo.GoalPosition != NewGoalPosition) TestServo.GoalPosition = NewGoalPosition;
}

This appears to solve the problem by leaving register 46 alone so that it only returns 1 when the servo is truly moving.

--patrick

Adam
07-08-2010, 09:48 PM
Here is my DynamixelNetwork.Moving method:



public bool Moving() {
foreach (KeyValuePair<int, Dynamixel> d in DynamixelMap)
{
if (d.Value.Moving)
{
return true;
}
}
return false;
}


If I don't do the above, the move will be preempted. When moving to a point using IK, I use an "error margin" to avoid the condition you are seeing.

FYI, you can set the compliance margin to a lower number to help with the accuracy a bit. In my experience, compliance margin means "if you get this close, it's close enough" whereas the compliance slope is what I intuitively think of as compliance, which is to say "go to exactly where I told you unless you encounter a certain amount of resistance."

Hope this helps. :)

Adam
07-08-2010, 10:06 PM
I also should mention, this type of synchronized movement is not useful in all situations. For example, in my object tracking code, allowing the movements to be preempted yielded a faster and smoother overall response.

Pi Robot
07-08-2010, 10:45 PM
Here is my DynamixelNetwork.Moving method:



public bool Moving() {
foreach (KeyValuePair<int, Dynamixel> d in DynamixelMap)
{
if (d.Value.Moving)
{
return true;
}
}
return false;
}
If I don't do the above, the move will be preempted. When moving to a point using IK, I use an "error margin" to avoid the condition you are seeing.

FYI, you can set the compliance margin to a lower number to help with the accuracy a bit. In my experience, compliance margin means "if you get this close, it's close enough" whereas the compliance slope is what I intuitively think of as compliance, which is to say "go to exactly where I told you unless you encounter a certain amount of resistance."

Hope this helps. :)

Thanks Adam. Yeah, that is similar to what I am doing now. And thanks for the tip on compliance. My AX-12's are currently set with a Compliance Margin of 1 and a Compliance Slope of 32 (which I think are the defaults?).