带步进电机的拾放机器人的平稳运动

Smooth movement of Pick and drop robot with stepper motor

提问人:Anshul Lanjewar 提问时间:9/21/2023 最后编辑:cyberbrainAnshul Lanjewar 更新时间:9/22/2023 访问量:70

问:

我正在构建一个具有 3 个步进电机的拾放机器人。我正在使用 NUCLEO-F746ZG 微控制器和 C++ 编程来控制它。

现在的问题是手臂在开始和结束时会随着抽搐(惯性)而移动,我想平滑运动。为此,我想在电机启动时加速,在电机停止时减速。我尝试了不同的方法,但没有一个有效,电机只能以恒定速度移动。请帮我解决这个问题,使步进电机平稳移动。

#include "stepperMotor.h"
#include "mbed.h"

int motorSpeed; // stepper speed
const float acc = 100;
int mspeed;

sMotor::sMotor(PinName A0, PinName A1, PinName A2, PinName A3) : _A0(A0), _A1(A1), _A2(A2), _A3(A3)
{ // Defenition of motor pins
    _A0 = 0;
    _A1 = 0;
    _A2 = 0;
    _A3 = 0;
}

void sMotor::anticlockwise(int mspeed)
{ // rotate the motor 1 step anticlockwise 
     for (int i = 0; i < 8; i++) {
        switch (i)
        { // activate the ports A0, A2, A3, A3 in a binary sequence for steps
            case 0:
            {
                _A0 = 0;
                _A1 = 0;
                _A2 = 1;
                _A3 = 0;
            }
            break;

            case 1:
            {
                _A0 = 0;
                _A1 = 0;
                _A2 = 0;
                _A3 = 0;
            }
            break;

            case 2:
            {
                _A0 = 0;
                _A1 = 0;
                _A2 = 0;
                _A3 = 1;
            }
            break;

            case 3:
            {
                _A0 = 0;
                _A1 = 1;
                _A2 = 0;
                _A3 = 1;
            }
            break;

            case 4:
            {
                _A0 = 0;
                _A1 = 1;
                _A2 = 1;
                _A3 = 1;
            }
            break;

            case 5:
            {
                _A0 = 1;
                _A1 = 1;
                _A2 = 1;
                _A3 = 1;
            }
            break;

            case 6:
            {
                _A0 = 1;
                _A1 = 0;
                _A2 = 1;
                _A3 = 1;
            }
            break;

            case 7:
            {
                _A0 = 1;
                _A1 = 0;
                _A2 = 1;
                _A3 = 0;
            }
            break;
        }

        wait_us(mspeed);
      // wait_us(motorSpeed); // wait time defines the speed 
        
    }
}

void sMotor::clockwise(int mspeed)
{ // rotate the motor 1 step clockwise 
    for (int i = 7; i >= 0; i--) {
        switch (i)
        {
            case 0:
            {
                _A0 = 0;
                _A1 = 0;
                _A2 = 0;
                _A3 = 1;
            }
            break;

            case 1:
            {
                _A0 = 0;
                _A1 = 0;
                _A2 = 1;
                _A3 = 1;
            }
            break;

            case 2:
            {
                _A0 = 0;
                _A1 = 0;
                _A2 = 1;
                _A3 = 0;
            }
            break;

            case 3:
            {
                _A0 = 0;
                _A1 = 1;
                _A2 = 1;
                _A3 = 0;
            }
            break;

            case 4:
            {
                _A0 = 0;
                _A1 = 1;
                _A2 = 0;
                _A3 = 0;
            }
            break;

            case 5:
            {
                _A0 = 1;
                _A1 = 1;
                _A2 = 0;
                _A3 = 0;
            }
            break;

            case 6:
            {
                _A0 = 1;
                _A1 = 0;
                _A2 = 0;
                _A3 = 0;
            }
            break;

            case 7:
            {
                _A0 = 1;
                _A1 = 0;
                _A2 = 0;
                _A3 = 1;
            }
            break;
        }
        wait_us(mspeed);
    }
}

void sMotor::step(int num_steps, int direction, int speed)
{// steper function: number of steps, direction (0- right, 1- left), speed (default 1200)
    int count = 0; // initalize step count
    float stepTime = 1.0 / speed;  //aTry
    int w = num_steps;
    mspeed = 250;
    int speedMultiplier = 10;
    
    motorSpeed = speed; //set motor speed
    if (direction == 0) // turn clockwise
        do
        {
            clockwise(mspeed);
            count++;

            for (int i = 0; i < (w/4); i++)
            {
                while (mspeed != speed)
                {
                    mspeed = mspeed - speedMultiplier;
                } 
            }
            for (int i = w/4; i < 3 * (w / 4); i++)
            {
                mspeed = speed; 
            }            
            for (int i = 3 * (w / 4); i < w; i++)
            {
                while (mspeed != 400)
                {
                    mspeed = mspeed + speedMultiplier;
                }
            }
        } while (count < num_steps); // turn number of steps applied 
        
    else if (direction == 1) // turn anticlockwise
    { 
        count = 0;
        do
        {
            anticlockwise(mspeed);
            count++;      

            for (int i = 0; i < (w / 4); i++)
            {
                while (mspeed != speed)
                {
                    mspeed = mspeed - speedMultiplier;
                } 
            }
            for (int i = w/4; i < 3 * (w / 4); i++)
            {
                mspeed = speed; 
            }            
            for (int i = 3 * (w / 4); i < w; i++)
            {
                while (mspeed != 400)
                {
                    mspeed = mspeed + speedMultiplier;
                }
            }
        } while (count < num_steps);// turn number of steps applied 
    }
}
C++ 机器人 固件 步进 Nucleo

评论

0赞 SK-logic 9/24/2023
顺便说一句 - 计算平滑轨迹的常用方法是使用 5 次方多项式函数。很容易找到这样一个函数的多项式系数,其约束条件是速度和加速度在轨迹的终点为 0,在中间点的最大值。

答:

1赞 cyberbrain 9/21/2023 #1

你的代码中有一些可能的改进:你有一个字段,你有两个方法中的参数 - 参数覆盖该字段。但是,正如您现在实现的那样,该参数根本不是必需的,因为方法和可以访问字段。mspeedmspeedclockwiseanticlockwisemspeed

此外,您分配了该字段,但从未使用它。motorspeed

字段和参数的名称具有误导性,通常移动速度更快,速度更快,但您将其用作等待时间,因此名称会更好。mspeeddelay

对于 和 方法:您确定使用正确的值和正确的顺序来激活步进电机的线圈吗?根据我的理解,您应该有一个完整步骤的值列表,您可以在一个方向上顺时针“播放”它,在相反方向上“播放”逆时针运动。这样,您就不必使用语句,也不必对两个方向使用一种方法。clockwiseanticlockwiseswitch

在方法中,您应该使用更好的名称,也许? 同样在该方法中,你有一个巨大的代码块,用于顺时针和逆时针运动,它是完全相等的,只是对 和 方法的调用不同。为了防止代码重复错误,应将该外部进一步移到内部,以便它仅决定对两个方法之一的实际调用。这是最重要的改进,因为如果您的出现问题,它会对修复产生影响!stepwpositionclockwiseanticlockwiseif

针对您的实际问题: 在您的方法中,您使用三个循环将延迟(速度)从目标位置的 0 降低到 1/4,将其保持静止从 1/4 到目标位置的 3/4,最后再次将延迟从 3/4 增加到完整的目标位置。 在加速和减速循环中,你有一个循环。 所有这些嵌套循环都包含在一个用于步进的外部循环中。stepforforwhiledowhile

但是:你只需要外层 - 循环。每一步都运行内部回路,因此电机的每一步都会加速、保持恒定和减速。 相反,你应该有一个嵌套在最外层的循环中,它决定每个周期:dowhileif

  • 如果在目标范围()的第一个四分之一,则进行加速countnum_steps
  • 否则,如果在目标范围的最后四分之一,则进行减速count
  • 否则,请使用方法中给定的延迟。step

请注意,为了获得更平稳的运动,您必须在方法中处理加速和减速,以将电机移动一整步,因为实际上您为一个步骤执行了 8 次相同的延迟,但您也可以在那里改变它!

这里有一些方法的代码 - 请注意,我的 C++ 知识已经好几年没有使用过了,我也无法测试这段代码,所以我不知道它是否能编译。必要时随时修复它;-)step

void sMotor::step(int num_steps, int direction, int delay)
{// stepper function: number of steps, direction (0- right, 1- left), waiting time (default 1200)
    int speedMultiplier = 10; 

    // ensure that input delay param is used for the largest part.
    mspeed = delay + speedMultiplier * num_steps / 4;

    for (int step = 0; step < num_steps; ++step)
    {
        if (step < (num_steps / 4))
        {
            mspeed -= speedMultiplier;
        }
        else if (step > (3 * (num_steps / 4)))
        {
            mspeed += speedMultiplier;
        }
        else
        {
            mspeed = delay;
        }

        if (direction == 0)
        {
            clockwise(mspeed);
        }
        else if (direction == 1)
        {
            anticlockwise(mspeed);
        }
    }
}

此代码在步骤之间不使用加速和减速,因此优化由您决定。

评论

0赞 Anshul Lanjewar 9/21/2023
感谢您的帮助,您能帮我更多更新加速和减速的代码吗?我的最终目标是使运动平稳。
0赞 cyberbrain 9/22/2023
我希望我的代码片段对您有所帮助,但我没有涵盖所有可能的改进,因为我缺乏测试它的能力。