5iMX.com 我爱模型 玩家论坛 ——专业遥控模型和无人机玩家论坛(玩模型就上我爱模型,创始于2003年)
标题:
关于arduino舵机扑翼机的全部说明以及教程
[打印本页]
作者:
boyboyboy
时间:
2022-11-20 13:23
标题:
关于arduino舵机扑翼机的全部说明以及教程
本帖最后由 boyboyboy 于 2022-11-22 23:27 编辑
欢迎大家进来观看哈,好久没上论坛,感觉这个好东西一定要分享给我爱模型,一直在发短视频之类的自媒体,视频很多,喜欢的、感兴趣的大家可以关注一下哈~抖音/西瓜/头条/B站,ID:飞行小匠,如有问题可通过自媒体平台联系到我,纯属爱好、义务发帖
正题:
声明:国内基本上没有关于舵机扑翼机的相关教程,我个人又特别喜欢,所以才做的这个教程类的东西,希望大家多多支持
以下是第一代编程扑翼机的总体规划,最终飞行效果不是很好,见自媒体视频有详细说明
我个人也不是商业使用,纯粹的爱好者,给大家分享出来,希望所有感兴趣的网友可以一起制作,一起玩,有个爱好不容易,模友本来就是应该分享的,这篇文章应该算是干货吧。。。
关于这段代码:每个信号都需要自己的一组中断函数。单个输入来说还可以,但对于多个信号来说,它感觉很笨拙。理想情况下,可以使用单个函数来解码任意数量的 PWM 信号。
能够找到非常接近这个理想的东西:
使用 Arduino 解码 6 个伺服通道输入--最紧凑和简洁的方法。(这段代码是一个国外网友的,哪个国家的我忘记了抱歉,很感谢他,这是第一代代码)
有了这个很好的例子,重命名了一些变量并稍微修改了逻辑,但主要添加的是一个死区过滤器,以解决micros() 函数的不确定性用于对信号进行计时。除此之外,通过一个额外的指数滤波器传递输入,以去除任何未被死区过滤的尖峰。结果是可以操纵以控制伺服系统的非常平滑的输入信号。
其余代码仅创建两个可以由伺服系统解释的振荡 PWM 信号。接收器输入用于执行以下操作:
- 油门控制襟翼幅度;线性变化,因此油门加倍会使振幅加倍。
- 俯仰控制机翼的平面角。两个翅膀被命令同时上升。
- 滚动控制机翼的不对称平面角。一个翼被命令上升,另一个下降。 作者:飞行小匠
https://www.bilibili.com/read/cv18947607
出处:bilibili
扑翼机第一代飞行测试:
扑翼机第三代飞行测试:
尾翼设计制作教程:
舵机扑翼测试:
一下为第一代扑翼机pwm信号代码
[hide=d3000][hide=d3000]#include <Servo.h>
// -- Constants:
// PWM input:
const int N_INPUTS = 3;
const int DEADBAND = 4;
// PWM output:
const int PWM_CHANGE = 500;
const int PWM_MID = 1500;
const float DECAY_INPUT = 0.1;
// Amplitude control:
const int AMP_CUTOFF = 10;
const int AMP_OFFSET = 300;
// Wave signals:
const float WAVE_INT = 150.0; // Half period
const float FREQ = PI/WAVE_INT;
//-- Variables:
Servo servo[2];
volatile int16_t pwm_raw[N_INPUTS] = {0};
int16_t pwm_input[N_INPUTS] = {0};
// -- Pin Change Interrupt to get PWM inputs:
ISR( PCINT0_vect ) {
static int32_t change_time[N_INPUTS] = {0};
uint8_t mask = B00000010;
for ( uint8_t index = 0 ; index < N_INPUTS ; index += 1 ) {
if( (change_time[index] == 0) && (PINB & mask) ) {
change_time[index] = micros();
}
else if( (change_time[index] != 0) && !(PINB & mask) ) {
change_time[index] = ( micros() - change_time[index] ) - PWM_MID;
int16_t diff = change_time[index] - pwm_raw[index];
if( diff > DEADBAND ) {
pwm_raw[index] = change_time[index] - DEADBAND;
}
if( diff < -DEADBAND ) {
pwm_raw[index] = change_time[index] + DEADBAND;
}
change_time[index] = 0;
}
mask = mask << 1;
}
}
// --
void input_filter( void ) {
for( int index = 0; index < N_INPUTS; index += 1 ) {
pwm_input[index] = pwm_raw[index]*DECAY_INPUT + pwm_input[index]*( 1 - DECAY_INPUT );
}
}
// -- Function to set amplitude via throttle:
int amp_func( int input ) {
int var = ( input + AMP_OFFSET );
if( var <= AMP_CUTOFF ) {
return 0;
} else {
return var - AMP_CUTOFF;
}
}
// -- Wave functions [for wing oscillation]:
float tri_wave( void ) {
static int last_time = millis();
int int_time = millis() - last_time;
if( int_time < WAVE_INT ) {
return 2*int_time/WAVE_INT - 1;
} else if ( (int_time > WAVE_INT) && (int_time < 2*WAVE_INT) ) {
return 3 - 2*int_time/WAVE_INT;
} else if( int_time > WAVE_INT ) {
last_time = millis();
return -1;
}
}
float saw_wave( void ) {
static int last_time = millis();
int int_time = millis() - last_time;
if( int_time < 2*WAVE_INT ) {
return int_time/WAVE_INT - 1;
} else {
last_time = millis();
return -1;
}
}
float sin_wave( void ) {
return sin( millis()*FREQ );
}
// -- Function to combine wing oscillation and dihedral angle:
int flap_func( int amplitude, int offset ) {
if( amplitude == 0 ) {
return constrain( offset , -PWM_CHANGE, PWM_CHANGE );
} else {
return constrain( offset + sin_wave()*amplitude , -PWM_CHANGE, PWM_CHANGE );
}
}
// -- Main functions:
void setup() {
// Enabling interrupt:
PCICR |= (B00000001 << 0);
// Setting PWM inputs:
for ( int index = 0; index < N_INPUTS ; index += 1 ) {
PCMSK0 = PCMSK0 | (B00000010 << index);
pinMode( index + 9 , INPUT_PULLUP );
}
// Setting servo outputs:
for( int index = 2; index <= 3 ; index += 1 ) {
pinMode( index , OUTPUT );
servo[index - 2].attach( index );
servo[index - 2].write( PWM_MID );
}
//Default to minimum throttle:
pwm_raw[2] = -AMP_OFFSET;
pwm_input[2] = pwm_raw[2];
//Serial.begin(9600);
}
void loop() {
input_filter();
int16_t amp = amp_func( pwm_input[2] );
servo[0].writeMicroseconds( PWM_MID - flap_func( amp , pwm_input[0] + pwm_input[1] ) );
servo[1].writeMicroseconds( PWM_MID + flap_func( amp , -pwm_input[0] + pwm_input[1] ) ); [/hide]
关于第一代编程类扑翼机我个人的总体规划:
因为国内外采用舵机驱动的扑翼机基本没有超过100g的(散热、强度、重量等因素)都是超轻设计,所以我采用了计算的方式,大概规划了一下扑翼机的整体参数
翼展:0.9m--舵机单边0.45m
平均弦长:0.3m
飞行重量:45g左右
电池2s100mah,采用降压6.0v给舵机供电
为了减轻重量,机身极简制作
蓝箭5023的堵转扭矩是1.76kg/cm--0.176nm,经计算得知:翅膀在.025m的位置上90度的行程下,轨迹为0.3m左右,计算翅膀重量10g,翼面积为0.15平米,计算空气阻力后,舵机负载后的运动速度是2.4m/s,大概需要0.125s跑完一次,理论状态下,也就是说在1s内,翅膀可以扑翼两回(4下)。
能否飞行还是未知,具体制作与安装过程中遇到问题我还是随时调成这个设计
关于arduino,我是使用了uno进行的测试,nano板比较mini,很合适
关于电路图,连接方式也非常简单,图片我也更改过,在红色位置上9-12口连接接收机即可,注意接收机需要pwm信号支持
关于舵机扭矩、翅膀的扑翼分析与计算:
(理论只涉及到了空气阻力与力学的基本计算;非专业人员,如有错误请指出)
(, 下载次数: 147)
上传
点击文件名下载附件
(, 下载次数: 159)
上传
点击文件名下载附件
(, 下载次数: 137)
上传
点击文件名下载附件
(, 下载次数: 146)
上传
点击文件名下载附件
(, 下载次数: 174)
上传
点击文件名下载附件
(, 下载次数: 167)
上传
点击文件名下载附件
作者:
lwglll
时间:
2022-11-21 09:50
高手
作者:
tangyi112
时间:
2022-11-21 10:04
厉害厉害,收藏了。
作者:
nbzhtjj
时间:
2022-11-21 11:14
加油,学习中
作者:
taijilaoying
时间:
2022-11-22 22:00
作者:
油电混合11
时间:
2022-11-23 23:52
的确不错
作者:
Glider
时间:
2022-11-24 07:10
servo库和ppm库自带了中断设置程序吗?
作者:
80华彩
时间:
2022-11-24 09:03
这个确实不错
作者:
jiangxt
时间:
2022-11-24 09:46
好多图片没打开
作者:
leo2006
时间:
2022-11-24 12:27
高手,舵机选择上有没有推荐
作者:
haujj
时间:
2022-11-24 15:39
这个有创意
作者:
jzmashe11
时间:
2022-11-25 10:55
舵机一直处于高速的正反转切换中 寿命是个问题
作者:
soone
时间:
2022-12-1 16:07
一个字,上链接
作者:
斩薪
时间:
2022-12-3 13:04
顶,收藏了
作者:
tomcool
时间:
2022-12-4 00:38
牛!!!
作者:
顶风飞不动
时间:
2022-12-5 08:32
高人,改用无刷舵机搞个大的吧。
作者:
轻松一下
时间:
2022-12-9 13:49
确实好看了,飞行姿太好看了,有鹰一样的飞行姿态,不像一些高速扑翼的难看样子,像个飞不起来,拼命扑扇翅膀的蛾子
。
作者:
dxr2013
时间:
2022-12-9 15:49
向大师致敬,果断收藏
作者:
dxr2013
时间:
2022-12-9 15:58
楼主许多照片咋打不开了啊
作者:
赵刚
时间:
2022-12-9 23:27
真不错
作者:
gggghuatao
时间:
2023-8-29 15:43
太厉害了
欢迎光临 5iMX.com 我爱模型 玩家论坛 ——专业遥控模型和无人机玩家论坛(玩模型就上我爱模型,创始于2003年) (http://wz.5imx.com/)
Powered by Discuz! X3.3