mavlink的Java語言之探索實現
1.mavlink是什麼,貼上官方的原話:大家自己腦補一下英文。
MAVLink is a very lightweight, header-only message marshalling library for micro air vehicles.
It can pack C-structs over serial channels with high effiency and send these packets to the ground control station. It is extensively tested on the PX4, PIXHAWK, APM and Parrot AR.Drone platforms and serves there as communication backbone for the MCU/IMU communication as well as for Linux interprocess and ground link communication.
mavlink支援多種語言,常見的有C/C++,Java,C#,JavaScript,Python等等。在開源無人機中,APM,pixhawk,pix4及其相關的地面站都使用了mavlink通訊協議。正如官方所說,要想在專案中使用mavlink,得有標頭檔案。標頭檔案是自動生成的,自動生成的軟體採用Python編寫,可在點選開啟連結
下載到。好了,本文打算使用Java語言在eclipse上探索實現,所有我們先生成相關的.java檔案吧。下載自動生成軟體後,它包含如圖所示的檔案目錄:
開啟命令列:進入這個檔案的目錄,輸入 python mav(按table鍵自動補全) 如圖:
按下enter鍵,彈出一個介面,如圖:
我們選擇Language項,這裡選擇Java,如圖:
然後在XML項載入剛剛下載的檔案,即\mavlink-master\message_definitions\v1.0,選擇common.xml,如圖:
然後選擇你的輸出檔案,新建一個資料夾一個,我這裡在桌面新建mavlink資料夾C:\Users\John\Desktop\mavlink,如圖:
最後一步,點選Generate即可,會提示你是否要覆蓋改資料夾下的內容,一般選擇“確定”,如圖:
如果生成成功,會彈出一個對話方塊,如圖:
檢視是否生成了檔案,我的是:
到這一步,就OK了,將這個資料夾的所有檔案匯入eclipse工程中,並建立相應的包(4個)。我的是這樣的:
注意:將common檔案中檔案導進來時有錯誤,這應該是疏忽吧,common資料夾的檔案在開始處的包是這樣子的:
package com.MAVLink.mavlink\common;
應該把\改成點(.),我這裡修改成這樣:package com.MAVLink.mavlink.common;
中間兩個包檔案,我就不展開了。然後我們使用socket模擬網路通訊。
2. 前面廢話挺多的,不好意思,下面開始寫程式碼,首先是客戶端,使用的socket,這裡我預設大家都知道什麼寫了,我就不詳細介紹,直接上程式碼:
客戶端:
package com.client.tcp;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import com.MAVLink.MAVLinkPacket;
import com.MAVLink.mavlink.common.msg_altitude;
import com.test.Test;
public class Client {
public static void main(String[] args) {
new ClientThread().start();
}
}
class ClientThread extends Thread {
private MAVLinkPacket packet = null;
private boolean flag = true;
private msg_altitude msgAltt = new msg_altitude();
private Socket socket = null;
@Override
public void run()
{
try {
socket = new Socket();
InetSocketAddress isa = new InetSocketAddress("127.0.0.1",40000);
socket.connect(isa);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
msgAltt.altitude_amsl = 34.5f;
msgAltt.altitude_local = 34.87f;
msgAltt.altitude_monotonic = 76.54f;
msgAltt.altitude_relative = 100.09f;
msgAltt.altitude_terrain = 23.5f;
msgAltt.bottom_clearance = 567.76f;
packet = msgAltt.pack();
oos.writeObject(packet);
oos.flush();
oos.close();
// socket.shutdownOutput();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}finally
{
if(null != socket)
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
服務端:
package com.server.tcp;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;
import com.MAVLink.MAVLinkPacket;
import com.MAVLink.Messages.MAVLinkPayload;
import com.MAVLink.mavlink.common.msg_altitude;
import com.test.Test;
public class Server {
public static void main(String[] args) {
ServerThread st = new ServerThread();
st.start();
}
}
class ServerThread extends Thread {
private ServerSocket server = null;
private Socket s = null;
private boolean flag = true;
private byte[] result = new byte[1024];
@Override
public void run() {
try {
server = new ServerSocket(40000);
System.out.println("Server is running....");
while(flag)
{
s = server.accept();
s.setSoTimeout(15000);
ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
try {
msg_altitude msgAltt = new msg_altitude();
MAVLinkPacket packet = (MAVLinkPacket)ois.readObject();
msgAltt.unpack(packet.payload);
msgAltt = (msg_altitude)ois.readObject();
System.out.println("time_usec=" + msgAltt.time_usec +
"\naltitude_monotonic=" + msgAltt.altitude_monotonic +
"\naltitude_amsl=" + msgAltt.altitude_amsl +
"\naltitude_local=" + msgAltt.altitude_local +
"\naltitude_relative=" + msgAltt.altitude_relative +
"\naltitude_terrain=" + msgAltt.altitude_terrain +
"\nbottom_clearance=" + msgAltt.bottom_clearance);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally
{
try {
if(null != s)s.close();
if(null != server)
server.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
客戶端和服務端都是使用序列化傳送和接收資料,這裡要傳送的類 msg_altitude 的例項,這個類是自動生成的。在APM中它表示無人機的高度。我們啟動伺服器:
然後啟動客戶端,出現如下錯誤:
錯誤訊息有點長,截圖看不清,我貼上在這裡:
java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: com.MAVLink.Messages.MAVLinkPayload
錯誤很明顯, com.MAVLink.Messages.MAVLinkPayload這個類沒有序列化,好我們讓它實現java.io.Serializable介面,如圖:
注意:官方說,自動生成的類不應該,如圖:
但是為了能夠執行,我們先改了再說。然後執行客戶端,然後又出現錯誤,如圖:
具體是:java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: java.nio.HeapByteBuffer。很明顯,又是沒有實現java.io.Serializable介面。這個該什麼辦???在這個MAVLinkPayload.java檔案中,有定義:
其中ByteBuffer是在java.nio.ByteBuffer定義的。沒法讓它序列化。我目前也沒想到什麼好方法去修改這個錯誤。這裡拋磚引玉,希望有大神能夠解決這個問題。謝謝。該博文還會繼續,當我想到好法子之後。