goroslib is a library in pure Go that allows to build clients (nodes) for the Robot Operating System (ROS).

goroslib

Test Lint Go Report Card CodeCov PkgGoDev

goroslib is a library in pure Go that allows to build clients (nodes) for the Robot Operating System (ROS).

The Robot Operating System (ROS) is a project that provides a specification to make multiple programs communicate with each other over time, exchanging structured data with topics, services, actions and parameters. It was conceived to link sensors, algorithms and actuators in unmanned ground vehicles (UGVs) and robots, but it is not bounded to the robot world and can be used anywhere there's the need of building streams of data (for example in video processing).

Features:

  • publish and subscribe to topics with TCP or UDP
  • provide and call services
  • provide and call actions
  • provide and call simple actions
  • get and set parameters
  • support namespaces and relative topics
  • support IPv6 (stateful addresses only)
  • support time API
  • compilation of .msg files is not necessary, message definitions are extracted from code
  • compile or cross-compile for all Go supported OSs (Linux, Windows, Mac OS X) and architectures
  • examples provided for every feature, comprehensive test suite, continuous integration

Table of contents

Installation

  1. Install Go ≥ 1.15.

  2. Create an empty folder, open a terminal in it and initialize the Go modules system:

    go mod init main
    
  3. Download one of the example files and place it in the folder:

  4. Compile and run (a ROS master must be already running in the background)

    go run name-of-the-go-file.go
    

API Documentation

https://pkg.go.dev/github.com/aler9/goroslib#pkg-index

FAQs

Comparison with other libraries

goroslib vs official C++/Python libraries

The official project provides libraries to write nodes in C++ and Python, but they require the download of over 1GB of data and work only with a fixed buildchain. This library allows to write lightweight nodes that can be built with the standard Go compiler, do not need any runtime library and have a size of some megabytes. Another advantage lies in the possibility of compiling nodes for all the Golang supported operating systems (Linux, Windows, Mac OS X, etc) and architectures.

goroslib vs rosgo

rosgo is currently unmaintained; furthermore, it requires compilation of .msg files, doesn't support UDP, doesn't support actions, doesn't support simulated clocks.

Full list of features

Current and missing features are described in the FEATURES document.

Use standard messages, services and actions

This library provides most of the standard messages, services and actions in the folder pkg/msgs:

package documentation repository
ackermann_msgs link link
actionlib link link
actionlib_msgs link link
audio_common_msgs link link
control_msgs link link
diagnostic_msgs link link
geometry_msgs link link
geographic_msgs link link
mavros_msgs link link
nav_msgs link link
rosgraph_msgs link link
sensor_msgs link link
shape_msgs link link
sound_play link link
std_msgs link link
std_srvs link link
stereo_msgs link link
tf link link
tf2_msgs link link
trajectory_msgs link link
uuid_msgs link link
velodyne_msgs link link
vision_msgs link link
visualization_msgs link link

Define custom messages, services and actions

To define custom messages, the standard ROS C++/Python libraries require .msg files in this format:

bool field1
int32 field2

This library doesn't require any .msg file, it is enough to write Go structures in this format:

import (
    "github.com/aler9/goroslib/pkg/msgs"
)

type MessageName struct {
    msg.Package `ros:"my_package"`
    Field1 bool
    Field2 int32
}

The type of a field can be one of the following:

  • one of the primitive field types:

    • bool
    • int8
    • uint8
    • int16
    • uint16
    • int32
    • uint32
    • int64
    • uint64
    • float32
    • float64
    • string
    • time.Time
    • time.Duration
  • another standard or custom message

The name of a field must be in CamelCase, and is converted to snake_case when interacting with C++/Python nodes. If this conversion is not possible, the tag rosname can be used to override the field name:

type MessageName struct {
    msg.Package `ros:"my_package"`
    Field bool  `rosname:"FIELD"`
}

Services in this format:

uint32 input
---
uint32 output

Are equivalent to Go structures in this format:

type ServiceNameReq struct {
    Input uint32
}

type ServiceNameRes struct {
	Output uint32
}

type ServiceName struct {
	msg.Package `ros:"my_package"`
	ServiceNameReq
	ServiceNameRes
}

Actions in this format:

uint32 goal
---
uint32 result
---
uint32 feedback

Are equivalent to Go structures in this format:

type ActionNameGoal struct {
	Goal uint32
}

type ActionNameResult struct {
	Result uint32
}

type ActionNameFeedback struct {
	Feedback uint32
}

type ActionName struct {
	msg.Package `ros:"my_package"`
	ActionNameGoal
	ActionNameResult
	ActionNameFeedback
}

Import existing messages, services and actions

A command-line utility is provided to convert existing .msg files into their equivalent Go structures:

go get github.com/aler9/goroslib/cmd/msg-import
msg-import --rospackage=my_package mymessage.msg > mymessage.go

Another one is provided to convert existing .srv files into their equivalent Go structures:

go get github.com/aler9/goroslib/cmd/srv-import
srv-import --rospackage=my_package myservice.srv > myservice.go

Another one is provided to convert existing .action files into their equivalent Go structures:

go get github.com/aler9/goroslib/cmd/action-import
action-import --rospackage=my_package myaction.action > myaction.go

Compile a node for another operating system

To compile a node for another OS, it's enough to follow the standard Golang procedure to cross-compile, that consists in setting the GOOS and GOARCH environment variables according to the target machine. For instance, to build a node for Windows from another OS, run:

GOOS=windows GOARCH=amd64 go build -o node.exe name-of-source-file.go

Edit the library

If you want to hack the library and test the results, unit tests can be launched with:

make test

Links

ROS v1 Documentation

Other Go libraries

Other non-Go libraries

Conventions

Owner
Alessandro Ros
Software and robotics engineer, i deal with anything that can be modeled and controlled. MSc @ PoliMi
Alessandro Ros
Comments
  • Improper String Constant Handling when using msg-import Command

    Improper String Constant Handling when using msg-import Command

    Which operating system are you using?

    OS

    • [X] Linux
    • [ ] Windows
    • [ ] macOS

    Architecture

    • [X] amd64
    • [ ] arm64
    • [ ] arm7
    • [ ] arm6

    Description

    When using the msg-import command constants of type string are not handled property.

    For example ROS definition:

    # A simple ROS message definition
    string CONSTANT1=CONSTANT_VALUE_1
    
    string source
    

    The following invalid Go code is generated:

    package main //nolint:golint
    
    import (
        "github.com/aler9/goroslib/pkg/msg"
    )
    
    
    const (
        Example1_CONSTANT1 string = CONSTANT_VALUE_1 //nolint:golint
    )
    
    type Example1 struct { //nolint:golint
        msg.Package `ros:"ocu_msgs"`
        msg.Definitions `ros:"string CONSTANT1=CONSTANT_VALUE_1"`
        Source string//nolint:golint
    }
    

    The initialization value for Example1_CONSTANT1 is missing quotations, it should be "CONSTANT_VALUE_1"

    A separate but perhaps related issue, for this example ROS definition file:

    # A simple ROS message definition
    string CONSTANT1="CONSTANT_VALUE_1"
    
    string source
    

    The following Go code is generated:

    package main //nolint:golint
    
    import (
        "github.com/aler9/goroslib/pkg/msg"
    )
    
    
    const (
        Example2_CONSTANT1 string = "CONSTANT_VALUE_1" //nolint:golint
    )
    
    type Example2 struct { //nolint:golint
        msg.Package `ros:"ocu_msgs"`
        msg.Definitions `ros:"string CONSTANT1="CONSTANT_VALUE_1""`
        Source string//nolint:golint
    }
    

    The problem here is more subtle, the struct tag for msg.Definitions is invalid because there are unescaped quotation marks. Instead is should be:

    msg.Definitions `ros:"string CONSTANT1=\"CONSTANT_VALUE_1\""`
    
  • Missing `message_definition` in publisher header

    Missing `message_definition` in publisher header

    Which operating system are you using?

    OS

    • [x] Linux
    • [ ] Windows
    • [ ] macOS

    Architecture

    • [x] amd64
    • [ ] arm64
    • [ ] arm7
    • [ ] arm6

    Describe the issue

    Description

    It seems that the message_definition header is "missing" from the HeaderPublisher. From what I can gather from here it shouldn't be needed (which seems weird to me...) but the documentation is from 2013 so might not be up-to-date.

    Looking at ros_comm, it seems the message_definition is expected to be included in both publisher and subscriber (look in this test for example) and my manual tests seem to confirm it.

    The reason this is an issue for me is that Foxglove Studio uses the message_definition to determine how to parse an incoming message. Since this is missing all messages become "empty" as well and an error is thrown. It works as expected for nodes using the official libraries which makes me think it is within spec to include it.

    What do you think? Would it be feasible to add the message_definition to the header field? This is needed for me to be able to use node-to-node communication without using the ROS bridge in Foxglove Studio.

  • Support non-snake-case field names

    Support non-snake-case field names

    When i use this lib to pusblish costom msgs to another CPP node, The CPP node tell me the datatype/md5sum check failed, the log as bellow:

    [ERROR] [1602764150.921571564]: Client [/avatar] wants topic /topic/response/signal/message to have datatype/md5sum [atris_msgs/SignalMessage/21bf35dedac23c2dd7049256f5f2f971], but our version has [atris_msgs/SignalMessage/47da1d8e018fea14775e1f7b4683149a]. Dropping connection.

  • Subscriber does not receive single message

    Subscriber does not receive single message

    Hi! I have discovered your work through the recent Ubuntu blog post. Nice job!

    You have done a great documentation job and I like how you test the issues in simple docker containers as in this comment https://github.com/aler9/goroslib/issues/2#issuecomment-601724672 :+1:

    My first try was to test a simple subscriber like the one in the examples and it seems to never receive a message from rostopic pub. But I have noticed that if I give a rate -r 1, the messages start to appear and from the Seq: 1 so all messages seem to be received.

    The issue is that sometimes, a node only waits for one message and not repeated messages so this behavior can be an issue.

    Steps to reproduce:

    1. roscore
      docker run --rm -it --network=host --name=roscore ros:melodic-ros-core-bionic roscore
      
    2. Go subscriber
      docker run --rm -it --network=host golang:1.14 sh -c "git clone https://github.com/aler9/goroslib && cd goroslib && go run examples/subscriber.go"
      
    3. rostopic echo to check that the message is published
      docker run --rm -it --network=host --name=rostopic_echo ros:melodic-ros-core-bionic rostopic echo /test_pub
      
    4. rostopic pub --once
      docker run --rm -it --network=host --name=rostopic_pub ros:melodic-ros-core-bionic rostopic pub --once /test_pub sensor_msgs/Imu "header:
        seq: 0
        stamp: {secs: 0, nsecs: 0}
        frame_id: ''
      orientation: {x: 0.0, y: 0.0, z: 0.0, w: 0.0}
      orientation_covariance: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
      angular_velocity: {x: 0.0, y: 0.0, z: 0.0}
      angular_velocity_covariance: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
      linear_acceleration: {x: 0.0, y: 0.0, z: 0.0}
      linear_acceleration_covariance: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]"
      

    And here, I get no message from in the go subscriber console.

    Now, if we publish with a rate, replace 4. with:

    docker run --rm -it --network=host --name=rostopic_pub ros:melodic-ros-core-bionic rostopic pub -r 1 /test_pub sensor_msgs/Imu "header:
      seq: 0
      stamp: {secs: 0, nsecs: 0}
      frame_id: ''
    orientation: {x: 0.0, y: 0.0, z: 0.0, w: 0.0}
    orientation_covariance: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    angular_velocity: {x: 0.0, y: 0.0, z: 0.0}
    angular_velocity_covariance: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    linear_acceleration: {x: 0.0, y: 0.0, z: 0.0}
    linear_acceleration_covariance: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]"
    

    It works!

  • fix(xmlrpc): workaround for non-standard `utf8` encoding name

    fix(xmlrpc): workaround for non-standard `utf8` encoding name

    Description

    Certain clients include encoding=utf8 (note the missing -) in the xmlrpc message which causes a 400 Bad Request error to be sent back to the client due to a missing charset reader.

    This fix checks that if we get an "utf8" encoding we just proxy it through (i.e. treat it the same as if it was an utf-8). If other charsets are received we error out (same as it would without this fix).

    This all comes from the fact that the xml decoder checks for "utf-8" charset, not "utf8".

    The offending client where I found this is the Foxglove Studio.

    Checks done

    • [x] make test
    • [x] make lint
    • [x] tested manually with Foxglove Studio
  • Simple action client stuck waiting for server

    Simple action client stuck waiting for server

    Which operating system are you using?

    OS

    • [x] Linux
    • [ ] Windows
    • [ ] macOS

    Architecture

    • [x] amd64
    • [ ] arm64
    • [ ] arm7
    • [ ] arm6

    Describe the issue

    Description I just updated, now the action clients are stuck in WaitForServer()

  • Time API

    Time API

    Hello, does this library support time API as in Python? For example, are there similar constructions to get time like rospy.get_time()? There is no problem with reality where we can use system time. But simulation time is different from the latter, therefore I wonder how could we get it.

  • Subscriber stops receiving messages when multimaster_fkie is running

    Subscriber stops receiving messages when multimaster_fkie is running

    Good morning.

    The commit that you refereed fixed the error that I was noticing when running multimaster_fkie and goroslib. However, it seems that now, after a while, the subscriber stops receiving information. It happens after approximately 10 minutes. I tried with a simple string just to test and the problem persists. Interesting bug.

    Best, Filipe Pinto

  • Desirability of basic type redefinitions

    Desirability of basic type redefinitions

    Hi, thanks for this package, it is extremely useful.

    Is there a good reason to redefine the basic types in msgs? I have an application that translates ROS messages to similar protobuf messages. I have to cast every value (for example msgs.Float64 to float64). And for slices I need to copy all values to new slices of the correct type. This wouldn't be necessary if goroslib was using the basic types (like google.golang.org/protobuf). Any chance you might agree to change it?

  • allow using struct with the very same fields as service client req and res

    allow using struct with the very same fields as service client req and res

    This loosens the requirement of having to use the very same structs defined in services.

    It's not uncommon to design the services to have the same response format for easier handling on both sides, and occasionally, different services may use the same request format. Here are two real world examples:

    string control_mode
    ---
    bool   success
    string message
    
    uint8 color
    ---
    bool success
    string message
    

    Using the same response struct can greatly simplify code, like using the same struct to receive all responses and turn to error.

    The added tests passed locally.

  • use rospy serviceProxy cycle call service err

    use rospy serviceProxy cycle call service err

    Which operating system are you using?

    OS

    • [x] Linux
    • [ ] Windows
    • [ ] macOS

    Architecture

    • [ ] amd64
    • [x] arm64
    • [ ] arm7
    • [ ] arm6

    Describe the issue

    roslog: service provider '/data/get_cabinet_ext_data' is unable to accept client '127.0.0.1:58296': a client with id '/test_client_31708_1665221359122' is already connected to the provider

    rospy.ServiceException: Service call failed: unable to connect to service: connection from sender terminated before handshake header received. 0 bytes were received. Please check sender for additional details.

    code: #!/usr/bin/env python

    import rospy import rail_mounted_robot_msgs.srv

    def call_get_cabinet_ext_data(room, cabinet): rospy.wait_for_service('data/get_cabinet_ext_data') try: get_cabinet_ext_data = rospy.ServiceProxy('data/get_cabinet_ext_data', rail_mounted_robot_msgs.srv.GetCabinetExtData) resp = get_cabinet_ext_data(cabinet, room) return resp.cabinet_name except rospy.ServiceException as e: print('Service call failed: {}'.format(e))

    if name == "main": rospy.init_node('test_client', anonymous=True) while not rospy.is_shutdown(): call_get_cabinet_ext_data('20200331', '')

  • After 17 days of continuous operation, some topics are published with a message indicating that i/o timeout and cannot be published again

    After 17 days of continuous operation, some topics are published with a message indicating that i/o timeout and cannot be published again

    Which operating system are you using?

    OS

    • [x] Linux

    Architecture

    • [x] arm64

    Describe the issue

    Description goroslib version:v0.0.0-20220623231355-7a670441a069

    Hello, I have a problem with my program, I need your help, thank you

    After 17 days of continuous operation, some topics are published with a message indicating that i/o timeout and cannot be published again, Data accumulation but failure to publish results in high CPU and memory usage

    `[2022/11/22 16:33:38] [ERROR] publisher '/hardware_status' is unable to write to subscriber '127.0.0.1:36040' (TCP): write tcp 127.0.0.1:39843->127.0.0.1:36040: i/o timeout

    [2022/11/22 16:33:39] [ERROR] publisher '/hardware_status' is unable to write to subscriber '127.0.0.1:36040' (TCP): write tcp 127.0.0.1:39843->127.0.0.1:36040: i/o timeout

    [2022/11/22 16:33:40] [ERROR] publisher '/hardware_status' is unable to write to subscriber '127.0.0.1:36040' (TCP): write tcp 127.0.0.1:39843->127.0.0.1:36040: i/o timeout

    [2022/11/22 16:33:41] [ERROR] publisher '/hardware_status' is unable to write to subscriber '127.0.0.1:36040' (TCP): write tcp 127.0.0.1:39843->127.0.0.1:36040: i/o timeout

    [2022/11/22 16:33:42] [ERROR] publisher '/hardware_status' is unable to write to subscriber '127.0.0.1:36040' (TCP): write tcp 127.0.0.1:39843->127.0.0.1:36040: i/o timeout

    [2022/11/22 16:33:43] [ERROR] publisher '/hardware_status' is unable to write to subscriber '127.0.0.1:36040' (TCP): write tcp 127.0.0.1:39843->127.0.0.1:36040: i/o timeout

    [2022/11/22 16:33:44] [ERROR] publisher '/hardware_status' is unable to write to subscriber '127.0.0.1:36040' (TCP): write tcp 127.0.0.1:39843->127.0.0.1:36040: i/o timeout

    [2022/11/22 16:33:45] [ERROR] publisher '/hardware_status' is unable to write to subscriber '127.0.0.1:36040' (TCP): write tcp 127.0.0.1:39843->127.0.0.1:36040: i/o timeout

    [2022/11/22 16:34:03] [ERROR] publisher '/rosout' is unable to write to subscriber '127.0.0.1:34718' (TCP): write tcp 127.0.0.1:39843->127.0.0.1:34718: i/o timeout

    [2022/11/22 16:34:27] [ERROR] publisher '/hardware_status' is unable to write to subscriber '127.0.0.1:36040' (TCP): write tcp 127.0.0.1:39843->127.0.0.1:36040: i/o timeout

    [2022/11/23 06:37:35] [ERROR] publisher '/alarm' is unable to write to subscriber '127.0.0.1:35988' (TCP): write tcp 127.0.0.1:39843->127.0.0.1:35988: i/o timeout`

Go library providing an abstraction to Ethereum execution nodes

go-execution-client Go library providing an abstraction to Ethereum execution nodes. Its external API follows the official Ethereum consensus APIs spe

Aug 12, 2022
A LoRaWAN nodes' and network simulator that works with a real LoRaWAN environment (such as Chirpstack) and equipped with a web interface for real-time interaction.
A LoRaWAN nodes' and network simulator that works with a real LoRaWAN environment (such as Chirpstack) and equipped with a web interface for real-time interaction.

LWN Simulator A LoRaWAN nodes' simulator to simulate a LoRaWAN Network. Table of Contents General Info Requirements Installation General Info LWN Simu

Nov 20, 2022
🌌 A libp2p DHT crawler that gathers information about running nodes in the network.
🌌 A libp2p DHT crawler that gathers information about running nodes in the network.

A libp2p DHT crawler that gathers information about running nodes in the network. The crawler runs every 30 minutes by connecting to the standard DHT bootstrap nodes and then recursively following all entries in the k-buckets until all peers have been visited.

Dec 27, 2022
Baseledger core consensus for running validator, full and seed nodes

baseledger-core Baseledger core consensus client for running a validator, full or seed node. ⚠️ WARNING: this code has not been audited and is not rea

Jan 13, 2022
LNC is a lightning network capital management tool built for routing nodes.

LNC is a lightning network capital management tool built for routing nodes.

Dec 21, 2021
CoreDNS plugin to create records for Kubernetes nodes.

kubenodes Name kubenodes - creates records for Kubernetes nodes. Description kubenodes watches the Kubernetes API and synthesizes A, AAAA, and PTR rec

Jul 7, 2022
Distributed RTC System by pure Go and Flutter
Distributed RTC System by pure Go and Flutter

ION is a distributed real-time communication system, the goal is to chat anydevice, anytime, anywhere! Distributed Real-time Communication System ION

Jan 2, 2023
DeepCopy a portable app that allows you to copy all forms of specified file types from your entire file system of the computer

DeepCopy a portable app that allows you to copy all forms of specified file types from your entire file system of the computer

Dec 20, 2021
Generate types and service clients from protobuf definitions annotated with http rules.

protoc-gen-typescript-http Generates Typescript types and service clients from protobuf definitions annotated with http rules. The generated types fol

Nov 22, 2022
protoc-gen-grpc-gateway-ts is a Typescript client generator for the grpc-gateway project. It generates idiomatic Typescript clients that connect the web frontend and golang backend fronted by grpc-gateway.

protoc-gen-grpc-gateway-ts protoc-gen-grpc-gateway-ts is a Typescript client generator for the grpc-gateway project. It generates idiomatic Typescript

Dec 19, 2022
A Wireguard VPN Server Manager and API to add and remove clients

Wireguard Manager And API A manager and API to add, remove clients as well as other features such as an auto reapplier which deletes and adds back a c

Dec 22, 2022
List running processes that are acting as DCE/RPC servers or clients

rpcls This project was made to assist in a larger research project. It pulls from a running process' PEB to enumerate the loaded DLLs. If a process im

Sep 14, 2022
Support for Unix domain sockets in Go HTTP clients

unixtransport This package adds support for Unix domain sockets in Go HTTP clients. t := &http.Transport{...} unixtransport.Register(t) client := &h

Dec 21, 2022
A simple UDP server to make a virtual secure channel with the clients

udpsocket I made this package to make a virtual stateful connection between the client & server using the UDP protocol for a golang game server (as yo

Jun 18, 2022
Proxy that keeps clients active until the backend server is back online

HoneySmoke HoneySmoke is a prototype proxy for testing until it eventually becomes HoneyHive. HoneySmoke will eventually implement a limbo mode that k

Nov 20, 2021
Clients able to speak JSON over HTTP to the server

Location History Server How to run: Call the make run command. Clients able to speak JSON over HTTP to the server. There are three endpoints supported

Nov 4, 2021
Code to be shared between EduVPN clients

EduVPN shared library This repository contains a Go library with functions that all EduVPN clients can use. The goal is to let EduVPN clients link aga

Mar 15, 2022
Kiwi-balancer - A balancer is a gateway between the clients and the server

Task description Imagine a standard client-server relationship, only in our case

Feb 11, 2022
Ephemeral One Time/Build-Time gRPC TLS PKI system.

PkiSauce Ephemeral Build Time TLS PKI saucing for your intra services GRPC (or not) communications. Description A simple attempt to avoid deploying co

Jul 4, 2022