OpenHarmony开源社区
直播中

jf_25674040

2年用户 109经验值
擅长:可编程逻辑 MEMS/传感技术 接口/总线/驱动 控制/MCU
私信 关注
[经验]

【九联科技Unionpi Tiger开发板试用体验】ros noetic pwm 驱动 6100空心杯

一、硬件说明

1. 610空心杯电机模块

image.png

1.1 tc214b驱动芯片

1.1.1 tc214b 用途

image.png

1.1.2 tc214b 真值表

image.png

1.1.3 tc214b 输入输出波形

image.png

1.1.4 tc214b 推荐工作条件

image.png

2 九联 Unionpi Tiger

2.1 从九联给出的文档来看,内存、存储、以及ubuntu系统是可以满足安装ROS1中noetic版本的。

image.png

2.2 根据tc214b驱动芯片来看通过两个PWM可以做到正、反转、刹车、停、以及调速功能,根据九联手册中的给出了如下信息:

image.png

image.png
image.png

image.png

3 硬件连接

将空心杯电机G、V、INA、INB与PWM接口GND、3V3、PWM_1、PWM_2相连。
image.png

image.png

软件说明

1. 参考九联gitee的操作文档,更改完后如下:

#ifndef UM_PWM_H
#define UM_PWM_H

/*
 * Copyright (c) 2022 Unionman Technology Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

// errno
#define PWM_ERR (-1)
#define PWM_WRONOG_CHANNEL (-2)
#define PWM_FILE_NOT_EXIST (-3)

// pwm enable
#define PWM_NOT_ENABLED 0
#define PWM_IS_ENABLED 1

// pwm polarity
#define PWM_POLARITY_NORMAL 0
#define PWM_POLARITY_INVERSED 1

#define PWM1 1
#define PWM2 2

// pwm的引脚目录
#define PWM1_PEX "/sys/class/pwm/pwmchip0"
#define PWM2_PEX "/sys/class/pwm/pwmchip2"

// Hilog
#undef LOG_DOMAIN
#undef LOG_TAG
#define LOG_DOMAIN 0  // 标识业务领域,范围0x0~0xFFFFF
#define LOG_TAG "Pwm_Test"

namespace tc214b{
class UmPwm
{
public:
  UmPwm(){}
  ~UmPwm(){}
/*
 * 作用:初始化引脚,生成对应的引脚目录
 * 参数:pwmChannel 为选择的引脚
 */
int init_pwm(int pwmChannel)
{
    char pwm_file_name[128] = {0};
    (void)memset(pwm_file_name, 0, sizeof(pwm_file_name));

    if (PWM1 == pwmChannel) {
        (void)sprintf(pwm_file_name, "%s/export", PWM1_PEX);
    } else if (PWM2 == pwmChannel) {
        (void)sprintf(pwm_file_name, "%s/export", PWM2_PEX);
    } else {
        return PWM_WRONOG_CHANNEL;
    }

    if (access(pwm_file_name, F_OK) != 0) {
        return PWM_FILE_NOT_EXIST;
    }

    FILE *fp = NULL;
    fp = fopen(pwm_file_name, "w");
    if (!fp) {
        return PWM_FILE_NOT_EXIST;
    }
    (void)fprintf(fp, "%d", 0);
    (void)fclose(fp);
    fp = NULL;
    return 0;
}

/*
 * 设置pwm的溢出值
 * 参数:pwmChannel 为选择的引脚,period 为溢出值
 */
int set_pwm_period(int pwmChannel, int period)
{
    char pwm_file_name[128] = {0};
    (void)memset(pwm_file_name, 0, sizeof(pwm_file_name));

    if (PWM1 == pwmChannel) {
        (void)sprintf(pwm_file_name, "%s/pwm0/period", PWM1_PEX);
    } else if (PWM2 == pwmChannel) {
        (void)sprintf(pwm_file_name, "%s/pwm0/period", PWM2_PEX);
    } else {
        return PWM_WRONOG_CHANNEL;
    }

    if (access(pwm_file_name, F_OK) != 0) {
        return PWM_FILE_NOT_EXIST;
    }

    FILE *fp = NULL;
    fp = fopen(pwm_file_name, "r+");
    if (!fp) {
        return PWM_FILE_NOT_EXIST;
    }
    if (period) {
        fprintf(fp, "%d", period);
    }
    (void)fclose(fp);
    fp = NULL;

    return 0;
}

/*
 * 设置pwm一个周期高电平时间
 * 参数:pwmChannel 为选择的引脚,dutyCycle 为一个周期高电平的值
 */
int set_pwm_dutyCycle(int pwmChannel, int dutyCycle)
{
    char pwm_file_name[128] = {0};
    (void)memset(pwm_file_name, 0, sizeof(pwm_file_name));

    if (PWM1 == pwmChannel) {
        (void)sprintf(pwm_file_name, "%s/pwm0/duty_cycle", PWM1_PEX);
    } else if (PWM2 == pwmChannel) {
        (void)sprintf(pwm_file_name, "%s/pwm0/duty_cycle", PWM2_PEX);
    } else {
        return PWM_WRONOG_CHANNEL;
    }

    if (access(pwm_file_name, F_OK) != 0) {
        return PWM_FILE_NOT_EXIST;
    }

    FILE *fp = NULL;
    fp = fopen(pwm_file_name, "r+");
    if (!fp) {
        return PWM_FILE_NOT_EXIST;
    }
    //if (dutyCycle) {
        fprintf(fp, "%d", dutyCycle);
    //}
    (void)fclose(fp);
    fp = NULL;

    return 0;
}

/*
 * 设置pwm的极性
 * 参数:pwmChannel 为选择的引脚,polarity 为极性
 */
int set_pwm_polarity(int pwmChannel, int polarity)
{
    char pwm_file_name[128] = {0};
    (void)memset(pwm_file_name, 0, sizeof(pwm_file_name));

    if (PWM1 == pwmChannel) {
        (void)sprintf(pwm_file_name, "%s/pwm0/polarity", PWM1_PEX);
    } else if (PWM2 == pwmChannel) {
        (void)sprintf(pwm_file_name, "%s/pwm0/polarity", PWM2_PEX);
    } else {
        return PWM_WRONOG_CHANNEL;
    }

    if (access(pwm_file_name, F_OK) != 0) {
        return PWM_FILE_NOT_EXIST;
    }

    FILE *fp = NULL;
    fp = fopen(pwm_file_name, "rw+");
    if (!fp) {
        return PWM_FILE_NOT_EXIST;
    }
    if (polarity == PWM_POLARITY_NORMAL) {
        fprintf(fp, "%s", "normal");
    } else if (polarity == PWM_POLARITY_INVERSED) {
        fprintf(fp, "%s", "inversed");
    }
    (void)fclose(fp);
    fp = NULL;

    return 0;
}

/*
 * 打开pwm引脚,使其使能
 * 参数:pwmChannel 为选择的引脚,isEnable 为开关值
 */
int set_pwm_enable(int pwmChannel, int isEnable)
{
    char buffer[256] = {0};
    char pwm_file_name[128] = {0};
    (void)memset(pwm_file_name, 0, sizeof(pwm_file_name));

    if (PWM1 == pwmChannel) {
        (void)sprintf(pwm_file_name, "%s/pwm0/enable", PWM1_PEX);
    } else if (PWM2 == pwmChannel) {
        (void)sprintf(pwm_file_name, "%s/pwm0/enable", PWM2_PEX);
    } else {
        return PWM_WRONOG_CHANNEL;
    }

    if (access(pwm_file_name, F_OK) != 0) {
        return PWM_FILE_NOT_EXIST;
    }

    (void)snprintf(buffer, sizeof(buffer), "echo %d > %s", isEnable, pwm_file_name);
    system(buffer);

    return 0;
}

/*
 * 得到pwm的溢出值
 * 参数:pwmChannel 为选择的引脚
 */
int get_pwm_period(int pwmChannel)
{
    int ret = 0;
    char pwm_file_name[128] = {0};
    (void)memset(pwm_file_name, 0, sizeof(pwm_file_name));

    if (PWM1 == pwmChannel) {
        (void)sprintf(pwm_file_name, "%s/pwm0/period", PWM1_PEX);
    } else if (PWM2 == pwmChannel) {
        (void)sprintf(pwm_file_name, "%s/pwm0/period", PWM2_PEX);
    } else {
        return PWM_WRONOG_CHANNEL;
    }

    if (access(pwm_file_name, F_OK) != 0) {
        return PWM_FILE_NOT_EXIST;
    }

    FILE *fp = NULL;
    char buffer[32] = {0};
    (void)memset(buffer, 0, sizeof(buffer));
    fp = fopen(pwm_file_name, "r");
    if (!fp) {
        return PWM_FILE_NOT_EXIST;
    }
    (void)fread(buffer, sizeof(buffer), 1, fp);
    (void)fclose(fp);
    fp = NULL;

    ret = atoi(buffer);
    return ret;
}

/*
 * 得到pwm的一个周期高电平的值
 * 参数:pwmChannel 为选择的引脚
 */
int get_pwm_dutyCycle(int pwmChannel)
{
    int ret = 0;
    char pwm_file_name[128] = {0};
    (void)memset(pwm_file_name, 0, sizeof(pwm_file_name));
    if (PWM1 == pwmChannel) {
        (void)sprintf(pwm_file_name, "%s/pwm0/duty_cycle", PWM1_PEX);
    } else if (PWM2 == pwmChannel) {
        (void)sprintf(pwm_file_name, "%s/pwm0/duty_cycle", PWM2_PEX);
    } else {
        return PWM_WRONOG_CHANNEL;
    }

    if (access(pwm_file_name, F_OK) != 0) {
        return PWM_FILE_NOT_EXIST;
    }

    FILE *fp = NULL;
    char buffer[32] = {0};
    (void)memset(buffer, 0, sizeof(buffer));
    fp = fopen(pwm_file_name, "r");
    if (!fp) {
        return PWM_FILE_NOT_EXIST;
    }
    (void)fread(buffer, sizeof(buffer), 1, fp);
    (void)fclose(fp);
    fp = NULL;

    ret = atoi(buffer);
    return ret;
}

/*
 * 得到pwm的极性
 * 参数:pwmChannel 为选择的引脚
 */
int get_pwm_polarity(int pwmChannel)
{
    int ret = 0;
    char pwm_file_name[128] = {0};
    (void)memset(pwm_file_name, 0, sizeof(pwm_file_name));

    if (PWM1 == pwmChannel) {
        (void)sprintf(pwm_file_name, "%s/pwm0/polarity", PWM1_PEX);
    } else if (PWM2 == pwmChannel) {
        (void)sprintf(pwm_file_name, "%s/pwm0/polarity", PWM2_PEX);
    } else {
        return PWM_WRONOG_CHANNEL;
    }

    if (access(pwm_file_name, F_OK) != 0) {
        return PWM_FILE_NOT_EXIST;
    }

    FILE *fp = NULL;
    char buffer[32] = {0};
    (void)memset(buffer, 0, sizeof(buffer));
    fp = fopen(pwm_file_name, "r");
    if (!fp) {
        return PWM_FILE_NOT_EXIST;
    }
    (void)fread(buffer, sizeof(buffer), 1, fp);
    (void)fclose(fp);
    fp = NULL;

    if (strstr(buffer, "normal") != NULL) {
        ret = PWM_POLARITY_NORMAL;
    } else if (strstr(buffer, "inversed") != NULL) {
        ret = PWM_POLARITY_INVERSED;
    } else {
        ret = PWM_ERR;
    }

    return ret;
}

/*
 * 查看pwm的引脚使能值
 * 参数:pwmChannel 为选择的引脚
 */
int is_pwm_enabled(int pwmChannel)
{
    int ret = 0;
    char pwm_file_name[128] = {0};
    (void)memset(pwm_file_name, 0, sizeof(pwm_file_name));

    if (PWM1 == pwmChannel) {
        (void)sprintf(pwm_file_name, "%s/pwm0/enable", PWM1_PEX);
    } else if (PWM2 == pwmChannel) {
        (void)sprintf(pwm_file_name, "%s/pwm0/enable", PWM2_PEX);
    } else {
        return PWM_WRONOG_CHANNEL;
    }

    if (access(pwm_file_name, F_OK) != 0) {
        return PWM_FILE_NOT_EXIST;
    }

    FILE *fp = NULL;
    char buffer[32] = {0};
    (void)memset(buffer, 0, sizeof(buffer));
    fp = fopen(pwm_file_name, "r");
    if (!fp) {
        return PWM_FILE_NOT_EXIST;
    }
    (void)fread(buffer, sizeof(buffer), 1, fp);
    (void)fclose(fp);
    fp = NULL;

    ret = atoi(buffer);
    return ret;
}
};
}
#endif

2. ROS的常规操作

$ catkin_create_pkg tc214b roscpp std_msgs 创建ROS包
$ catkin_make 编译包
$ source 编译目录下的devel/detup.bash
$ roscore 启动master
$rosrun tc214b tc214n_node

另外重新定义以下消息格式

uint8 TC214B_WAIT = 0
uint8 TC214B_HEAD = 1
uint8 TC214B_BACK = 2
uint8 TC214B_BRAKE =3

uint8 cmd
uint32 duty_cycle

3. 部分软件代码说明

3.1 头文件中主要说明

boost::shared_ptr<tc214b::UmPwm> um_pwm_;

 uint32_t a_period_;
 uint32_t b_period_;
 uint32_t a_duty_cycle_;
 uint32_t b_duty_cycle_;

3.2 cpp文件主要说明

um_pwm_ = boost::shared_ptr<tc214b::UmPwm>(new tc214b::UmPwm());

  a_period_ = um_pwm_->get_pwm_period(PWM1);
  b_period_ = um_pwm_->get_pwm_period(PWM2);
  a_period_ = 1000000;
  b_period_ = 1000000;
  um_pwm_->set_pwm_period(PWM1, a_period_);
  um_pwm_->set_pwm_period(PWM2, b_period_);
  a_duty_cycle_ = um_pwm_->get_pwm_dutyCycle(PWM1);
  b_duty_cycle_ = um_pwm_->get_pwm_dutyCycle(PWM2);
  a_duty_cycle_ = 0;
  b_duty_cycle_ = 0;
  um_pwm_->set_pwm_dutyCycle(PWM1, a_duty_cycle_);
  um_pwm_->set_pwm_dutyCycle(PWM2, b_duty_cycle_);

  switch (msg->cmd) {
    case tc214b::Tc214bCmd::TC214B_WAIT:
      a_duty_cycle_ = 0;
      b_duty_cycle_ = 0;
      um_pwm_->set_pwm_dutyCycle(PWM1, a_duty_cycle_);
      um_pwm_->set_pwm_dutyCycle(PWM2, b_duty_cycle_);
      break;
    case tc214b::Tc214bCmd::TC214B_BACK:
      a_duty_cycle_ = 0;
      b_duty_cycle_ = msg->duty_cycle % b_period_;
      um_pwm_->set_pwm_dutyCycle(PWM1, a_duty_cycle_);
      um_pwm_->set_pwm_dutyCycle(PWM2, b_duty_cycle_);
      break;
    case tc214b::Tc214bCmd::TC214B_BRAKE:
      a_duty_cycle_ = a_period_;
      b_duty_cycle_ = b_period_;
      um_pwm_->set_pwm_dutyCycle(PWM1, a_duty_cycle_);
      um_pwm_->set_pwm_dutyCycle(PWM2, b_duty_cycle_);
      break;
    case tc214b::Tc214bCmd::TC214B_HEAD:
      a_duty_cycle_ = msg->duty_cycle % a_period_;
      b_duty_cycle_ = 0;
      um_pwm_->set_pwm_dutyCycle(PWM1, a_duty_cycle_);
      um_pwm_->set_pwm_dutyCycle(PWM2, b_duty_cycle_);
      break;
    default:
      ROS_WARN("cmd error");
      break;
  }

3.3 利用systemd将PWM初始化,其中主要配置如下

echo 0 > /sys/class/pwm/pwmchip0/export
sudo chmod a+rw /sys/class/pwm/pwmchip0/pwm0/polarity
sudo chmod a+rw /sys/class/pwm/pwmchip0/pwm0/enable
sudo chmod a+rw /sys/class/pwm/pwmchip0/pwm0/period
sudo chmod a+rw /sys/class/pwm/pwmchip0/pwm0/duty_cycle
echo normal > /sys/class/pwm/pwmchip0/pwm0/polarity
echo 1000000 > /sys/class/pwm/pwmchip0/pwm0/period
echo 0 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle
echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable

echo 0 > /sys/class/pwm/pwmchip2/export
sudo chmod a+rw /sys/class/pwm/pwmchip2/pwm0/polarity
sudo chmod a+rw /sys/class/pwm/pwmchip2/pwm0/enable
sudo chmod a+rw /sys/class/pwm/pwmchip2/pwm0/period
sudo chmod a+rw /sys/class/pwm/pwmchip2/pwm0/duty_cycle
echo normal > /sys/class/pwm/pwmchip2/pwm0/polarity
echo 1000000 > /sys/class/pwm/pwmchip2/pwm0/period
echo 0 > /sys/class/pwm/pwmchip2/pwm0/duty_cycle
echo 1 > /sys/class/pwm/pwmchip2/pwm0/enable

三、实验现象

四、总结

4.1 本实验借助电位器输入的电压值来控制占空比的输出,来实现调速

4.2 正反转、刹车都可以通过cmd来控制,暂时未通过电位器来控制,可以通过ROS指令来操作。

4.3 ros的节点的启动也可以通过systemd来控制,因为是做的整个项目,故不贴出是如何启动。

4.4 该操作可以做到上电启动就可以通过电位器来操作,后续会增加甲醛、温度的判断。

610空心杯调速

回帖(1)

醉清歌

2022-10-26 14:32:01
有趣的联动,感谢分享
举报

更多回帖

发帖
×
20
完善资料,
赚取积分