Go Down

Topic: NMEA 2000 Shield (Read 216687 times) previous topic - next topic

timolappalainen

Shortly answer: it is implemented, but you do not need to do anything.

The explanation is right, but a bit misleading. I found problem on one device NMEA 2000 certification tests and it appeared only, when test device used complex group function to change device instances. The complex group function handler calls function tNMEA2000::SetDeviceInformationInstances and due to change, it has to send SendIsoAddressClaim at the end of routine. The handler and response was too fast and I could see response on the bus, but test device did not see it and the test fails. This may not be real problem and may be just caused by old design of test device, but I had to modify code so that tests passes. Currently the delay is used only on tNMEA2000::SetDeviceInformationInstances.

Better not to break code, since that passes NMEA 2000 certification tests.

autopilotNOR

Hello,

I have a question regarding calibration of sensors through NMEA2K bus as well as how to upgrade the firmware of devices through NMEA2K.

In detail, I purchased the NMEA2K trim tab indicator kit from Bennett to make my tabs visible. The sensors follow an NMEA2k device which should drop the position on the bus to be picked up by MFD's for example.
My Raymarine Axiom 9 should be able to show the trim tab position but the sender has to be calibrated first. Of course, this function is not supported by the Raymarine Axiom according to Raymarine.
I have read that it should be possible to run the calibration through the NMEA2k but I have no idea how to start.
At least the device is shown as small craft status at the diagnostic screen of the Axiom.

The second part of my question, the Lowrance Link-8 should be able to upgrade through MFD of Lowrance OR through NMEA2k. Same situation, where to start?

Can somebody help out?

Thanks!

timolappalainen

These setup and calibration for different devices uses proprietary N2k messages. So if you do not know them or can not get document for them, the only way is to use reverse engineering. Unfortunately you need for that also device, which is capable to do calibration.

For Lowrance Link-8 I prefer to go dealer or to buy proper upgrade tool. That has been also done with proprietary messages.

autopilotNOR

#768
Aug 29, 2019, 02:25 pm Last Edit: Aug 29, 2019, 02:29 pm by autopilotNOR
Hi Timo,

I had the hope that there exist standardized calibration sentences to talk to senders. I have sent now an email to the Bennett support but I do not expect help from there.
In case I do not get this information, are you known with the type of sensors used in trim tabs? It is an iron stang moving up and down, according to the position of the tabs, inside a coil. Do you know how to interface them?


Rudder Position example:

Code: [Select]

// Demo: NMEA2000 library. Read rudder angle from the Analog sensor

#include <NMEA2000.h>
#include <N2kMessages.h>
#include <NMEA2000_teensy.h>
#include <CircularBuffer.h>

// CircularBuffer<double, 5> buffer

unsigned long time = 0;

double rudderValueAVG;
#define rudderPosSens A1

tNMEA2000_teensy NMEA2000;
// List here messages your device will transmit.
const unsigned long TransmitMessages[] PROGMEM = {127245L, 0};

// *****************************************************************************
void setup() {
        // Set Product information
        NMEA2000.SetProductInformation("40155", // Manufacturer's Model serial code
                                       100, // Manufacturer's product code
                                       "Rudder Position", // Manufacturer's Model ID
                                       "1.0.0.1 (15-09-2018)", // Manufacturer's Software version code
                                       "1.0.0.0 (15-09-2018)" // Manufacturer's Model version
                                       );
        // Set device information
        NMEA2000.SetDeviceInformation(40155, // Unique number. Use e.g. Serial number.
                                      155, // Device function=Rudder. See codes on http://www.nmea.org/Assets/20120726%20nmea%202000%20class%20&%20function%20codes%20v%202.00.pdf
                                      40, // Device class=Steering and Control Surfaces. See codes on  http://www.nmea.org/Assets/20120726%20nmea%202000%20class%20&%20function%20codes%20v%202.00.pdf
                                      1851 // Just choosen free from code list on http://www.nmea.org/Assets/20121020%20nmea%202000%20registration%20list.pdf
                                      );
        // Uncomment 2 rows below to see, what device will send to bus. Use e.g. OpenSkipper or Actisense NMEA Reader
        Serial.begin(115200);
        NMEA2000.SetForwardStream(&Serial);
        // If you want to use simple ascii monitor like Arduino Serial Monitor, uncomment next line
        //NMEA2000.SetForwardType(tNMEA2000::fwdt_Text); // Show in clear text. Leave uncommented for default Actisense format.

        // If you also want to see all traffic on the bus use N2km_ListenAndNode instead of N2km_NodeOnly below
        NMEA2000.SetMode(tNMEA2000::N2km_ListenAndNode, 23);
        //NMEA2000.SetDebugMode(tNMEA2000::dm_Actisense); // Uncomment this, so you can test code without CAN bus chips on Arduino Mega
        //NMEA2000.EnableForward(false);
        NMEA2000.ExtendTransmitMessages(TransmitMessages);
        NMEA2000.Open();
}

// *****************************************************************************
// Double replacement for standard map function
double dMap(double x, double in_min, double in_max, double out_min, double out_max) {
        return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

// *****************************************************************************
// Function reads rudder postion from A0 input and scales it to angle in degrees
double ReadRudderPosition() {
        double rudderValue = dMap(analogRead(rudderPosSens), 60, 900, -45, 45);
/*
   // We actually would need here some filter function to prevent noise on analog.
   buffer.push(rudderValue);
   for (unsigned int i = 0; i < buffer.size(); i++) {
    rudderValueAVG += buffer[i] / buffer.size();
   }
 */
        return rudderValue;
}
// *****************************************************************************

#define RudderSendPeriod 100
#define RudderSamplePeriod 1
#define RudderSampleCount 40

void SendRudder() {
        static unsigned long RudderSendTime = millis() + RudderSendPeriod;
        static unsigned long RudderSampleTime = RudderSendTime - RudderSampleCount * RudderSamplePeriod;
        static double RudderSampleSum = 0;
        static size_t RudderSamplesDone = 0;

        tN2kMsg N2kMsg;
        if ( RudderSampleTime < millis() ) {
                RudderSampleSum += ReadRudderPosition();
                RudderSamplesDone++;
                if ( RudderSendTime < RudderSampleTime ) {
                        RudderSendTime += RudderSendPeriod;
                        RudderSampleTime = RudderSendTime - RudderSampleCount * RudderSamplePeriod;
                        double rudderValue = RudderSampleSum / RudderSamplesDone;
                        RudderSampleSum = 0;
                        RudderSamplesDone = 0;
//      Serial.print("Rudder value: "); Serial.println(rudderValueAVG);
                        SetN2kRudder(N2kMsg, DegToRad(rudderValue));
                        NMEA2000.SendMsg(N2kMsg);
                } else {
                        RudderSampleTime += RudderSamplePeriod;
                }
        }
}

void loop() {
        NMEA2000.ParseMessages();
        SendRudder();
}

timolappalainen

No idea. May also depend of manufacturer like calibration.

If you are making some NMEA 2000 device with Teensy, you can fool the system:
- Read trim tab positions from Bennett to Teensy.
- Make calibration on Teensy (your device)
- Send calibrated values back to NMEA 2000 bus from your device.
- On Axiom select your device for trim tab instead of Bennett.

It should be possible to have several devices to sent trim tab and Axiom should also hangle that and show options, which device to use. "Should" is again good word here!

autopilotNOR

Hello Timo,

I jjust saw that there is missing text I wrote in my last post. It was about the rudder position sketch I posted. This causes a problem in the network, or at least I think it is a problem.
If this device is part of the network than the MFD is giving the message "It is not possible to manually choose devices while Rudder Position with SN 40155 is part of the network".

For example while I try to change the depth sensor this message comes up. What causes this "block"?


Another thing is driving me nuts, I just programmed the TeensyActisenseLitenerSender from the example and I can not see anything at all. I tried it now on two devices, changed the MCP2562 twice and tried different baud rates. Not the NMEA reader can see something (Serial port is open by the reader) nor the Serial Monitor of Arduino IDE is showing something. I also modified to show data in clear text on serial.
What do I make wrong, is there more to be modified of the TeensyActisenseLitenerSender when using with Teensy3.2 and MCP2562?
Both devices where working before.

THX!

timolappalainen

On SetDeviceInformation you have set manufacturer code to be Raymarine code. Maybe it checks that this is not right Raymarine rudder sensor and refuces to work.

Note that TeensyActisenseListenerSender is made for that schematic and uses Serial1 for data output to PC. So you should have USB-serial (3.3V) converter on Teensy Serial1. Use just simple ActisenseListener for spying data on bus with NMEA reader.

skyjumper

I have a question about Timo's library...

I'm trying to extract the manufacturer and industry codes from proprietary PGNs and I'm getting data that I don't think can be right. For reference the manufacturer code is the left most 11 bits of the first two bytes while the industry code is the rightmost 3 bits (the first three fields, with the middle 2 bit field reserved). So my code looks like:


Code: [Select]

int index = 0;
uint16_t propHeader = 0;

uint16_t manCode;
unsigned char industryGroup;


propHeader = N2kMsg.Get2ByteUInt(index, 0);

industryGroup = industryGroup & 0x0003;
manCode = (manCode & 0xFFE0) >> 5;


Am I extracting the first two bytes correctly?


timolappalainen

You do not set manCode and industryGroup. I prefere to turn on all warnings and also define all warnings are errors, so you can cot compile this kind of clear problem.

Also data is in little-endian. So also fields insize value has to be handled in that way. So try:

int index = 0;
uint16_t propHeader = N2kMsg.Get2ByteUInt(index);

uint16_t manCode=propHeader & 0x7ff;
unsigned char industryGroup=(propHeader >> 13);

pkeiramo

I use ESP32 and I'm trying to send engine data to my B&G Triton T41 MFD. For some reason, MFD does not recognize my device as source for engine data. However it recognizes it as source for fuel level. It also recognizes it as device and shows data I am sending to bus.

For engine data I use PGN 127489 and for fuel level PGN 127505.

B&G Zeus2 plotter accepts my device as source for engine data. Confusing.

All data is hardcoded at the moment. Some code:

Code: [Select]

  NMEA2000.SetProductInformation("112233", // Manufacturer's Model serial code
                                 100, // Manufacturer's product code
                                 "Engine monitor",  // Manufacturer's Model ID
                                 "1.1.0.21 (2016-12-31)",  // Manufacturer's Software version code
                                 "1.1.0.0 (2016-12-31)" // Manufacturer's Model version
                                 );


  NMEA2000.SetDeviceInformation(112233,
                                140,
                                50, // Device class=Propulsion.
                                2040
                               );



Message sending:
Code: [Select]

#define EngineDataUpdatePeriod 1000

void SendN2kEngineData() {
  static unsigned long EngineDataUpdated=millis();
  tN2kMsg N2kMsg;

  if ( EngineDataUpdated+EngineDataUpdatePeriod<millis() ) {
    EngineDataUpdated=millis();
    SetN2kEngineDynamicParam(N2kMsg, 0, ReadOilPressure(), N2kDoubleNA, ReadEngineCoolantTemp(), ReadAlternatorVoltage(), ReadFuelRate(), N2kDoubleNA);
    NMEA2000.SendMsg(N2kMsg);   
  }
}

#define TankDataUpdatePeriod 2500
#define TankCapacity 75

void SendN2kTankData() {
  static unsigned long TankDataUpdated=millis();
  tN2kMsg N2kMsg;

  if ( TankDataUpdated+TankDataUpdatePeriod<millis() ) {
    TankDataUpdated=millis();
    SetN2kFluidLevel(N2kMsg, 0, N2kft_Fuel, ReadTankLevel(), TankCapacity);
    NMEA2000.SendMsg(N2kMsg);   
  }
}


See attachments. Ideas?

timolappalainen

Have you defined PGNs you sent?

...
const unsigned long TransmitMessages[] PROGMEM={127489UL ,127505UL,0};
...

setup() {
...
  NMEA2000.ExtendTransmitMessages(TransmitMessages);
...
  NMEA2000.Open();
...
}

hirppa10

Hello Timo,

I'm facing problem that occurs every now and then. I have built test system with two esp32, other is reading data from bus and the other is acting as simulator feeding data to bus. My bus is just short piece of breadboard with 2x 120ohm resistors at the both ends.

My other esp32 is using mcp2562 tranceiver and other esp32 is using SN65HVD230 tranceiver. For Can controller both esp32 uses it's internal controller.

Now however, sometimes my simulator sails to send messages to bus (e.g. "PGN 127488 send failed..").
Sometimes simulator is sending data to bus but my receiving esp32 is not getting this data (Forward type = text and nothing showing in console). Anyway sometimes when I reset few times both Esp's things starts to work for a while and then just stops in less than an hour.


Do you have any ideas what could cause this kind of problems? Do you think this would be hardware related or software related problem?

pkeiramo

Have you defined PGNs you sent?

...
const unsigned long TransmitMessages[] PROGMEM={127489UL ,127505UL,0};
...

setup() {
...
  NMEA2000.ExtendTransmitMessages(TransmitMessages);
...
  NMEA2000.Open();
...
}
Yes, I have but with a little difference:

const unsigned long TransmitMessages[] PROGMEM={127489L,127505L,0};

As you can see - without "U" after PGN number. Can it cause this odd behavior?

timolappalainen

Do you have any ideas what could cause this kind of problems? Do you think this would be hardware related or software related problem?
Please email me your .ino files so I can test do I have same behaviour.

hirppa10

#779
Sep 15, 2019, 07:49 pm Last Edit: Sep 15, 2019, 07:52 pm by hirppa10
Where I'm able to find your email? Ill send Ino's right away

edit: found it

Go Up