Some camera controls
This commit is contained in:
		@@ -23,6 +23,13 @@ Ping = {
 | 
				
			|||||||
	payload = nil,
 | 
						payload = nil,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ControllerState = {
 | 
				
			||||||
 | 
						viewX = 0,
 | 
				
			||||||
 | 
						viewY = 0,
 | 
				
			||||||
 | 
						viewChanged = false,
 | 
				
			||||||
 | 
						viewLastUpdated = 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function love.update2()
 | 
					function love.update2()
 | 
				
			||||||
	local now = love.timer.getTime()
 | 
						local now = love.timer.getTime()
 | 
				
			||||||
	if now - Ping.timeSent > 5 then
 | 
						if now - Ping.timeSent > 5 then
 | 
				
			||||||
@@ -34,6 +41,24 @@ function love.update2()
 | 
				
			|||||||
		love.mqtt.send("command/ping", Ping.payload)
 | 
							love.mqtt.send("command/ping", Ping.payload)
 | 
				
			||||||
		print("Sending ping")
 | 
							print("Sending ping")
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
						if ControllerState.viewChanged and (now - ControllerState.viewLastUpdated) >= 0.05 then
 | 
				
			||||||
 | 
							love.mqtt.send("command/set_camera_xy", toJSON({
 | 
				
			||||||
 | 
								x = -ControllerState.viewX * 0.3 + 0.5,
 | 
				
			||||||
 | 
								y = -ControllerState.viewY * 0.3 + 0.5
 | 
				
			||||||
 | 
							}))
 | 
				
			||||||
 | 
							ControllerState.viewChanged = false
 | 
				
			||||||
 | 
							ControllerState.viewLastUpdated = now
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function love.joystickaxis2(joystick, axis, value)
 | 
				
			||||||
 | 
						if axis == 3 and value ~= ControllerState.viewX then
 | 
				
			||||||
 | 
							ControllerState.viewX = value
 | 
				
			||||||
 | 
							ControllerState.viewChanged = true
 | 
				
			||||||
 | 
						elseif axis == 4 and value ~= ControllerState.viewY then
 | 
				
			||||||
 | 
							ControllerState.viewY = value
 | 
				
			||||||
 | 
							ControllerState.viewChanged = true
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function formatSafe(format, value, ...)
 | 
					function formatSafe(format, value, ...)
 | 
				
			||||||
@@ -81,3 +106,22 @@ function love.gamepadpressed2(joystick, button)
 | 
				
			|||||||
		UIState.showUI = not UIState.showUI
 | 
							UIState.showUI = not UIState.showUI
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function toJSON(arg)
 | 
				
			||||||
 | 
						local t = type(arg)
 | 
				
			||||||
 | 
						if t == "number" then
 | 
				
			||||||
 | 
							return tostring(arg)
 | 
				
			||||||
 | 
						elseif t == "nil" then
 | 
				
			||||||
 | 
							return "null"
 | 
				
			||||||
 | 
						elseif t == "string" then
 | 
				
			||||||
 | 
							return '"' .. arg .. '"'
 | 
				
			||||||
 | 
						elseif t == "boolean" then
 | 
				
			||||||
 | 
							return tostring(arg)
 | 
				
			||||||
 | 
						elseif t == "table" then
 | 
				
			||||||
 | 
							local fields = {}
 | 
				
			||||||
 | 
							for key, value in pairs(arg) do
 | 
				
			||||||
 | 
								fields[#fields+1] = string.format('"%s":%s', key, toJSON(value))
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
							return '{' .. table.concat(fields, ',') .. '}'
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@ local oldPrint = print
 | 
				
			|||||||
function print(...)
 | 
					function print(...)
 | 
				
			||||||
	local string = ""
 | 
						local string = ""
 | 
				
			||||||
	for _, v in ipairs({...}) do
 | 
						for _, v in ipairs({...}) do
 | 
				
			||||||
		string = string .. v
 | 
							string = string .. tostring(v)
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
	love.mqtt.send("controller/stdout", string)
 | 
						love.mqtt.send("controller/stdout", string)
 | 
				
			||||||
	oldPrint(...)
 | 
						oldPrint(...)
 | 
				
			||||||
@@ -86,6 +86,12 @@ function love.gamepadpressed(joystick, button)
 | 
				
			|||||||
	end
 | 
						end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function love.joystickaxis(joystick, axis, value)
 | 
				
			||||||
 | 
						if love.joystickaxis2 then
 | 
				
			||||||
 | 
							safeCall(love.joystickaxis2, joystick, axis, value)
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function love.mqtt.onError(message)
 | 
					function love.mqtt.onError(message)
 | 
				
			||||||
	print("MQTT error: " .. message)
 | 
						print("MQTT error: " .. message)
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,18 +2,16 @@ package main
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"gobot.io/x/gobot/drivers/i2c"
 | 
						"gobot.io/x/gobot/drivers/i2c"
 | 
				
			||||||
	"gobot.io/x/gobot/platforms/raspi"
 | 
					 | 
				
			||||||
	"log"
 | 
						"log"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var rpi *raspi.Adaptor
 | 
					 | 
				
			||||||
var ads *ADS7830
 | 
					var ads *ADS7830
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//var mpu *i2c.MPU6050Driver
 | 
					//var mpu *i2c.MPU6050Driver
 | 
				
			||||||
//mpu = i2c.NewMPU6050Driver(rpi, i2c.WithBus(0), i2c.WithAddress(0x40))
 | 
					//mpu = i2c.NewMPU6050Driver(rpi, i2c.WithBus(0), i2c.WithAddress(0x40))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func InitBattery() {
 | 
					func InitBattery() {
 | 
				
			||||||
	rpi = raspi.NewAdaptor()
 | 
						rpi := GetAdaptor()
 | 
				
			||||||
	rpi.Connect()
 | 
						rpi.Connect()
 | 
				
			||||||
	ads = NewADS7830(rpi, i2c.WithBus(1), i2c.WithAddress(0x48))
 | 
						ads = NewADS7830(rpi, i2c.WithBus(1), i2c.WithAddress(0x48))
 | 
				
			||||||
	ads.Start()
 | 
						ads.Start()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	mqtt "github.com/eclipse/paho.mqtt.golang"
 | 
						mqtt "github.com/eclipse/paho.mqtt.golang"
 | 
				
			||||||
	"log"
 | 
						"log"
 | 
				
			||||||
@@ -44,10 +45,41 @@ func onPing(client mqtt.Client, msg mqtt.Message) {
 | 
				
			|||||||
	publishTelemetry(client, "pong", msg.Payload())
 | 
						publishTelemetry(client, "pong", msg.Payload())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func onSetCameraXY(client mqtt.Client, msg mqtt.Message) {
 | 
				
			||||||
 | 
						log.Print("Got move camera")
 | 
				
			||||||
 | 
						payload := make(map[string]float64)
 | 
				
			||||||
 | 
						err := json.Unmarshal(msg.Payload(), &payload)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Printf("Error unmarshalling set_camera_xy payload: %v\n", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						x, ok := payload["x"]
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							log.Printf("Missing x in set_camera_xy")
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						y, ok := payload["y"]
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							log.Printf("Missing y in set_camera_xy")
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						SetServoAngle(ServoHeadHorizontal, x)
 | 
				
			||||||
 | 
						SetServoAngle(ServoHeadVertical, y)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func subscribe(client mqtt.Client, topic string, handler mqtt.MessageHandler) {
 | 
				
			||||||
 | 
						token := client.Subscribe(topic, 0, handler)
 | 
				
			||||||
 | 
						token.Wait()
 | 
				
			||||||
 | 
						if token.Error() != nil {
 | 
				
			||||||
 | 
							log.Fatalf("Failed to subscribe to command topic: %v\n", token.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
	opts := mqtt.NewClientOptions()
 | 
						opts := mqtt.NewClientOptions()
 | 
				
			||||||
	opts.AddBroker(broker)
 | 
						opts.AddBroker(broker)
 | 
				
			||||||
	opts.SetClientID("spider-host-client")
 | 
						opts.SetClientID("spider-host-client")
 | 
				
			||||||
 | 
						opts.SetResumeSubs(true)
 | 
				
			||||||
	client := mqtt.NewClient(opts)
 | 
						client := mqtt.NewClient(opts)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	token := client.Connect()
 | 
						token := client.Connect()
 | 
				
			||||||
@@ -57,22 +89,30 @@ func main() {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log.Print("Subscribing to command topics")
 | 
						log.Print("Subscribing to command topics")
 | 
				
			||||||
	token = client.Subscribe("spider/command/ping", 0, onPing)
 | 
						subscribe(client, "spider/command/ping", onPing)
 | 
				
			||||||
	token.Wait()
 | 
						subscribe(client, "spider/command/set_camera_xy", onSetCameraXY)
 | 
				
			||||||
	if token.Error() != nil {
 | 
					 | 
				
			||||||
		log.Fatalf("Failed to subscribe to command topic: %v\n", token.Error())
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	InitBattery()
 | 
						InitBattery()
 | 
				
			||||||
 | 
						InitServo()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ServosOff()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	slowTelemetry := time.NewTicker(3 * time.Second)
 | 
						slowTelemetry := time.NewTicker(3 * time.Second)
 | 
				
			||||||
	defer slowTelemetry.Stop()
 | 
						defer slowTelemetry.Stop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//moveServo := time.NewTicker(100 * time.Millisecond)
 | 
				
			||||||
 | 
						//defer moveServo.Stop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	publishSlowTelemetry(client)
 | 
						publishSlowTelemetry(client)
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
		select {
 | 
							select {
 | 
				
			||||||
		case <-slowTelemetry.C:
 | 
							case <-slowTelemetry.C:
 | 
				
			||||||
			publishSlowTelemetry(client)
 | 
								publishSlowTelemetry(client)
 | 
				
			||||||
 | 
								//case <-moveServo.C:
 | 
				
			||||||
 | 
								//	seconds := time.Now().UnixMilli()
 | 
				
			||||||
 | 
								//	angle := (math.Cos(float64(seconds)/2_500) + 1) * 0.5
 | 
				
			||||||
 | 
								//	log.Printf("Target angle: %.1f\n", angle)
 | 
				
			||||||
 | 
								//	SetServoAngle(ServoHeadHorizontal, angle)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								spider-host/rpi.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								spider-host/rpi.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "gobot.io/x/gobot/platforms/raspi"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var rpi *raspi.Adaptor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func GetAdaptor() *raspi.Adaptor {
 | 
				
			||||||
 | 
						if rpi == nil {
 | 
				
			||||||
 | 
							rpi = raspi.NewAdaptor()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return rpi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										87
									
								
								spider-host/servo.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								spider-host/servo.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,87 @@
 | 
				
			|||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"gobot.io/x/gobot/drivers/i2c"
 | 
				
			||||||
 | 
						"log"
 | 
				
			||||||
 | 
						"math"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Servo int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						ServoHeadHorizontal Servo = iota
 | 
				
			||||||
 | 
						ServoHeadVertical
 | 
				
			||||||
 | 
						ServoCount
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ServoChannel struct {
 | 
				
			||||||
 | 
						controller *i2c.PCA9685Driver
 | 
				
			||||||
 | 
						channel    int
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var servoController1 *i2c.PCA9685Driver
 | 
				
			||||||
 | 
					var servoController2 *i2c.PCA9685Driver
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// var servos = new([ServoCount]*gpio.ServoDriver)
 | 
				
			||||||
 | 
					var servos = new([ServoCount]*ServoChannel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func InitServo() {
 | 
				
			||||||
 | 
						adaptor := GetAdaptor()
 | 
				
			||||||
 | 
						servoController1 = i2c.NewPCA9685Driver(adaptor, i2c.WithBus(1), i2c.WithAddress(0x40))
 | 
				
			||||||
 | 
						servoController2 = i2c.NewPCA9685Driver(adaptor, i2c.WithBus(1), i2c.WithAddress(0x41))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						createServo(ServoHeadHorizontal, servoController2, 1)
 | 
				
			||||||
 | 
						createServo(ServoHeadVertical, servoController2, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := servoController1.Start()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Print("Could not start servo controller 1: ", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = servoController2.Start()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Print("Could not start servo controller 1: ", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = servoController1.SetPWMFreq(50)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Print("Could not set servo controller 1 frequency: ", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = servoController2.SetPWMFreq(50)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Print("Could not set servo controller 2 frequency: ", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Halt the controllers to stop any current movement
 | 
				
			||||||
 | 
						ServosOff()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func ServosOff() {
 | 
				
			||||||
 | 
						err := servoController1.Halt()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Print("Could not stop servo controller 1: ", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = servoController2.Halt()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Print("Could not stop servo controller 2: ", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SetServoAngle Sets the angle to a value of 0 - 1
 | 
				
			||||||
 | 
					func SetServoAngle(servo Servo, angle float64) {
 | 
				
			||||||
 | 
						pulseDuration := angle + 1
 | 
				
			||||||
 | 
						pulseDurationRatio := pulseDuration / 20
 | 
				
			||||||
 | 
						pulseDurationTicks := pulseDurationRatio * 4095
 | 
				
			||||||
 | 
						servoDriver := servos[servo]
 | 
				
			||||||
 | 
						err := servoDriver.controller.SetPWM(servoDriver.channel, 0, uint16(math.Floor(pulseDurationTicks)))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Printf("Could not set servo %d to angle %0.1f: %v\n", servo, angle, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func createServo(servo Servo, pwmDriver *i2c.PCA9685Driver, channel int) {
 | 
				
			||||||
 | 
						//servoDriver := gpio.NewServoDriver(pwmDriver, channel)
 | 
				
			||||||
 | 
						//servos[servo] = servoDriver
 | 
				
			||||||
 | 
						servos[servo] = &ServoChannel{
 | 
				
			||||||
 | 
							controller: pwmDriver,
 | 
				
			||||||
 | 
							channel:    channel,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user