舵机转向编程实现

SG90舵机开发

舵机基本介绍

如下图所示,最便宜的舵机sg90,常用三根或者四根接线,黄色为PWM信号控制用处:垃圾桶项目开盖 用、智能小车的全比例转向、摄像头云台、机械臂等 常见的有0-90°、0-180°、0-360°

image-20240506190224115

接线

红色线:5v

黄色线:GND

灰色线:5号口

舵机接线

怎么控制转角

向黄色信号线“灌入”PWM信号。 PWM波的频率不能太高,50hz,即周期=1/频率=1/50=0.02s,20ms左右数据: 不同的PWM波形对应不同的旋转角度,以20ms为周期,50hz为频率的PWM波

高电平持续时间低电平持续时间波形图角度
0.5ms19.5msimage-202405061905006110
1ms19msimage-2024050619071412045
1.5ms18.5msimage-2024050619074690890
2.0ms18ms如上图推理135
25ms17.5ms如上图推理180

定时器需要定时20ms,关心的单位0.5ms, 20ms = 0.5ms * 40:


Linux定时器

**分析:**实现定时器,通过itimerval结构体以及函数setitimer产生的信号,系统随之使用signal信号处理 函数来处理产生的定时信号。从而实现定时器。 先看itimerval的结构体

struct itimerval
 {
    /* Value to put into `it_value' when the timer expires. */
    struct timeval it_interval;
    /* Time to the next timer expiration. */
    struct timeval it_value;
 };

it_interval:计时器的初始值,一般基于这个初始值来加或者来减,看控制函数的参数配置
it_value:程序跑到这之后,多久启动定时器
    
struct timeval
{
  __time_t tv_sec; /* Seconds. */
  __suseconds_t tv_usec; /* Microseconds. */
};

int setitimer (__itimer_which_t __which,
      const struct itimerval *__restrict __new,
      struct itimerval *__restrict __old)

setitimer()将value指向的结构体设为计时器的当前值,如果ovalue不是NULL,将返回计时器原有值。

which:三种类型

ITIMER_REAL //数值为0,计时器的值实时递减,发送的信号是SIGALRM。 ITIMER_VIRTUAL //数值为1,进程执行时递减计时器的值,发送的信号是SIGVTALRM。 ITIMER_PROF //数值为2,进程和系统执行时都递减计时器的值,发送的信号是SIGPROF。

很明显,这边需要捕获对应的信号进行逻辑相关处理signal(SIGALRM,signal_handler);

返回说明:

成功执行时,返回0。失败返回-1

实现代码:

/*创建一个每0.5秒触发一次的定时器,并且在第一次触发1秒后,每隔0.5秒触发一次。每次触发时,都会调用signal_handler函数,该函数内部有一个计数器i,当计数器达到2000时,会打印出"hello",并将计数器重置为0,以便重新开始计数。程序将一直运行,直到外部中断。*/

#include <stdio.h> // 标准输入输出库
#include <sys/time.h> // 系统时间库,用于时间相关的操作
#include <stdlib.h> // 标准库,提供一些通用函数,如exit
#include <signal.h> // 信号处理库

static int i; // 静态变量i,用于计数

// 信号处理函数,当接收到SIGALRM信号时被调用
void signal_handler(int signum) {
    i++; // 每次信号到来时,i的值增加1
    if(i == 2000){ // 每接收到2000次信号,输出hello
        printf("hello\n");
        i = 0; // 重置i的值为0,重新开始计数
    }
}

int main() {
    struct itimerval itv; // 定义一个itimerval结构体,用于设置定时器

    // 设置定时器的间隔,即每隔一段时间就发送SIGALRM信号
    itv.it_interval.tv_sec = 0; // 间隔的秒数设置为0
    itv.it_interval.tv_usec = 500; // 间隔的微秒数设置为500,即0.5秒

    // 设置定时器的初始值,即定时器启动后多久发送第一次SIGALRM信号
    itv.it_value.tv_sec = 1; // 初始值的秒数设置为1秒
    itv.it_value.tv_usec = 0; // 初始值的微秒数设置为0

    // 使用setitimer设置定时器
    if(-1 == setitimer(ITIMER_REAL, &itv, NULL)){ // 如果设置失败
        perror("error"); // 打印错误信息
        exit(-1); // 退出程序
    }

    // 注册SIGALRM信号的处理函数为signal_handler
    signal(SIGALRM, signal_handler);

    while(1); // 无限循环,等待信号的到来

    return 0;
}

这种方法需要注意的是,一个进程只能创建一个定时器

代码与运行结果

1.本次使用的舵机,与前面描述的舵机在控制角度上略有差异,输出占空比为 2.5% 的 PWM 信号时,舵机旋转至 0 度的位置,输出占空比为 12.5% 的 PWM 信号时,舵机旋转至 180 度。

#include <stdio.h> // 标准输入输出库
#include <stdlib.h> // 标准库,提供exit等函数
#include <wiringPi.h> // Wiring Pi GPIO操作库
#include <softPwm.h> // Wiring Pi提供的软件PWM库

#define PWM_PIN 5 // 定义PWM信号输出的GPIO引脚编号为5
#define PWM_CYCLE 200 // 设置PWM周期为20毫秒
#define PWM_DUTY_MAX 25 // 设置PWM最大占空比为12.5%(2.5毫秒脉宽)
#define PWM_DUTY_MIN 5 // 设置PWM最小占空比为2.5%(0.5毫秒脉宽)

int main(void) {
    if (wiringPiSetup() == -1) // 初始化WiringPi库
        exit(1); // 如果初始化失败,退出程序

    softPwmCreate(PWM_PIN, PWM_DUTY_MAX, PWM_CYCLE); // 初始化指定的PWM引脚,设置最大脉宽和周期

    int val = PWM_DUTY_MAX; // 初始化PWM脉宽变量
    int mark = 0; // 初始化转向标志

    while (1) { // 无限循环,持续控制舵机
        if (mark == 0) // 如果当前是递减过程
            val--; // 脉宽减1
        else // 否则(当前是递增过程)
            val++; // 脉宽加1

        if (val <= PWM_DUTY_MIN) // 如果脉宽小于等于最小脉宽
            mark = 1; // 切换到递增过程
        if (val >= PWM_DUTY_MAX) // 如果脉宽大于等于最大脉宽
            mark = 0; // 切换到递减过程

        softPwmWrite(PWM_PIN, val); // 写入当前脉宽值到PWM引脚
        delay(100); // 等待100毫秒,产生可见的舵机转动
    }

    return 0; // 正常退出程序,但实际不会执行到这里,因为while(1)是无限循环
}


2.SG90编程实现:键盘输入不同的值,让舵机转动,软件PWM实现

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <wiringPi.h>
#include <softPwm.h>

#define SG90Pin 5 // 定义舵机连接的GPIO引脚编号
#define PWM_MIN 5  // 舵机最小PWM脉宽值
#define PWM_MAX 25 // 舵机最大PWM脉宽值
#define PWM_RANGE (PWM_MAX - PWM_MIN) // PWM脉宽值范围

int jd; // 用户输入的角度值

// 信号处理函数,根据用户输入的角度值调整PWM占空比
void signal_handler(int signum) {
    // 根据用户输入的角度和PWM脉宽值范围计算PWM的占空比
   int pwmValue = PWM_MIN + (PWM_RANGE * jd) / 180;
    softPwmWrite(SG90Pin, pwmValue); // 设置PWM占空比
}

int main() {
   struct itimerval itv;
    jd = 0;
    if (wiringPiSetup() == -1) {
       exit(1); // 初始化wiringPi失败则退出
    }
    pinMode(SG90Pin, OUTPUT); // 设置SG90Pin为输出模式
    softPwmCreate(SG90Pin, PWM_MIN, PWM_MAX); // 创建软件PWM

   // 设置定时器间隔为0.5秒,用于周期性更新PWM值
    itv.it_interval.tv_sec = 0;
    itv.it_interval.tv_usec = 500;
     // 设置定时器第一次触发时间为1秒后
    itv.it_value.tv_sec = 1;
    itv.it_value.tv_usec = 0;
    if (-1 == setitimer(ITIMER_REAL, &itv, NULL)) {
        perror("error"); // 设置定时器失败则打印错误并退出
      exit(-1);
     }

    // 注册信号SIGALRM的处理函数
    signal(SIGALRM, signal_handler);

     while (1) {
         printf("input angle (0-180): \n"); // 提示用户输入角度
         scanf("%d", &jd); // 读取用户输入的角度
       if (jd < 0 || jd > 180) {
             printf("Angle out of range. Please enter a value between 0 and180.\n");
            jd = 0; // 重置角度为0
        }
     }

   return 0;
 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值