Example #1
0
* @Author: Sebastien Soudan
* @Date:   2015-09-22 11:55:49
* @Last Modified by:   Sebastien Soudan
* @Last Modified time: 2015-10-21 12:53:12
 */

package control

import (
	"github.com/ssoudan/edisonIsThePilot/infrastructure/logger"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/types"

	"time"
)

var log = logger.Log("control")

// Control is a component that monitors change on a types.Readable and Enable or Disable its target
type Control struct {
	controlHandler types.Readable
	target         types.Enablable
	stateEnable    bool

	// channels
	shutdownChan chan interface{}
	panicChan    chan interface{}
}

// New creates a new Control component
func New(controlHandler types.Readable, target types.Enablable) *Control {
	return &Control{controlHandler: controlHandler, target: target, shutdownChan: make(chan interface{})}
Example #2
0
* @Author: Sebastien Soudan
* @Date:   2015-09-21 15:42:21
* @Last Modified by:   Sebastien Soudan
* @Last Modified time: 2015-10-21 14:21:19
 */

package alarm

import (
	"sync"

	"github.com/ssoudan/edisonIsThePilot/infrastructure/logger"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/types"
)

var log = logger.Log("alarm")

// Alarm is the component that manage the external alarm
type Alarm struct {
	alarmHandler types.Enablable

	mu         sync.RWMutex
	alarmState bool // protected by mu

	// channels
	inputChan    chan interface{}
	shutdownChan chan interface{}
	panicChan    chan interface{}
}

// New creates a new Alarm component for an types.Enablable
Example #3
0
*/

/*
* @Author: Sebastien Soudan
* @Date:   2015-10-13 17:12:30
* @Last Modified by:   Sebastien Soudan
* @Last Modified time: 2015-10-19 15:34:13
 */

package ap100

import (
	"github.com/ssoudan/edisonIsThePilot/infrastructure/logger"
)

var log = logger.Log("ap100")

// AP100 is the component that send the course to an external device (via a sin/cos interface)
type AP100 struct {
	output Compass

	// channels
	inputChan    chan interface{}
	shutdownChan chan interface{}
	panicChan    chan interface{}
}

// Compass is something on which we can update the course (in degree)
type Compass interface {
	UpdateCourse(course uint16) error
}
Example #4
0
package webserver

import (
	"fmt"
	"io"
	"net/http"

	"github.com/ant0ine/go-json-rest/rest"

	"github.com/ssoudan/edisonIsThePilot/infrastructure/logger"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/types"
	"github.com/ssoudan/edisonIsThePilot/pilot"
)

var log = logger.Log("webserver")

// VersionEndpoint is the endpoint providing the version of this piece of software
func VersionEndpoint(version string) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, fmt.Sprintf("Edison is the pilot - %s", version))
	}
}

func redirect(w http.ResponseWriter, r *http.Request) {

	http.Redirect(w, r, "static/", 301)
}

// Control is the serializable structure used to change the autopilot state
type Control struct {
Example #5
0
/*
* @Author: Sebastien Soudan
* @Date:   2015-10-21 15:37:36
* @Last Modified by:   Sebastien Soudan
* @Last Modified time: 2015-10-22 18:10:06
 */

package tracer

import (
	"github.com/ssoudan/edisonIsThePilot/infrastructure/logger"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/types"
)

var log = logger.Log("tracer")

// Tracer is the component that stores the recent position history
type Tracer struct {
	maxPoints        uint32
	nextPosition     uint32
	points           []types.Point
	fullyInitialized bool

	// Channels
	inputChan    chan interface{}
	shutdownChan chan interface{}
	panicChan    chan interface{}
}

// New creates a new Tracer component
Example #6
0
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"sync"
	"time"

	"github.com/ssoudan/edisonIsThePilot/infrastructure/logger"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/types"
	"github.com/ssoudan/edisonIsThePilot/pilot"
	"github.com/ssoudan/edisonIsThePilot/steering"

	"github.com/adrianmo/go-nmea"
)

var log = logger.Log("stepper")

// Input is the definition of a step
type Input struct {
	Duration types.JSONDuration
	Heading  float64
	Step     float64
}

// Point is the structure collected when a step is RUNNING
type Point struct {
	Timestamp     types.JSONTime
	FixTime       string
	FixDate       string
	Course        float64
	Speed         float64
Example #7
0
* @Last Modified time: 2015-10-21 12:59:58
 */

package main

import (
	"github.com/jessevdk/go-flags"

	"time"

	"github.com/ssoudan/edisonIsThePilot/conf"
	"github.com/ssoudan/edisonIsThePilot/drivers/motor"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/logger"
)

var log = logger.Log("motorControl")

// Options are the command line options for this tool
type Options struct {
	Clockwise  bool    `short:"c" long:"clockwise" description:"clockwise rotation" default:"false"`
	Speed      uint32  `short:"s" long:"speed" description:"rotation speed pps" default:"600"`
	Duration   float64 `short:"d" long:"duration" description:"duration (seconds)" default:"1"`
	Repetition int     `short:"r" long:"rep" description:"repetitions" default:"1"`
	Pause      float64 `short:"p" long:"pause" description:"pause" default:"0"`
}

var opts Options

var parser = flags.NewParser(&opts, flags.Default)

func step(motor *motor.Motor, clockwise bool, stepsBySecond uint32, duration time.Duration) {
Example #8
0
* @Last Modified time: 2015-10-21 14:23:56
 */

package main

import (
	"github.com/jessevdk/go-flags"

	"time"

	"github.com/ssoudan/edisonIsThePilot/conf"
	"github.com/ssoudan/edisonIsThePilot/drivers/motor"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/logger"
)

var log = logger.Log("mario")

// Options are the command line options for mario tool
type Options struct {
	Clockwise bool `short:"c" long:"clockwise" description:"clockwise rotation" default:"false"`
	// Speed     uint32  `short:"s" long:"speed" description:"rotation speed pps" default:"600"`
	// Duration  float64 `short:"d" long:"duration" description:"duration (seconds)" default:"1"`
}

var opts Options

var parser = flags.NewParser(&opts, flags.Default)

func doStep(motor *motor.Motor, clockwise bool, stepsBySecond uint32, duration time.Duration) {
	motor.Enable()
	log.Info("Moving clockwise[%v] for %v at %v[steps/s]", clockwise, duration, stepsBySecond)
	"net/http"
	"time"

	"github.com/ssoudan/edisonIsThePilot/conf"
	"github.com/ssoudan/edisonIsThePilot/control"
	"github.com/ssoudan/edisonIsThePilot/drivers/gpio"
	"github.com/ssoudan/edisonIsThePilot/drivers/motor"
	"github.com/ssoudan/edisonIsThePilot/gps"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/logger"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/utils"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/webserver"
	"github.com/ssoudan/edisonIsThePilot/steering"
	"github.com/ssoudan/edisonIsThePilot/stepper"
)

var log = logger.Log("systemCalibration")

// Version is the version of this code -- sets at compilation time
var Version = "unknown"

// Options are the command line options of this tool
type Options struct {
	Step        float64 `short:"s" long:"step" description:"step intensity (motor rotation in degree)" required:"true"`
	Duration    int64   `short:"d" long:"duration" description:"duration (seconds)" required:"true"`
	Description string  `short:"D" long:"description" description:"description of the test" required:"true"`
}

var opts Options

var parser = flags.NewParser(&opts, flags.Default)
Example #10
0
	"bufio"
	"strconv"
	"strings"
	"time"

	"github.com/ssoudan/edisonIsThePilot/ap100"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/logger"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/types"
	"github.com/ssoudan/edisonIsThePilot/pilot"
	"github.com/ssoudan/edisonIsThePilot/tracer"

	"github.com/adrianmo/go-nmea"
	"github.com/tarm/serial"
)

var log = logger.Log("gps")

// GPS is a driver for a serial attached NMEA GPS
type GPS struct {
	deviceName string
	baud       int

	// channels
	messagesChan chan interface{}
	headingChan  chan interface{}
	errorChan    chan interface{}
	panicChan    chan interface{}
	tracerChan   chan interface{}
}

// New creates a new GPS component
Example #11
0
* @Last Modified by:   Sebastien Soudan
* @Last Modified time: 2015-10-21 12:48:18
 */

package pilot

import (
	"github.com/ssoudan/edisonIsThePilot/alarm"
	"github.com/ssoudan/edisonIsThePilot/conf"
	"github.com/ssoudan/edisonIsThePilot/dashboard"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/logger"
	"github.com/ssoudan/edisonIsThePilot/steering"
	"time"
)

var log = logger.Log("pilot")

// Pilot is the main type for the component that decide what correction to apply depending
// on the provided course and setpoint and various other configuration parameters
type Pilot struct {
	heading       float64 // target heading (set point)
	headingOffset float64
	bound         float64
	course        float64
	speed         float64

	alarm      Alarm
	enabled    bool
	headingSet bool

	leds map[string]bool
Example #12
0
* @Last Modified by:   Sebastien Soudan
* @Last Modified time: 2015-10-21 14:25:26
 */

package mcp4725

import (
	"bitbucket.org/gmcbay/i2c"

	"encoding/binary"

	"github.com/ssoudan/edisonIsThePilot/drivers/gpio"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/logger"
)

var log = logger.Log("mcp4725")

const (
	// writeDacCommand is the MCP4725 command to set the output
	writeDacCommand = 0x40
	// writedacEepromCommand is the MCP4725 command to set the output and store the value in the eeprom
	writedacEepromCommand = 0x60
)

// MCP4725 is a driver for the MCP4725 i2c 12 bits DAC
type MCP4725 struct {
	bus     byte
	address byte
	i2c     *i2c.I2CBus
}
Example #13
0
* @Author: Sebastien Soudan
* @Date:   2015-09-22 13:18:01
* @Last Modified by:   Sebastien Soudan
* @Last Modified time: 2015-10-22 15:13:00
 */

package conf

import (
	"github.com/spf13/viper"

	"github.com/ssoudan/edisonIsThePilot/dashboard"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/logger"
)

var log = logger.Log("conf")

// MessagePin is the mapping of pin to a message
type MessagePin struct {
	Message string
	Pin     byte
}

// MessageToPin contains the mapping of the dashboard messages to the LED pin
var MessageToPin = []MessagePin{
	{dashboard.NoGPSFix, 43},                // J19 - pin 11
	{dashboard.InvalidGPSData, 48},          // J19 - pin 6
	{dashboard.SpeedTooLow, 40},             // J19 - pin 10
	{dashboard.HeadingErrorOutOfBounds, 82}, // J19 - pin 13
	{dashboard.CorrectionAtLimit, 83},       // J19 - pin 14
}
Example #14
0
import (
	"github.com/ssoudan/edisonIsThePilot/infrastructure/logger"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/types"
)

// Warning/Error leds
const (
	NoGPSFix                = "NoGPSFix"
	InvalidGPSData          = "InvalidGPSData"
	SpeedTooLow             = "SpeedTooLow"
	HeadingErrorOutOfBounds = "HeadingErrorOutOfBounds"
	CorrectionAtLimit       = "CorrectionAtLimit"
)

var log = logger.Log("dashboard")

// Dashboard is the component that receives the alarms and warnings and enable or disable the corresponding LEDs
type Dashboard struct {
	leds       map[string]bool
	ledHandler map[string]types.Enablable

	// channels
	inputChan    chan interface{}
	shutdownChan chan interface{}
	panicChan    chan interface{}
}

// New creates a new Dashboard component
func New() *Dashboard {
	return &Dashboard{
Example #15
0
* @Author: Sebastien Soudan
* @Date:   2015-10-12 19:20:55
* @Last Modified by:   Sebastien Soudan
* @Last Modified time: 2015-10-21 12:12:32
 */

package sincos

import (
	"math"

	"github.com/ssoudan/edisonIsThePilot/drivers/mcp4725"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/logger"
)

var log = logger.Log("sincos")

// ToSinCos returns the Sine/Cosine values as expected by the Robertson autopilots (+/- 2V centered on 2.5V)
func ToSinCos(theta uint16) (uint16, uint16) {
	s, c := math.Sincos(float64(theta) * math.Pi / 180)

	// MCP4725 is a 12 bits DAC between 0 and Vcc(=5V)
	sf := float64(0xfff) * (0.5 + 0.4*s)
	cf := float64(0xfff) * (0.5 + 0.4*c)

	return uint16(sf), uint16(cf)
}

// SinCos is a Sine/Cosine interace -- based on two MCP4725 DACs -- as used by AP100 autopilot to get the heading
type SinCos struct {
	sin *mcp4725.MCP4725
Example #16
0
* @Last Modified by:   Sebastien Soudan
* @Last Modified time: 2015-10-21 14:21:42
 */

package main

import (
	"time"

	"github.com/ssoudan/edisonIsThePilot/alarm"
	"github.com/ssoudan/edisonIsThePilot/conf"
	"github.com/ssoudan/edisonIsThePilot/drivers/pwm"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/logger"
)

var log = logger.Log("alarmControl")

func main() {

	panicChan := make(chan interface{})
	go func() {
		select {
		case m := <-panicChan:
			log.Fatal("Received a panic error - exiting: %v", m)
		}
	}()

	////////////////////////////////////////
	// a nice and delicate alarm
	////////////////////////////////////////
	alarmPwm := func(pin byte, pwmId byte) *pwm.Pwm {
Example #17
0
* @Date:   2015-09-21 18:58:22
* @Last Modified by:   Sebastien Soudan
* @Last Modified time: 2015-10-21 13:09:34
 */

package motor

import (
	"time"

	"github.com/ssoudan/edisonIsThePilot/drivers/gpio"
	"github.com/ssoudan/edisonIsThePilot/drivers/pwm"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/logger"
)

var log = logger.Log("motor")

// Motor is a driver for a stepper motor
type Motor struct {
	dirGPIO gpio.Gpio

	sleepGPIO gpio.Gpio
	stepPwm   *pwm.Pwm
}

func check(err error) {
	if err != nil {
		log.Fatal(err)
	}
}
* @Last Modified by:   Sebastien Soudan
* @Last Modified time: 2015-09-25 11:59:31
 */

package main

import (
	"fmt"
	"github.com/ssoudan/edisonIsThePilot/conf"
	"github.com/ssoudan/edisonIsThePilot/drivers/motor"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/logger"
	"math"
	"time"
)

var log = logger.Log("motorCalibration")

var numberOfSteps = float64(200)

func rotationInDegreeToMove(speed uint32, rotationInDegree float64) (clockwise bool, duration time.Duration) {
	clockwise = rotationInDegree > 0.
	duration = time.Duration(
		math.Abs(rotationInDegree/360.*numberOfSteps/float64(speed)) * float64(time.Second))

	return
}
func doStep(motor *motor.Motor, s step) {

	clockwise, duration := rotationInDegreeToMove(s.stepsBySecond, s.rotationInDegree)

	motor.Enable()
Example #19
0
* @Date:   2015-09-21 17:40:00
* @Last Modified by:   Sebastien Soudan
* @Last Modified time: 2015-10-21 12:31:39
 */

package steering

import (
	"math"
	"time"

	"github.com/ssoudan/edisonIsThePilot/infrastructure/logger"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/types"
)

var log = logger.Log("steering")

const (
	numberOfSteps                 = 200
	rotationSpeedInStepPerSeconds = 2 * numberOfSteps // aka 2 rotation per second
)

// Steering is the component driving the steering wheel through an Actionner
type Steering struct {
	actionner Actionner

	// channels
	inputChan    chan interface{}
	shutdownChan chan interface{}
	panicChan    chan interface{}
}
	"github.com/ssoudan/edisonIsThePilot/dashboard"
	"github.com/ssoudan/edisonIsThePilot/drivers/gpio"
	"github.com/ssoudan/edisonIsThePilot/drivers/motor"
	"github.com/ssoudan/edisonIsThePilot/drivers/pwm"
	"github.com/ssoudan/edisonIsThePilot/drivers/sincos"
	"github.com/ssoudan/edisonIsThePilot/gps"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/logger"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/pid"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/utils"
	"github.com/ssoudan/edisonIsThePilot/infrastructure/webserver"
	"github.com/ssoudan/edisonIsThePilot/pilot"
	"github.com/ssoudan/edisonIsThePilot/steering"
	"github.com/ssoudan/edisonIsThePilot/tracer"
)

var log = logger.Log("edisonIsThePilot")

// Version is the version of this code -- sets at compilation time
var Version = "unknown"

func main() {
	log.Info("Starting -- version %s", Version)

	panicChan := make(chan interface{})
	defer func() {
		if r := recover(); r != nil {
			panicChan <- r
		}
	}()

	go func() {