【问题标题】:Raspberry Pi getting data from MultiWiiRaspberry Pi 从 MultiWii 获取数据
【发布时间】:2017-01-11 20:22:45
【问题描述】:

我有一个 Raspberry Pi 3B 和一个 CRIUS All in One Pro (v2.0) MultiWii 飞行控制器。我正在使用 MultiWii 2.4 版本和最新的 NOOBS。我能够很好地设置两者,现在我正试图让 Raspberry Pi 通过连接两个板的 USB/Micro USB 电缆与 MultiWii 通信。

目前,MultiWii 没有返回任何数据,我不知道为什么。据我所知,我的协议是正确的。我查看了几个工作代码库(用 Python of Java for Arduino 编写),并遵循 MultiWii documentation 并阅读了相关的 forum post

这是我编写的客户端代码。

package com.jmace.MaceDrone.msp;


import com.pi4j.io.serial.Baud;
import com.pi4j.io.serial.DataBits;
import com.pi4j.io.serial.FlowControl;
import com.pi4j.io.serial.Parity;
import com.pi4j.io.serial.Serial;
import com.pi4j.io.serial.SerialConfig;
import com.pi4j.io.serial.SerialDataEvent;
import com.pi4j.io.serial.SerialDataEventListener;
import com.pi4j.io.serial.SerialFactory;
import com.pi4j.io.serial.StopBits;
import java.io.IOException;
import java.math.BigInteger;

public class MultiWiiClient {

    private final Serial serial;

    //The preamble is defined by the protocol.
    //Every message must begin with the characters $M
    private static final String PREAMBLE = "$M";
    //Character that denotes information being passed to the MultiWii
    private static final char TO_MUTLIWII = '<';
    //Character that denotes information being requested from by the MultiWii
    private static final char FROM_MUTLIWII = '>';

    public MultiWiiClient(String usbPort) {
        SerialConfig config = new SerialConfig();
        config.device(usbPort)
              .baud(Baud._115200)
              .dataBits(DataBits._8)
              .parity(Parity.NONE)
              .stopBits(StopBits._1)
              .flowControl(FlowControl.NONE);

        this.serial = SerialFactory.createInstance();

        serial.addListener(new SerialDataEventListener() {
            @Override
            public void dataReceived(SerialDataEvent event) {
                try {
                    System.out.println("[HEX DATA]   " + event.getHexByteString());
                    System.out.println("[ASCII DATA] " + event.getAsciiString());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });

        try {
            this.serial.open(config);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public String sendRequest(MultiWiiRequest request) throws IllegalStateException, IOException {
        String message = createMessage(request.getId(), false, null);
        //////////////////////////////////////////////////////////////////////////////////
        System.out.println(message);
        System.out.println(String.format("%040x", new BigInteger(1, message.getBytes())));
        //////////////////////////////////////////////////////////////////////////////////
        return sendMessage(message);
    }


    public String sendCommand(MultiWiiCommand command, String payload) throws IllegalStateException, IOException {
        String message = createMessage(command.getId(), true, payload);
        return sendMessage(message);
    }

    /**
     * This method creates the message that will be sent to the MultiWii
     * 
     * Message format is as follows:
     * +--------+---------+----+-------+----+---+
     * |preamble|direction|size|command|data|crc|
     * +--------+---------+----+-------+----+---+
     * 
     * Preamble (2 bytes):
     *      Marks the start of a new message; always "$M"
     * 
     * Direction (1 byte):
     *      Either '<' for a command going to the MultiWii or '>' for
     *      information being requested from the MultiWii
     * 
     * Size (1 byte):
     *      The number of bytes in the payload
     * 
     * Command (1 byte):
     *      The message ID of the command, as defined in the protocol
     *      100's for requesting data, and 200's for requesting an action
     * 
     * Data (variable bytes):
     *      The data to pass along with the command
     * 
     * CRC (1 byte):
     *      Calculated with an XOR of the size, command, and each byte of data 
     */
    private String createMessage(int mutliWiiCommandnumber, boolean isCommand, String payload) {
        StringBuilder message = new StringBuilder(PREAMBLE);
        byte checksum=0;

        //Get the direction of the message
        if (isCommand) {
            message.append(TO_MUTLIWII);
        } else {
            message.append(FROM_MUTLIWII);
        }

        int datalength = (payload != null) ? payload.length() : 0;

        message.append((char) datalength);
        checksum ^= datalength;

        message.append((char) mutliWiiCommandnumber);
        checksum ^= ((int) mutliWiiCommandnumber);

        if (payload != null) {
            for (char c : payload.toCharArray()){ 
                message.append(c);
                checksum ^= (int) c;
            }
        }

        message.append((char) checksum);
        return message.toString();
    }


    private String sendMessage(String message) throws IllegalStateException, IOException {
        serial.write(message.getBytes());

        serial.flush();
        System.out.println("TESTING ------------------");

        return "";
    }

}

我正在使用“/dev/ttyUSB0”进行连接,我确认这是正确的位置并且它似乎正在工作(我运行它时没有错误;如果我开始运行然后断开 USB,它会抛出一个异常,因为它失去了连接)。

运行时,我得到以下输出(发送命令 100,MSP_IDENT):

$M>dd
00000000000000000000000000244d3e006464
TESTING ------------------

有关更多代码上下文,请参阅my Git repo

编辑:修复了我帖子中的校验和代码

【问题讨论】:

    标签: java serial-communication raspberry-pi3


    【解决方案1】:

    看起来一切正常,但我看不到您从串行端口接收回版本字节的位置。在 sendMessage 中,您有 return ""

    查看您的 github 存储库,我发现 sendMessage 有点不同。

        while (!serial.getCTS()) {
            try{
                Thread.sleep(100);
            } catch (Exception e) {}
        }
    
        StringBuilder response = new StringBuilder();
        while (serial.available() != 0) {
            response.append(serial.read());
        }
    

    不应使用serial.getCTS(),因为在构造函数中初始化端口时禁用了流控制。

    我猜 CTS 在这里被用作检测其他设备何时完成处理消息并做出响应的一种方式。

    似乎无法保证在看到 CTS 线变高后,这些字节实际上可以被接收; CTS 信号仅表示设备已完成将它们发送给您。 您可能希望在 CTS 变高后再次延迟,以确保所有字节确实已传输。

    【讨论】:

    • 你是对的。我结束了一段时间 (serial.available() == 0) 来等待数据返回。我添加了一个计数以确保我不会等待太长时间才能返回数据,否则我可能会占用线程。
    【解决方案2】:

    我发现问题出在我的方向上。我虽然那里''用于请求数据。事实证明,在这两种情况下,都应该使用“' 字符仅在 MultiWii 响应时使用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多