Merge branch 'esp32' into 'master'
Esp32 See merge request vato007/picar!5
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -32,4 +32,6 @@ SwiftyCar/Sources/SwiftyCar/car
|
||||
xcuserdata/
|
||||
.settings
|
||||
.project
|
||||
.classpath
|
||||
.classpath
|
||||
|
||||
.vscode/settings.json
|
||||
@@ -15,6 +15,12 @@ build_pycar_docker:
|
||||
- echo ${DOCKER_PASSWORD} | docker login vato.ddns.net:8083 --username ${DOCKER_USERNAME} --password-stdin
|
||||
- docker build -f pycar/Dockerfile --build-arg PYPI_USERNAME=${PYPI_USERNAME} --build-arg PYPI_PASSWORD=${PYPI_PASSWORD} -t vato.ddns.net:8082/pycar:latest pycar
|
||||
|
||||
build_esp32:
|
||||
image: vato.ddns.net:8083/shaguarger/platformio
|
||||
stage: build
|
||||
script:
|
||||
- platformio ci --project-conf esp32/platformio.ini esp32
|
||||
|
||||
deploy_pycar:
|
||||
image: vato.ddns.net:8083/python-infra:buster
|
||||
stage: deploy
|
||||
|
||||
18
.idea/codeStyles/Project.xml
generated
18
.idea/codeStyles/Project.xml
generated
@@ -1,5 +1,23 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<JetCodeStyleSettings>
|
||||
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
||||
<value>
|
||||
<package name="java.util" alias="false" withSubpackages="false" />
|
||||
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
|
||||
<package name="io.ktor" alias="false" withSubpackages="true" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="PACKAGES_IMPORT_LAYOUT">
|
||||
<value>
|
||||
<package name="" alias="false" withSubpackages="true" />
|
||||
<package name="java" alias="false" withSubpackages="true" />
|
||||
<package name="javax" alias="false" withSubpackages="true" />
|
||||
<package name="kotlin" alias="false" withSubpackages="true" />
|
||||
<package name="" alias="true" withSubpackages="true" />
|
||||
</value>
|
||||
</option>
|
||||
</JetCodeStyleSettings>
|
||||
<codeStyleSettings language="XML">
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
|
||||
3
.idea/gradle.xml
generated
3
.idea/gradle.xml
generated
@@ -11,9 +11,10 @@
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/CarControlleriOS" />
|
||||
<option value="$PROJECT_DIR$/SwiftyCar" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
<option value="$PROJECT_DIR$/car" />
|
||||
<option value="$PROJECT_DIR$/protobuf" />
|
||||
<option value="$PROJECT_DIR$/pycar" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
|
||||
3
.vscode/launch.json
vendored
3
.vscode/launch.json
vendored
@@ -10,7 +10,8 @@
|
||||
"request": "launch",
|
||||
"module": "car",
|
||||
"env": {
|
||||
"CAR_VEHICLE": "CAR_MOCK",
|
||||
"CAR_VEHICLE": "VEHICLE_MOCK",
|
||||
// "CAR_VEHICLE": "VEHICLE_SERIAL",
|
||||
// "CAR_LIDAR": "/dev/tty.usbserial-0001",
|
||||
"CAR_LIDAR": "LIDAR_MOCK"
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
"repositoryURL": "https://github.com/grpc/grpc-swift.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "b83ee1ee2caa0660eb02444977b9b6e353c2adbf",
|
||||
"version": "1.0.0-alpha.12"
|
||||
"revision": "640b0ef1d0be63bda0ada86786cfda678ab2aae9",
|
||||
"version": "1.0.0-alpha.19"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -15,8 +15,8 @@
|
||||
"repositoryURL": "https://github.com/apple/swift-log.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "74d7b91ceebc85daf387ebb206003f78813f71aa",
|
||||
"version": "1.2.0"
|
||||
"revision": "173f567a2dfec11d74588eea82cecea555bdc0bc",
|
||||
"version": "1.4.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -24,8 +24,8 @@
|
||||
"repositoryURL": "https://github.com/apple/swift-nio.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "40bdad80882d307abe2c0bb36cf3bd4d3e03fe04",
|
||||
"version": "2.16.1"
|
||||
"revision": "5fc24345f92ec4c274121776c215ab0aa1ed4d50",
|
||||
"version": "2.22.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -33,8 +33,8 @@
|
||||
"repositoryURL": "https://github.com/apple/swift-nio-http2.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "82eb3fa0974b838358ee46bc6c5381e5ae5de6b9",
|
||||
"version": "1.11.0"
|
||||
"revision": "1e68e51752be0b43c5a0ef35818c1dd24d13e77c",
|
||||
"version": "1.14.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -42,8 +42,8 @@
|
||||
"repositoryURL": "https://github.com/apple/swift-nio-ssl.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "ae213938e151964aa691f0e902462fbe06baeeb6",
|
||||
"version": "2.7.1"
|
||||
"revision": "ea1dfd64193bf5af4490635a4a44c4fb43b1e1ae",
|
||||
"version": "2.9.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -51,8 +51,8 @@
|
||||
"repositoryURL": "https://github.com/apple/swift-nio-transport-services.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "85a67aea7caf5396ed599543dd23cffeb6dbbf96",
|
||||
"version": "1.5.1"
|
||||
"revision": "bb56586c4cab9a79dce6ec4738baddb5802c5de7",
|
||||
"version": "1.9.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -60,8 +60,35 @@
|
||||
"repositoryURL": "https://github.com/apple/swift-protobuf.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "7790acf0a81d08429cb20375bf42a8c7d279c5fe",
|
||||
"version": "1.8.0"
|
||||
"revision": "0279688c9fc5a40028e1b5bb0cb56534a45a6020",
|
||||
"version": "1.12.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "Swift2dCar",
|
||||
"repositoryURL": "https://vato.ddns.net/gitlab/vato007/swift2dcar.git",
|
||||
"state": {
|
||||
"branch": "master",
|
||||
"revision": "970aac902531408614db0a37a7300e9373dafb50",
|
||||
"version": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "SwiftRPLidar",
|
||||
"repositoryURL": "https://vato.ddns.net/gitlab/vato007/swiftrplidar.git",
|
||||
"state": {
|
||||
"branch": "master",
|
||||
"revision": "761eb0bc1a00b4627a7870ffac121a542ff0cd6b",
|
||||
"version": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "SwiftSerial",
|
||||
"repositoryURL": "https://vato.ddns.net/gitlab/vato007/SwiftSerial.git",
|
||||
"state": {
|
||||
"branch": "master",
|
||||
"revision": "27a5d92aa00f6e91581389485994364e16bed2c5",
|
||||
"version": null
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -69,8 +96,8 @@
|
||||
"repositoryURL": "https://github.com/uraimo/SwiftyGPIO.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "4127ff9dd5c6aa8acb6be34b7ce2af2f6e0b942d",
|
||||
"version": "1.1.14"
|
||||
"revision": "2038228e020cf12a62012b1ebe36bb9b8e6fdb6a",
|
||||
"version": "1.2.5"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -14,7 +14,7 @@ let package = Package(
|
||||
.package(url: "https://github.com/grpc/grpc-swift.git", from: "1.0.0-alpha.19"),
|
||||
.package(url: "https://github.com/uraimo/SwiftyGPIO.git", from: "1.0.0"),
|
||||
.package(url: "https://vato.ddns.net/gitlab/vato007/swiftrplidar.git", .branch("master")),
|
||||
.package(url: "https://vato.ddns.net/gitlab/vato007/SwiftSerial.git", .branch("dtr_support")),
|
||||
.package(url: "https://vato.ddns.net/gitlab/vato007/SwiftSerial.git", .branch("master")),
|
||||
.package(url: "https://vato.ddns.net/gitlab/vato007/swift2dcar.git", .branch("master"))
|
||||
],
|
||||
targets: [
|
||||
@@ -22,7 +22,12 @@ let package = Package(
|
||||
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
|
||||
.target(
|
||||
name: "SwiftyCar",
|
||||
dependencies: ["SwiftyGPIO", .product(name: "GRPC", package: "grpc-swift"), "SwiftRPLidar", "SwiftSerial", "Swift2dCar"]),
|
||||
dependencies: [
|
||||
"SwiftyGPIO",
|
||||
.product(name: "GRPC", package: "grpc-swift"),
|
||||
"SwiftRPLidar",
|
||||
"SwiftSerial",
|
||||
"Swift2dCar"]),
|
||||
.testTarget(
|
||||
name: "SwiftyCarTests",
|
||||
dependencies: ["SwiftyCar"]),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// File.swift
|
||||
// VehicleFactory.swift
|
||||
//
|
||||
//
|
||||
// Created by Michael Pivato on 20/5/20.
|
||||
@@ -8,16 +8,35 @@
|
||||
import Foundation
|
||||
import SwiftyGPIO
|
||||
import Swift2dCar
|
||||
import SwiftSerial
|
||||
|
||||
func getVehicle2D() throws -> Vehicle2D {
|
||||
func getVehicle2D() throws -> Vehicle2D? {
|
||||
// TODO: Clean up this factory, or see if we can get dependency injection working.
|
||||
if let value = ProcessInfo.processInfo.environment["CAR_VEHICLE"] {
|
||||
switch value{
|
||||
case "CAR_2D":
|
||||
case "VEHICLE_2D":
|
||||
// Get car for rpi.
|
||||
let pwms = SwiftyGPIO.hardwarePWMs(for:.RaspberryPi3)!
|
||||
|
||||
// Read the feature database.
|
||||
return try RPiVehicle2D(withThrottlePin: PWMHardwareServo(forPin: (pwms[0]?[.P18])!)!, withSteeringPin:PWMHardwareServo(forPin: (pwms[1]?[.P19])!)!)
|
||||
case "VEHICLE_SERIAL":
|
||||
// TODO: Get from environment variable. tty won't work in macos anyway.
|
||||
// We share the serialport object, as cu will block on macOS (required by SwiftSerial), so can't open 2 of the same port.
|
||||
let serialPort = SerialPort(path: "/dev/ttyUSB0")
|
||||
|
||||
// The port does not open/initialise inside of the ESP32ServoOutputs, as on macOS /dev/cu.* blocks.
|
||||
try initPort.openPort()
|
||||
initPort.setSettings(receiveRate: .baud115200, transmitRate: .baud115200, minimumBytesToRead: 1)x
|
||||
guard let throttlePin = Esp32ServoOutput(forChannel: 1, forPin: 14, onPort: serialPort) else {
|
||||
print("Failed to create throttle pin.")
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let steeringPin = Esp32ServoOutput(forChannel: 2, forPin: 12, onPort: serialPort) else {
|
||||
print("Failed to create steering pin.")
|
||||
return nil
|
||||
}
|
||||
|
||||
return try RPiVehicle2D(withThrottlePin: PWMHardwareServo(forPin: throttlePin)!, withSteeringPin: PWMHardwareServo(forPin: steeringPin)!)
|
||||
default:
|
||||
return MockVehicle()
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ func doServer() throws {
|
||||
return false
|
||||
}
|
||||
// Create a provider using the features we read.
|
||||
let provider = try MotorProvider(vehicle: getVehicle2D())
|
||||
let provider = try MotorProvider(vehicle: getVehicle2D()!)
|
||||
let trackingProvider = LidarProvider(lidar: lidar)
|
||||
|
||||
// Start the server and print its address once it has started.
|
||||
|
||||
5
esp32/.gitignore
vendored
Normal file
5
esp32/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
7
esp32/.vscode/extensions.json
vendored
Normal file
7
esp32/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
]
|
||||
}
|
||||
28
esp32/README.md
Normal file
28
esp32/README.md
Normal file
@@ -0,0 +1,28 @@
|
||||
This module includes an arduino sketch designed to run on the ESP32.
|
||||
|
||||
The sketch takes simple input from serial (ESP32 microusb port), and converts the input to a duty cycle that can be used on servos.
|
||||
|
||||
The protocol specification is as follows, assuming an array of bytes:
|
||||
|
||||
|
||||
| Byte Number | Value Description |
|
||||
| :---------- | ----------: |
|
||||
| 0 | 0 if Calibrating a servo. Higher values indicates channel number to set duty cycle on. |
|
||||
| 1 | If byte 0 = 0: number of servos to calibrate. Else, the new duty cycle value for the channel specified in byte 0. |
|
||||
|
||||
When setting the duty cycle, the current min angle is 0, and the max angle is 255, which allows the entire byte to be used for setting the duty cycle.
|
||||
|
||||
The table below describes the byte format for calibrating a servo. This array of bytes can be repeated for the given number of servos in byte 1:
|
||||
|
||||
| Byte Number | Value Description |
|
||||
| :---------- | ----------: |
|
||||
| 0 | Servo channel to set (this will be byte 0 when setting duty cycle, so don't use 0). |
|
||||
| 1 | The pin number to setup |
|
||||
|
||||
The min/max pulse widths are hardcoded to 1000us/2000us respectively.
|
||||
|
||||
At the end of each loop, the entire array will be read, to flush any data that may cause issues later.
|
||||
|
||||
Upcoming (TODO):
|
||||
- Use bit shift to allow 12 bits to be used for the duty cycle range, as there can only be a max of 16 channels anyway (4 bits).
|
||||
- Consider protobuf or msgpack for serialisation format, for more advanced use cases, and more maintainable communication formats (currently changing the message format will require changes to the entire protocol)
|
||||
39
esp32/include/README
Normal file
39
esp32/include/README
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
||||
46
esp32/lib/README
Normal file
46
esp32/lib/README
Normal file
@@ -0,0 +1,46 @@
|
||||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
||||
15
esp32/platformio.ini
Normal file
15
esp32/platformio.ini
Normal file
@@ -0,0 +1,15 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:esp32doit-devkit-v1]
|
||||
platform = espressif32
|
||||
board = esp32doit-devkit-v1
|
||||
framework = arduino
|
||||
lib_deps = roboticsbrno/ServoESP32@^1.0.3
|
||||
59
esp32/src/main.cpp
Normal file
59
esp32/src/main.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <map>
|
||||
#include "Servo.h"
|
||||
|
||||
// Min/max widths, used to calculate min/max duty cycles.
|
||||
#define MIN_PULSE_WIDTH 1000
|
||||
#define MAX_PULSE_WIDTH 2000
|
||||
|
||||
#define MIN_ANGLE 0
|
||||
#define MAX_ANGLE 255
|
||||
|
||||
std::map<uint8_t, Servo *> servos;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
}
|
||||
|
||||
void setupServos(uint8_t size, uint8_t *calibrationValues)
|
||||
{
|
||||
// We assume there are 3 bytes per servo. Ignore if there aren't.
|
||||
if (size % 3 == 0)
|
||||
{
|
||||
for (int i = 0; i < size; i += 2)
|
||||
{
|
||||
Servo *newServo = new Servo();
|
||||
newServo->attach(calibrationValues[i + 1], calibrationValues[i], MIN_ANGLE, MAX_ANGLE, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
|
||||
servos.insert(std::make_pair(calibrationValues[i], newServo));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void modifyServo(uint8_t channel, uint8_t newAngle)
|
||||
{
|
||||
if(servos.count(channel) > 0){
|
||||
servos[channel]->write(newAngle);
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint8_t *header = new uint8_t[2];
|
||||
Serial.readBytes(header, 2);
|
||||
|
||||
if (header[0] == 0)
|
||||
{
|
||||
uint8_t *calibration = new uint8_t[2 * header[1]];
|
||||
Serial.readBytes(calibration, header[1]);
|
||||
setupServos(header[1], calibration);
|
||||
delete [] calibration;
|
||||
}
|
||||
else
|
||||
{
|
||||
modifyServo(header[0], header[1]);
|
||||
}
|
||||
|
||||
delete [] header;
|
||||
}
|
||||
11
esp32/test/README
Normal file
11
esp32/test/README
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
This directory is intended for PlatformIO Unit Testing and project tests.
|
||||
|
||||
Unit Testing is a software testing method by which individual units of
|
||||
source code, sets of one or more MCU program modules together with associated
|
||||
control data, usage procedures, and operating procedures, are tested to
|
||||
determine whether they are fit for use. Unit testing finds problems early
|
||||
in the development cycle.
|
||||
|
||||
More information about PlatformIO Unit Testing:
|
||||
- https://docs.platformio.org/page/plus/unit-testing.html
|
||||
26
pycar/src/car/control/gpio/abstract_vehicle.py
Normal file
26
pycar/src/car/control/gpio/abstract_vehicle.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from abc import ABC, abstractmethod, abstractproperty
|
||||
|
||||
class AbstractVehicle(ABC):
|
||||
|
||||
@abstractmethod
|
||||
@property
|
||||
def throttle(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
@throttle.setter
|
||||
def throttle(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
@property
|
||||
def steering(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
@steering.setter
|
||||
def throttle(self):
|
||||
pass
|
||||
|
||||
def stop(self):
|
||||
pass
|
||||
@@ -1,18 +1,25 @@
|
||||
from car.control.gpio.abstract_vehicle import AbstractVehicle
|
||||
from car.control.gpio.serial_vehicle import SerialVehicle
|
||||
from .mockvehicle import MockVehicle
|
||||
import os
|
||||
|
||||
|
||||
def get_vehicle(motor_pin=19, steering_pin=18):
|
||||
# TODO: Remove need for motor/steering pin, instead retrieve from env variable.
|
||||
# TODO: Dependency injectino in python?
|
||||
def get_vehicle(motor_pin=19, steering_pin=18) -> AbstractVehicle:
|
||||
ENV_CAR = None if 'CAR_VEHICLE' not in os.environ else os.environ['CAR_VEHICLE']
|
||||
if ENV_CAR == "CAR_2D":
|
||||
if ENV_CAR == "VEHICLE_2D":
|
||||
try:
|
||||
from .vehicle import Vehicle
|
||||
return Vehicle(motor_pin, steering_pin)
|
||||
except ImportError:
|
||||
print(
|
||||
'Could not import CAR_2D vehicle. Have you installed the GPIOZERO package?')
|
||||
elif ENV_CAR == "CAR_MOCK":
|
||||
return MockVehicle(motor_pin, steering_pin)
|
||||
elif ENV_CAR == "VEHICLE_MOCK":
|
||||
return MockVehicle()
|
||||
elif ENV_CAR == "VEHICLE_SERIAL":
|
||||
# TODO: Pins in environment variables.
|
||||
return SerialVehicle()
|
||||
else:
|
||||
print('No valid vehicle found. Have you set the CAR_VEHICLE environment variable?')
|
||||
return None
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
|
||||
|
||||
# A dummy vehicle class to use when
|
||||
class MockVehicle:
|
||||
def __init__(self, motor_pin=19, servo_pin=18):
|
||||
self.motor_pin = motor_pin
|
||||
self.steering_pin = servo_pin
|
||||
# A dummy vehicle class to use when testing/not connected to a real device.
|
||||
from car.control.gpio.abstract_vehicle import AbstractVehicle
|
||||
|
||||
|
||||
class MockVehicle(AbstractVehicle):
|
||||
def __init__(self):
|
||||
print('Using Mock Vehicle')
|
||||
|
||||
@property
|
||||
@@ -23,21 +24,5 @@ class MockVehicle:
|
||||
def steering(self, value):
|
||||
self._steering = value
|
||||
|
||||
@property
|
||||
def motor_pin(self):
|
||||
return self._motor_pin
|
||||
|
||||
@motor_pin.setter
|
||||
def motor_pin(self, value):
|
||||
self._motor_pin = value
|
||||
|
||||
@property
|
||||
def steering_pin(self):
|
||||
return self._steering_pin
|
||||
|
||||
@steering_pin.setter
|
||||
def steering_pin(self, value):
|
||||
self._steering_pin = value
|
||||
|
||||
def stop(self):
|
||||
self.throttle = 0
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import datetime
|
||||
from .abstract_vehicle import AbstractVehicle
|
||||
|
||||
|
||||
class VehicleRecordingDecorator:
|
||||
class VehicleRecordingDecorator(AbstractVehicle):
|
||||
def __init__(self, vehicle):
|
||||
"""
|
||||
A decorator for a vehicle object to record the changes in steering/throttle.
|
||||
This will be recorded to memory, and will save to the given file when save is called.
|
||||
This will be recorded to memory, and will save to the given file when save_data is called.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@@ -66,21 +67,5 @@ class VehicleRecordingDecorator:
|
||||
's,' + str(value) + ',' + datetime.datetime.now().isoformat(sep=' ', timespec='seconds'))
|
||||
self._vehicle.steering = value
|
||||
|
||||
@property
|
||||
def motor_pin(self):
|
||||
return self._vehicle.motor_pin
|
||||
|
||||
@motor_pin.setter
|
||||
def motor_pin(self, value):
|
||||
self._vehicle.motor_pin = value
|
||||
|
||||
@property
|
||||
def steering_pin(self):
|
||||
return self._vehicle.steering_pin
|
||||
|
||||
@steering_pin.setter
|
||||
def steering_pin(self, value):
|
||||
self._vehicle.steering_pin = value
|
||||
|
||||
def stop(self):
|
||||
self.throttle = 0
|
||||
|
||||
42
pycar/src/car/control/gpio/serial_vehicle.py
Normal file
42
pycar/src/car/control/gpio/serial_vehicle.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from .abstract_vehicle import AbstractVehicle
|
||||
from serial import Serial
|
||||
|
||||
STEERING_CHANNEL = 1
|
||||
THROTTLE_CHANNEL = 2
|
||||
|
||||
|
||||
class SerialVehicle(AbstractVehicle):
|
||||
|
||||
def __init__(self, serial_port='/dev/ttyUSB0', steering_pin=12, throttle_pin=14):
|
||||
self.serial_port = Serial(port=serial_port, baudrate=115200)
|
||||
|
||||
# Initialise the channels and pins on esp32.
|
||||
self._init_esp32_pwm(steering_pin, throttle_pin)
|
||||
self.throttle = 0
|
||||
self.steering = 0
|
||||
|
||||
@property
|
||||
def throttle(self) -> float:
|
||||
return self.throttle
|
||||
|
||||
@throttle.setter
|
||||
def throttle(self, new_throttle: float):
|
||||
self.throttle = new_throttle
|
||||
self._set_servo_value(THROTTLE_CHANNEL, new_throttle)
|
||||
|
||||
@property
|
||||
def steering(self) -> float:
|
||||
return self.steering
|
||||
|
||||
@steering.setter
|
||||
def steering(self, new_steering: float):
|
||||
self.steering = new_steering
|
||||
self._set_servo_value(STEERING_CHANNEL, new_steering)
|
||||
|
||||
def _set_servo_value(self, channel, value):
|
||||
# Scale the value to a byte, as 0-255 is the angle range for the esp32 servo.
|
||||
self.serial_port.write(bytes[channel, (value + 1) / 2 * 255])
|
||||
|
||||
def _init_esp32_pwm(self, steering_pin, throttle_pin):
|
||||
self.serial_port.write(bytes([0, 2, STEERING_CHANNEL,
|
||||
steering_pin, THROTTLE_CHANNEL, throttle_pin]))
|
||||
@@ -1,3 +1,4 @@
|
||||
from .abstract_vehicle import AbstractVehicle
|
||||
from gpiozero import Servo, Device
|
||||
from gpiozero.pins.pigpio import PiGPIOFactory
|
||||
import subprocess
|
||||
@@ -29,7 +30,7 @@ def _is_pin_valid(pin):
|
||||
# two servos for controls (e.g. drone, dog)
|
||||
|
||||
|
||||
class Vehicle:
|
||||
class Vehicle(AbstractVehicle):
|
||||
def __init__(self, motor_pin=19, servo_pin=18):
|
||||
subprocess.call(['pigpiod'])
|
||||
Device.pin_factory = PiGPIOFactory()
|
||||
|
||||
Reference in New Issue
Block a user