Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Going driverless at Einride

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest. →

Going driverless at Einride

An overview of Einride's use of Go in the development of driverless vehicles, and a drill-down into the open source CAN-Go library for vehicle network communication.

Avatar for Oscar Söderlund

Oscar Söderlund

June 17, 2020

More Decks by Oscar Söderlund

Other Decks in Programming

Transcript

  1. 064#A9FF BO_ 100 SteerCommand: 2 VCU SG_ AngleDegrees : 0|16@1-

    (0.1,0) [-470|470] "°" EPAS • • ◦ ◦ ◦ • ◦ ▪ ▪ ◦ ▪ ◦ ▪ ▪
  2. 064#A9FF BO_ 100 SteerCommand: 2 VCU SG_ AngleDegrees : 0|16@1-

    (0.1,0) [-470|470] "°" EPAS Message name Message ID (base10) Data length Transmitting node Receiving node(s) Unit Min/max Value scale, offset Signed: - Unsigned: + Big Endian: 0 Little Endian: 1 Signal name Bit offset, length BO_ = message definition SG_ = signal definition • • ◦ ◦ ◦ • ◦ ▪ ▪ ◦ ▪ ◦ ▪ ▪
  3. 064#A9FF BO_ 100 SteerCommand: 2 VCU SG_ AngleDegrees : 0|16@1-

    (0.1,0) [-470|470] "°" EPAS Message name Message ID (base10) Data length Transmitting node Receiving node(s) Unit Min/max Value scale, offset Signed: - Unsigned: + Big Endian: 0 Little Endian: 1 Signal name Bit offset, length BO_ = message definition SG_ = signal definition • • ◦ ◦ ◦ • ◦ ▪ ▪ ◦ ▪ ◦ ▪ ▪ AngleDegrees = float64(int16(0xffa9)) * 0.1 = -8.7°
  4. • ◦ ◦ ◦ ▪ ▪ • ◦ ◦ •

    ◦ https://www.kernel.org/doc/Documentation/networking/can.txt
  5. • ◦ ◦ ◦ ▪ ▪ • ◦ ◦ •

    ◦ https://www.kernel.org/doc/Documentation/networking/can.txt
  6. func main() { const interfaceName = "vcan0" ifi, err :=

    net.InterfaceByName(interfaceName) if err != nil { panic(err) } fd, err := unix.Socket(unix.AF_CAN, unix.SOCK_RAW, unix.CAN_RAW) if err != nil { panic(err) } if err := unix.Bind( fd, &unix.SockaddrCAN{Ifindex: ifi.Index}, ); err != nil { panic(err) } if err := syscall.SetNonblock(fd, true); err != nil { panic(err) } f := os.NewFile(uintptr(fd), interfaceName) if _, err := f.Write([]byte{ 0x23, 0x01, 0x00, 0x00, // id: 0x123 0x08, 0x00, 0x00, 0x00, // data length: 8 bytes 'h', 'i', ' ', 'w', 'o', 'r', 'l', 'd', // data }); err != nil { panic(err) } } • ◦ ◦ • ◦ • ◦ ◦ ◦ ◦ ◦
  7. • ◦ github.com/brutella/can ◦ github.com/linklayer/go-socketcan • ◦ ◦ ◦ ◦

    • ◦ go.einride.tech/can • ◦ func transmit() { conn, err := socketcan.Dial("can", "vcan0") if err != nil { panic(err) } tx := socketcan.NewTransmitter(conn) if err := tx.TransmitFrame(context.Background(), can.Frame{ ID: 0x123, Length: 8, Data: can.Data{'h', 'i', ' ', 'w', 'o', 'r', 'l', 'd'}, }); err != nil { panic(err) } } func receive() { conn, err := socketcan.Dial("can", "vcan0") if err != nil { panic(err) } rx := socketcan.NewReceiver(conn) for rx.Receive() { fmt.Println(rx.Frame()) } if rx.Err() != nil { panic(err) } }
  8. • ◦ github.com/brutella/can ◦ github.com/linklayer/go-socketcan • ◦ ◦ ◦ ◦

    • ◦ go.einride.tech/can • ◦ func main() { const dbcFile = ` BO_ 100 SteerCommand: 2 VCU SG_ AngleDegrees : 0|16@1- (0.1,0) [-470|470] "°" EPAS ` p := dbc.NewParser("example.dbc", []byte(dbcFile)) if err := p.Parse(); err != nil { panic(err) } _, _ = pretty.Println(p.Defs()) }
  9. • ◦ github.com/brutella/can ◦ github.com/linklayer/go-socketcan • ◦ ◦ ◦ ◦

    • ◦ go.einride.tech/can • ◦ []dbc.Def{ &dbc.MessageDef{ Pos: scanner.Position{ Filename: "example.dbc", Offset: 2, Line: 2, Column: 2, }, MessageID: 0x64, Name: "SteerCommand", Size: 0x2, Transmitter: "VCU", Signals: []dbc.SignalDef{ { Pos: scanner.Position{ /* ... */ }, Name: "AngleDegrees", StartBit: 0, Size: 16, IsBigEndian: false, IsSigned: true, Offset: 0, Factor: 0.1, Minimum: -470, Maximum: 470, Unit: "°", Receivers: []dbc.Identifier{"EPAS"}, }, }, }, } BO_ 100 SteerCommand: 2 VCU SG_ AngleDegrees : 0|16@1- (0.1,0) [-470|470] "°" EPAS
  10. • ◦ github.com/brutella/can ◦ github.com/linklayer/go-socketcan • ◦ ◦ ◦ ◦

    • ◦ go.einride.tech/can • ◦ func main() { conn, err := socketcan.Dial("can", "can0") if err != nil { panic(err) } rx := socketcan.NewReceiver(conn) steerReport := mrlangcan.NewSteerReport() for rx.Receive() { frame := rx.Frame() switch frame.ID { case mrlangcan.Messages().SteerReport.ID: if err := steerReport.UnmarshalFrame(frame); err != nil { panic(err) } fmt.Println(steerReport.AngleDegrees()) } } if rx.Err() != nil { panic(err) } }
  11. • ◦ github.com/brutella/can ◦ github.com/linklayer/go-socketcan • ◦ ◦ ◦ ◦

    • ◦ go.einride.tech/can • ◦ func main() { node := mrlangcan.NewVCU("can", "vcan0") node.Tx().TurnSignalCommand().SetCyclicTransmissionEnabled(true) go func() { if err := node.Run(context.Background()); err != nil { panic(err) } }() for { var turnSignal mrlangcan.TurnSignalCommand_TurnSignal switch rand.Intn(3) { case 0: turnSignal = mrlangcan.TurnSignalCommand_TurnSignal_Left case 1: turnSignal = mrlangcan.TurnSignalCommand_TurnSignal_Right default: turnSignal = mrlangcan.TurnSignalCommand_TurnSignal_Off } node.Lock() node.Tx().TurnSignalCommand().SetTurnSignal(turnSignal) node.Unlock() time.Sleep(time.Second) } }