前言:
之前假期做的一个小项目,炸了好几套桨叶233,分享出来希望能帮助更多人快速学习。
使用正点原子ATK-MiniFly 飞行器二次开发多旋翼Apriltag追踪;
使用LABVIEW自主设计地面站用于发送控制指令与信息接收;
飞行器: STM32F4+FreeRTOS;
遥控器: STM32F1+FreeRTOS;
OPENMV: STM32H7
用户可将OPENMV更换成高级视觉opencv、yolo等,只需根据已有接口设计协议即可快速二次开发其他功能。
本项目适用于STM32(涉及F1、F4、H7)以及FreeRTOS操作系统初学者以及对多旋翼飞行控制系统导航与控制开发感兴趣的人员,需一定编程能力,本项目已完完结,以下功能均已实现,欢迎评论区交流。
功能说明:
1.labview自主设计地面站(安装依赖包后可独立运行不依赖labview),地面站端包含一键起飞、一键急停、一键降落、一键追踪tag码按钮,以及相关信息的显示界面;
2. 使用openmv官方例程Apriltag识别tag标签与位姿信息,在图像中框出tag标签,并通过串口上传至四轴飞行器;
3. 遥控器与地面站之间采用USB/数传连接,飞行器与OPENMV采用串口连接;
4. 遥控器端可反应相关状态信息,一键接管自主控制状态,保证安全飞行;
材料说明:
1.ATK-MiniFly
2. OPENMV4
3. Apriltag (tag16h5)
地面站协议说明: (具体可反推飞控代码)
1.一键起飞、降落:0xaa 0x11 (地面状态则起飞,空中状态则降落)
2. 一键急停: 0xaa 0x22 (直接锁桨,注意安全)
3. 一键追踪tag码:0xaa 0x33(起飞完成后再点击,否则openmv视野不足)
地面站ui界面:
飞行器相关资料:(官方资料自行搜索下载)
OPENMV引导飞行器核心代码:
bool opv_control_state=0;
float opv_x_data=0,opv_y_data=0; //北西天坐标系 前x正 左y正 上z正
void opv_Communication_Task(void *param)
{
while(1)
{
if(opv_control_state==1)
{
if(SDK_tag.Tx<0)opv_y_data=-5;
else if(SDK_tag.Tx>0)opv_y_data=5;
else opv_y_data=0;
if(SDK_tag.Ty<0)opv_x_data=-5;
else if(SDK_tag.Ty>0)opv_x_data=5;
else opv_x_data=0;
}
else
{
opv_x_data=0;
opv_y_data=0;
}
ledSet(LED_BLUE_L,opv_control_state); //飞机左后小灯判断opv控制状态,亮(1)允许追踪tag
vTaskDelay(200);
}
}
飞行器位置输出核心代码:
if(getOpDataState() && commander.ctrlMode == 0x03) /*光流数据可用,定点模式*/
{
setpoint->attitude.yaw *= 0.5f; /*定点模式减慢yaw调节*/
/*调整位置 速度模式*/
if(fabsf(setpoint->attitude.roll) > 1.5f || fabsf(setpoint->attitude.pitch) > 1.5f || opv_control_state == 1)
{
adjustPosXYTime = 0;
isAdjustingPosXY = true;
setpoint->mode.x = modeVelocity;
setpoint->mode.y = modeVelocity;
setpoint->velocity.x = setpoint->attitude.pitch * 4.0f + opv_x_data;//倾角大于1.5°时执行
setpoint->velocity.y = setpoint->attitude.roll * 4.0f + opv_y_data;
}
else if(isAdjustingPosXY == true)
{
if(adjustPosXYTime++ > 100)
{
adjustPosXYTime = 0;
isAdjustingPosXY = false;
}
setpoint->mode.x = modeAbs;
setpoint->mode.y = modeAbs;
setpoint->position.x = state->position.x + errorPosX; //调整新位置
setpoint->position.y = state->position.y + errorPosY; //调整新位置
}
else if(isAdjustingPosXY == false) /*位移误差*/
{
errorPosX = setpoint->position.x - state->position.x ;//动摇杆后执行此处
errorPosY = setpoint->position.y - state->position.y ;
errorPosX = constrainf(errorPosX, -30.0f, 30.0f); /*误差限幅 单位cm*/
errorPosY = constrainf(errorPosY, -30.0f, 30.0f); /*误差限幅 单位cm*/
}
}
else /*手动模式*/
{
setpoint->mode.x = modeDisable;
setpoint->mode.y = modeDisable;
}
一键起飞、降落、急停、追踪等指令核心代码:
if(drone_control_state==0x11)//pc端一键起飞、一键降落
{
if( getRCLock()==false && getIsMFCanFly()==true &&
(configParam.flight.ctrl == ALTHOLD_MODE || configParam.flight.ctrl == THREEHOLD_MODE)
)
{
sendRmotorCmd(CMD_FLIGHT_LAND, NULL);
}
drone_control_state=0;
}
else if(drone_control_state==0x22)//pc端一键急停
{
sendRmotorCmd(CMD_EMER_STOP, NULL);
drone_control_state=0;
}
else if(drone_control_state==0x33)//pc端一键追踪tag码
{
sendRmotorCmd(CMD_TAG_TRACK, NULL);
LED_RED = !LED_RED;
drone_control_state=0;
}
else drone_control_state=0;
部分飞行器信息发送至LABVIEW核心代码:
/***************************************************************************************************************************/
printf("A"); //0
/***************************************************************************************************************************/
drone_pit=limit(plane_pitch*10,-999,999);//将flyControl.pitch*100替换为plane_pitch*10即可上传飞机姿态信息
if(drone_pit>0)printf("+");
else
{
printf("-"); //1
drone_pit=-drone_pit;
}
send_bai=drone_pit/100;
send_shi=drone_pit%100/10;
send_ge=drone_pit%100%10;
printf("%d",send_bai); //2
printf("%d",send_shi); //3
printf("%d",send_ge); //4
/***************************************************************************************************************************/
drone_rol=limit(plane_roll*10,-999,999);
if(drone_rol>0)printf("+");
else
{
printf("-"); //5
drone_rol=-drone_rol;
}
send_bai=drone_rol/100;
send_shi=drone_rol%100/10;
send_ge=drone_rol%100%10;
printf("%d",send_bai); //6
printf("%d",send_shi); //7
printf("%d",send_ge); //8
/***************************************************************************************************************************/
drone_yaw=limit(plane_yaw*10,-1800,1800);
if(drone_yaw>0)printf("+");
else
{
printf("-"); //9
drone_yaw=-drone_yaw;
}
send_qian=drone_yaw/1000;
send_bai=drone_yaw%1000/100;
send_shi=drone_yaw%1000%100/10;
send_ge=drone_yaw%1000%100%10;
printf("%d",send_qian); //10
printf("%d",send_bai); //11
printf("%d",send_shi); //12
printf("%d",send_ge); //13
/***************************************************************************************************************************/
全部资料链接见评论区,有问题请留言或评论区讨论。
作者:锦官城外
时间:2021.11
祝好!
资料下载链接