基于HarmonyOS控制Hi3861小车之信息通信 原创 精华

软通动力HOS
发布于 2021-8-31 11:37
2.5w浏览
28收藏

基于HarmonyOS控制Hi3861小车之信息通信-鸿蒙开发者社区

引言 

      在鸿蒙应用实际开发中,经常会遇到App与IOT设备间的通信,本节主要详细讲述一下通信关键技术,考虑到TCP/UDP协议的特性,两者间通过UDP进行通信是一种必然的选择,UDP一种无连接的协议,具有资源消耗小,处理速度快的优点,了解UDP是怎么通信的,这对于每一个HarmonyOS开发者也是需要了解的重点知识。

核心类

DatagramSocket、DatagramPacket、EventHandler下面分别简单介绍下:

1.DatagramSocket:

构造器DatagramSocket(int port, InetAddress laddr):创建一个DatagramSocket实例,并将该对象绑定到指定IP地址、指定端口。主要方法receive(DatagramPacket p):从该DatagramSocket中接收数据报,send(DatagramPacket p):以该DatagramSocket对象向外发送数据报。

2.DatagramPacket:

构造器DatagramPacket(byte[] buf, int length, InetAddress addr, int port):以一个包含数据的数组来创建DatagramPacket对象,创建该DatagramPacket对象时还指定了IP地址和端口--这就决定了该数据报的目的地。

3.EventHandler:

是HarmonyOS用于处理线程间通信的一种机制,可以通过EventRunner创建新线程,将耗时的操作放到新线程上执行。这样既不阻塞原来的线程,任务又可以得到合理的处理。比如:主线程使用EventHandler创建子线程,子线程做耗时的下载图片操作,下载完成后,子线程通过EventHandler通知主线程,主线程再更新UI。

功能介绍

 通过App Demo控制小车运动(前进、后退、左转、右转、停止),主要通过UDP数据包发送命令,来说明它们间是怎么通信的,它们间控制命令以json格式发送。

如:

"mode": "CarControl",//控制命令分类
    "cmd": "forward"//具体命令
}。
  • 1.
  • 2.
  • 3.

开发指南

1、创建UDP协议的发送命令对象 

private UdpManager() {
        try {
            mGpsDatagramSocket = new DatagramSocket();
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

2、将要发送的数据封装成DatagramPacket对象发送

DatagramPacket sRequest = new DatagramPacket(mInfoArray, mInfoArray.length,
InetAddress.getByName(getIp()), PORT);
// 开始发送
mGpsDatagramSocket.send(sRequest);
  • 1.
  • 2.
  • 3.
  • 4.

3、构造发送的命令

public void sendMessage(String info) {
        Gson gson = new Gson();
        WifiCommand messageInfo = new WifiCommand();
        messageInfo.setCmd(info);
        //控制类型
        messageInfo.setMode();
        //转换成json
        String resultJson = gson.toJson(messageInfo);
        // 创建发送命令SendMessageRunnable对象
        mSendMessageRunnable = new SendMessageRunnable();
        mSendMessageRunnable.setInfoArray(resultJson.getBytes(StandardCharsets.UTF_8));
        // 启动发送命令线程
        mEventHandler.postTask(mSendMessageRunnable);
        if ("stop".equals(info) || "tripod_on".equals(info) || "tripod_off".equals(info)){
            HiLog.info(label, "info = " + info);
        } else {
            // 启动发送Gps请求线程和接收信息线程
            startReceive();
            startSendGpsMessage();
        }
        HiLog.info(label, "sendMessage = " + resultJson);
    }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.

实现效果

 基于HarmonyOS控制Hi3861小车之信息通信-鸿蒙开发者社区

附上主要源代码

1. MainAbilitySlice

public class MainAbilitySlice extends AbilitySlice implements Component.ClickedListener{
    private Button iTurnUp,iTurnDown,iTurnLeft,iTurnRight,iTurnRun;

    private UdpManager udpManager;
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_main);
        initComponent();
        // 初始化WiFi控制对象
        udpManager = UdpManager.getInstance(this);
    }

    private void initComponent(){
        iTurnUp = (Button) findComponentById(ResourceTable.Id_i_up);
        iTurnUp.setClickedListener(this);

        iTurnDown = (Button) findComponentById(ResourceTable.Id_i_down);
        iTurnDown.setClickedListener(this);

        iTurnLeft = (Button) findComponentById(ResourceTable.Id_i_left);
        iTurnLeft.setClickedListener(this);

        iTurnRight = (Button) findComponentById(ResourceTable.Id_i_right);
        iTurnRight.setClickedListener(this);

        iTurnRun = (Button) findComponentById(ResourceTable.Id_i_run);
        iTurnRun.setClickedListener(this);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.

2.  UdpManager

/**
 * UDP连接类
 */
public class UdpManager {
    private static final HiLogLabel label = new HiLogLabel(HiLog.LOG_APP, 0x00134, "UdpManager");
    private static final int PORT = 48100;
    private static final int GET_MESSAGE = 1;
    private static UdpManager sUdpManager;
    private static Context sContext;
    private UdpReceiveCallback mReceiveInformationCallback;
    private ReceiveMessageRunnable mReceiveMessageRunnable;
    private SendGpsMessageRunnable mSendGpsMessageRunnable;
    private SendMessageRunnable mSendMessageRunnable;
    private DatagramSocket mGpsDatagramSocket;
    private static  String ip = "192.168.0.1";

    /**
     * 控制是否还需要接收信息控制器
     */
    private boolean flag = false;

    private final EventHandler mEventHandler = new EventHandler(EventRunner.create()) {
        @Override
        protected void processEvent(InnerEvent event) {
            super.processEvent(event);
            if (event.eventId == GET_MESSAGE) {
                if (mReceiveInformationCallback != null) {
                    mReceiveInformationCallback.getMessage(event.object);
                }
            }
        }
    };

    private final EventHandler mReceiveEventHandler = new EventHandler(EventRunner.create()) {
    };

    private final EventHandler mSendGpsEventHandler = new EventHandler(EventRunner.create()) {
    };

    /**
     * UdpManager的单例
     *
     * @return UdpManager单例对象
     */
    public static UdpManager getInstance(Context context) {
        if (sUdpManager == null) {
            sUdpManager = new UdpManager();
            sContext = context;
        }
        return sUdpManager;
    }

    /**
     * 构造函数
     */
    private UdpManager() {
        // 创建UDP协议的发送命令对象
        try {
            mGpsDatagramSocket = new DatagramSocket();
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }

    /**
     * 注册接收信息的回调函数
     *
     * @param callback 接收信息回调函数
     */
    public void registerCallback(UdpReceiveCallback callback) {
        mReceiveInformationCallback = callback;
    }

    /**
     * 对外提供的发送命令方法
     *
     * @param info 需要发送的命令
     */
    public void sendMessage(String info) {
        Gson gson = new Gson();
        UdpCommand messageInfo = new UdpCommand();

        // 传进来的控制命令
        messageInfo.setCmd(info);

        //控制类型
        messageInfo.setMode();

        //转换成json
        String resultJson = gson.toJson(messageInfo);

        // 创建发送命令SendMessageRunnable对象
        mSendMessageRunnable = new SendMessageRunnable();
        mSendMessageRunnable.setInfoArray(resultJson.getBytes(StandardCharsets.UTF_8));

        // 启动发送命令线程
        mEventHandler.postTask(mSendMessageRunnable);

        // 启动发送Gps请求线程和接收信息线程
        if ("stop".equals(info)) {
            HiLog.info(label, "info = " + info);
        } else {
            // 启动发送Gps请求线程和接收信息线程
            startReceive();
            startSendGpsMessage();
        }
        HiLog.info(label, "sendMessage = " + resultJson);
    }

    public String getIp() {
        return ip;
    }


    public void setIp(String mIp) {
        this.ip = mIp;
    }

    /**
     * 内部类,用作发送命令
     */
    private class SendMessageRunnable implements Runnable {
        private byte[] mInfoArray;

        void setInfoArray(byte[] infoArray) {
            mInfoArray = infoArray;
        }

        @Override
        public void run() {
            HiLog.info(label, "发送线程 = " + Thread.currentThread().getName());

            // 发送数据
            try {
                // 延时发送50毫秒,因为如果不延时会将小车卡死
                Thread.sleep(50);

                // 将要发送的数据封装成DatagramPacket对象
                DatagramPacket sRequest = new DatagramPacket(mInfoArray, mInfoArray.length,
                        InetAddress.getByName(getIp()), PORT);

                // 开始发送
                mGpsDatagramSocket.send(sRequest);
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
                HiLog.info(label, "sendMessage error");
            }
        }
    }

    /**
     * 内部类,用作接收命令
     */
    private class ReceiveMessageRunnable implements Runnable {

        @Override
        public void run() {
            try {
                while (flag) {
                    byte[] buf = new byte[1024];
                    DatagramPacket receiveDatagramPacket = new DatagramPacket(buf, buf.length);
                    if (mGpsDatagramSocket != null && !mGpsDatagramSocket.isClosed()) {
                        HiLog.info(label, "接收线程开始阻塞" + Thread.currentThread().getName());

                        // 接收返回数据,会阻塞线程
                        mGpsDatagramSocket.receive(receiveDatagramPacket);

                        // 将得到的数据转成json
                        String json = new String(receiveDatagramPacket.getData(), StandardCharsets.UTF_8);
                        json = json.substring(json.indexOf("{"), json.lastIndexOf("}")+1);
                        HiLog.info(label, "receiveMessage json = " + json);

                        // 将对象发送给需要接收返回值的地方
                        mEventHandler.sendEvent(InnerEvent.get(GET_MESSAGE, json));
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                HiLog.error(label, "receiveMessage error");
            }
        }
    }

    /**
     * 内部类,用作发送请求Gps命令
     */
    private class SendGpsMessageRunnable implements Runnable {

        @Override
        public void run() {
            Gson gson = new Gson();
            UdpCommand messageInfo = new UdpCommand();

            // 传进来的控制命令
            messageInfo.setCmd("getinfo");

            //控制类型
            messageInfo.setMode();

            //转换成json
            String resultJson = gson.toJson(messageInfo);

            byte[] infoArray = resultJson.getBytes(StandardCharsets.UTF_8);

            try {
                // 将要发送的数据封装成DatagramPacket对象
                DatagramPacket sRequest = new DatagramPacket(infoArray, infoArray.length,
                        InetAddress.getByName(getIp()), PORT);

                // 开始发送
                mGpsDatagramSocket.send(sRequest);

                // 启动获取Gps命令线程
                mSendGpsEventHandler.postTask(mSendGpsMessageRunnable, 2000);
                HiLog.info(label, "发送gps");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 启动接收消息
     */
    private void startReceive() {
        if (!flag) {
            flag = true;

            // 创建接收命令ReceiveMessageRunnable对象
            mReceiveMessageRunnable = new ReceiveMessageRunnable();

            // 启动接收命令线程
            mReceiveEventHandler.postTask(mReceiveMessageRunnable);
            HiLog.info(label, "开启接收线程");
        }
    }

    /**
     * 开始获取gps点
     */
    private void startSendGpsMessage() {
        // 创建发送Gps命令SendGpsMessageRunnable对象
        if (mSendGpsMessageRunnable == null) {
            mSendGpsMessageRunnable = new SendGpsMessageRunnable();
        }

        // 启动获取Gps命令线程
        mSendGpsEventHandler.postTask(mSendGpsMessageRunnable);
        HiLog.info(label, "开启发送gps请求线程");
    }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.
  • 209.
  • 210.
  • 211.
  • 212.
  • 213.
  • 214.
  • 215.
  • 216.
  • 217.
  • 218.
  • 219.
  • 220.
  • 221.
  • 222.
  • 223.
  • 224.
  • 225.
  • 226.
  • 227.
  • 228.
  • 229.
  • 230.
  • 231.
  • 232.
  • 233.
  • 234.
  • 235.
  • 236.
  • 237.
  • 238.
  • 239.
  • 240.
  • 241.
  • 242.
  • 243.
  • 244.
  • 245.
  • 246.
  • 247.
  • 248.
  • 249.
  • 250.

3. UdpCommand

class UdpCommand {
    // 控制命令:forward,back,left,right
    private String cmd;
    // 控制类型
    private String mode;

    public String getCmd() {
        return cmd;
    }

    void setCmd(String cmd) {
        this.cmd = cmd;
    }

    public String getMode() {
        return mode;
    }

    void setMode() {
        this.mode = "CarControl";
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.

4. UdpReceiveCallback

/**
 * 接收小车返回数据的回调函数
 */
public interface UdpReceiveCallback {
    void getMessage(Object value);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

5. xml布局文件

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:alignment="center"
    ohos:orientation="vertical">

    <DirectionalLayout
        ohos:height="70vp"
        ohos:width="match_parent"
        ohos:orientation="horizontal"
        ohos:layout_alignment="center"
        ohos:top_margin="10vp" >
        <Button
            ohos:id="$+id:i_up"
            ohos:height="50vp"
            ohos:width="120vp"
            ohos:background_element="#FF9F9F9F"
            ohos:left_margin="60vp"
            ohos:text_size="25fp"
            ohos:text="前进"/>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
分类
已于2021-8-31 11:37:14修改
26
收藏 28
回复
举报
26
7
28
7条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

感谢分享,回去试的跑一下。

回复
2021-8-31 11:56:37
软通田可辉
软通田可辉

软通同事文章写的越来越好了

1
回复
2021-8-31 14:05:52
软通小精灵
软通小精灵

感谢软通同事分享

回复
2021-8-31 14:29:52
软通动力HOS
软通动力HOS 回复了 红叶亦知秋
感谢分享,回去试的跑一下。

感谢大家的支持

回复
2021-9-1 09:20:26
芒果爱学习
芒果爱学习

加油加油

回复
2021-9-2 09:22:53
小梁学鸿蒙
小梁学鸿蒙

感谢老师分享

回复
2021-9-2 09:29:48
鸿联
鸿联

前几天收到一个3861小车,试着用手机跑一下

回复
2021-9-25 08:56:22


回复
    相关推荐
    恭喜您,今日已阅读两篇内容,特奖励+2声望, 快来领取吧。