drone无人机应用_drone无人机教程视频

drone无人机应用_drone无人机教程视频目录文章目录目录摘要1.增加姿态信息界面2.在activity中显示更新姿态数据摘要本节主要记录打造自己的HelloDrone无人机APP过程《2》—如何获取并且显示姿态信息。1.增加姿态信息界面<?xmlversion=”1.0″encoding=”utf-8″?><ScrollViewxmlns:android=”http://schemas.android.com/apk/res/android”xmlns:tools=”http://schemas.

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

目录

摘要

本节主要记录打造自己的HelloDrone 无人机APP过程《2》—如何获取并且显示姿态信息。

1.增加姿态信息界面

在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:orientation="vertical"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingBottom="@dimen/activity_vertical_margin"
        tools:context="hello.MainActivity">

        <androidx.cardview.widget.CardView
            android:id="@+id/connection_type_card"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="5dp">

            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="10dp">

                <Button
                    android:id="@+id/btnConnect"
                    android:layout_width="150dp"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/connectionTypeLabel"
                    android:layout_alignParentEnd="true"
                    android:layout_alignParentRight="true"
                    android:onClick="onBtnConnectTap"
                    android:text="Connect" />

                <Spinner
                    android:id="@+id/selectConnectionType"
                    android:layout_width="120dp"
                    android:layout_height="44dp"
                    android:layout_below="@+id/connectionTypeLabel"
                    android:layout_alignParentStart="true"
                    android:layout_alignParentLeft="true"
                    android:layout_toLeftOf="@+id/btnConnect"
                    android:entries="@array/drone_connection_types"
                    android:spinnerMode="dropdown" />

                <TextView
                    android:id="@+id/connectionTypeLabel"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentTop="true"
                    android:layout_centerHorizontal="true"
                    android:layout_marginBottom="10dp"
                    android:text="Connection Type"
                    android:textAppearance="?android:attr/textAppearanceMedium" />

            </RelativeLayout>

        </androidx.cardview.widget.CardView>

        <androidx.cardview.widget.CardView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="5dp">

            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="10dp">

                <TextView
                    android:id="@+id/telemetryLabel"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerHorizontal="true"
                    android:layout_marginTop="10dp"
                    android:text="Vehicle Telemetry"
                    android:textAppearance="?android:attr/textAppearanceMedium" />

                <TableLayout
                    android:id="@+id/telemetryInfo"
                    android:layout_width="fill_parent"
                    android:layout_height="200dp"
                    android:layout_below="@+id/telemetryLabel"
                    android:layout_alignParentStart="true"
                    android:layout_alignParentLeft="true"
                    android:layout_marginTop="10dp">

                    <TableRow
                        android:id="@+id/vehTelemRow1"
                        android:layout_width="fill_parent"
                        android:layout_height="fill_parent">

                        <TextView
                            android:id="@+id/vehicleModeLabelTextView"
                            android:layout_width="100dp"
                            android:layout_height="wrap_content"
                            android:layout_column="0"
                            android:paddingTop="5dp"
                            android:paddingBottom="5dp"
                            android:text="Mode:"
                            android:textAppearance="?android:attr/textAppearanceMedium" />

                        <Spinner
                            android:id="@+id/modeSelect"
                            android:layout_width="fill_parent"
                            android:layout_height="44dp"
                            android:layout_column="1"
                            android:layout_below="@+id/connectionTypeLabel"
                            android:layout_alignParentStart="true"
                            android:layout_alignParentLeft="true"
                            android:layout_toLeftOf="@+id/btnConnect"
                            android:spinnerMode="dropdown" />
                    </TableRow>

                    <TableRow
                        android:id="@+id/vehTelemRow2"
                        android:layout_width="fill_parent"
                        android:layout_height="fill_parent">

                        <TextView
                            android:id="@+id/altitudeLabelTextView"
                            android:layout_width="100dp"
                            android:layout_height="wrap_content"
                            android:layout_column="0"
                            android:paddingTop="5dp"
                            android:paddingBottom="5dp"
                            android:text="Altitude:"
                            android:textAppearance="?android:attr/textAppearanceMedium" />

                        <TextView
                            android:id="@+id/altitudeValueTextView"
                            android:layout_width="fill_parent"
                            android:layout_height="wrap_content"
                            android:layout_column="1"
                            android:layout_gravity="left"
                            android:paddingTop="5dp"
                            android:paddingBottom="5dp"
                            android:text="0m"
                            android:textAppearance="?android:attr/textAppearanceMedium" />
                    </TableRow>

                    <TableRow
                        android:id="@+id/vehTelemRow3"
                        android:layout_width="fill_parent"
                        android:layout_height="fill_parent">

                        <TextView
                            android:id="@+id/speedLabelTextView"
                            android:layout_width="100dp"
                            android:layout_height="wrap_content"
                            android:layout_column="0"
                            android:paddingTop="5dp"
                            android:paddingBottom="5dp"
                            android:text="Speed:"
                            android:textAppearance="?android:attr/textAppearanceMedium" />

                        <TextView
                            android:id="@+id/speedValueTextView"
                            android:layout_width="fill_parent"
                            android:layout_height="wrap_content"
                            android:layout_column="1"
                            android:layout_gravity="left"
                            android:paddingTop="5dp"
                            android:paddingBottom="5dp"
                            android:text="0m/s"
                            android:textAppearance="?android:attr/textAppearanceMedium" />
                    </TableRow>

                    <TableRow
                        android:id="@+id/vehTelemRow4"
                        android:layout_width="fill_parent"
                        android:layout_height="fill_parent">

                        <TextView
                            android:id="@+id/distanceLabelTextView"
                            android:layout_width="100dp"
                            android:layout_height="wrap_content"
                            android:layout_column="0"
                            android:paddingTop="5dp"
                            android:paddingBottom="5dp"
                            android:text="Distance:"
                            android:textAppearance="?android:attr/textAppearanceMedium" />

                        <TextView
                            android:id="@+id/distanceValueTextView"
                            android:layout_width="fill_parent"
                            android:layout_height="wrap_content"
                            android:layout_column="1"
                            android:layout_gravity="left"
                            android:paddingTop="5dp"
                            android:paddingBottom="5dp"
                            android:text="0m"
                            android:textAppearance="?android:attr/textAppearanceMedium" />
                    </TableRow>

                    <TableRow
                        android:layout_width="fill_parent"
                        android:layout_height="fill_parent">

                        <Button
                            android:id="@+id/btnArmTakeOff"
                            android:layout_width="120dp"
                            android:layout_height="wrap_content"
                            android:layout_column="1"
                            android:layout_below="@+id/connectionTypeLabel"
                            android:layout_alignParentEnd="true"
                            android:layout_alignParentRight="true"
                            android:onClick="onArmButtonTap"
                            android:visibility="invisible" />
                    </TableRow>
                </TableLayout>

                <TableLayout
                    android:id="@+id/ahrs"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/telemetryInfo"
                    android:layout_alignParentStart="true"
                    android:layout_alignParentLeft="true">

                    <TableRow
                        android:layout_width="match_parent"
                        android:layout_height="match_parent">

                        <TextView
                            android:id="@+id/roll"
                            android:layout_width="100dp"
                            android:layout_height="wrap_content"
                            android:layout_column="0"
                            android:paddingTop="5dp"
                            android:paddingBottom="5dp"
                            android:text="横滚角:"
                            android:textAppearance="?android:attr/textAppearanceMedium" />

                        <TextView
                            android:id="@+id/roll_value"
                            android:layout_width="fill_parent"
                            android:layout_height="wrap_content"
                            android:layout_column="1"
                            android:layout_gravity="left"
                            android:paddingTop="5dp"
                            android:paddingBottom="5dp"
                            android:text="0度"
                            android:textAppearance="?android:attr/textAppearanceMedium" />
                    </TableRow>

                    <TableRow
                        android:layout_width="fill_parent"
                        android:layout_height="fill_parent">

                        <TextView
                            android:id="@+id/pitch"
                            android:layout_width="100dp"
                            android:layout_height="wrap_content"
                            android:layout_column="0"
                            android:paddingTop="5dp"
                            android:paddingBottom="5dp"
                            android:text="俯仰角:"
                            android:textAppearance="?android:attr/textAppearanceMedium" />

                        <TextView
                            android:id="@+id/pitch_value"
                            android:layout_width="fill_parent"
                            android:layout_height="wrap_content"
                            android:layout_column="1"
                            android:layout_gravity="left"
                            android:paddingTop="5dp"
                            android:paddingBottom="5dp"
                            android:text="0度"
                            android:textAppearance="?android:attr/textAppearanceMedium" />
                    </TableRow>
                    <TableRow
                        android:layout_width="fill_parent"
                        android:layout_height="fill_parent">

                        <TextView
                            android:id="@+id/yaw"
                            android:layout_width="100dp"
                            android:layout_height="wrap_content"
                            android:layout_column="0"
                            android:paddingTop="5dp"
                            android:paddingBottom="5dp"
                            android:text="偏航角:"
                            android:textAppearance="?android:attr/textAppearanceMedium" />

                        <TextView
                            android:id="@+id/yaw_value"
                            android:layout_width="fill_parent"
                            android:layout_height="wrap_content"
                            android:layout_column="1"
                            android:layout_gravity="left"
                            android:paddingTop="5dp"
                            android:paddingBottom="5dp"
                            android:text="0度"
                            android:textAppearance="?android:attr/textAppearanceMedium" />
                    </TableRow>
                </TableLayout>

            </RelativeLayout>

        </androidx.cardview.widget.CardView>


    </LinearLayout>
</ScrollView>

姿态UI布局代码,主要如下所示,采用表格布局

                <TableLayout
                    android:id="@+id/ahrs"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/telemetryInfo"
                    android:layout_alignParentStart="true"
                    android:layout_alignParentLeft="true">

                    <TableRow
                        android:layout_width="match_parent"
                        android:layout_height="match_parent">

                        <TextView
                            android:id="@+id/roll"
                            android:layout_width="100dp"
                            android:layout_height="wrap_content"
                            android:layout_column="0"
                            android:paddingTop="5dp"
                            android:paddingBottom="5dp"
                            android:text="横滚角:"
                            android:textAppearance="?android:attr/textAppearanceMedium" />

                        <TextView
                            android:id="@+id/roll_value"
                            android:layout_width="fill_parent"
                            android:layout_height="wrap_content"
                            android:layout_column="1"
                            android:layout_gravity="left"
                            android:paddingTop="5dp"
                            android:paddingBottom="5dp"
                            android:text="0度"
                            android:textAppearance="?android:attr/textAppearanceMedium" />
                    </TableRow>

                    <TableRow
                        android:layout_width="fill_parent"
                        android:layout_height="fill_parent">

                        <TextView
                            android:id="@+id/pitch"
                            android:layout_width="100dp"
                            android:layout_height="wrap_content"
                            android:layout_column="0"
                            android:paddingTop="5dp"
                            android:paddingBottom="5dp"
                            android:text="俯仰角:"
                            android:textAppearance="?android:attr/textAppearanceMedium" />

                        <TextView
                            android:id="@+id/pitch_value"
                            android:layout_width="fill_parent"
                            android:layout_height="wrap_content"
                            android:layout_column="1"
                            android:layout_gravity="left"
                            android:paddingTop="5dp"
                            android:paddingBottom="5dp"
                            android:text="0度"
                            android:textAppearance="?android:attr/textAppearanceMedium" />
                    </TableRow>
                    <TableRow
                        android:layout_width="fill_parent"
                        android:layout_height="fill_parent">

                        <TextView
                            android:id="@+id/yaw"
                            android:layout_width="100dp"
                            android:layout_height="wrap_content"
                            android:layout_column="0"
                            android:paddingTop="5dp"
                            android:paddingBottom="5dp"
                            android:text="偏航角:"
                            android:textAppearance="?android:attr/textAppearanceMedium" />

                        <TextView
                            android:id="@+id/yaw_value"
                            android:layout_width="fill_parent"
                            android:layout_height="wrap_content"
                            android:layout_column="1"
                            android:layout_gravity="left"
                            android:paddingTop="5dp"
                            android:paddingBottom="5dp"
                            android:text="0度"
                            android:textAppearance="?android:attr/textAppearanceMedium" />
                    </TableRow>
                </TableLayout>

2.在activity中显示更新姿态数据

首先在主activity中重写void onDroneEvent(String event, Bundle extras);方法
在这里插入图片描述

    @Override
    public void onDroneEvent(String event, Bundle extras)
    { 
   
        switch (event) { 
   
            case AttributeEvent.STATE_CONNECTED:
                alertUser("Drone Connected");
                updateConnectedButton(this.drone.isConnected());
                //更新解锁连接按钮
                updateArmButton();
                break;

            case AttributeEvent.STATE_DISCONNECTED:
                alertUser("Drone Disconnected");
                updateConnectedButton(this.drone.isConnected());
                //更新解锁断开按钮
                updateArmButton();
                break;

            case AttributeEvent.STATE_UPDATED:
            case AttributeEvent.STATE_ARMING:
                //更新解锁按钮
                updateArmButton();
                break;

            case AttributeEvent.TYPE_UPDATED:
                Type newDroneType = this.drone.getAttribute(AttributeType.TYPE);
                if (newDroneType.getDroneType() != this.droneType) { 
   
                    this.droneType = newDroneType.getDroneType();
                    updateVehicleModesForType(this.droneType);
                }
                break;

            case AttributeEvent.STATE_VEHICLE_MODE:
                //更新模式
                updateVehicleMode();
                break;

            case AttributeEvent.SPEED_UPDATED:
                //更新姿态
                updateAttitude();
                break;
            case AttributeEvent.ATTITUDE_UPDATED:
                //更新速度
                updateSpeed();
                break;
            case AttributeEvent.ALTITUDE_UPDATED:
                //更新高度
                updateAltitude();
                break;

            case AttributeEvent.HOME_UPDATED:
                //更新到home点距离
                updateDistanceFromHome();
                break;

            default:
                // Log.i("DRONE_EVENT", event); //Uncomment to see events from the drone
                break;
        }
    }

在这里插入图片描述
这里我们看下更新姿态是如何实现的

    /** * 更新姿态信息 */
    protected void updateAttitude() { 
   
        //找到对应要显示的横滚位置的ID
        TextView rollValue = (TextView) findViewById(R.id.roll_value);
        //找到对应要显示的俯仰位置的ID
        TextView pitchValue = (TextView) findViewById(R.id.pitch_value);
        //找到对应要显示的偏航位置的ID
        TextView yawValue = (TextView) findViewById(R.id.yaw_value);
        //关键代码,获取姿态信息实例
        Attitude attitude = this.drone.getAttribute(AttributeType.ATTITUDE);
        //获取信息后,修改需要显示的位置
        //显示横滚角的值
        rollValue.setText(String.format("%3.1f", attitude.getRoll()) + "度");
       //显示横滚俯仰角的值
        pitchValue.setText(String.format("%3.1f", attitude.getPitch()) + "度");
       //显示偏航角的值
        yawValue.setText(String.format("%3.1f", attitude.getYaw()) + "度");
    }

因此这里比较重要的函数是:

Attitude attitude = this.drone.getAttribute(AttributeType.ATTITUDE);


    /** *获取属性 * @param type * @param <T> * @return */
    public <T extends Parcelable> T getAttribute(String type)
    { 
   
        final IDroneApi droneApi = droneApiRef.get();
        if (!isStarted(droneApi) || type == null)
        { 
   
            return this.getAttributeDefaultValue(type);
        }

        T attribute = null;
        Bundle carrier = null;
        try 
        { 
   
            carrier = droneApi.getAttribute(type);
        } catch (RemoteException e) 
        { 
   
            handleRemoteException(e);
        }

        if (carrier != null) 
        { 
   
            try 
            { 
   
                carrier.setClassLoader(contextClassLoader);
                attribute = carrier.getParcelable(type);
            } catch (Exception e) { 
   
                Log.e(TAG, e.getMessage(), e);
            }
        }

        return attribute == null ? this.<T>getAttributeDefaultValue(type) : attribute;
    }

从这里直接寻找怎么找到如何拿取姿态数据不太好找,我们可以从协议直接倒着找。我们先看下app接收到飞控的数据进行的处理

    @Override
    public void onMavLinkMessageReceived(MAVLinkMessage message) { 
   
        Log.i("lxw","ardupilot message.sysid :"+message.sysid );

        if ((message.sysid != this.getSysid()) && !isMavLinkMessageException(message)) { 
   
            // Reject Messages that are not for the system id
            return;
        }

        // Filter Components IDs to be specifically the IDs that can be processed
        int compId = message.compid;
        if (compId != AUTOPILOT_COMPONENT_ID
                && compId != ARTOO_COMPONENT_ID
                && compId != SiK_RADIO_FIXED_COMPID ){ 
   
            return;
        }

        if (!getParameterManager().processMessage(message)) { 
   

            getWaypointManager().processMessage(message);
            getCalibrationSetup().processMessage(message);

            switch (message.msgid) { 
   
                //msg-id=253 文本信息
                case msg_statustext.MAVLINK_MSG_ID_STATUSTEXT:
                    // These are any warnings sent from APM:Copter with
                    // gcs_send_text_P()
                    // This includes important thing like arm fails, prearm fails, low
                    // battery, etc.
                    // also less important things like "erasing logs" and
                    // "calibrating barometer"
                    msg_statustext msg_statustext = (msg_statustext) message;
                    processStatusText(msg_statustext);
                    break;
                //msg-id=74 固定翼飞机平视显示器上通常显示的指标
                case msg_vfr_hud.MAVLINK_MSG_ID_VFR_HUD:
                    processVfrHud((msg_vfr_hud) message);
                    break;
                //msg-id=27 原始IMU信息
                case msg_raw_imu.MAVLINK_MSG_ID_RAW_IMU:
                    msg_raw_imu msg_imu = (msg_raw_imu) message;
                    mag.newData(msg_imu);
                    break;
                //msg-id=166 遥控状态信息
                case msg_radio.MAVLINK_MSG_ID_RADIO:
                    msg_radio m_radio = (msg_radio) message;
                    processSignalUpdate(m_radio.rxerrors, m_radio.fixed, m_radio.rssi,
                            m_radio.remrssi, m_radio.txbuf, m_radio.noise, m_radio.remnoise);
                    break;
                //msg-id=35 遥控通道信息
                case msg_rc_channels_raw.MAVLINK_MSG_ID_RC_CHANNELS_RAW:
                    rc.setRcInputValues((msg_rc_channels_raw) message);
                    break;
                //msg-id=36 伺服通道信息
                case msg_servo_output_raw.MAVLINK_MSG_ID_SERVO_OUTPUT_RAW:
                    rc.setRcOutputValues((msg_servo_output_raw) message);
                    break;
                //msg-id=36 相机信息
                case msg_camera_feedback.MAVLINK_MSG_ID_CAMERA_FEEDBACK:
                    getCamera().newImageLocation((msg_camera_feedback) message);
                    break;
                //msg-id=158 挂载信息
                case msg_mount_status.MAVLINK_MSG_ID_MOUNT_STATUS:
                    processMountStatus((msg_mount_status) message);
                    break;
                //msg-id=252 名字值信息
                case msg_named_value_int.MAVLINK_MSG_ID_NAMED_VALUE_INT:
                    processNamedValueInt((msg_named_value_int) message);
                    break;

                //***************罗盘校准信息处理 Magnetometer calibration messages handling *************//
                //msg-id=191 罗盘校准信息
                //msg-id=192 罗盘校准取消信息
                case msg_mag_cal_progress.MAVLINK_MSG_ID_MAG_CAL_PROGRESS:
                case msg_mag_cal_report.MAVLINK_MSG_ID_MAG_CAL_REPORT:
                    getMagnetometerCalibration().processCalibrationMessage(message);
                    break;

                default:
                    break;
            }
        }
        Log.i("lxw","super message.sysid :"+message.sysid );
        //这里开始调用父类的实现,因此我们需要继续看相关msg->id的处理
        super.onMavLinkMessageReceived(message);
    }

    /** * 处理mavlink接收信息 * @param message */
    @Override
    public void onMavLinkMessageReceived(MAVLinkMessage message) { 
   
        
        Log.i("lxw","message.sysid :"+message.sysid );
        if ( (message.sysid != this.getSysid()) && !isMavLinkMessageException(message) )
        { 
   
            // Reject messages that are not for this drone's system id
            return;
        }
        //处理心跳信息
        onHeartbeat(message);

        switch (message.msgid) { 
   
            //msg-id=109 遥控器状态信息
            case msg_radio_status.MAVLINK_MSG_ID_RADIO_STATUS:
                msg_radio_status m_radio_status = (msg_radio_status) message;
                processSignalUpdate(m_radio_status.rxerrors, m_radio_status.fixed, m_radio_status.rssi,
                        m_radio_status.remrssi, m_radio_status.txbuf, m_radio_status.noise, m_radio_status.remnoise);
                break;
            //msg-id=30 姿态信息
            case msg_attitude.MAVLINK_MSG_ID_ATTITUDE:
                msg_attitude m_att = (msg_attitude) message;
                processAttitude(m_att);
                break;
            //msg-id=0 心跳信息
            case msg_heartbeat.MAVLINK_MSG_ID_HEARTBEAT:
                msg_heartbeat msg_heart = (msg_heartbeat) message;
                processHeartbeat(msg_heart);
                break;
            //msg-id=241 振动级和加速度计夹持
            case msg_vibration.MAVLINK_MSG_ID_VIBRATION:
                msg_vibration vibrationMsg = (msg_vibration) message;
                processVibrationMessage(vibrationMsg);
                break;

            //*************** EKF State handling ******************//
            msg-id=193 EKF状态处理
            case msg_ekf_status_report.MAVLINK_MSG_ID_EKF_STATUS_REPORT:
                processEfkStatus((msg_ekf_status_report) message);
                break;
            //msg-id=1 系统状态
            case msg_sys_status.MAVLINK_MSG_ID_SYS_STATUS:
                msg_sys_status m_sys = (msg_sys_status) message;
                processSysStatus(m_sys);
                break;
            //msg-id=33 全局位置信息
            case msg_global_position_int.MAVLINK_MSG_ID_GLOBAL_POSITION_INT:
                processGlobalPositionInt((msg_global_position_int) message);
                break;
            //msg-id=24 系统状态原始GPS信息
            case msg_gps_raw_int.MAVLINK_MSG_ID_GPS_RAW_INT:
                processGpsState((msg_gps_raw_int) message);
                break;
            //msg-id=39 任务相关信息
            case msg_mission_item.MAVLINK_MSG_ID_MISSION_ITEM:
                processHomeUpdate((msg_mission_item) message);
                break;
            //msg-id=42 当前任务信息
            case msg_mission_current.MAVLINK_MSG_ID_MISSION_CURRENT:
                missionStats.setWpno(((msg_mission_current) message).seq);
                break;
            //msg-id=46 任务到达信息
            case msg_mission_item_reached.MAVLINK_MSG_ID_MISSION_ITEM_REACHED:
                missionStats.setLastReachedWaypointNumber(((msg_mission_item_reached) message).seq);
                break;
            //msg-id=62 控制输出信息
            case msg_nav_controller_output.MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT:
                msg_nav_controller_output m_nav = (msg_nav_controller_output) message;
                setDisttowpAndSpeedAltErrors(m_nav.wp_dist, m_nav.alt_error, m_nav.aspd_error);
                break;
        }
    }

从这里我们可以看到姿态数据的处理
在这里插入图片描述
核心在于:processAttitude(m_att);但是注意的还是先把message转换成姿态相关的协议信息

    /** * 处理姿态信息 * @param m_att */
    private void processAttitude(msg_attitude m_att) { 
   
        //设置横滚角
        attitude.setRoll(Math.toDegrees(m_att.roll));
        //设置横滚角速度
        attitude.setRollSpeed((float) Math.toDegrees(m_att.rollspeed));
        //设置俯仰角
        attitude.setPitch(Math.toDegrees(m_att.pitch));
        //设置俯仰角速度
        attitude.setPitchSpeed((float) Math.toDegrees(m_att.pitchspeed));
        //设置偏航角
        attitude.setYaw(Math.toDegrees(m_att.yaw));
        //设置偏航角速度
        attitude.setYawSpeed((float) Math.toDegrees(m_att.yawspeed));
        //通知无人机事件
        notifyDroneEvent(DroneInterfaces.DroneEventsType.ATTITUDE);
    }

加粗样式我们看下姿态信息的协议定义:

/* AUTO-GENERATED FILE. DO NOT MODIFY. * * This class was automatically generated by the * java mavlink generator tool. It should not be modified by hand. */

// MESSAGE ATTITUDE PACKING
package com.MAVLink.common;
import com.MAVLink.MAVLinkPacket;
import com.MAVLink.Messages.MAVLinkMessage;
import com.MAVLink.Messages.MAVLinkPayload;
        
/** * 这个姿态是在航空坐标系下(右手坐标系:Z-向下,X-前,Y-右) * The attitude in the aeronautical frame (right-handed, Z-down, X-front, Y-right). */
public class msg_attitude extends MAVLinkMessage{ 
   

    //姿态协议msg-id=30
    public static final int MAVLINK_MSG_ID_ATTITUDE = 30;
    //姿态协议长度
    public static final int MAVLINK_MSG_LENGTH = 28;
    //串口版本UID
    private static final long serialVersionUID = MAVLINK_MSG_ID_ATTITUDE;


      
    /** * 时间戳(系统启动后的毫秒数) */
    public long time_boot_ms;
      
    /** * 横滚角 (rad, -pi..+pi) */
    public float roll;
      
    /** * 俯仰角 (rad, -pi..+pi) */
    public float pitch;
      
    /** * 偏航角 (rad, -pi..+pi) */
    public float yaw;
      
    /** * 横滚角速度 (rad/s) */
    public float rollspeed;
      
    /** * 俯仰角速度 (rad/s) */
    public float pitchspeed;
      
    /** *偏航角速度 (rad/s) */
    public float yawspeed;
    

    /** * 为这种类型的消息生成mavlink消息的有效负载,组包数据 * @return */
    public MAVLinkPacket pack(){ 
   
        MAVLinkPacket packet = new MAVLinkPacket(MAVLINK_MSG_LENGTH);
        packet.sysid = 255;
        packet.compid = 190;
        packet.msgid = MAVLINK_MSG_ID_ATTITUDE;
              
        packet.payload.putUnsignedInt(time_boot_ms);
              
        packet.payload.putFloat(roll);
              
        packet.payload.putFloat(pitch);
              
        packet.payload.putFloat(yaw);
              
        packet.payload.putFloat(rollspeed);
              
        packet.payload.putFloat(pitchspeed);
              
        packet.payload.putFloat(yawspeed);
        
        return packet;
    }

    /** * Decode a attitude message into this class fields * 将姿态信息解码到该类字段中 * @param payload The message to decode */
    public void unpack(MAVLinkPayload payload) { 
   
        payload.resetIndex();
              
        this.time_boot_ms = payload.getUnsignedInt();
        //横滚角
        this.roll = payload.getFloat();
        //俯仰角
        this.pitch = payload.getFloat();
        //偏航角
        this.yaw = payload.getFloat();
        //横滚角速度
        this.rollspeed = payload.getFloat();
        //俯仰角速度
        this.pitchspeed = payload.getFloat();
        //偏航角速度
        this.yawspeed = payload.getFloat();
        
    }

    /** * 构造函数,只需初始化msgid * Constructor for a new message, just initializes the msgid */
    public msg_attitude(){ 
   
        msgid = MAVLINK_MSG_ID_ATTITUDE;
    }

    /** * Constructor for a new message, initializes the message with the payload * from a mavlink packet * 构造函数,用有效负载初始化消息,从mavlink数据包 */
    public msg_attitude(MAVLinkPacket mavLinkPacket){ 
   
        this.sysid = mavLinkPacket.sysid;
        this.compid = mavLinkPacket.compid;
        this.msgid = MAVLINK_MSG_ID_ATTITUDE;
        unpack(mavLinkPacket.payload);        
    }

                  
    /** * 返回包含消息名称和数据的字符串 * Returns a string with the MSG name and data */
    public String toString(){ 
   
        return "MAVLINK_MSG_ID_ATTITUDE - " +
                "sysid:"+sysid+
                " compid:"+compid+
                " time_boot_ms:"+time_boot_ms+
                " roll:"+roll+
                " pitch:"+pitch+
                " yaw:"+yaw+
                " rollspeed:"+rollspeed+
                " pitchspeed:"+pitchspeed+
                " yawspeed:"+yawspeed+"";
    }
}
        

我们现在在回去看下刚刚看到的姿态更新函数:

    /** * 更新姿态信息 */
    protected void updateAttitude() { 
   
        //找到对应要显示的横滚位置的ID
        TextView rollValue = (TextView) findViewById(R.id.roll_value);
        //找到对应要显示的俯仰位置的ID
        TextView pitchValue = (TextView) findViewById(R.id.pitch_value);
        //找到对应要显示的偏航位置的ID
        TextView yawValue = (TextView) findViewById(R.id.yaw_value);
        //关键代码,获取姿态信息实例
        Attitude attitude = this.drone.getAttribute(AttributeType.ATTITUDE);
        //获取信息后,修改需要显示的位置
        //显示横滚角的值
        rollValue.setText(String.format("%3.1f", attitude.getRoll()) + "度");
       //显示横滚俯仰角的值
        pitchValue.setText(String.format("%3.1f", attitude.getPitch()) + "度");
       //显示偏航角的值
        yawValue.setText(String.format("%3.1f", attitude.getYaw()) + "度");
    }

其中:attitude.getRoll()获取姿态横滚角数据;attitude.getPitch()获取姿态俯仰角数据;获取姿态偏航角数据。
其中attitude,是Attitude attitude的对象,我们去看下Attitude类

package com.o3dr.services.android.lib.drone.property;

import android.os.Parcel;
import android.os.Parcelable;

/** * Created by fhuya on 10/28/14. */
public class Attitude implements DroneAttribute { 
   

    /** * 横滚角 (deg, -180..+180) */
    private double roll;

    /** * 横滚角速度 (deg/s) */
    private float rollSpeed;

    /** * 俯仰角 (deg, -180 to 180) */
    private  double pitch;

    /** * 俯仰角速度 (deg / s) */
    private float pitchSpeed;

    /** * 偏航(deg, -180 to 180) */
    private  double yaw;

    /** * 偏航角速度 (deg/ s) */
    private float yawSpeed;

    public Attitude(){ 
   }
    //构造函数
    public Attitude(double roll, double pitch, double yaw, float rollSpeed, float pitchSpeed, float yawSpeed) 
    { 
   
        this.roll = roll;
        this.pitch = pitch;
        this.yaw = yaw;
        this.rollSpeed = rollSpeed;
        this.pitchSpeed = pitchSpeed;
        this.yawSpeed = yawSpeed;
    }

    /** * 更新横滚角--- * Updates the roll angle * @param roll Roll angle (deg, -180..+180) */
    public void setRoll(double roll) { 
   
        this.roll = roll;
    }

    /** * 更新俯仰角Updates the pitch angle * @param pitch Pitch angle (deg, -180..+180) */
    public void setPitch(double pitch) { 
   
        this.pitch = pitch;
    }

    /** *更新偏航角 Updates the yaw angle * @param yaw Yaw angle (deg, -180..+180) */
    public void setYaw(double yaw) { 
   
        this.yaw = yaw;
    }

    /** * 获取横滚角 * @return Vehicle roll angle (deg, -180..+180) */
    public double getRoll() { 
   
        return roll;
    }

    /** * 获取俯仰角 * @return Vehicle pitch angle (deg, -180 to 180) */
    public double getPitch() { 
   
        return pitch;
    }

    /** * 获取偏航角 * @return Vehicle yaw angle (deg, -180 to 180) */
    public double getYaw() { 
   
        return yaw;
    }

    /** * 获取俯仰角速度 * @return Vehicle pitch angular speed (deg / s) */
    public float getPitchSpeed() { 
   
        return pitchSpeed;
    }

    /** * 更新俯仰角速度 * Updates the pitch angular speed * @param pitchSpeed Pitch angular speed (deg/s) */
    public void setPitchSpeed(float pitchSpeed) { 
   
        this.pitchSpeed = pitchSpeed;
    }

    /** * 获取横滚角速度 * @return Vehicle roll angular speed (deg/s) */
    public float getRollSpeed() { 
   
        return rollSpeed;
    }

    /** * 设置横滚角速度 * Updates the roll angular speed * @param rollSpeed Roll angular speed (deg/s) */
    public void setRollSpeed(float rollSpeed) { 
   
        this.rollSpeed = rollSpeed;
    }

    /** * 获取设备偏航角速度 * @return Vehicle yaw angular speed (deg/ s) */
    public float getYawSpeed() { 
   
        return yawSpeed;
    }

    /** * 更新偏航角速度 * Updates the yaw angular speed * @param yawSpeed Yaw angular speed (deg/s) */
    public void setYawSpeed(float yawSpeed) { 
   
        this.yawSpeed = yawSpeed;
    }

    @Override
    public String toString() { 
   
        return "Attitude{" +
                "pitch=" + pitch +
                ", roll=" + roll +
                ", rollSpeed=" + rollSpeed +
                ", pitchSpeed=" + pitchSpeed +
                ", yaw=" + yaw +
                ", yawSpeed=" + yawSpeed +
                '}';
    }

    @Override
    public boolean equals(Object o) { 
   
        if (this == o) return true;
        if (!(o instanceof Attitude)) return false;

        Attitude attitude = (Attitude) o;

        if (Double.compare(attitude.roll, roll) != 0) return false;
        if (Float.compare(attitude.rollSpeed, rollSpeed) != 0) return false;
        if (Double.compare(attitude.pitch, pitch) != 0) return false;
        if (Float.compare(attitude.pitchSpeed, pitchSpeed) != 0) return false;
        if (Double.compare(attitude.yaw, yaw) != 0) return false;
        return Float.compare(attitude.yawSpeed, yawSpeed) == 0;

    }

    @Override
    public int hashCode() { 
   
        int result;
        long temp;
        temp = Double.doubleToLongBits(roll);
        result = (int) (temp ^ (temp >>> 32));
        result = 31 * result + (rollSpeed != +0.0f ? Float.floatToIntBits(rollSpeed) : 0);
        temp = Double.doubleToLongBits(pitch);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        result = 31 * result + (pitchSpeed != +0.0f ? Float.floatToIntBits(pitchSpeed) : 0);
        temp = Double.doubleToLongBits(yaw);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        result = 31 * result + (yawSpeed != +0.0f ? Float.floatToIntBits(yawSpeed) : 0);
        return result;
    }


    @Override
    public int describeContents() { 
   
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) { 
   
        dest.writeDouble(this.roll);
        dest.writeDouble(this.pitch);
        dest.writeDouble(this.yaw);
        dest.writeFloat(this.rollSpeed);
        dest.writeFloat(this.pitchSpeed);
        dest.writeFloat(this.yawSpeed);
    }

    private Attitude(Parcel in) { 
   
        this.roll = in.readDouble();
        this.pitch = in.readDouble();
        this.yaw = in.readDouble();
        this.rollSpeed = in.readFloat();
        this.pitchSpeed = in.readFloat();
        this.yawSpeed = in.readFloat();
    }

    public static final Parcelable.Creator<Attitude> CREATOR = new Parcelable.Creator<Attitude>() { 
   
        public Attitude createFromParcel(Parcel source) { 
   
            return new Attitude(source);
        }

        public Attitude[] newArray(int size) { 
   
            return new Attitude[size];
        }
    };
}

从Attitude类的实现可以看出我们获取的姿态角相关信息,是从
在这里插入图片描述
传递进去,因此要想建立mavlink解析到的数据和UI获取数据建立联系,这个set函数是关键。我们进行全局查找,只有找到了下面的使用
在这里插入图片描述
可以看出只有mavlink协议解析出进行了这个设置,这个跟我们想象的是一致的,就是通过set函数实现。

在这里插入图片描述
其中:对象attitude是 protected final Attitude attitude = new Attitude();的对象,而Attitude正好是我们刚刚在UI中使用的类。所以他们之间建立了联系。只需要进行mavlink姿态数据的解析,然后进行更新这个值,UI界面通过get函数就可以获取到数据
在这里插入图片描述
综上可以得到,Attitude类是建立UI和后端数据进行解析的桥梁。


3.根源问题

到这里我们还有一个问题没有解决,就是之前说的那个疑问?只要解决这个疑问一切就打通

    /** * 更新姿态信息 */
    protected void updateAttitude() { 
   
        //找到对应要显示的横滚位置的ID
        TextView rollValue = (TextView) findViewById(R.id.roll_value);
        //找到对应要显示的俯仰位置的ID
        TextView pitchValue = (TextView) findViewById(R.id.pitch_value);
        //找到对应要显示的偏航位置的ID
        TextView yawValue = (TextView) findViewById(R.id.yaw_value);
        //关键代码,获取姿态信息实例
        Attitude attitude = this.drone.getAttribute(AttributeType.ATTITUDE);
        //获取信息后,修改需要显示的位置
        //显示横滚角的值
        rollValue.setText(String.format("%3.1f", attitude.getRoll()) + "度");
       //显示横滚俯仰角的值
        pitchValue.setText(String.format("%3.1f", attitude.getPitch()) + "度");
       //显示偏航角的值
        yawValue.setText(String.format("%3.1f", attitude.getYaw()) + "度");
    }

结合前面的讲述,目前主要是获取实时更新姿态的对象实例,也就是这个代码
Attitude attitude = this.drone.getAttribute(AttributeType.ATTITUDE);。为什么这样说呢?因为从第二部分我们可以看出数据之间的关联是通过Attitude attitude的对象建立了联系,而Attitude attitude = this.drone.getAttribute(AttributeType.ATTITUDE);正好是获取一个对象给attitude,只要说明:



!!!
this.drone.getAttribute(AttributeType.ATTITUDE)返回的是一个可以实时获取姿态更新的数据对象就可以。
!!!



其中: private Drone drone;
在这里插入图片描述
在这里插入图片描述
我们可以看出PACKAGE_NAME是被定义成:

private static final String PACKAGE_NAME = “com.o3dr.services.android.lib.attribute”;

而: public static final String ALTITUDE = PACKAGE_NAME + “.ALTITUDE”;
则表示的是com.o3dr.services.android.lib.attribute.ATTITUDE
在这里插入图片描述
现在关键还是那个public T getAttribute(String type)方法,
在这里插入图片描述

 /** * 获取默认值 * @param attributeType * @param <T> * @return */
    private <T extends Parcelable> T getAttributeDefaultValue(String attributeType) 
    { 
   
        if (attributeType == null) { 
   
            return null;
        }

        switch (attributeType) { 
   
            case AttributeType.ALTITUDE:
                return (T) new Altitude();

            case AttributeType.GPS:
                return (T) new Gps();

            case AttributeType.STATE:
                return (T) new State();

            case AttributeType.PARAMETERS:
                return (T) new Parameters();

            case AttributeType.SPEED:
                return (T) new Speed();

            case AttributeType.ATTITUDE:
                //可以看出这里new了一个对象,而Attitude正好是我们想要得到的值
                return (T) new Attitude();

            case AttributeType.HOME:
                return (T) new Home();

            case AttributeType.BATTERY:
                return (T) new Battery();

            case AttributeType.MISSION:
                return (T) new Mission();

            case AttributeType.SIGNAL:
                return (T) new Signal();

            case AttributeType.GUIDED_STATE:
                return (T) new GuidedState();

            case AttributeType.TYPE:
                return (T) new Type();

            case AttributeType.FOLLOW_STATE:
                return (T) new FollowState();

            case AttributeType.MAGNETOMETER_CALIBRATION_STATUS:
                return (T) new MagnetometerCalibrationStatus();

            case AttributeType.RETURN_TO_ME_STATE:
                return (T) new ReturnToMeState();

            case AttributeType.CAMERA:
            case SoloAttributes.SOLO_STATE:
            case SoloAttributes.SOLO_GOPRO_STATE:
            case SoloAttributes.SOLO_GOPRO_STATE_V2:
            default:
                return null;
        }
    }

因此按照这种简单的理解思路是对的,也就解释了我们的疑惑,对于attribute如果不等于空,那么将会有
在这里插入图片描述
为了验证具体执行哪里我们增加log进行监视。

在这里插入图片描述


    /** *获取属性 * @param type * @param <T> * @return */
    public <T extends Parcelable> T getAttribute(String type)
    { 
   
        final IDroneApi droneApi = droneApiRef.get();
        Log.i("zqj"," droneApiRef:"+droneApiRef.get());
        if (!isStarted(droneApi) || type == null)
        { 
   
            Log.i("zqj"," droneApiRef null:");
            return this.getAttributeDefaultValue(type);
        }

        T attribute = null;
        Bundle carrier = null;
        try
        { 
   
            carrier = droneApi.getAttribute(type);
            Log.i("zqj"," carrier:"+carrier);
        } catch (RemoteException e)
        { 
   
            handleRemoteException(e);
            Log.i("zqj"," carrier1:"+carrier);
        }

        if (carrier != null)
        { 
   
            try
            { 
   
                carrier.setClassLoader(contextClassLoader);
                attribute = carrier.getParcelable(type);
                Log.i("zqj"," attribute:"+attribute);
            } catch (Exception e)
            { 
   
                Log.i("zqj"," Exception:");
                Log.e(TAG, e.getMessage(), e);
            }
        }
        Log.i("zqj"," attribute2:"+attribute);
        return attribute == null ? this.<T>getAttributeDefaultValue(type) : attribute;
    }

在这里插入图片描述
从日志可以看出数据是从: attribute = carrier.getParcelable(type);获取。而Bundle carrier = null;,所以

在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/170565.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 如何解决数据库查询慢的问题_炖锅怎么那么慢熟

    如何解决数据库查询慢的问题_炖锅怎么那么慢熟一条慢查询会造成什么后果?年轻时,我一直觉得不就是返回数据会慢一些么,用户体验变差?其实远远不止,我经历过几次`线上事故`,有一次就是由一条SQL慢查询导致的。

    2022年10月14日
  • 游戏是怎么赚钱的 – 进阶篇[通俗易懂]

    游戏是怎么赚钱的 – 进阶篇[通俗易懂]首先回答几个常见的问题1、昨天提到的广州神武,其实是广州多益,主打产品叫做神武,感谢评论区勘误,这个公司创始人徐波也是个挺传奇的故事,然而很抱歉,今天不讲八卦,有兴趣的可…

  • Oracle 12.1.0.2 对JSON的支持

    Oracle 12.1.0.2 对JSON的支持

  • ThinkPHP5+小程序商城 网盘视频

    ThinkPHP5+小程序商城 网盘视频

    2021年10月31日
  • pidstat_pidstat「建议收藏」

    pidstat_pidstat「建议收藏」性能监控,pidstat就够了!安装:yuminstall-ysysstat常用参数:-u:默认的参数,显示各个进程的cpu使用统计-r:显示各个进程的内存使用统计-d:显示各个进程的IO使用情况-p:指定进程号-w:显示每个进程的上下文切换情况-t:显示选择任务的线程的统计信息外的额外信息-T{TASK|CHILD|ALL}这个选项指定了pidstat监控的。TASK表示报告…

    2022年10月22日
  • gis中char是什么字段_gis中字段类型char

    gis中char是什么字段_gis中字段类型char维护一个字符串集合,支持两种操作:I x 向集合中插入一个字符串 x;Q x 询问一个字符串在集合中出现了多少次。共有 N 个操作,输入的字符串总长度不超过 105,字符串仅包含小写英文字母。输入格式第一行包含整数 N,表示操作数。接下来 N 行,每行包含一个操作指令,指令为 I x 或 Q x 中的一种。输出格式对于每个询问指令 Q x,都要输出一个整数作为结果,表示 x 在集合中出现的次数。每个结果占一行。数据范围1≤N≤2∗104输入样例:5I abcQ abcQ ab

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号