2016-09-04 2 views
1

J'ai un Raspberry Pi 3B et un contrôleur de vol CRIUS All in One Pro (v2.0) MultiWii. J'utilise la version MultiWii 2.4 et la dernière version de NOOBS. J'ai été capable de configurer les deux très bien, et maintenant j'essaie d'obtenir le Raspberry Pi pour communiquer avec le MultiWii via un câble USB/Micro USB qui relie les deux cartes. À l'heure actuelle, le MultiWii ne renvoie aucune donnée, et je ne sais pas pourquoi. D'après ce que je peux voir, j'ai le protocole correct. J'ai regardé plusieurs repos de code de travail (écrit en Python de Java pour Arduino), et ai suivi le MultiWii documentation et ai lu par le forum post associé.Raspberry Pi reçoit des données de MultiWii

Voici le code client que j'ai écrit.

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 ""; 
    } 

} 

J'utilise «/dev/ttyUSB0 » pour se connecter, que je confirme est l'emplacement correct et il semble fonctionner (pas d'erreurs quand je le lance, et si je commence à courir, puis débranchez le câble USB , il lance une exception car il a perdu la connexion).

Lors de l'exécution, je reçois la sortie suivante (envoi de commande 100, MSP_IDENT):

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

Voir my Git repo pour plus de contexte de code.

EDIT: Fixe le code de contrôle dans mon post

Répondre

1

Je tourne que le problème était dans mon bit de direction. Je pensais que '<' était utilisé pour l'envoi de commandes et que '>' était utilisé pour demander des données. Il s'avère que dans les deux cas, "<" doit être utilisé. Le caractère '>' est utilisé uniquement lorsque le MultiWii répond.

1

Il semble que tout soit comme il se doit, même si je ne vois pas où vous recevez l'octet de version à partir du port série. Dans sendMessage, vous avez return "".

En regardant votre repo github, je vois que sendMessage est un peu différent.

while (!serial.getCTS()) { 
     try{ 
      Thread.sleep(100); 
     } catch (Exception e) {} 
    } 

    StringBuilder response = new StringBuilder(); 
    while (serial.available() != 0) { 
     response.append(serial.read()); 
    } 

serial.getCTS() ne doivent pas être utilisés comme vous le contrôle de flux désactivé lors de l'initialisation du port dans le constructeur.

Je suppose que CTS est ici utilisé comme un moyen de détecter quand l'autre périphérique a fini de traiter le message et a répondu.

Il semble qu'il n'y ait aucune garantie qu'après avoir vu la ligne CTS aller haut, ces octets sont réellement disponibles pour être reçus; le signal CTS signifierait seulement que l'appareil a fini de vous les envoyer. Vous voudrez peut-être mettre un autre délai après que CTS soit haut pour s'assurer que tous les octets ont bien été transmis.

+0

Vous avez raison. Je me suis retrouvé avec un certain temps (serial.available() == 0) pour attendre que les données reviennent à la place. J'ai ajouté un compte pour m'assurer que je n'ai pas attendu trop longtemps sur les données pour revenir, sinon je pourrais nouer des discussions. – Jason