将空心杯电机G、V、INA、INB与PWM接口GND、3V3、PWM_1、PWM_2相连。
#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
$ 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
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_;
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;
}
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
更多回帖