倍福:驱动电机两种控制方式对比

驱动电机两种控制方式对比

在这里插入图片描述

验证用修改Override值控制电机转速的实际效果

规定反复启动Mc_MoveVelocity功能块为方法一,修改Override值为方法二

control_drive.cpp

#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
#include "myAds.hpp"
#include "myTools.hpp"

AdsTalker::Ptr adsCtrl;
AidTool::Ptr aidTool;

#define MC_Positive_Direction 1
#define MC_Negative_Direction 3;
const double rotate_reduce = 100.0;
const double drive_reduce = 50.0;
const double tire_diameter = 0.155;
const double twincat_ratio = 360.0;
const double V_MAXSPEED = 0.2;

void cmd_callback(const geometry_msgs::Twist::ConstPtr &cmd_msg)
{
    //通过不断重新启动Mc_MOveVelocity功能块更改速度
    adsCtrl->drive_move_vel_val = (cmd_msg->linear.x / (M_PI * tire_diameter)) * rotate_reduce * twincat_ratio;
    adsCtrl->drive_move_vel_do = false;
    adsCtrl->drive_halt = false;
    cout << aidTool->toc() << " " << adsCtrl->drive_move_vel_val << " " << adsCtrl->drive_act_vel << endl; 
    if (adsCtrl->drive_move_vel_val > 0)
    {
        adsCtrl->drive_move_vel_direction = MC_Positive_Direction;
        adsCtrl->drive_move_vel_do = true;
    }
    else if (adsCtrl->drive_move_vel_val < 0)
    {
        adsCtrl->drive_move_vel_val = -adsCtrl->drive_move_vel_val;
        adsCtrl->drive_move_vel_direction = MC_Negative_Direction;
        adsCtrl->drive_move_vel_do = true;
    }
    else
    {
        adsCtrl->drive_halt = true;
        if (adsCtrl->drive_halt_over)
        {
            adsCtrl->drive_halt = false;
        }
    }

    //控制速度比率从而控制电机速度
    // adsCtrl->drive_move_vel_do = false;
    // double velocity_ratio = cmd_msg->linear.x / V_MAXSPEED;
    // if (cmd_msg->linear.x < 0)
    // {
    //     adsCtrl->drive_move_vel_direction = MC_Negative_Direction;
    //     adsCtrl->drive_move_vel_do = true;
    //     adsCtrl->drive_vel_ratio = - velocity_ratio * 100;
    // }
    // else if (cmd_msg->linear.x > 0)
    // {
    //     adsCtrl->drive_move_vel_direction = MC_Positive_Direction;
    //     adsCtrl->drive_move_vel_do = true;
    //     adsCtrl->drive_vel_ratio = velocity_ratio * 100;
    // }
    // else
    // {
    //     adsCtrl->drive_move_vel_ratio = 0.0;
    //     adsCtrl->drive_halt = true;
    //     if (adsCtrl->drive_halt_over)
    //     {
    //         adsCtrl->drive_halt = false;
    //     }
    // }
    // cout << aidTool->toc() << " " << adsCtrl->drive_move_vel_val * velocity_ratio << " " << adsCtrl->drive_act_vel << endl; 
}

int main(int argc, char *argv[])
{
    string netid = "169.254.254.142.1.1";
    string ipv4 = "169.254.254.142";
    adsCtrl = make_shared<AdsTalker>(netid, ipv4, AMSPORT_R0_PLC_TC3);
    aidTool = make_shared<AidTool>();

    if (adsCtrl->motor_enable)
    {
        cout << "Motor enabled!" << endl;
    }
    else
    {
        cout << "Motor disabled!" << endl;
        adsCtrl->motor_enable = !adsCtrl->motor_enable;
    }
    // adsCtrl->drive_move_vel_do = true;
    // adsCtrl->drive_vel_ratio = 0.0;
    // adsCtrl->drive_move_vel_val = (V_MAXSPEED / (M_PI * tire_diameter)) * rotate_reduce * twincat_ratio;

    ros::init(argc, argv, "ads_jog");
    ros::NodeHandle nh;
    aidTool->tic();
    ros::Subscriber cmd_sub = nh.subscribe("/cmd_vel", 1, cmd_callback);

    ros::spin();

    return 0;
}

在AidTool里添加了记录程序运行时间的功能,也可以用作时间戳,这里是借鉴了**A-LOAM**

#ifndef MY_TOOLS_H
#define MY_TOOLS_H

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <time.h>
#include <string.h>
#include <memory>
#include <chrono>

using namespace std;

class AidTool
{
private:
    chrono::time_point<chrono::system_clock> start, end;
public:
    typedef shared_ptr<AidTool> Ptr;

    AidTool(){};

    char *getNowTime(void)
    {
        time_t timer;
        struct tm *now_time;
        timer = time(NULL);
        now_time = localtime(&timer);
        return asctime(now_time);
    }

    char *getPreciseTime(void)
    {
        static char timestr[200] = {0};
        struct tm *pTempTm;
        struct timeval time;

        gettimeofday(&time, NULL);
        pTempTm = localtime(&time.tv_sec);
        if (pTempTm != NULL)
        {
            snprintf(timestr, 199, "%04d-%02d-%02d %02d:%02d:%02d.%03ld",
                     pTempTm->tm_year + 1900, pTempTm->tm_mon + 1,
                     pTempTm->tm_mday, pTempTm->tm_hour, pTempTm->tm_min,
                     pTempTm->tm_sec, time.tv_usec / 1000);
        }
        return timestr;
    }

    void tic()
    {
        start = chrono::system_clock::now();
    }

    double toc()
    {
        end = chrono::system_clock::now();
        chrono::duration<double> elapsed_seconds = end - start;
        return elapsed_seconds.count() * 1000;
    }

    ~AidTool(){};
};

#endif

记录分别在下面几个txt,02效果不太好,没有用

  • 2022-10-19-moorn01.txt(beckhoff_drive_mod1_00.csv)
  • 2022-10-19-moorn02.txt
  • 2022-10-19-moorn03.txt(beckhoff_drive_mod2_00.csv)

可以在Excel中绘制,但效果不太好,上下分别为方法一和二

在这里插入图片描述

在这里插入图片描述

所以在MATLAB里绘图,beckhoff_drivemod_comp.m

time除1000是因为log里的单位是ms,绘图时会比较大,以s为单位更合适

data1 = csvread('beckhoff_drive_mod1_00.csv',2,0);
time1 = data1(:,1) / 1000.0;
target_velocity1 = data1(:,2);
actual_velocity1 = data1(:,3);

figure(1);
plot(time1,target_velocity1,'g');
xlabel('时间/s');
ylabel('转速/度/s');
title('电机控制方式一');
grid on;
xlim([0,35]);
ylim([-15000,13000]);
set(gca,'xtick',0:2.5:35);
set(gca,'ytick',-15000:2000:13000);
hold on;
plot(time1,actual_velocity1,'r');
legend('目标转速','实际转速');
hold on;

data2 = csvread('beckhoff_drive_mod2_00.csv',2,0);
time2 = data2(:,1) / 1000.0;
target_velocity2 = data2(:,2);
actual_velocity2 = data2(:,3);

figure(2);
plot(time2,target_velocity2,'g');
xlabel('时间/s');
ylabel('转速/度/s');
title('电机控制方式二');
grid on;
xlim([0,30]);
ylim([-15000,15000]);
set(gca,'xtick',0:2.5:30);
set(gca,'ytick',-15000:2000:15000);
hold on;
plot(time2,actual_velocity2,'r');
legend('目标转速','实际转速');
hold on;

效果如下,上下分别为方法一和二

在这里插入图片描述

在这里插入图片描述

两种方法对目标速度的跟随都比较好,方法一更利于实现转向速度的补偿,因此仍采用方法一控制驱动电机

当前的独轮车控制代码,control_test.cpp

#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
#include <mutex>
#include "myAds.hpp"
#include "myTools.hpp"

AdsTalker::Ptr adsCtrl;
AidTool::Ptr aidTool;

#define MC_Positive_Direction 1
#define MC_Negative_Direction 3;
const double rotate_reduce = 100.0;
const double drive_reduce = 50.0;
const double tire_diameter = 0.155;
const double twincat_ratio = 360.0;

mutex mut;

bool rotateHome()
{
    lock_guard<mutex> lock(mut);
    adsCtrl->home_vel = 0.05 * twincat_ratio * rotate_reduce;

    int count = 0;
    while (!adsCtrl->couple_over && count <= 10)
    {
        adsCtrl->home_run = false;
        adsCtrl->couple_do = false;
        ++count;
        adsCtrl->couple_do = true;
    }
    adsCtrl->decouple_do = false;

    adsCtrl->home_do = true;
    while (!adsCtrl->rotate_act_vel)
    {
        adsCtrl->home_run = false;
        adsCtrl->home_run = true;
        usleep(1000);
    }

    while (!adsCtrl->home_over)
    {
        cout << "Tire is homing..." << endl;
    }
    if (adsCtrl->home_over)
    {
        cout << "Tire succeeds to back home!" << endl;
        adsCtrl->home_do = false;
        return true;
    }
    mut.unlock();
    return false;
}

void cmd_callback(const geometry_msgs::Twist::ConstPtr &cmd_msg)
{
    //判断是否为回零命令
    if (cmd_msg->linear.z == -1.0)
    {
        if (abs(adsCtrl->rotate_act_pos) > 10.0)
        {
            if (!rotateHome())
            {
                ROS_ERROR("Tire fails to back home!");
                return;
            }
        }
    }

    lock_guard<mutex> lock(mut);
    adsCtrl->ptpRel_pos = (cmd_msg->angular.z / (M_PI * 2)) * twincat_ratio * rotate_reduce;
    adsCtrl->drive_move_vel_val = (cmd_msg->linear.x / (M_PI * tire_diameter)) * rotate_reduce * twincat_ratio;
    //转向电机控制
    adsCtrl->ptpRel_do = false;
    if (adsCtrl->ptpRel_pos != 0)
    {
        adsCtrl->ptpRel_do = true;
    }
    if (adsCtrl->ptpRel_over)
    {
        adsCtrl->ptpRel_do = false;
    }

    //驱动电机控制
    adsCtrl->drive_move_vel_do = false;
    adsCtrl->drive_halt = false;
    adsCtrl->rotate_statusCheck = false;
    adsCtrl->rotate_statusCheck = true;
    if (fabs(adsCtrl->rotate_act_vel) > 60)
    {
        if (!adsCtrl->rotate_isDecelerating)
        {
            adsCtrl->drive_move_vel_val = adsCtrl->drive_move_vel_val + adsCtrl->rotate_act_vel / 2;
        }
    }
    cout << aidTool->getPreciseTime() << "  drive target velocity:" << adsCtrl->drive_move_vel_val << "; drive actual velocity:" << adsCtrl->drive_act_vel << "; rotate actual velocity:" << adsCtrl->rotate_act_vel << endl;
    if (adsCtrl->drive_move_vel_val > 0)
    {
        adsCtrl->drive_move_vel_direction = MC_Positive_Direction;
        adsCtrl->drive_move_vel_do = true;
    }
    else if (adsCtrl->drive_move_vel_val < 0)
    {
        adsCtrl->drive_move_vel_val = -adsCtrl->drive_move_vel_val;
        adsCtrl->drive_move_vel_direction = MC_Negative_Direction;
        adsCtrl->drive_move_vel_do = true;
    }
    else
    {
        adsCtrl->drive_halt = true;
        if (adsCtrl->drive_halt_over)
        {
            adsCtrl->drive_halt = false;
        }
    }
    mut.unlock();
}

int main(int argc, char *argv[])
{
    string netid = "169.254.254.142.1.1";
    string ipv4 = "169.254.254.142";
    adsCtrl = make_shared<AdsTalker>(netid, ipv4, AMSPORT_R0_PLC_TC3);
    aidTool = make_shared<AidTool>();

    if (adsCtrl->motor_enable)
    {
        cout << "Motor enabled!" << endl;
    }
    else
    {
        cout << "Motor disabled!" << endl;
        adsCtrl->motor_enable = !adsCtrl->motor_enable;
    }
    adsCtrl->ptp_vel = 0.1 * twincat_ratio * rotate_reduce;
    adsCtrl->drive_vel_ratio = 100.0;

    if (!rotateHome())
    {
        ROS_ERROR("Tire fails to back home!");
        return -1;
    }

    ros::init(argc, argv, "ads_control");
    ros::NodeHandle nh;
    ros::Subscriber cmd_sub = nh.subscribe("/cmd_vel", 1, cmd_callback);

    ros::spin();

    return 0;
}
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Prejudices

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值