Heartbeat Not Showing In watch command output

I’m not entirely sure where to post this as it touches on a few subjects.
I am writing an application to communicate with an ArduPilot instance and I have been testing it with the SIL setup and MAVProxy.
My external application is written in C# and is communicating to MAVProxy via UDP.
The ArduPilot simulation is being run like:

sim_vehicle.py -v ArduPlane --out=udp:127.0.0.1:14580

I put together a very simple program to just emit a heartbeat packet over udp just to make sure I can get something sent to MAVProxy:

using System;
using MavLink;
using System.Threading;
using System.Net;
using System.Net.Sockets;

namespace HBTest
{
	class MainClass
	{
		public static void Main (string[] args)
		{
			Console.WriteLine ("Testing Heartbeat Sending ___________________ ");
			Msg_heartbeat hbMsg = new Msg_heartbeat ();
			Mavlink mav = new Mavlink ();
			// Udp Com ________________________________________________________
			IPEndPoint epOut = new IPEndPoint(IPAddress.Parse ("127.0.0.1"), 14580);
			IPEndPoint epThis = new IPEndPoint (IPAddress.Parse ("127.0.0.1"), 14660);
			UdpClient udpCom = new UdpClient (epThis);
                        // Heartbeat message
			hbMsg.autopilot = (byte)MavLink.MAV_AUTOPILOT.MAV_AUTOPILOT_GENERIC; 
			hbMsg.base_mode = (byte)MavLink.MAV_MODE.MAV_MODE_PREFLIGHT;
			hbMsg.custom_mode = 0;
			hbMsg.mavlink_version = 3;
			hbMsg.system_status = (byte)MavLink.MAV_STATE.MAV_STATE_STANDBY;
			hbMsg.type = (byte)MavLink.MAV_TYPE.MAV_TYPE_GCS; 
                        // Heartbeat packet
			MavlinkPacket hbPkt = new MavlinkPacket ();
			hbPkt.SystemId = 250;
			hbPkt.ComponentId = 0;
			hbPkt.SequenceNumber = 0;
			hbPkt.TimeStamp = System.DateTime.Now;
			int hbSent = 0;
			hbPkt.Message = hbMsg;

			byte[] pktbytes;
			while(true)
			{
				hbPkt.SequenceNumber = (byte)hbSent;
				pktbytes = mav.Send (hbPkt);
				Console.WriteLine ("[{0}] AP:{1} BM:{2} T:{3} S:{4}", hbPkt.SequenceNumber, hbMsg.autopilot, 
					hbMsg.base_mode, hbMsg.type, hbMsg.system_status);
				udpCom.Send (pktbytes, pktbytes.Length, epOut);
				Thread.Sleep (500);
				hbSent++;
			}
		}
	}
}

When I run watch HEARTBEAT from the MAVProxy shell, I only see the simulated vehicle and MAVProxy’s heartbeat:

I looked at what MAVProxy uses for the fields in its heartbeat and it matches the Heartbeat with type 6 (MAV_TYPE_GCS). So mine is not showing up.

I thought maybe I’m missing something with how I am communicating with UDP but when I look at wireshark for the UPD Port that I had set for output but I can see that there is the heartbeat packet being sent from my application’s source UDP address (127.0.0.1:14660) to the output UDP (127.0.0.1:14580) that I had defined:

You can see the packet being sent from 14460 to 14580. So that leads me to believe that the packet is getting there.
I looked at the packets that are in that datagram and can confirm that they are the correct bytes:

  1. 0xFE Start of Mavlink Packet
  2. 0x09 Payload Length
  3. 0x81 Payload Sequence
  4. 0xFA System ID
  5. 0x00 Component ID
  6. 0x00 Message ID (0 = HEARTBEAT)
  7. 0x00 HeartBeat Custom Mode byte 0
  8. 0x00 HeartBeat Custom Mode byte 1
  9. 0x00 HeartBeat Custom Mode byte 2
  10. 0x00 HeartBeat Custom Mode byte 3
  11. 0x06 HeartBeat Type
  12. 0x00 HeartBeat Autopilot
  13. 0x00 Heartbeat Base Mode
  14. 0x03 Heartbeat System Status
  15. 0x03 Heartbeat Mavlink Version
  16. 0xC8 CRC
  17. 0x81 CRC

Everything seems to be packed correctly.

When I use APM Planner I can see the heartbeats it emits with the “watch HEARTBEAT” command in MAVProxy. So it seems that I am not initializing communication with MAVProxy properly?
I can receive messages in my application from the output of MAVProxy just fine, but sending messages the other way is giving me problems. I did not see any documentation for initializing a connection or something similar. I thought it was just that you make sure you send enough heartbeats.

Thanks for any suggestions

Do you have the correct system and component ID for your heartbeat packet? The default for SITL is Component 1, System 1.

Edit: Also check you’re using the correct mavlink version too. I think APM still defaults to Mavlink 1.0. There’s a parameter in APM (Serial0_ something) to switch to mavlink 2

@stephendade thank you for your response.
It was my understanding that the System ID and Component ID of the packet were related to the sender. I was looking at the Wikipedia page: https://en.wikipedia.org/wiki/MAVLink

When I look at the heartbeat packets from MavProxy to the simulated instance over tcp the system ID is 255 and the component is 0. Here is one of the packets:

0000   fe 09 00 ff 00 00 00 00 00 00 06 08 00 00 03 a1
0010   df

And the mavlink field is set to 3 which I don’t see an option for with SERIAL0_PROTOCOL, it looks like the only options are 1:Mavlink01 and 2:Mavlink02.
I’m not sure if MavProxy is not accepting my messages or the simulated instance isn’t. It seems like they are not being processed by MavProxy though. Heartbeats from other things like APM planner seem to be getting registered just fine by the watch function.

@stephendade You know what? I think I was filtering out the ICMP packets that showed that the destination was unreachable. So It looks like it was an issue with me not fully understanding UDP. I set the mavproxy to have an out parameter as 127.0.0.1:14580. I can listen on this with my application just fine but I can’t send a UDP packet to that port.

I need to look more at how other applications do this because I can send messages from something like APM Planner to the out port of the MAVProxy instance and the message gets passed to the ArduPilot instance connected to the port designated by the master argument.

Since UDP is connectionless I thought that just sending bytes to a udp port would get picked up by anything else listening on that port. I may be confusing how UDP works though.

Inspect the Udp packet on the receiver to understand which port to reply to.

@billb Thank you so much!
That is what it was!
I was really misunderstanding how UDP works. I get it a little better now!

I’ll clean up my little test program here and post one that illustrates it working.