Chief Delphi

Chief Delphi (http://www.chiefdelphi.com/forums/index.php)
-   C/C++ (http://www.chiefdelphi.com/forums/forumdisplay.php?f=183)
-   -   Keeping two motors in sync (http://www.chiefdelphi.com/forums/showthread.php?t=134738)

amesmich 16-02-2015 22:09

Keeping two motors in sync
 
Excuse any ignorance I may have since I am reaching out on behalf of our programing team. We have two lead screws that we are trying to keep in sync with each other. We are using these encoders which are mechanically attached to the screws. http://www.andymark.com/product-p/am-2899.htm

Does anyoen have any ideas or input as to how they would incorporate a PID loop that would take the encoder values and slow the faster screw down so that both are in sync?

I know it may seem simple to some btu our team is strugling to find an exampl as to how to implement this type of design. ANy info or direction is appreciated. Thanks.

http://cdn3.volusion.com/vyfsn.knvgw...jpg?1421043935

wilsonmw04 16-02-2015 22:12

Re: Keeping two motors in sync
 
how close are the screws to each other? The easiest way to do this is to tie them mechanically together with a chain and a pair of sprockets.

Ether 16-02-2015 22:27

Re: Keeping two motors in sync
 

What is the driver interface to the lead screws? Is the driver commanding speed or position?

speed: driver pulls joystick back and expects the leadscrews to turn faster in proportion to how far he pulls back

position: driver pulls joystick back and expects the leadscrews to "follow" the joystick angle (height proportional to joystick angle).



Kevin Sevcik 16-02-2015 23:32

Re: Keeping two motors in sync
 
What ether said. The key question is if your pid loop is controlling position or speed.

If you're controlling speed then it's nearly hopeless, since any speed errors will build up over time into large position errors.

If you're controlling position, then it's relatively easy. I'm assuming you have basic familiarity with position PID loops, though. With that caveat, you have two options:
1. Pick one of the screws as a master. This is the only screw you directly command a position for. Set up the other screw as a slave by passing the master's feedback position as the position setpoint/command for the slave. pro: slightly easier to set up, guarantees the slave will be at the same position as the master, even if the master hangs up. Con: slave will always trail the master, since the best it can do is zero error to the master position, and there's bound to be some error. Best for really tightly controlled servos.
2. Two separate pid loops, one for each screw. Command for both pid loops is a single position value that you slowly ramp from one position to the next. Instant changes won't work, because each screw will try to get there as fast as possible, which means at different speeds. Slowly ramping the commanded position means each screw follows the ramped position second by second, which means the screws go up evenly since they're both trying to hit the same target. pros: even movement aside from whatever error is in your pid. Con's: somewhat more complicated, you need to ramp the position somewhat slower than the top speed of the slower motor. Ramping the position too fast means the motors can't keep up and it basically turns back into the instant setpoint change scenario

amesmich 17-02-2015 08:15

Re: Keeping two motors in sync
 
Thank you all. We are doing this by position not speed. Are there any examples of code that you may know of that are similar to this setup? If not no big deal, thought this was common enough that there may be.

gpetilli 17-02-2015 08:55

Re: Keeping two motors in sync
 
Quote:

Originally Posted by amesmich (Post 1445566)
Thank you all. We are doing this by position not speed. Are there any examples of code that you may know of that are similar to this setup? If not no big deal, thought this was common enough that there may be.

As said in a previous post, the simplest way is to mechanically tie the two systems together. Belts or chains work well for this - you can keep the two motors if you need the extra lift. It can be solved electronically, but it is much more difficult and any mismatch in either speed or position will likely bind up the carriage between the two screws. Our team went with a single screw to eliminate the matching issue.

If you are committed to doing this electronically, Ether posted an architecture in another thread that could work. First you need to "Home" your carriage to a known stop each time you boot and zero your two encoders while you know the carriage is level. Then you make one motor a "partial" slave to the other. In a PID like loop, you drive the master to the desired position P as sensed by encoder E1. You simultaneously drive the second motor to the same position P as sensed by encoder E2 but in addition add the error between the master and slave (E2-E1). This way both motors start moving at the same time, but you also drive the error in final position towards zero. If you update your motor drive voltages fast enough, you may be able to match velocities as well.

amesmich 17-02-2015 09:20

Re: Keeping two motors in sync
 
Yes we thought our programing team was capable of this so we did not tie them with a timing belt. We have it 100% built and at this time adding the mechanical tie is not realistic since this is the last day. We do have the limit switches for the home position the problem is our programing team bit off more than they could chew so now we are tryign to help them. That wahy I was looking for sample code of PID loops in C++

gpetilli 17-02-2015 11:51

Re: Keeping two motors in sync
 
http://first.wpi.edu/FRC/roborio/rel...Subsystem.html

kylelanman 18-02-2015 01:07

Re: Keeping two motors in sync
 
We started out with 2 motors and 2 encoders on a lift with 2 PID loops and could not keep the 2 in sync close enough to prevent binding. We linked them with a criss-cross chain and 2 sprockets and then tied them together in software under the control of 1 PID controller and 1 encoder.

Here was the code we used to tie them together. We like to implement limit switches and inverting of motors if needed as close to the hardware as possible. This ensures the motors are never fighting each other.

Code:

/*
 * DualCANTalon.h
 *
 *  Created on: Jan 29, 2015
 *      Author: Team2481
 */

#ifndef SRC_COMPONENTS_DUALCANTALON_H_
#define SRC_COMPONENTS_DUALCANTALON_H_

#include "WPILib.h"

class DualCANTalon : public PIDOutput {
private:
        CANTalon* mAMotor;
        CANTalon* mBMotor;
        bool mAInverted;
        bool mBInverted;
public:
        DualCANTalon(int motorA, int motorB, bool AInvert, bool BInvert);
        virtual ~DualCANTalon();
        void PIDWrite(float output);
        void Set(float speed);
        float GetOutputCurrent();
        float GetOutputVoltage();
};

#endif /* SRC_COMPONENTS_DUALCANTALON_H_ */

Code:

/*
 * DualCANTalon.cpp
 *
 *  Created on: Jan 29, 2015
 *      Author: Team2481
 */

#include <Components/DualCANTalon.h>


DualCANTalon::DualCANTalon(int motorA, int motorB, bool AInvert, bool BInvert) {
        mAMotor = new CANTalon(motorA);
        mBMotor = new CANTalon(motorB);
        mAInverted = AInvert;
        mBInverted = BInvert;

        mAMotor->ConfigNeutralMode(CANTalon::kNeutralMode_Brake);
        mBMotor->ConfigNeutralMode(CANTalon::kNeutralMode_Brake);
}

DualCANTalon::~DualCANTalon() {
        delete mAMotor;
        delete mBMotor;
}

void DualCANTalon::PIDWrite(float output) {
        Set(output);
}

void DualCANTalon::Set(float speed) {
        mAMotor->Set(mAInverted ? speed * -1 : speed);
        mBMotor->Set(mBInverted ? speed * -1 : speed);
}

float DualCANTalon::GetOutputCurrent() {
        float outputCurrentA = mAMotor->GetOutputCurrent();
        float outputCurrentB = mBMotor->GetOutputCurrent();

        float averageCurrent = (outputCurrentA + outputCurrentB) / 2;

        return averageCurrent;
}

float DualCANTalon::GetOutputVoltage() {
        float outputVoltageA = mAMotor->GetOutputVoltage();
        float outputVoltageB = mBMotor->GetOutputVoltage();

        float averageVoltage = (outputVoltageA + outputVoltageB) / 2;

        return averageVoltage;
}


GeeTwo 18-02-2015 02:11

Re: Keeping two motors in sync
 
Quote:

Originally Posted by kylelanman (Post 1446194)
We linked them with a criss-cross chain and 2 sprockets and then tied them together in software under the control of 1 PID controller and 1 encoder.

Belt and suspenders? No argument here.

OBTW, by "criss-cross chain", you don't mean a figure 8, do you? It's an idea I had about two years ago when thinking about linkage drives, and that we tried to implement as a novelty in our "infinite possibilities" sign over the pit last year. Operationally, it sounds like a recipe for short chain life.

Kevin Sevcik 18-02-2015 12:51

Re: Keeping two motors in sync
 
Important question. Are the two lead screws pushing the same carriage, or are they pushing separate carriages?

On our bot, we have two screws and two independent carriages. Each carriage lifts one side of the crate. So we only have to stay mostly level, since we won't have any binding issues or anything. I modified the PID controller class so it ramps setpoints, and we're running two PID loops that ramp the setpoint position at the same rate. If the screws start level, the setpoint positions will stay level since they're moving at the same rate. The screws aren't guaranteed to stay level due to following error, but they manage fairly well. The biggest problem is that (currently) the moving setpoint is the only synchronization between the sides. If the left side jams or hits max command and starts falling behind the setpoint, the right side doesn't know or care and will continue merrily on its way.

Practically speaking, this limits our max speed, since we have to make sure we never have to hit max command for either motor, even under varying battery conditions and loading. That's obviously not ideal, but I'm still working out the most robust way to tackle that problem. Anyways, I have code for this approach if you're interested.

Another approach is what Ether talks about in this thread. There, you're semi-slaving one motor to another, and just commanding pure setpoint positions. I think that will work as well, and will take care of things if the master motor jams or maxes out, but it still doesn't handle things if the slave motor jams or maxes out. You're basically assuming that the master motor/screw is the weaker/easier to jam of the two. I don't have code for that, so you'd have to work out your own modifications to the PIDController class.

amesmich 18-02-2015 17:02

Re: Keeping two motors in sync
 
We have the same setup as you two lead screws with two seperate carriages each with their own motors and encoders. So binding is only an issue with the tote. We would like to keep it within 2 inches. We can tolerate more but within 2 is acceptable.

If you dont mind giving us an example we would greatly appreciate it. I could email you or PM you. Our programers understand the concept of PID but were not sure what values to put where. After some reading its becoming more clear, but we have never done it so not sure what we dont know.

Our main problem is that with no load at full speed one side is slightly faster. We want the PID to slow the faster since the slower woudl already be at 100%. So based on this I assume we woudl make our slower lift the "master" and slave the faster side to track the slower? I understand what your saying about the master side continuing even if the other side got stoped for some reason. I would assume you could code it so that if a max seperation value was exceeded you could stop the higher side.

Thanks for your response. This will be our project over the next few weeks.

Kevin Sevcik 18-02-2015 17:21

Re: Keeping two motors in sync
 
I don't have code for a master-slave system yet. I do have C++ code for a PIDController derivative that will let you smoothly ramp the setpoint from A to B at a given rate. As long as you have the PID loops tuned well and you keep the rate below the max speed for your slower side, things should work and stay level.

I should've asked earlier, but what language are you guys using? If it's C++, I can cleanup and better document my code tonight and post it tomorrow. If it's Java, I'll have to port things, which will take a day or two, and won't be tested, obviously. If it's Labview.... I'll have to think about how to approach the problem in Labview.

Ether 18-02-2015 17:27

Re: Keeping two motors in sync
 

I threw this together quickly. Can you guys critique it? Maybe someone can debug it on real hardware, or in a simulation.

Code:

double change, PosCmd, error1, e1pos, error1i,
error1d, cmd1, error2a, e2pos, cmd2a,
error2b, error2bi, cmd2b, cmd2;

// initialize these:

double RLPC = 0;  // Rate-Limited Position Command
double previous_error1 = 0;

// tuning constants:

double rateLimit = 1;  // allowable position change per iteration
double i1Limit = 1;    // integrator clamp for M1
double i2bLimit = 1;  // integrator clamping value for M2
double Kp1 = 0;  // PID gains
double Ki1 = 0;
double Kd1 = 0;
double Kp2 = 0;
double Ki2 = 0;


// this is your control loop:

// rate-limit the change in position command

change = PosCmd - RLPC;
if (change>rateLimit) change = rateLimit;
else if (change<-rateLimit) change = -rateLimit;
RLPC += change;

// PID controller for M1 (Master)

error1 = RLPC - e1pos;  // closed loop error
error1i += error1;  // integrate the error
if (error1i>i1Limit) error1i = i1Limit;  // clamp the integrated error
else if (error1i<-i1Limit) error1i = -i1Limit;
error1d = error1 - previous_error1; // rate of change in error1 for D term
previous_error1 = error1; // save for next iteration
cmd1 = Kp1*error1 + Ki1*error1i + Kd1*error1d;

// P + I controller for M2 (slave)

error2a = RLPC - e2pos;  // closed loop error for Proportional part
cmd2a = Kp2*error2a;

error2b = e1pos - e2pos;  // closed loop error for Integral part
error2bi += error2b;  // integrate the error
if (error2bi>i2bLimit) error2bi = i2bLimit;  // clamp the integrated error
else if (error2bi<-i2bLimit) error2bi = -i2bLimit;
cmd2b = Ki2*error2bi;

cmd2 = cmd2a + cmd2b;




GeeTwo 18-02-2015 17:49

Re: Keeping two motors in sync
 
I am wondering about the slave part:
Quote:

Originally Posted by Ether (Post 1446600)
Code:

// P + I controller for M2 (slave)

error2a = RLPC - e2pos;  // closed loop error for Proportional part
cmd2a = Kp2*error2a;

error2b = e1pos - e2pos;  // closed loop error for Integral part
error2bi += error2b;  // integrate the error
if (error2bi>i2bLimit) error2bi = i2bLimit;  // clamp the integrated error
else if (error2bi<-i2bLimit) error2bi = -i2bLimit;
cmd2b = Ki2*error2bi;

cmd2 = cmd2a + cmd2b;


Are you intentionally basing the P value on the error from the set point, but the I value on the error from the master? If so, I'm going to have to puzzle a bit as to what would happen if the master jammed.


All times are GMT -5. The time now is 14:50.

Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi