舵机的控制
舵机的伺服系统由可变宽度的脉冲来进行控制,控制线是用来传送脉冲的。脉冲的参数有最小值,最大值,和频率。一般而言,舵机的基准信号都是周期为20ms,宽度为1.5ms。这个基准信号定义的位置为中间位置。舵机有最大转动角度,中间位置的定义就是从这个位置到最大角度与最小角度的量完全一样。最重要的一点是,不同舵机的最大转动角度可能不相同,但是其中间位置的脉冲宽度是一定的,那就是1.5ms。
编程原理
ESP32C3针对LED的控制,提供了6个独立的PWM生成器,可实现占空比自动渐变,最大精度14位。本程序采用13位精度,角度值取整数。实现了从-90°到90°的舵机信号输出,每秒偏转10°。
#include "driver/ledc.h"
#define SERVO_MIN_PULSEWIDTH_US (1000) // Minimum pulse width in microsecond
#define SERVO_MAX_PULSEWIDTH_US (2000) // Maximum pulse width in microsecond
#define SERVO_MAX_DEGREE (90) // Maximum angle in degree upto which servo can rotate
#define SERVO_FREQUENCY (50) //PWM frequency
static uint32_t convert_servo_angle_to_duty(int angle)
{
uint32_t us;
if((angle > SERVO_MAX_DEGREE) || (angle + SERVO_MAX_DEGREE < 0)){
angle = 0;
}
us = SERVO_MIN_PULSEWIDTH_US + (angle + SERVO_MAX_DEGREE) * (SERVO_MAX_PULSEWIDTH_US - SERVO_MIN_PULSEWIDTH_US) / (2 * SERVO_MAX_DEGREE);
//printf("angle: %d us:%d\r\n",angle,us);
return (int)(SERVO_FREQUENCY*us*8191/1000000);//仅针对LEDC_TIMER_13_BIT
}
//舵机每秒钟完成10°的偏转,从负90°至正90°共180°。信号频率50hz,未采用平滑过渡。
void servo_control_task(void){
#define SERVO_LS_CH0_GPIO (5)
#define SERVO_LS_CH0_CHANNEL LEDC_CHANNEL_0
uint16_t duty;//from 0 to 8*1024-1
ledc_timer_config_t servo_timer = {
.duty_resolution = LEDC_TIMER_13_BIT, // resolution of PWM duty
.freq_hz = SERVO_FREQUENCY, // frequency of PWM signal
.speed_mode = LEDC_LOW_SPEED_MODE, // timer mode
.timer_num = LEDC_TIMER_1, // timer index
.clk_cfg = LEDC_AUTO_CLK, // Auto select the source clock
};
ledc_timer_config(&servo_timer);
ledc_channel_config_t servo_channel = {
.channel = LEDC_LS_CH0_CHANNEL,
.duty = 0,
.gpio_num = LEDC_LS_CH0_GPIO,
.speed_mode = LEDC_LOW_SPEED_MODE,
.hpoint = 0,
.timer_sel = LEDC_TIMER_1,
.flags.output_invert = 0
};
// Set LED Controller with previously prepared configuration for servo control
ledc_channel_config(&servo_channel);
do{
for(int i=(0-SERVO_MAX_DEGREE) ; i<=SERVO_MAX_DEGREE;i++){
duty = convert_servo_angle_to_duty(i);
//printf("Servo is on %d degree\r\n",i);
ledc_set_duty(servo_channel.speed_mode, servo_channel.channel, duty);
ledc_update_duty(servo_channel.speed_mode, servo_channel.channel);
vTaskDelay(100/portTICK_PERIOD_MS);
}
for(int i=SERVO_MAX_DEGREE; i>=(0-SERVO_MAX_DEGREE);i--){
duty = convert_servo_angle_to_duty(i);
//printf("Servo is on %d degree\r\n",i);
ledc_set_duty(servo_channel.speed_mode, servo_channel.channel, duty);
ledc_update_duty(servo_channel.speed_mode, servo_channel.channel);
vTaskDelay(100/portTICK_PERIOD_MS);
}
}while (1);
}
void app_main(void)
{
servo_control_task();
}
以前买过几个小舵机不知道在哪个角落吃灰,手头没有找到,用示波器看了下波形,没问题。