飞机油门 1000-2000 ms 频率50hz 单个周期1/50HZ=20ms
1首先了解下遥控器是如何控制云台的
简单来说,遥控器输出pwm1000-2000来控制云台、
https://blog.csdn.net/qq_45598353/article/details/119064475
原理:arduino模拟遥控器
以无人机的无刷电机为例,遥控器与无刷电机进行校准:
1.遥控器将油门打到最大
2.接收机油门输出端口的pwm输出最大,(一般在2000左右)
3.pwm输出到电调
4.给电调上电
5.因为输出到电调的pwm比较大,电调进行校对,设定现在的值为最大值,并发出滴滴声
6.遥控器将油门打到最小
7.接收机油门油门输出端口的pwm输出最小,(一般在1000左右)
8.pwm输出到电调
9.电调设定现在的值为最小值,并发出滴滴滴声
10.慢慢把遥控器往上掰,无刷电机开始转动。
我们用arduino代替遥控器和接收机,只需要arduino去模拟遥控器的pwm输出给电调就好了,不用纠结接收机的pwm具体是多少,因为电调会和arduino的pwm重新校对最大值和最小值。
1 确定遥控器各通道和对应的按钮
可以配合pix地面站,波动遥控器查看

2设置控制模式
例如设置通道8和通道6控制云台的旋转
设置遥控器

3连线和控制
接收机的6-8通道 接触杜邦线,插在云台的接口上
这里用的是一个轴云台 分别是x 和y党乡的控制
2 模拟控制
三轴云台storm32 BGC HAKRC调试+
https://item.taobao.com/item.htm?spm=a1z0d.7625083.1998302264.5.5c5f4e69ZXr5PC&id=41842088229
诸如此类的云台,都是遥控器pwm控制(1000-2000)

单片机 arduino nano

扩展版 要不要无所谓(引脚用的少)



ARduino控制
单片机程序

样例1 单个引脚控制一个自由度
如果超出范围 自己讲1000-2000对应到具体的角度
#include <Servo.h>
Servo myservo1;//
int Max=2000; //转速最大时候的pwm
int Min=1000; //转速最小时候的pwm
int pos=Min; //初始转速赋值
int sign=0; //标志位,用于切换转速增大还是减小
void setup() {
myservo1.attach(3); //pwm输出口为9号端口
myservo1.write(Max); //输出定义的pwm最大值,模拟遥控器油门打到最大
delay(5000); //等待电机设定最大值,会滴滴的发出声音
myservo1.write(Min); //输出定义的pwm最小值,模拟遥控器油门打到最小
delay(5000); //等待电机设定最小值,会滴滴滴的发出声音
Serial.begin(9600);
}
void loop() //电机转速从小变大再变小,反复循环. pwm数值会从串口输出。
{
delay(10);
if(sign==0) //让转速逐渐增大,增大到最大速度的一半
{
Serial.println(pos);
myservo1.write(pos); //输出pwm到9号端口
pos++;
if(pos==(Max+Min)/2)
sign=1;
}
if(sign==1) //让转速逐渐减小,减小到电机停止转动
{
Serial.println(pos);
myservo1.write(pos); //输出pwm到9号端口
pos--;
if(pos==Min)
sign=0;
}
}
样例2 上电自检 0-180度 180度到0度
串口输入 0-180
90; 敲回车发送控制转到90度

#include <Servo.h>
Servo myservo_x;//pwm类
int pin_x=3; //x引脚 x y z
int Max=2000; //转速/角度最大时候的pwm 180度(具体度数实际测量可能是270度)
int Min=1000; //转速/角度最小时候的pwm 0度
int zhong=int(Max+Min)/2;//转速/角度中间时候的pwm 90度
int pos=Min; //初始转速赋值
//电机转速从小变大再变小,反复循环. pwm数值会从串口输出。
void Test_MinToMax(){
for(int i=Min;i<=Max;i++)
{
myservo_x.write(i);
delay(10);
}
for(int i=Max;i>=Min;i--)
{
myservo_x.write(i);
delay(10);
}
}
int SetDegreeToPWM(int jiaodu){
int Pwm=int((Min+Max)/2);
if(jiaodu<0){jiaodu=0;Pwm=Min;}
else if(jiaodu>180){jiaodu=180;Pwm=Max;}
else{Pwm=int(float(jiaodu)/180.0*float(Max-Min)+float(Min));}
Serial.print("角度:"); Serial.print(jiaodu); Serial.print(" 转换PWM:"); Serial.println(Pwm);
return Pwm ;
}
void setup() {
myservo_x.attach(pin_x); //pwm输出口为9号端口
myservo_x.write(SetDegreeToPWM(0));
delay(3000);
Test_MinToMax();//min-max-min
delay(3000);
myservo_x.write(SetDegreeToPWM(90));
delay(3000);
Serial.begin(9600);
while(Serial.read()>= 0){} //clear serialbuffer
}
void loop()
{
if(Serial.available()>0){
String comdata =Serial.readStringUntil(";");
int jiaodu=comdata.toInt();
int Pwm_=SetDegreeToPWM(jiaodu);
myservo_x.write(Pwm_);
delay(10);
}
}
STM32控制


直接舵机角度控制 无需再转化
#include <Servo.h>
Servo myservo_x;//pwm类
int pin_x=PA6 ; //x引脚 x y z
int Max=2000; //转速/角度最大时候的pwm 180度(具体度数实际测量可能是270度)
int Min=1000; //转速/角度最小时候的pwm 0度
int zhong=int(Max+Min)/2;//转速/角度中间时候的pwm 90度
int pos=Min; //初始转速赋值
//电机转速从小变大再变小,反复循环. pwm数值会从串口输出。
void Test_MinToMax(){
for(int i=Min;i<=Max;i++)
{
myservo_x.write(i);
delay(10);
}
for(int i=Max;i>=Min;i--)
{
myservo_x.write(i);
delay(10);
}
}
int SetDegreeToPWM(int jiaodu){
int Pwm=int((Min+Max)/2);
if(jiaodu<0){jiaodu=0;Pwm=Min;}
else if(jiaodu>180){jiaodu=180;Pwm=Max;}
else{Pwm=int(float(jiaodu)/180.0*float(Max-Min)+float(Min));}
Serial1.print("角度:"); Serial1.print(jiaodu); Serial1.print(" 转换PWM:"); Serial1.println(Pwm);
return Pwm ;
}
void setup() {
Serial1.begin(9600);
while(Serial1.read()>= 0){} //clear serialbuffer
Serial1.println("开始运行,请输入0-180,默认90度,指令 “度数;” ");
myservo_x.attach(pin_x); //pwm输出口为9号端口
myservo_x.write(SetDegreeToPWM(90));
delay(10);
// Test_MinToMax();//min-max-min
// delay(3000);
//
// myservo_x.write(SetDegreeToPWM(90));
// delay(3000);
}
void loop()
{
if(Serial1.available()>0){
String comdata =Serial1.readStringUntil(';');
int jiaodu=comdata.toInt();
int Pwm_=SetDegreeToPWM(jiaodu);
String msg=String("设定角度: ")+String(jiaodu)+" pwm:"+String(Pwm_);
Serial1.println(msg);
myservo_x.write(jiaodu);
delay(10);
}
}
python 树莓派 pca6805
pca 3.3V SCL SDA GNS (5V+ NO NEED )
import cv2
import socket
import struct
import pickle
import threading
import RPi.GPIO as GPIO
from Adafruit_PCA9685 import PCA9685
import busio
from board import SCL, SDA
#SCL (时钟线):GPIO 3(物理引脚 5)
#SDA (数据线):GPIO 2(物理引脚 3)
import time
# 初始化 GPIO
GPIO.setmode(GPIO.BCM)
# L298N 电机驱动引脚
# M1 left-qian M2 right-qian M3 left-hou M4-right-hou
motor_pins = {
"M1": (4, 17),
"M2": (27, 22),
"M3": (5, 6),
"M4": (13, 19),
}
for pins in motor_pins.values():
GPIO.setup(pins[0], GPIO.OUT)
GPIO.setup(pins[1], GPIO.OUT)
# 初始化 I2C 连接 (PCA9685)
i2c = busio.I2C(SCL, SDA)
if not i2c.try_lock():
print("I2C 未能成功初始化!")
else:
try:
print("I2C 初始化成功!")
finally:
i2c.unlock() # 释放 I2C 锁
pca = PCA9685()
pca.set_pwm_freq(50)
pca.frequency = 50 # 设置 PWM 频率为 50Hz(舵机标准)
#使用 树莓派 + PCA9685 模拟四旋翼无人机 遥控器(RC)PWM 信号。
#输出 四个通道的 PWM 信号,分别对应 油门、偏航、俯仰、横滚(Throttle, Yaw, Pitch, Roll)。
#PWM 范围:1000us(最小油门)~ 2000us(最大油门)(典型遥控器信号)。
#更新 PWM 频率为 50Hz(标准 RC 频率)。
# 3️⃣ 设置舵机的 PWM 范围
SERVO_MIN_PULSE = 1000 # 1000us → 0°
SERVO_MAX_PULSE = 2000 # 2000us → 180°
SERVO_RANGE = 180 # 舵机角度范围(0° - 180°)
# 4️⃣ 计算 PWM 幅度
def set_servo_angle(channel, angle):
"""使用 set_pwm 设置舵机角度"""
pulse_length = 1000000 / pca.frequency # 计算 PWM 总周期(微秒)
pulse_length //= 4096 # PCA9685 12-bit 分辨率,每步 = 总周期 / 4096
# 计算脉冲宽度(单位:4096 级)
pulse = int((angle / SERVO_RANGE) * (SERVO_MAX_PULSE - SERVO_MIN_PULSE) + SERVO_MIN_PULSE)
pulse //= pulse_length
# 使用 set_pwm 设置 PWM (0=起始点, pulse=结束点)
pca.set_pwm(channel, 0, int(pulse))
# 5️⃣ 让舵机在 0° - 180° 之间移动
servo_channel = 4 # 连接舵机的 PCA9685 通道
def test_seroe():
print("0")
#set_servo_angle(servo_channel, 0) # 转到 0°
#time.sleep(1)
#print("90")
#set_servo_angle(servo_channel, 90) # 转到 90°
time.sleep(1)
#print("180")
set_servo_angle(6, 45) # 转到 180°
#time.sleep(1)
#pca.frequency = 1000 # PWM 频率
# PCA9685 控制通道
pwm_channels = {"M1": 0, "M2": 1, "M3": 2, "M4": 3}
current_speed = 50
Dgree_pin ={'yaw':4,'roll':5,'pitch':6}
# 设定电机方向和速度
def set_motor_direction(motor, direction):
pin1, pin2 = motor_pins[motor]# 1 motor 2 pin
if direction == "FORWARD":
GPIO.output(pin1, GPIO.HIGH)
GPIO.output(pin2, GPIO.LOW)
elif direction == "BACKWARD":
GPIO.output(pin1, GPIO.LOW)
GPIO.output(pin2, GPIO.HIGH)
elif direction == "STOP":
GPIO.output(pin1, GPIO.LOW)
GPIO.output(pin2, GPIO.LOW)
def set_motor_speed(motor, speed): # 1 speed
if speed >100:
speed=100
elif speed<0:
speed=0
pwm_id=pwm_channels[motor]
speed_pwm = int((speed / 100) * 0xFFFF)
print(motor,pwm_id,speed,speed_pwm)
pca.set_pwm(pwm_id,0,speed_pwm)
#pca.channels[pwm_id].duty_cycle = int((speed / 100) * 0xFFFF)
def set_dgree(pin, speed): # 1 speed
if speed >100:
speed=100
elif speed<0:
speed=0
pwm_id=Dgree_pin[pin]
speed_pwm = int((speed / 100) * 0xFFFF)
print(pin,pwm_id,speed,speed_pwm)
pca.set_pwm(pwm_id,0,speed_pwm)
def set_all_speed(speed):
set_motor_speed("M1", speed)
set_motor_speed("M2", speed)
set_motor_speed("M3", speed)
set_motor_speed("M4", speed)
def move_forward(speed):
set_motor_direction("M1", "FORWARD")
set_motor_direction("M2", "FORWARD")
set_motor_direction("M3", "FORWARD")
set_motor_direction("M4", "FORWARD")
set_motor_speed("M1", speed)
set_motor_speed("M2", speed)
set_motor_speed("M3", speed)
set_motor_speed("M4", speed)
def move_backward(speed):
set_motor_direction("M1", "BACKWARD")
set_motor_direction("M2", "BACKWARD")
set_motor_direction("M3", "BACKWARD")
set_motor_direction("M4", "BACKWARD")
set_motor_speed("M1", speed)
set_motor_speed("M2", speed)
set_motor_speed("M3", speed)
set_motor_speed("M4", speed)
def turn_left(speed):
set_motor_direction("M1", "BACKWARD")
set_motor_direction("M2", "BACKWARD")
set_motor_direction("M3", "FORWARD")
set_motor_direction("M4", "FORWARD")
set_motor_speed("M1", speed)
set_motor_speed("M2", speed)
set_motor_speed("M3", speed)
set_motor_speed("M4", speed)
def turn_right(speed):
set_motor_direction("M1", "FORWARD")
set_motor_direction("M2", "FORWARD")
set_motor_direction("M3", "BACKWARD")
set_motor_direction("M4", "BACKWARD")
set_motor_speed("M1", speed)
set_motor_speed("M2", speed)
set_motor_speed("M3", speed)
set_motor_speed("M4", speed)
def stop():
set_motor_direction("M1", "STOP")
set_motor_direction("M2", "STOP")
set_motor_direction("M3", "STOP")
set_motor_direction("M4", "STOP")
speed=0
set_motor_speed("M1", speed)
set_motor_speed("M2", speed)
set_motor_speed("M3", speed)
set_motor_speed("M4", speed)
# 视频流服务器
def video_stream_server():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('0.0.0.0', 5002))
server.listen(5)
print("视频服务器启动,等待连接...")
client, addr = server.accept()
print(f"视频客户端连接:{addr}")
cap = cv2.VideoCapture(0)
while True:
success, frame = cap.read()
if not success:
break
frame = cv2.resize(frame, (640, 480)) # 降低分辨率
_, buffer = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, 50]) # JPEG 压缩
data = pickle.dumps(buffer)
client.sendall(struct.pack("Q", len(data)) + data) # 发送数据大小+压缩图像
time.sleep(0.05) # 控制帧率 (20FPS)
cap.release()
client.close()
# 控制指令服务器
def control_server():
global current_speed
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('0.0.0.0', 5003))
server.listen(5)
print("控制服务器启动,等待连接...")
while True:
client, addr = server.accept()
print(f"控制客户端连接:{addr}")
while True:
try:
data = client.recv(1024).decode().strip()
if not data:
break
print("Rec data:",data)
if data.startswith("FORWARD"):
_, speed = data.split()
current_speed = int(speed)
print(f"FORWARD 速度设置为 {current_speed}%")
move_forward(current_speed)
elif data.startswith("BACKWARD"):
_, speed = data.split()
current_speed = int(speed)
print(f"BACKWARD 速度设置为 {current_speed}%")
move_backward(current_speed)
elif data.startswith("LEFT"):
_, speed = data.split()
current_speed = int(speed)
print(f"LEFT 速度设置为 {current_speed}%")
move_backward(current_speed)
elif data.startswith("RIGHT"):
_, speed = data.split()
current_speed = int(speed)
print(f"RIGHT 速度设置为 {current_speed}%")
move_backward(current_speed)
elif data.startswith("ALLSPEED"):
_, speed = data.split()
current_speed = int(speed)
print(f"速度设置为 {current_speed}%")
set_all_speed(current_speed)
elif data == "STOP":
stop()
elif data.startswith("yaw"):
_, speed = data.split()
print(f"yaw 设置为 {speed}%")
set_dgree('yaw', int(speed))
elif data.startswith("roll"):
_, speed = data.split()
print(f"roll 设置为 {speed}%")
set_dgree('roll', int(speed))
elif data.startswith("pitch"):
_, speed = data.split()
print(f"pitch 设置为 {speed}%")
set_dgree('pitch', int(speed))
#stop()
client.send(b"OK")
except:
break
client.close()
if __name__ == "__main__":
#threading.Thread(target=video_stream_server, daemon=True).start()
#threading.Thread(target=control_server, daemon=True).start()
while True:
#time.sleep(1)
test_seroe()
浙公网安备 33010602011771号