使用4g网络制作一个无人机云台

制作云台

驱动器制作

云台由两个无刷电机分别控制摄像头的 yaw,pitch。
无刷电机由SimpleFOC库驱动,由esp32作为控制器,drv8313为无刷电机驱动器最大输出电流2.5a,对于云台电机已经足够了。
下面是驱动板的原理图,可以驱动两个云台电机,板载了一个5v-5a线性稳压芯片 可以给外部设备供电
在这里插入图片描述
无刷电机需要位置反馈,这里使用了as5600磁编码器,下面是原理图

在这里插入图片描述

simpleFoc库的使用

simplefoc基于arduino环境,vscode安装platformlo插件,然后board选择 espressif esp32 dev module,framework选择 arduino就可以自动下载arduino环境了。然后在libraries中选择simplefoc就可以自动下载了。自带了各种实例由于使用了arduino框架,所以使用非常的简单
。官网地址https://docs.simplefoc.com/
下面代码可以控制一个电机且通过串口对电机进行控制

#include <SimpleFOC.h>

MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);
TwoWire I2Cone = TwoWire(0);
BLDCMotor motor = BLDCMotor(7);  //根据选用电机的极对数,修改此处BLDCMotor()的值                             
BLDCDriver3PWM driver = BLDCDriver3PWM(32, 33, 25, 22);//修改pwm接口
Commander commander = Commander(Serial);

void onMotion(char* cmd){ commander.motion(&motor,cmd); }
void onMotor(char* cmd){ commander.motor(&motor,cmd); }

void setup(){
  Serial.begin(115200);
  I2Cone.begin(19, 18, 400000); 
  sensor.init(&I2Cone);//修改i2c口
  motor.linkSensor(&sensor);
  driver.voltage_power_supply = 12;//电机供电电压这里是12v
  driver.init();
  motor.linkDriver(&driver);

  motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
  motor.controller = MotionControlType::angle;//闭环角度控制

  /控制参数///                             
  motor.PID_velocity.P = 0.05;//每个电机的pid参数不同,需要自己修改         
  motor.PID_velocity.I = 1;
  motor.P_angle.P = 10;
  motor.voltage_limit = 1.5;                
  motor.LPF_velocity.Tf = 0.01;
  motor.velocity_limit = 20;
  motor.init();
  motor.initFOC();
  ///打印参数//
  motor.monitor_variables = _MON_TARGET | _MON_VEL | _MON_ANGLE; 
  motor.monitor_downsample = 1000;//1s打印一次可以修改单位ms
  motor.useMonitoring(Serial);
  commander.add('T',onMotion,"motion control");
  commander.add('M',onMotor,"full motor config");
}

void loop(){
  motor.loopFOC();
  motor.monitor();
  motor.move();
  commander.run();
}

不同的电机pid参数不同,使用串口命令修改参数,下图是命令的格式
在这里插入图片描述
比较常用的一些命令
D - D current PID controller & LPF (see pid and lpf for commands)
V - Velocity PID controller & LPF (see pid and lpf for commands)
A - Angle PID controller & LPF- (see pid and lpf for commands)
S - Sensor offsets
M - sensor offset
E - sensor electrical zero
M - Monitoring control
D - downsample monitoring
C - clear monitor
S - set monitoring variables
G - get variable value
C - Motion control type config - see motion control
D - downsample motion loop
0 - torque
1 - velocity
2 - angle
3 - velocity_openloop
4 - angle_openloop
E - Motor status (enable/disable) - see motion control
0 - enable
1 - disable
MMG0 get variable - target
MMG6 get variable - angle

4G网络搭建

ipv6介绍

普通的图传在低空或者有遮挡的情况下性能会变得非常差,依靠4g网络就可以解决这个问题。
现在手机的4g5g网络都支持ipv6,开启热点后连接它的设备也都会分配ipv6地址,并且这个地址是公网可以访问的,这个地址不是固定的,重启网络就会变
当然也可以淘宝购买4g模块,就可以将设备联网了

使用ifconfig查看本机ipv6地址,ipv6地址是冒分十六进制表示法,格式如“ABCD:CCDD:…”一共128位
在这里插入图片描述
电信网络ipv6是240e开头的,移动是2409开头的,联通是2408开头的。将这个地址记录下来,可以使用ping命令看看网络是否连通。

数传的实现

这里用EC600S模块为数据的发送端和接收端
首先安装驱动

安装驱动

uname -r #查看内核版本安装相近的驱动
cd v5.6.11 #进入驱动目录
sudo make 
sudo make install

在这里插入图片描述
报错了,需要安装头文件可以参考https://blog.csdn.net/m0_58944591/article/details/129836645
安装好linux头文件就可以顺利安装了,安装号后需要重启

此时在/dev中将会多ttyUSB0 ttyUSB1 ttyUSB2设备
使用minicom打开usb1

sudo apt-get install minicom
minicom -D /dev/ttyUSB1

为了使用方便先设置串口的设置

USB 端口绑定

将模块插到usb口查看USB端口信息,使用KERNELS作为标识

udevadm info --attribute-walk --name=/dev/ttyUSB1 |grep KERNELS
 	KERNELS=="ttyUSB1"
    KERNELS=="2-1:1.3"
    KERNELS=="2-1"
    KERNELS=="usb2"
    KERNELS=="fc880000.usb"
    KERNELS=="platform"

创建映射文件

sudo vim /etc/udev/rules.d/×××.rules

在新建的*.rules文件中添加刚刚获取的设备id

KERNEL=="ttyUSB*", KERNELS=="2-1:1.3", MODE:="0777", SYMLINK+="my_network"

重启生效,可以查看创建成功了

ll /dev/ | grep ttyUS*
lrwxrwxrwx   1 root     root           7 Sep  5 15:38 myNetwork -> ttyUSB1

sudo minicom -s

在Serial port setup设置 Serial Device 为/dev/my_network,然后Save setup as dfl 就可以了
按ctrl+a q就能退出minicom了

AT指令udp通信

使用at指令创建sock,依靠UDP传输数据
at指令可以参考官方的手册Quectel_EC200x&EG912Y&EC600S系列_TCP(IP)_应用指导_V1.2
下面的python代码可以把两块EC600S模块设置为udp的服务端与客户端,并互发消息
服务端

import serial
import time
import threading

class UDPOperate:
    def __init__(self):
        self.uartAT = serial.Serial(port='/dev/ttyUSB1', baudrate=115200,timeout=5)
        self.initSock()
        self.radioIp = None
        self.radioPort = '1081'
        self.readDate = ''
        readThread = threading.Thread(target=self.read)
        readThread.start()
        
        while True:
            self.write('hello')
            time.sleep(2)

    def read(self):
        while True:
            rec = self.uartAT.readline().decode().strip()
            if rec:
                if rec.startswith('+'): #获取从机ip格式+QIACT: 1,1,3,"10.122.217.145","240E:440:100C:9D5:177C:665F:1D69:E883"
                    temp = rec.split() 
                    ip = temp[1].split(',')[3] 
                    self.radioIp = ip.strip('"')
                if not (rec.startswith('SEND') or rec.startswith('>') or rec.startswith('+')):#乎略
                    self.readDate = rec
                    print('read: ',self.readDate)

    def write(self,data):
        if not self.radioIp is None:
            l = len(data)
            cmd = 'AT+QISEND=0,' + str(l) + ',' + self.radioIp + ',' + self.radioPort + '\r\n'
            self.uartAT.write(cmd.encode())
            time.sleep(0.005)
            self.uartAT.write(data.encode())
        else:
            print('now do not rec target ip ')

    def initSock(self):
        print('now init sock...')
        time.sleep(1)
        cmd0 = b'ATE1\r\n'#显示回显
        cmd1 = b'AT+QICLOSE=0\r\n' #关闭存在的sock
        cmd2 = b'AT+QIOPEN=1,0,"UDP SERVICE",":::1",0,1080,1\r\n'
        cmd3 = b'AT+QIACT?\r\n'#获取ip
        cmd4 = b'ATE0\r\n' #关闭回显
        self.sendCmd(cmd0)
        self.sendCmd(cmd1)
        self.sendCmd(cmd2)
        self.sendCmd(cmd3)
        self.sendCmd(cmd4)

    def sendCmd(self,cmd):
        self.uartAT.write(cmd)
        rec = self.uartAT.read_until(b'OK').decode().strip()
        time.sleep(0.3)
        print(rec)
udp = UDPOperate()

客户端

import serial
import time
import threading
# AT+CSQ 
# 是查询信号的,如果注册网络成功,会有信号产生,最大 31,如果信号小于 10,说明当前网络信号不佳
# AT+CGATT?
# 是查询注册网络情况,如果注册成功,会返回 1,如果失败,返回 0
class UDPOperate:
    def __init__(self):
        self.readDate = ''
        self.serialIP = '240E:440:100C:9D5:177C:665F:1D69:E883'

        self.uartAT = serial.Serial(port='/dev/ttyUSB1', baudrate=115200,timeout=5)
        self.initSock()
        readThread = threading.Thread(target=self.read)
        readThread.start()
        
        cnt = 0
        while True:
            cnt = cnt+1
            self.write('a' + str(cnt))
            time.sleep(2)

    def read(self):
        while True:
            rec = self.uartAT.readline().decode().strip()
            if rec:
                if not (rec.startswith('SEND') or rec.startswith('>')):
                    if not rec.startswith('+'):
                        self.readDate = rec
                        print('rec',self.readDate)

    def write(self,data):
        l = len(data)
        cmd = 'AT+QISEND=0,' + str(l) + '\r\n'
        self.uartAT.write(cmd.encode())
        time.sleep(0.005)
        self.uartAT.write(data.encode())

    def initSock(self):
        print('now init sock...')
        time.sleep(1)
        cmd0 = b'ATE1\r\n'#显示回显
        cmd1 = b'AT+QICLOSE=0\r\n' #关闭存在的sock
        cmd2 = 'AT+QIOPEN=1,0,"UDP",' + self.serialIP + ',1080,1081,1\r\n'
        cmd3 = b'AT+QIACT?\r\n'#获取ip
        cmd4 = b'ATE0\r\n' #关闭回显
        self.sendCmd(cmd0)
        self.sendCmd(cmd1)
        self.sendCmd(cmd2.encode())
        self.sendCmd(cmd3)
        self.sendCmd(cmd4)

    def sendCmd(self,cmd):
        self.uartAT.write(cmd)
        rec = self.uartAT.read_until(b'OK').decode().strip()
        time.sleep(0.3)
        print(rec)
udp = UDPOperate()

在这里插入图片描述

下面就可以依靠udp来做更加有意义的事情了

使用udp传输摄像头视频

gst-launch-1.0 v4l2src device=/dev/video10  !  video/x-raw,width=640,height=480,framerate=30/1  ! x264enc speed-preset=1 tune=zerolatency ! udpsink host=240e:440:1002:17db:39f2:c71f:6eb2:7f36   port=4951

如果有硬件编码器可以修改一下

gst-launch-1.0 v4l2src device=/dev/video0  ! video/x-raw,width=640,height=480,framerate=30/1  !  mpph264enc ! queue  ! udpsink host=240e:440:1002:17db:39f2:c71f:6eb2:7f36 port=4951

接收端用mpv播放器

mpv -v --geometry=115:0 --no-border  --profile=low-latency --untimed   udp://[::1]:4951

可以显示实时画面,几乎看不到延迟。当然这个视网络情况有差异。
在这里插入图片描述
这样使用4g模块和simpleFOC库就搭建好了低成本的图数传,并且在4g网络覆盖的区域无限距离传输。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值