How to send RTCM3 message to Rover gps module without CRC error?

I have two SparkFun GPS-RTK2 and two arduino uno board.

Then, I connect each SparkFun GPS-RTK2 to each arduino uno board. I call them base station and rover station.

There is no problem to get RTCM correction data from A and send them to arduino uno of rover station.

https://portal.u-blox.com/sfc/servlet.s … cR4&page=0

COM3 data is RTCM correction data and CRC test result of base station RTCM correction data.

COM4 data is RTCM correction data on rover arudino Uno come from base station by using Uart wireless communication and CRC test result of rover station RTCM correction data.

There are no problem.

and I send RTCM correction data from rover arduino Uno to gps module by using I2C communication.

but, rover gps module can’t go into RTK mode.

so, i check which data that rover gps module get by using u-center.

https://portal.u-blox.com/sfc/servlet.s … clm&page=0

https://portal.u-blox.com/sfc/servlet.s … clr&page=0

I check msg 1005, 1230(relatively short data packet) pass crc test , but 1074,1084,1094, 1124 can’t pass CRC test.

How solve this problem??

I attached base arduino code and rover arduino code.

base arduino code

/*
  Send UBX binary commands to enable RTCM sentences on Ublox ZED-F9P module
  By: Nathan Seidle
  SparkFun Electronics
  Date: January 9th, 2019
  License: MIT. See license file for more information but you can
  basically do whatever you want with this code.

  This example does all steps to configure and enable a ZED-F9P as a base station:
    Begin Survey-In
    Once we've achieved 2m accuracy and 300s have passed, survey is complete
    Enable six RTCM messages
    Begin outputting RTCM bytes

  Feel like supporting open source hardware?
  Buy a board from SparkFun!
  ZED-F9P RTK2: https://www.sparkfun.com/products/15136
  NEO-M8P RTK: https://www.sparkfun.com/products/15005
  SAM-M8Q: https://www.sparkfun.com/products/15106

  Hardware Connections:
  Plug a Qwiic cable into the GPS and a BlackBoard
  If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
  Open the serial monitor at 115200 baud to see the output
*/

#include <Wire.h> //Needed for I2C to GPS
#include <SoftwareSerial.h>

#include "SparkFun_Ublox_Arduino_Library.h" //http://librarymanager/All#SparkFun_Ublox_GPS
SoftwareSerial S2(2,3);    // 2:RX 3:TX  // added to send RTCM3 format data packet to rover arduino by using HC-11 ( wireless uart communication)
SFE_UBLOX_GPS myGPS;

int sum = 0;
int cnt = 1;
int num = 0;
uint8_t test[200]={0,};    // RTCM3 format data packet
void setup()
{
  Serial.begin(9600);       // 115200 -> 9600
  S2.begin(9600);           // wireless uart communication baud rate
  S2.flush(); 
  while (!Serial); //Wait for user to open terminal
  Serial.println("Ublox Base station example");

  Wire.begin();
  Wire.setClock(400000); //Increase I2C clock speed to 400kHz

  if (myGPS.begin() == false) //Connect to the Ublox module using Wire port
  {
    Serial.println(F("Freezing."));
    while (1);
  }

  myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
  //myGPS.saveConfiguration(); //Save the current settings to flash and BBR

  while (Serial.available()) Serial.read(); //Clear any latent chars in serial buffer
  Serial.println("Press any key");
  while (Serial.available() == 0) ; //Wait for user to press a key

  boolean response = true;
  response &= myGPS.enableRTCMmessage(UBX_RTCM_1005, COM_PORT_I2C, 1); //Enable message 1005 to output through I2C port, message every second
  response &= myGPS.enableRTCMmessage(UBX_RTCM_1074, COM_PORT_I2C, 1);
  response &= myGPS.enableRTCMmessage(UBX_RTCM_1084, COM_PORT_I2C, 1);
  response &= myGPS.enableRTCMmessage(UBX_RTCM_1094, COM_PORT_I2C, 1);
  response &= myGPS.enableRTCMmessage(UBX_RTCM_1124, COM_PORT_I2C, 1);
  response &= myGPS.enableRTCMmessage(UBX_RTCM_1230, COM_PORT_I2C, 10); //Enable message every 10 seconds

  //Use COM_PORT_UART1 for the above six messages to direct RTCM messages out UART1
  //COM_PORT_UART2, COM_PORT_USB, COM_PORT_SPI are also available
  //For example: response &= myGPS.enableRTCMmessage(UBX_RTCM_1005, COM_PORT_UART1, 10);

  if (response == true)
  {
    Serial.println("RTCM messages enabled");
  }
  else
  {
    Serial.println("RTCM failed to enable. Are you sure you have an ZED-F9P?"); // 
    while (1); //Freeze
  }

  //Check if Survey is in Progress before initiating one
  response = myGPS.getSurveyStatus(2000); //Query module for SVIN status with 2000ms timeout (request can take a long time)
  if (response == false)
  {
    Serial.println("b?"); //Failed to get Survey In status
    while (1); //Freeze
  }

  if (myGPS.svin.active == true)
  {
    Serial.print("in"); //Survey already in progress.
  }
  else
  {
    //Start survey
    //The ZED-F9P is slightly different than the NEO-M8P. See the Integration manual 3.5.8 for more info.
    //response = myGPS.enableSurveyMode(300, 2.000); //Enable Survey in on NEO-M8P, 300 seconds, 2.0m
    response = myGPS.enableSurveyMode(60, 5.000); //Enable Survey in, 60 seconds, 5.0m
    if (response == false)
    {
      Serial.println("fai"); // Survey start failed
      while (1);
    }
    Serial.println("Survey started."); // This will run until 60s has passed and less than 5m accuracy is achieved.
  }

  while(Serial.available()) Serial.read(); //Clear buffer
  
  //Begin waiting for survey to complete
  while (myGPS.svin.valid == false)
  {
    if(Serial.available())
    {
      byte incoming = Serial.read();
      if(incoming == 'x')
      {
        //Stop survey mode
        response = myGPS.disableSurveyMode(); //Disable survey
        Serial.println("Survey stopped");
        break;
      }
    }
    
    response = myGPS.getSurveyStatus(2000); //Query module for SVIN status with 2000ms timeout (req can take a long time)
    if (response == true)
    {
      Serial.print("Press x to end survey - ");
      Serial.print("Time elapsed: ");
      Serial.print((String)myGPS.svin.observationTime);

      Serial.print(" Accuracy: ");
      Serial.print((String)myGPS.svin.meanAccuracy);
      Serial.println();
    }
    else
    {
      Serial.println("SVIN request failed");
    }

    delay(1000);
  }
  Serial.println("Survey valid!");
  myGPS.setI2COutput(COM_TYPE_UBX | COM_TYPE_RTCM3); //Set the I2C port to output UBX and RTCM sentences (not really an option, turns on NMEA as well)

  // Serial.println(myGPS.getCarrierSolutionType());
}

void loop()
{
  myGPS.checkUblox(); //See if new data is available. Process bytes as they come in.

  delay(250); //Don't pound too hard on the I2C bus
}

//This function gets called from the SparkFun Ublox Arduino Library.
//As each RTCM byte comes in you can specify what to do with it
//Useful for passing the RTCM correction data to a radio, Ntrip broadcaster, etc.
void SFE_UBLOX_GPS::processRTCM(uint8_t incoming)
{
  //Let's just pretty-print the HEX values for now
  //if(incoming == 0xD3)
    
    if(myGPS.rtcmFrameCounter == 1)
    {
    //S2.write("ba"); //hex - b (62), a(61) // added to inform start of packet to rover arduino
    test[0] = 'b';
    test[1] = 'a';
    sum = 0;
    }

    if(myGPS.rtcmFrameCounter+1 > 180) return;
    
    test[myGPS.rtcmFrameCounter+1] = incoming;
    sum += incoming;
    if(myGPS.rtcmLen == myGPS.rtcmFrameCounter)
    {
      // hex - g (67), h(68)
      cnt = 1;
      test[myGPS.rtcmLen+2] = 'i';
      test[myGPS.rtcmLen+3] = 'j';
      S2.write(test,myGPS.rtcmLen+4);
      for(int i=0;i<myGPS.rtcmLen+4;i++)
      {
      Serial.print(test[i], HEX);
      Serial.print(" ");
      }
      delay(1);
      Serial.println("");
      Serial.println(sum);
    }
}

rover arduino code

/*
  Send UBX binary commands to enable RTCM sentences on Ublox ZED-F9P module
  By: Nathan Seidle
  SparkFun Electronics
  Date: January 9th, 2019
  License: MIT. See license file for more information but you can
  basically do whatever you want with this code.

  This example shows how to query the module for RELPOS information in the NED frame.
  It assumes you already have RTCM correction data being fed to the receiver.

  Feel like supporting open source hardware?
  Buy a board from SparkFun!
  ZED-F9P RTK2: https://www.sparkfun.com/products/15136
  NEO-M8P RTK: https://www.sparkfun.com/products/15005
  SAM-M8Q: https://www.sparkfun.com/products/15106

  Hardware Connections:
  Plug a Qwiic cable into the GPS and a RedBoard Qwiic or BlackBoard
  If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
  Open the serial monitor at 115200 baud to see the output
*/

#include <Wire.h> //Needed for I2C to GPS
// ㅡㅡㅡㅡㅡㅡadded ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
#include <SoftwareSerial.h>
uint8_t ch;
uint8_t cnt = 0;
int flag = 1;
uint8_t test[200] = {0,};
int num;
float lastTime = 0;
int sum = 0;
int sum2 = 0;
// ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
#include "SparkFun_Ublox_Arduino_Library.h" //http://librarymanager/All#SparkFun_Ublox_GPS
SFE_UBLOX_GPS myGPS;
SoftwareSerial S2(2,3);    // 2:RX 3:TX       // added

void setup()
{
  Serial.begin(9600);                         // modified (115200 -> 9600)
  S2.begin(9600);                             // added
  S2.flush();                                 // added
  while (!Serial); //Wait for user to open terminal
  Serial.println("Ublox Base station example");

  Wire.begin();
  Wire.setClock(400000); //Increase I2C clock speed to 400kHz

  if (myGPS.begin() == false) //Connect to the Ublox module using Wire port
  {
    Serial.println(F("Ublox GPS not detected at default I2C address. Please check wiring. Freezing."));
    while (1);
  }
  
  myGPS.setI2COutput(COM_TYPE_UBX|COM_TYPE_NMEA);   // get NMEA, UBX format data from gps module
  
  //Configure a given port to input UBX, NMEA, RTCM3 or a combination thereof
  //Port 0=I2c, 1=UART1, 2=UART2, 3=USB, 4=SPI
  //Bit:0 = UBX, :1=NMEA, :5=RTCM3
  myGPS.setPortInput(0, 0x23);                        // send rtcm3 data to gps module
  // 코드 안 넣음 : 값 받음
  // 0x01, 0x21, 0x23 : 값 받음


  // Serial.println(myGPS.getCarrierSolutionType());
}

bool flag_b_wait = true;
bool flag_a_wait = true;
int cnt_rcv = 0;
int rcvlen = 0;
int loopcnt = 0;
  
void loop()
{
  // in base arduino code, i send "ba" to inform start of data packet.
  
  
  if(S2.available()) 
  {
    ch = S2.read();

    // ch = b 체크
    if(flag_b_wait == true)
    {
      if(ch == 'b')
      {
        flag_b_wait = false; 
      }
      return;
    }

    // ch = a 체크
    if(flag_b_wait == false && flag_a_wait == true)
    {
      if(ch == 'a')
      {
        flag_a_wait = false;
        cnt_rcv = 0;
      }
      else
      { // 연속이 아니어서 다시 b wait로 복귀
        flag_a_wait = true; 
        flag_b_wait = true;
      }
      return;
    }

    // 정상문자 저장
    if(flag_b_wait == false && flag_a_wait == false && cnt_rcv < 200)
    {
        test[cnt_rcv] = ch;

        // 마지막 문자 체크
        if(cnt_rcv >= 1 && test[cnt_rcv-1] == 'i' && test[cnt_rcv] == 'j')
        {
          goto jmp1;
        }
      
        cnt_rcv++;
        if(cnt_rcv >=200)
        {
          flag_a_wait = true; 
          flag_b_wait = true;
        }

        return;
    }
    else
    {
       flag_a_wait = true; 
       flag_b_wait = true;
       return;
    }

    //flag_a_wait = true; 
    //flag_b_wait = true;
    //return;
  } // if(S2.available()) 
  
return;
  

jmp1 :

  flag_a_wait = true; 
  flag_b_wait = true;

  rcvlen = cnt_rcv + 1;
  Serial.print(rcvlen);
  Serial.print(" ");

  for(int i =0; i<rcvlen-2; i++)
  {
    
    Serial.print(test[i], HEX);
    Serial.print(" ");
    sum2 += test[i];
  }
  
  Serial.println();
  Serial.println(sum2);
  sum2 = 0;
  Wire.beginTransmission(0x42);
  Wire.write(0xFF); 
  Wire.write(test,rcvlen-2);
  //delay(1);
  Wire.endTransmission();
  
  //delay(10);

  /*
  while(Wire.available())
  {
    Serial.print("시작");
    ch = Wire.read();
    Serial.println(ch);
    Serial.print(" ");
  }
    Serial.println();
  */
  /*
  if (millis() - lastTime > 5000)             // modified 1000 -> 5000
  {
    lastTime = millis(); //Update the timer
  if (myGPS.getRELPOSNED() == true)
  {
    Serial.print("relPosN: ");
    Serial.println(myGPS.relPosInfo.relPosN, 4);
    Serial.print("relPosE: ");
    Serial.println(myGPS.relPosInfo.relPosE, 4);
    Serial.print("relPosD: ");
    Serial.println(myGPS.relPosInfo.relPosD, 4);
  }
  else
    Serial.println("RELPOS request failed");
  }
  */
  
}