Using GCSReceiver via UAVTalk to control thrust
« on: April 22, 2018, 05:39:56 pm »
Hi all,

First of all i have seen some people trying this on the forums but have only found one article by a fellow called JAMANTA, but clearly i am either doing something wrong or not fully understanding his post. Any help greatly appreciated.

I am writing some code to control the CC3D board via UAVTalk over the telemetry port, however i am seeing no results.

My setup is as follows;

I have configured the CC3D using LibrePilot GCS, to ensure the HW is working and the motors are working. Everything seems fine from that perspective and function as intended. I have configured the board to GCS for the respective channels to control the motors etc. 

I then hook up my rpi to the CC3D and try and construct my header and message to turn the motors. (i have done tests and written code that requests UAVObjects from the board etc, which also work fine and i can decode the the messages from the FC).

I have set the of the throttle to such that 1200uS as my neutral point is around 1180uS. thus i shoud see some movement.
the other hex values i have put are just 1000uS.

Now i have written some code as below:


Code: [Select]
int main(){
char *portname = "/dev/serial0";
int fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
set_interface_attribs (fd, B57600, 0);  // set speed to 57,600 bps, 8n1 (no parity)
set_blocking (fd, 0);                // set no blocking

GCSReceiverData gcs;

if (fd < 0)
{
        error_message ("error %d opening %s: %s", errno, portname, strerror (errno));
        return 1;
}

        printf("constructing data msg\n");
        memset(&gcs, 0, sizeof(gcs));
        gcs.Channel[0] = 0x4b0;
        printf("%ul:", gcs.Channel[0]);
        gcs.Channel[1] = 0x3E8;     // Roll         (-1.0 -> 1.0) -> (1000 -> 2000)
        gcs.Channel[2] = 0x3E8;    // Pitch        (-1.0 -> 1.0) -> (1000 -> 2000)
        gcs.Channel[3] = 0x3E8;      // Yaw          (-1.0 -> 1.0) -> (1000 -> 2000)
        gcs.Channel[4] = 0x3E8;                                                  // Flight mode

unsigned long objId = GCSRECEIVER_OBJID;
  _pBuf[0] = 0x3c; //sync
  _pBuf[1] = 0x20; //msgtype (0x20 = data send)
  _pBuf[2] = 0x1a; //len
  _pBuf[3] = 0x00; //len
  _pBuf[4] = (objId >> (8*0)) & 0xff;
        printf("%x", _pBuf[4]);
  _pBuf[5] = (objId >> (8*1)) & 0xff;
        printf("%x", _pBuf[5]);
  _pBuf[6] = (objId >> (8*2)) & 0xff;
        printf("%x", _pBuf[6]);
  _pBuf[7] = (objId >> (8*3)) & 0xff;
        printf("%x", _pBuf[7]);
  _pBuf[8] = 0x00; //iid
  _pBuf[9] = 0x00; //iid
//_pBuf[10] = _crc(10); //crc

write(fd, _pBuf, 11);
write(fd, gcs.Channel, 5);
byte crc = _crc(_pBuf, gcs.Channel, 26);
write(fd, crc);
}

I realise i am probably going wrong somewhere from a code point of view. I was wondering if anyone had a secondary set of eyes or any tips/advice here on how to solve this issue? or if someone has done this before and can give some advice.

Maybe i am doing something wrong with the CRC or am i misunderstanding here?
Jonny

mr_w

  • *
  • 207
    • LibrePilot
Re: Using GCSReceiver via UAVTalk to control thrust
« Reply #1 on: April 22, 2018, 06:31:09 pm »
GCSReceiver object is not supported by cc3d by default. You have to rebuild the firmware, but change flight/target/boards/coptercontrol/firmware/Makefile line which reads

# Set to yes to include Gcsreceiver module
GCSRECEIVER ?= NO

to YES

Then do
make fw_coptercontrol_clean
make fw_coptercontrol

and upload freshly built firmware.

If you are using release version and not being able to build from source, somebody else can build firmware for you.

Re: Using GCSReceiver via UAVTalk to control thrust
« Reply #2 on: April 29, 2018, 06:50:05 pm »
Mr_w,

thanks for your reply, i rebuilt my firmware and flashed and ensured what i was flashing was the new updated Makefile with YES.

Now i have tried again with no luck,  the example of what i am doing is as below:
Code: [Select]
int main(){
   
   char *portname = "/dev/serial0";
   int fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
   set_interface_attribs (fd, B57600, 0);  // set speed to 57,600 bps, 8n1 (no parity)
   set_blocking (fd, 0);                // set no blocking

   GCSReceiverData gcs;

if (fd < 0)
{
        error_message ("error %d opening %s: %s", errno, portname, strerror (errno));
        return 1;
}

        printf("constructing data msg\n");
        memset(&gcs, 0, sizeof(gcs));
        gcs.Channel[0] = 0x578;// Throttle     ( 0.0 -> 1.0) -> (1000 -> 2000)
        printf("%ul:", gcs.Channel[0]);
        gcs.Channel[1] = 1000;     // Roll         (-1.0 -> 1.0) -> (1000 -> 2000)
        gcs.Channel[2] = 1000;    // Pitch        (-1.0 -> 1.0) -> (1000 -> 2000)
        gcs.Channel[3] = 1000;      // Yaw          (-1.0 -> 1.0) -> (1000 -> 2000)
        gcs.Channel[4] = 1000;                                                  // Flight mode
        gcs.Channel[5] = 1000;                           // Accessory0
        gcs.Channel[6] = 1000;                                                  // Accessory1
        gcs.Channel[7] = 1000;

unsigned long objId = GCSRECEIVER_OBJID;
  _pBuf[0] = 0x3c; //sync
  _pBuf[1] = 0x20; //msgtype (0x20 = data send)
  _pBuf[2] = 0x1a; //len
  _pBuf[3] = 0x00; //len
  printf("\n");
  _pBuf[4] = (objId >> (8*0)) & 0xff;
  printf("%x", _pBuf[4]);
  _pBuf[5] = (objId >> (8*1)) & 0xff;
  printf("%x", _pBuf[5]);
  _pBuf[6] = (objId >> (8*2)) & 0xff;
  printf("%x", _pBuf[6]);
  _pBuf[7] = (objId >> (8*3)) & 0xff;
  printf("%x", _pBuf[7]);
  _pBuf[8] = 0x00; //iid
  _pBuf[9] = 0x00; //iid

  write(fd, _pBuf, 10);
  write(fd, gcs.Channel, 16);
  byte crc = _crc(_pBuf, gcs.Channel, 26);
  write(fd, reinterpret_cast<const char*>(crc), 1);       
/*
*/
}

a couple of questions for myself to clarify, when i send these values to the FC, i can send hev values no problem?
My neutral points on the motors is 1150-1230uS thus i send a test value of 1400 (or  0x578 - i have tested with a hex and unsigned long value here). I send this value as i just want to check motion on my motors.

Howevewr, nothing happens, one thing i did change and i am not to sure whether or not this will make a difference is, on the example i am using by https://github.com/MarcProe/LibrePilot.arduino/blob/master/src/LibrePilotSerial/LibrePilotSerial/LibrePilotSerial.cpp (this is used as a template for me to write my code).

he has done this -
Code: [Select]
yte LibrePilotSerial::_crc(byte* header, byte* data, int len) {
  byte ccrc = 0;
  for (unsigned int k = 0; k < 10; k++) {
      ccrc = _CRC_TABLE[((byte) (ccrc ^ header[k])) & 0xFF];
  }
  for (unsigned int k = 0; k < len; k++) {
      ccrc = _CRC_TABLE[((byte) (ccrc ^ data[k])) & 0xFF];
  }
  return (ccrc & 0xFF);
}

My function was exactly the same as this to begin with when i was testing my request messages from the FC (which works fine btw, so i can mitigate this as an issue, i believe) However, with the GCSReceiver.Channel being uint16_t instead of uint8_t i tweaked this code about slightly to the data param being of type uint16_t instead of byte as i was getting errors on this. The change has resolved my error however when i move to test with my above code i am still seeing no signs of movement on the motors.


Again, does anyone have any suggestions on how to resolve this? I am thinking this is probably a code related issue rather than firmware or h/w. Post my new firmware flash i also reconfigured my FC as is needed for the GCS. I have attached the snapshots of the configs i am using on the GCS.

mr_w

  • *
  • 207
    • LibrePilot
Re: Using GCSReceiver via UAVTalk to control thrust
« Reply #3 on: April 29, 2018, 07:01:07 pm »
You should keep in mind that when you update GCSReceiver object, that is the input to the flight controller. It is usually not directly related to your motor outputs. The vehicle would still need to be armed (by using correct aux channel or control stick sequence - whatever is configured) in order for input to create some output, depending of course on mixer and stabilization options.

Also, as you are using cc3d, do you have usb connected to the computer while trying this? If yes, then cc3d will not send/receive telemetry over uart while usb is connected.

Re: Using GCSReceiver via UAVTalk to control thrust
« Reply #4 on: April 30, 2018, 03:43:58 am »
I don't know how write() is implemented.  If it is simple stuff into a serial port and the serial port has less than 26 bytes of hardware buffer (like e.g. 16 bytes) then part of the message will get dropped.  Or it's really simple to just add a delay (0.2ms, or try more, like 0.5ms to be sure) between each byte for a test.

I would capture it on the GCS side and dump out exactly what is received.

Also, do you know that your CRC function is correct?  Uses correct polynomial and correct initialization (e.g. 0 or ff).

Also, you could capture a known good message and hard code that into the sender to make sure the receiver gets it and decodes it correctly.

Re: Using GCSReceiver via UAVTalk to control thrust
« Reply #5 on: May 02, 2018, 07:16:16 pm »
The write function is POSIX linux write().

When you say capture it on the GCS side, how can i do this with CC3D when i am writing to the uart and also having this connected via USB to the FC? I know in the build i can add debug code to see whats happening, however, with the uart being used to send my packets, how can i then view the debug simultaneously? or can i log debugs on the FC to be later read on the GCS?

As for my CRC function is as follows:

Code: [Select]
byte _crc(byte* header, uint16_t* data, int len) {
  byte ccrc = 0;
  for (unsigned int k = 0; k < 10; k++) {
      ccrc = _CRC_TABLE[((byte) (ccrc ^ header[k])) & 0xFF];
  }
  for (unsigned int k = 0; k < len; k++) {
      ccrc = _CRC_TABLE[((byte) (ccrc ^ data[k])) & 0xFF];
  }
  return (ccrc & 0xFF);
}

and where in the CRC_TABLE is

Code: [Select]
byte _CRC_TABLE[] = {
        0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d,
        0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65, 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d,
        0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
        0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd,
        0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea,
        0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
        0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a,
        0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a,
        0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
        0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4,
        0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44,
        0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
        0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63,
        0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13,
        0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83,
        0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3
};

Where in the data is uint16_t as the Channel elements of the GCSReceiver are of 16bit.  To my knowledge of CRC and the polynomial i believe this is correct.

Yes, very good suggestion on transmitting a known packet which should work - then i can read again from the FC and see if it updates!

Thanks a lot for the help here guys, greatly appreciated.

Re: Using GCSReceiver via UAVTalk to control thrust
« Reply #6 on: May 02, 2018, 10:02:42 pm »
I don't know how Linux write() works in your example.  It probably has to do with blocking/unblocking buffered/unbuffered bits and how the underlying serial driver works.

Whether it is on the PC side or the FC side, I caution that serial (e.g.16x50 or STMF32) hardware has a limited transmit buffer in hardware and it depends on how you access it as to whether overflow is a problem.  Once you fill the buffer up, any further writes will loose data unless there is e.g. an intermediate buffer and the hardware transmit buffer is being filled via e.g. low water mark interrupt.

Beware that debug of what you wrote to the port is not necessarily what the port outputs later if you overflow the hardware buffer.  That is why, if there is a serial port involved, you should see what actually comes out, like with an FTDI etc.