This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm whether you accept or reject these cookies being set.

A cookie will be stored in your browser regardless of choice to prevent you being asked this question again. You will be able to change your cookie settings at any time using the link in the footer.

Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
SeaTalk 1 to NMEA0183/2000 with Raspberry Pi
#21
That's awesome! Thanks for sharing.

There have been implementation of SofwareSerial that does 9 bit successfully.

I need to try this on my AutoHelm system!
Reply
#22
Thank you very much Cari20!

I didn't know about the signalk-autopilot plugin, this saves a lot of time.
What I started doing was creating a NodeRed dashboard with buttons, which when pressed would trigger Marco Bergman's script.
This is what I had so far:
Code:
[{"id":"69638511.9f0fdc","type":"tab","label":"seatalk tiller pilot remote","disabled":false,"info":""},{"id":"cbb1ef69.90424","type":"ui_button","z":"69638511.9f0fdc","name":"","group":"966da9df.2c4648","order":0,"width":0,"height":0,"passthru":true,"label":"AUTO","tooltip":"Enable autopilot","color":"","bgcolor":"","icon":"","payload":"2","payloadType":"num","topic":"","x":470,"y":340,"wires":[["3f72a40.aac515c"]]},{"id":"3f72a40.aac515c","type":"python-function","z":"69638511.9f0fdc","name":"write seatalk","func":"#!/usr/bin/env python\n\nimport RPi.GPIO as GPIO\nimport time\nimport serial\nimport os\n\n# ST2000 remote control with Raspberry Pi 2\n# Marco Bergman 2019\n#\n#   +5V    (01) ---------------------+\n#                                    |\n#                                   +++\n#               2 x NPN             | |\n#               2 x 10k             | |\n#                                   +++       c------o SEATALK\n#                                    |     | /\n#                              c-----+----b|<\n#                   +---+   | /            | \\\n#   GPIO14 (08) ----+   +--b|<                e\n#                   +---+   | \\               |\n#                              e              |\n#                              |              |\n#   GND    (03) ---------------+--------------+\n\n# GPIO constants: connect switches to ground on these GPIO pins\n#AU = 24    # Auto       GPIO 24 (pin# 18) BROWN\n#M1 = 22    # Minus 1    GPIO 22 (pin# 15) ORANGE\n#M10 = 27   # Minus 10   GPIO 27 (pin# 13) GREEN\n#P10 = 17   # Plus 10    GPIO 17 (pin# 11) BLUE\n#P1 = 18    # Plus 1     GPIO 18 (pin# 12) YELLOW\n#SB = 23    # Standby    GPIO 23 (pin# 16) WHITE\nBUZZER = 25 # Buzzer    GPIO 25 (pin# 22) WHITE\n\nnode.log(\"test\")\n\nMODE_NORMAL = 1\nMODE_STEER_INTO_WIND = 2\n\ndef write_seatalk (xx, yy):\n# thanks to http://www.thomasknauf.de/seatalk.htm\n        with serial.Serial() as ser:\n                ser.baudrate = 4800\n                ser.port = '/dev/serial0'\n                ser.stopbits=serial.STOPBITS_ONE\n                ser.bytesize=serial.EIGHTBITS\n\n                ser.open()\n                ser.parity = serial.PARITY_MARK\n                ser.write(b'\\x86')\n                ser.parity = serial.PARITY_SPACE\n                ser.write(b'\\x11' + chr(int(xx, 16)) + chr(int(yy, 16)))\n                ser.close()\n                \n                \nangle = 0\nprevious_angle = 0\n\ndef send_command(command):\n        global angle\n        print \"command=\"+str(command)\n\n        if command == -10:\n                write_seatalk(\"06\", \"F9\")\n        if command == -1:\n                write_seatalk(\"05\", \"FA\")\n        if command == +1:\n                write_seatalk(\"07\", \"F8\")\n        if command == +10:\n                write_seatalk(\"08\", \"F7\")\n        angle = angle - command\n\n\ndef steer_to_angle(angle_to_steer_to):\n        global angle\n        angle = angle_to_steer_to\n\n        while angle != 0:\n                if angle <= -10:\n                        send_command(-10)\n                if angle > -10 and angle < 0:\n                        send_command(-1)\n                if angle > 0 and angle < 10:\n                        send_command(+1)\n                if angle >= 10:\n                        send_command(+10)\n\ndef steer_into_wind():\n        global previous_angle\n\n        try:\n                with open('/tmp/AWA', 'r') as myfile:\n                        line = myfile.read().replace(\"\\n\", \"\")\n                        awa = int(line)\n        except:\n                awa = 0\n\n        angle=(awa+180) % 360-180\n        previous_angle = angle\n        node.log(\"awa=\" + str(awa) + \"; angle=\" + str(angle))\n\n        steer_to_angle(angle)\n\n\ndef steer_previous_angle():\n        global previous_angle\n\n        steer_to_angle(-previous_angle)\n        \nGPIO.setmode(GPIO.BCM)\n#GPIO.setup(SB, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # Stand By:   1\n#GPIO.setup(AU, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # Auto:       2\n#GPIO.setup(P1, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # +1:         4\n#GPIO.setup(P10, GPIO.IN, pull_up_down=GPIO.PUD_UP) # +10:        8\n#GPIO.setup(M10, GPIO.IN, pull_up_down=GPIO.PUD_UP) # -10:       16\n#GPIO.setup(M1, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # -1:        32\nGPIO.setup(BUZZER, GPIO.OUT)        \n\n        \ndef beep(b):\n        if ( b == 1 ):\n                GPIO.output(BUZZER, 1)\n                time.sleep(0.1)\n                GPIO.output(BUZZER, 0)\n        if ( b == 2 ):\n                GPIO.output(BUZZER, 1)\n                time.sleep(0.2)\n                GPIO.output(BUZZER, 0)\n        if ( b == 3 ):\n                beep(1)\n                time.sleep(0.1)\n                beep(1)\n\n\nbeep(3)\n\nmode=MODE_NORMAL\n\nwhile 1:\n\n\tkey=msg['payload']\n\n\t# Stand by\n\tif (key == 1):\n\t\t\tnode.log(\"Stand by (\" + str(key) + \")\")\n\t\t\tbeep(2)\n\t\t\twrite_seatalk(\"02\", \"FD\")\n\t\t\tmode = MODE_NORMAL\n\t# Auto\n\tif (key == 2 and mode == MODE_NORMAL):\n\t\t\tnode.log(\"Auto (\" + str(key) + \")\")\n\t\t\tbeep(1)\n\t\t\twrite_seatalk(\"01\", \"FE\")\n\t# Auto steer back\n\tif (key == 2 and mode == MODE_STEER_INTO_WIND):\n\t\t\tnode.log(\"Steer previous wind angle\")\n\t\t\tbeep(3)\n\t\t\tsteer_previous_angle()\n\t\t\tmode = MODE_NORMAL\n\n\t# +1\n\tif (key == 4):\n\t\t\tnode.log(\"+1 (\" + str(key) + \")\")\n\t\t\tbeep(1)\n\t\t\twrite_seatalk(\"07\", \"F8\")\n\t# +10\n\tif (key == 8):\n\t\t\tnode.log(\"+10 (\" + str(key) + \")\")\n\t\t\tbeep(2)\n\t\t\twrite_seatalk(\"08\", \"F7\")\n\t# -10\n\tif (key == 16):\n\t\t\tnode.log(\"-10 (\" + str(key) + \")\")\n\t\t\tbeep(2)\n\t\t\twrite_seatalk(\"06\", \"F9\")\n\t# -1\n\tif (key == 32):\n\t\t\tnode.log(\"-1 (\" + str(key) + \")\")\n\t\t\tbeep(1)\n\t\t\twrite_seatalk(\"05\", \"FA\")\n\n\t# Track -10 & +10\n\tif (key == 24):\n\t\t\tnode.log(\"Track (\" + str(key) + \")\")\n\t\t\tbeep(3)\n\t\t\twrite_seatalk(\"28\", \"D7\")\n\t# Tack Port -1 & -10\n\tif (key == 48):\n\t\t\tnode.log(\"Tack Port (\" + str(key) + \")\")\n\t\t\tbeep(3)\n\t\t\twrite_seatalk(\"21\", \"DE\")\n\t# Tack Starboard +1 & +10\n\tif (key == 12):\n\t\t\tnode.log(\"Tack Starboard (\" + str(key) + \")\")\n\t\t\tbeep(3)\n\t\t\twrite_seatalk(\"22\", \"DD\")\n\t# Toggle auto seastate +1 & -1\n\tif (key == 36):\n\t\t\tnode.log(\"Toggle auto seastate (\" + str(key) + \")\")\n\t\t\tbeep(3)\n\t\t\twrite_seatalk(\"20\", \"DF\")\n\n\tif (key == 3 and mode == MODE_NORMAL):\n\t\t\tnode.log(\"Steer into wind\")\n\t\t\tbeep(3)\n\t\t\tsteer_into_wind()\n\t\t\tmode = MODE_STEER_INTO_WIND","outputs":1,"x":640,"y":300,"wires":[[]]},{"id":"55bb2f92.c05b3","type":"ui_button","z":"69638511.9f0fdc","name":"","group":"966da9df.2c4648","order":1,"width":0,"height":0,"passthru":true,"label":"STANDBY","tooltip":"","color":"","bgcolor":"","icon":"","payload":"1","payloadType":"num","topic":"","x":450,"y":260,"wires":[["3f72a40.aac515c"]]},{"id":"63cd06d1.cc5018","type":"inject","z":"69638511.9f0fdc","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":300,"y":260,"wires":[["55bb2f92.c05b3"]]},{"id":"71191e8a.4a8df","type":"inject","z":"69638511.9f0fdc","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":300,"y":340,"wires":[["cbb1ef69.90424"]]},{"id":"966da9df.2c4648","type":"ui_group","z":"","name":"Müdür","tab":"2cac5f75.ceba6","order":1,"disp":true,"width":"6","collapse":true},{"id":"2cac5f75.ceba6","type":"ui_tab","z":"","name":"Monitor","icon":"dashboard","order":1,"disabled":false,"hidden":false}]
Mind you, this is still rough and probably full of bugs while I'm learning to use Python and NodeRed.
I got stuck last night on the fact I had to enable UART first, but openplotter warned me this was going to disable bluetooth (which I'd maybe need later).
I'm using an RPi 4, which should have 6 UARTs, so I need to investigate if I can use one of them without disabling bluetooth, as it's only disable when using UART0 I think.

Another problem is I don't have my ST2000 here, so testing is difficult Smile
But as Seatalk is a single-wire system, probably STALK_read.py will pick up the transmitted datagrams again?

By the way, do you know if the signalk-plugin does any collision detection?
Quote:To detect data collision, every single bit sent out to the SeaTalk bus is read back again and checked for successful transmission. If the transmission was corrupted, this transmission is stopped immediately. This single datagram will be discarded. When the bus becomes free again, the transmission will be started again. The lost datagram will be repeated on the next update from NMEA data.
Source: http://www.fwma.de/stalk/ManualUsb.pdf

Quote:There is no master on the bus. Every device has equal rights and is allowed to talk as soon as it recognizes the bus to be idle (+12V for at least 10/4800 seconds). Low priority messages use a longer or randomly selected idle-bus-waiting-time. This allows messages from other devices with a higher priority to be transmitted first. The different waiting times of all devices make data collisions (two or more devices start talking at exactly the same moment) very rare. Since each device also listens to its own transmission it will recognize when its message is garbled by a second talker. In this case it abandons the remaining characters of the datagram. It waits for the bus to become free again and then retransmits the whole message. For listeners this means that messages which are shorter than expected are invalid and have to be cancelled totally.
Source: http://www.thomasknauf.de/rap/seatalk1.htm

With all the bits of info I have now, there must be a way for me to translate NMEA XTE messages, coming from OpenCPN, to Seatalk.
But let's take baby steps and get this remote plugin working first Smile
Reply
#23
I'm confused. The npm page says that the signalk-autopilot plugin speaks Seatalk (https://www.npmjs.com/package/@signalk/s...-autopilot) and the "NMEA 0183 outputEvent for the Seatalk Connection" setting in the plugin settings seems to confirm it.
But when I look at the source code (https://github.com/sbender9/signalk-autopilot) I find no trace of it...

I was interested to see how he translates NMEA0183 to Seatalk datagrams, to allow me to build on that.
Reply
#24
The repo link in npm is outdated, see https://github.com/signalk/signalk-autopilot
Reply
#25
(2020-09-08, 05:25 PM)tkurki Wrote: The repo link in npm is outdated, see https://github.com/signalk/signalk-autopilot

Thanks tkurki! It seems that collision detection is indeed not done by the signalk-autopilot plugin, which makes sense if I think about it, as it's not doing the actual sending of datagrams.

So could Cari20's script be expanded to check for data collisions?
Or am I worrying about nothing?

I've got an ST40 bidata (depth sounder and log) talking seatalk as well, so I wouldn't want them to interfere with the autopilot, or vice versa...
Reply
#26
(2020-09-08, 09:32 PM)Nikotine Wrote:
(2020-09-08, 05:25 PM)tkurki Wrote: The repo link in npm is outdated, see https://github.com/signalk/signalk-autopilot

Thanks tkurki! It seems that collision detection is indeed not done by the signalk-autopilot plugin, which makes sense if I think about it, as it's not doing the actual sending of datagrams.

So could Cari20's script be expanded to check for data collisions?
Or am I worrying about nothing?

I've got an ST40 bidata (depth sounder and log) talking seatalk as well, so I wouldn't want them to interfere with the autopilot, or vice versa...

The script could be expanded to check for data collisions. When you send a message you could listen on the input for that message and repeat it if you don´t see it after a given time.

I would´t worry so much about collisions because every device in the bus does this so if you use the interface just for the remote worst case you will end up having to press a button twice every once in a while, I mean the other devices won't be affected because they will be doing their own cheking (repeating garbled messages).  Anyway, It's at the bottom of my ToDo list.
Reply
#27
A new openplotter app to help with seatalk 1: https://forum.openmarine.net/showthread.php?tid=3029
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)