飞机油门 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号
浙公网安备 33010602011771号