Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
0b4611b93e
11 changed files with 453 additions and 208 deletions
254
.gitignore
vendored
Normal file
254
.gitignore
vendored
Normal file
|
@ -0,0 +1,254 @@
|
||||||
|
|
||||||
|
# Created by https://www.toptal.com/developers/gitignore/api/python,pycharm,code
|
||||||
|
# Edit at https://www.toptal.com/developers/gitignore?templates=python,pycharm,code
|
||||||
|
|
||||||
|
### Code ###
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
|
### PyCharm ###
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/**/usage.statistics.xml
|
||||||
|
.idea/**/dictionaries
|
||||||
|
.idea/**/shelf
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
.idea/**/contentModel.xml
|
||||||
|
|
||||||
|
# Sensitive or high-churn files
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
.idea/**/dbnavigator.xml
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# Gradle and Maven with auto-import
|
||||||
|
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||||
|
# since they will be recreated, and may cause churn. Uncomment if using
|
||||||
|
# auto-import.
|
||||||
|
# .idea/artifacts
|
||||||
|
# .idea/compiler.xml
|
||||||
|
# .idea/jarRepositories.xml
|
||||||
|
# .idea/modules.xml
|
||||||
|
# .idea/*.iml
|
||||||
|
# .idea/modules
|
||||||
|
# *.iml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-*/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
# File-based project format
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Editor-based Rest Client
|
||||||
|
.idea/httpRequests
|
||||||
|
|
||||||
|
# Android studio 3.1+ serialized cache file
|
||||||
|
.idea/caches/build_file_checksums.ser
|
||||||
|
|
||||||
|
### PyCharm Patch ###
|
||||||
|
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||||
|
|
||||||
|
# *.iml
|
||||||
|
# modules.xml
|
||||||
|
# .idea/misc.xml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# Sonarlint plugin
|
||||||
|
# https://plugins.jetbrains.com/plugin/7973-sonarlint
|
||||||
|
.idea/**/sonarlint/
|
||||||
|
|
||||||
|
# SonarQube Plugin
|
||||||
|
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
|
||||||
|
.idea/**/sonarIssues.xml
|
||||||
|
|
||||||
|
# Markdown Navigator plugin
|
||||||
|
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
|
||||||
|
.idea/**/markdown-navigator.xml
|
||||||
|
.idea/**/markdown-navigator-enh.xml
|
||||||
|
.idea/**/markdown-navigator/
|
||||||
|
|
||||||
|
# Cache file creation bug
|
||||||
|
# See https://youtrack.jetbrains.com/issue/JBR-2257
|
||||||
|
.idea/$CACHE_FILE$
|
||||||
|
|
||||||
|
# CodeStream plugin
|
||||||
|
# https://plugins.jetbrains.com/plugin/12206-codestream
|
||||||
|
.idea/codestream.xml
|
||||||
|
|
||||||
|
### Python ###
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
pip-wheel-metadata/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
pytestdebug.log
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
doc/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
pythonenv*
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# profiling data
|
||||||
|
.prof
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api/python,pycharm,code
|
109
compLIB/ADC.py
109
compLIB/ADC.py
|
@ -1,94 +1,35 @@
|
||||||
import smbus
|
import smbus
|
||||||
import time
|
|
||||||
|
SINGLE_ENDED = 0x84
|
||||||
|
ADDRESS = 0x48
|
||||||
|
|
||||||
|
bus = smbus.SMBus(1)
|
||||||
|
|
||||||
|
|
||||||
class Adc:
|
class ADC:
|
||||||
def __init__(self):
|
|
||||||
# Get I2C bus
|
|
||||||
self.bus = smbus.SMBus(1)
|
|
||||||
|
|
||||||
# I2C address of the device
|
@staticmethod
|
||||||
self.ADDRESS = 0x48
|
def read(channel) -> float:
|
||||||
|
"""
|
||||||
|
Read from adc channel
|
||||||
|
0 -> Left IR Sensor
|
||||||
|
1 -> Right IR Sensor
|
||||||
|
2 -> Battery voltage / 3
|
||||||
|
:param channel: Channel between 0 and 2
|
||||||
|
:return: voltage
|
||||||
|
"""
|
||||||
|
|
||||||
# PCF8591 Command
|
|
||||||
self.PCF8591_CMD = 0x40 # Command
|
|
||||||
|
|
||||||
# ADS7830 Command
|
|
||||||
self.ADS7830_CMD = 0x84 # Single-Ended Inputs
|
|
||||||
|
|
||||||
for i in range(3):
|
|
||||||
aa = self.bus.read_byte_data(self.ADDRESS, 0xf4)
|
|
||||||
if aa < 150:
|
|
||||||
self.Index = "PCF8591"
|
|
||||||
else:
|
|
||||||
self.Index = "ADS7830"
|
|
||||||
|
|
||||||
def analogReadPCF8591(self, chn): # PCF8591 read ADC value,chn:0,1,2,3
|
|
||||||
value = [0, 0, 0, 0, 0, 0, 0, 0, 0]
|
|
||||||
for i in range(9):
|
|
||||||
value[i] = self.bus.read_byte_data(self.ADDRESS, self.PCF8591_CMD + chn)
|
|
||||||
value = sorted(value)
|
|
||||||
return value[4]
|
|
||||||
|
|
||||||
# TODO: bug in original code???
|
|
||||||
#def analogWritePCF8591(self, value): # PCF8591 write DAC value
|
|
||||||
# self.bus.write_byte_data(self.ADDRESS, cmd, value)
|
|
||||||
|
|
||||||
def recvPCF8591(self, channel): # PCF8591 write DAC value
|
|
||||||
while (1):
|
|
||||||
value1 = self.analogReadPCF8591(channel) # read the ADC value of channel 0,1,2,
|
|
||||||
value2 = self.analogReadPCF8591(channel)
|
|
||||||
if value1 == value2:
|
|
||||||
break;
|
|
||||||
voltage = value1 / 256.0 * 3.3 # calculate the voltage value
|
|
||||||
voltage = round(voltage, 2)
|
|
||||||
return voltage
|
|
||||||
|
|
||||||
def recvADS7830(self, channel):
|
|
||||||
"""Select the Command data from the given provided value above"""
|
"""Select the Command data from the given provided value above"""
|
||||||
COMMAND_SET = self.ADS7830_CMD | ((((channel << 2) | (channel >> 1)) & 0x07) << 4)
|
command = SINGLE_ENDED | ((((channel << 2) | (channel >> 1)) & 0x07) << 4)
|
||||||
self.bus.write_byte(self.ADDRESS, COMMAND_SET)
|
bus.write_byte(ADDRESS, command)
|
||||||
while (1):
|
|
||||||
value1 = self.bus.read_byte(self.ADDRESS)
|
while "Koka is great":
|
||||||
value2 = self.bus.read_byte(self.ADDRESS)
|
value1 = bus.read_byte(ADDRESS)
|
||||||
|
value2 = bus.read_byte(ADDRESS)
|
||||||
if value1 == value2:
|
if value1 == value2:
|
||||||
break;
|
break
|
||||||
|
|
||||||
voltage = value1 / 255.0 * 3.3 # calculate the voltage value
|
voltage = value1 / 255.0 * 3.3 # calculate the voltage value
|
||||||
voltage = round(voltage, 2)
|
voltage = round(voltage, 2)
|
||||||
|
|
||||||
return voltage
|
return voltage
|
||||||
|
|
||||||
def recvADC(self, channel):
|
|
||||||
if self.Index == "PCF8591":
|
|
||||||
data = self.recvPCF8591(channel)
|
|
||||||
elif self.Index == "ADS7830":
|
|
||||||
data = self.recvADS7830(channel)
|
|
||||||
return data
|
|
||||||
|
|
||||||
def i2cClose(self):
|
|
||||||
self.bus.close()
|
|
||||||
|
|
||||||
|
|
||||||
def loop():
|
|
||||||
adc = Adc()
|
|
||||||
while True:
|
|
||||||
Left_IDR = adc.recvADC(0)
|
|
||||||
print(Left_IDR)
|
|
||||||
Right_IDR = adc.recvADC(1)
|
|
||||||
print(Right_IDR)
|
|
||||||
Power = adc.recvADC(2) * 3
|
|
||||||
print(Power)
|
|
||||||
time.sleep(1)
|
|
||||||
print('----')
|
|
||||||
|
|
||||||
|
|
||||||
def destroy():
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
# Main program logic follows:
|
|
||||||
if __name__ == '__main__':
|
|
||||||
print('Program is starting ... ')
|
|
||||||
try:
|
|
||||||
loop()
|
|
||||||
except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
|
|
||||||
destroy()
|
|
||||||
|
|
22
compLIB/Battery.py
Normal file
22
compLIB/Battery.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
from compLIB.ADC import ADC
|
||||||
|
|
||||||
|
|
||||||
|
BATTERY_CHANNEL = 2
|
||||||
|
BATTERY_COUNT = 2
|
||||||
|
BATTERY_MULTIPLIER = 3
|
||||||
|
BATTERY_MIN_VOLTAGE = 3.6
|
||||||
|
BATTERY_MAX_VOLTAGE = 4.1
|
||||||
|
|
||||||
|
adc = ADC()
|
||||||
|
|
||||||
|
|
||||||
|
class Battery(object):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def percent() -> int:
|
||||||
|
"""
|
||||||
|
Get battery percentage between 0 and 100
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
voltage = adc.read(BATTERY_CHANNEL) * BATTERY_MULTIPLIER
|
||||||
|
return int((voltage - BATTERY_MIN_VOLTAGE) / BATTERY_MAX_VOLTAGE * 100)
|
|
@ -1,6 +1,5 @@
|
||||||
import time
|
|
||||||
import RPi.GPIO as GPIO
|
import RPi.GPIO as GPIO
|
||||||
from Command import COMMAND as cmd
|
import atexit
|
||||||
|
|
||||||
GPIO.setwarnings(False)
|
GPIO.setwarnings(False)
|
||||||
Buzzer_Pin = 17
|
Buzzer_Pin = 17
|
||||||
|
@ -9,15 +8,17 @@ GPIO.setup(Buzzer_Pin, GPIO.OUT)
|
||||||
|
|
||||||
|
|
||||||
class Buzzer:
|
class Buzzer:
|
||||||
def run(self, command):
|
|
||||||
if command != "0":
|
|
||||||
GPIO.output(Buzzer_Pin, True)
|
|
||||||
else:
|
|
||||||
GPIO.output(Buzzer_Pin, False)
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def set(on: bool):
|
||||||
|
"""
|
||||||
|
Turn the buzzer on / off
|
||||||
|
:param on: True if on, False if off
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
GPIO.output(Buzzer_Pin, on)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
def exit():
|
||||||
B = Buzzer()
|
Buzzer.set(0)
|
||||||
B.run('1')
|
|
||||||
time.sleep(3)
|
atexit.register(exit)
|
||||||
B.run('0')
|
|
|
@ -1,13 +0,0 @@
|
||||||
class COMMAND:
|
|
||||||
CMD_MOTOR = "CMD_MOTOR"
|
|
||||||
CMD_LED = "CMD_LED"
|
|
||||||
CMD_LED_MOD = "CMD_LED_MOD"
|
|
||||||
CMD_SERVO = "CMD_SERVO"
|
|
||||||
CMD_BUZZER = "CMD_BUZZER"
|
|
||||||
CMD_SONIC = "CMD_SONIC"
|
|
||||||
CMD_LIGHT = "CMD_LIGHT"
|
|
||||||
CMD_POWER = "CMD_POWER"
|
|
||||||
CMD_MODE = "CMD_MODE"
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
65
compLIB/IRSensor.py
Normal file
65
compLIB/IRSensor.py
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
from compLIB.ADC import ADC
|
||||||
|
import RPi.GPIO as GPIO
|
||||||
|
|
||||||
|
TOP_LEFT_CHANNEL = 0
|
||||||
|
TOP_RIGHT_CHANNEL = 1
|
||||||
|
|
||||||
|
TOP_IR_MIN_VOLTAGE = 0.0
|
||||||
|
TOP_IR_MAX_VOLTAGE = 3.3
|
||||||
|
|
||||||
|
BOTTOM_LEFT_PIN = 14
|
||||||
|
BOTTOM_MIDDLE_PIN = 15
|
||||||
|
BOTTOM_RIGHT_PIN = 23
|
||||||
|
|
||||||
|
adc = ADC()
|
||||||
|
|
||||||
|
GPIO.setmode(GPIO.BCM)
|
||||||
|
|
||||||
|
GPIO.setup(BOTTOM_LEFT_PIN, GPIO.IN)
|
||||||
|
GPIO.setup(BOTTOM_MIDDLE_PIN, GPIO.IN)
|
||||||
|
GPIO.setup(BOTTOM_RIGHT_PIN, GPIO.IN)
|
||||||
|
|
||||||
|
|
||||||
|
class IRSensor(object):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def top_left_percent() -> int:
|
||||||
|
"""
|
||||||
|
Get left infrared sensor percentage between 0 and 100
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
voltage = adc.read(TOP_LEFT_CHANNEL)
|
||||||
|
return int((voltage - TOP_IR_MIN_VOLTAGE) / TOP_IR_MAX_VOLTAGE * 100)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def top_right_percent() -> int:
|
||||||
|
"""
|
||||||
|
Get right infrared sensor percentage between 0 and 100
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
voltage = adc.read(TOP_RIGHT_CHANNEL)
|
||||||
|
return int((voltage - TOP_IR_MIN_VOLTAGE) / TOP_IR_MAX_VOLTAGE * 100)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def bottom_left() -> bool:
|
||||||
|
"""
|
||||||
|
Get status of bottom infrared sensor
|
||||||
|
:return: bool
|
||||||
|
"""
|
||||||
|
return GPIO.input(BOTTOM_LEFT_PIN)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def bottom_middle() -> bool:
|
||||||
|
"""
|
||||||
|
Get status of bottom infrared sensor
|
||||||
|
:return: bool
|
||||||
|
"""
|
||||||
|
return GPIO.input(BOTTOM_MIDDLE_PIN)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def bottom_right() -> bool:
|
||||||
|
"""
|
||||||
|
Get status of bottom infrared sensor
|
||||||
|
:return: bool
|
||||||
|
"""
|
||||||
|
return GPIO.input(BOTTOM_RIGHT_PIN)
|
138
compLIB/Motor.py
138
compLIB/Motor.py
|
@ -1,107 +1,51 @@
|
||||||
import time
|
import atexit
|
||||||
from PCA9685 import PCA9685
|
|
||||||
|
from compLIB.PCA9685 import PCA9685
|
||||||
|
|
||||||
|
pwm = PCA9685(0x40, debug=True)
|
||||||
|
pwm.setPWMFreq(50)
|
||||||
|
|
||||||
|
MOTOR_COUNT = 4
|
||||||
|
MAX_MOTOR_SPEED = 4095.0
|
||||||
|
MOTOR_PERCENTAGE_MULT = MAX_MOTOR_SPEED / 100.0
|
||||||
|
|
||||||
|
|
||||||
class Motor:
|
class Motor(object):
|
||||||
def __init__(self):
|
|
||||||
self.pwm = PCA9685(0x40, debug=True)
|
|
||||||
self.pwm.setPWMFreq(50)
|
|
||||||
|
|
||||||
def duty_range(self, duty1, duty2, duty3, duty4):
|
@staticmethod
|
||||||
if duty1 > 4095:
|
def power(port: int, percent: int):
|
||||||
duty1 = 4095
|
"""
|
||||||
elif duty1 < -4095:
|
Set specified motor to percentage power
|
||||||
duty1 = -4095
|
:param port: Port, which the motor is connected to. 0-3, 0 -> top left, 3 -> top right
|
||||||
|
:param percent: Percentage of max speed. between -100 and 100
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
forward = True
|
||||||
|
if percent < 0:
|
||||||
|
percent = abs(percent)
|
||||||
|
forward = False
|
||||||
|
|
||||||
if duty2 > 4095:
|
# bottom left motor is inverted - REEEEEEEEEEEE
|
||||||
duty2 = 4095
|
if port == 1:
|
||||||
elif duty2 < -4095:
|
forward = not forward
|
||||||
duty2 = -4095
|
|
||||||
|
|
||||||
if duty3 > 4095:
|
adjusted_speed = int(min(max(0, percent), 100) * MOTOR_PERCENTAGE_MULT)
|
||||||
duty3 = 4095
|
|
||||||
elif duty3 < -4095:
|
|
||||||
duty3 = -4095
|
|
||||||
|
|
||||||
if duty4 > 4095:
|
if forward:
|
||||||
duty4 = 4095
|
pwm.setMotorPwm(port * 2, 0)
|
||||||
elif duty4 < -4095:
|
pwm.setMotorPwm(port * 2 + 1, adjusted_speed)
|
||||||
duty4 = -4095
|
|
||||||
return duty1, duty2, duty3, duty4
|
|
||||||
|
|
||||||
def left_Upper_Wheel(self, duty):
|
|
||||||
if duty > 0:
|
|
||||||
self.pwm.setMotorPwm(0, 0)
|
|
||||||
self.pwm.setMotorPwm(1, duty)
|
|
||||||
elif duty < 0:
|
|
||||||
self.pwm.setMotorPwm(1, 0)
|
|
||||||
self.pwm.setMotorPwm(0, abs(duty))
|
|
||||||
else:
|
else:
|
||||||
self.pwm.setMotorPwm(0, 4095)
|
pwm.setMotorPwm(port * 2, adjusted_speed)
|
||||||
self.pwm.setMotorPwm(1, 4095)
|
pwm.setMotorPwm(port * 2 + 1, 0)
|
||||||
|
|
||||||
def left_Lower_Wheel(self, duty):
|
@staticmethod
|
||||||
if duty > 0:
|
def all_off():
|
||||||
self.pwm.setMotorPwm(3, 0)
|
"""
|
||||||
self.pwm.setMotorPwm(2, duty)
|
Turns of all motors
|
||||||
elif duty < 0:
|
:return:
|
||||||
self.pwm.setMotorPwm(2, 0)
|
"""
|
||||||
self.pwm.setMotorPwm(3, abs(duty))
|
for i in range(0, MOTOR_COUNT):
|
||||||
else:
|
Motor.power(i, 0)
|
||||||
self.pwm.setMotorPwm(2, 4095)
|
|
||||||
self.pwm.setMotorPwm(3, 4095)
|
|
||||||
|
|
||||||
def right_Upper_Wheel(self, duty):
|
|
||||||
if duty > 0:
|
|
||||||
self.pwm.setMotorPwm(6, 0)
|
|
||||||
self.pwm.setMotorPwm(7, duty)
|
|
||||||
elif duty < 0:
|
|
||||||
self.pwm.setMotorPwm(7, 0)
|
|
||||||
self.pwm.setMotorPwm(6, abs(duty))
|
|
||||||
else:
|
|
||||||
self.pwm.setMotorPwm(6, 4095)
|
|
||||||
self.pwm.setMotorPwm(7, 4095)
|
|
||||||
|
|
||||||
def right_Lower_Wheel(self, duty):
|
|
||||||
if duty > 0:
|
|
||||||
self.pwm.setMotorPwm(4, 0)
|
|
||||||
self.pwm.setMotorPwm(5, duty)
|
|
||||||
elif duty < 0:
|
|
||||||
self.pwm.setMotorPwm(5, 0)
|
|
||||||
self.pwm.setMotorPwm(4, abs(duty))
|
|
||||||
else:
|
|
||||||
self.pwm.setMotorPwm(4, 4095)
|
|
||||||
self.pwm.setMotorPwm(5, 4095)
|
|
||||||
|
|
||||||
def setMotorModel(self, duty1, duty2, duty3, duty4):
|
|
||||||
duty1, duty2, duty3, duty4 = self.duty_range(duty1, duty2, duty3, duty4)
|
|
||||||
self.left_Upper_Wheel(duty1)
|
|
||||||
self.left_Lower_Wheel(duty2)
|
|
||||||
self.right_Upper_Wheel(duty3)
|
|
||||||
self.right_Lower_Wheel(duty4)
|
|
||||||
|
|
||||||
|
|
||||||
PWM = Motor()
|
atexit.register(Motor.all_off())
|
||||||
|
|
||||||
|
|
||||||
def loop():
|
|
||||||
PWM.setMotorModel(2000, 2000, 2000, 2000) # Forward
|
|
||||||
time.sleep(3)
|
|
||||||
PWM.setMotorModel(-2000, -2000, -2000, -2000) # Back
|
|
||||||
time.sleep(3)
|
|
||||||
PWM.setMotorModel(-500, -500, 2000, 2000) # Left
|
|
||||||
time.sleep(3)
|
|
||||||
PWM.setMotorModel(2000, 2000, -500, -500) # Right
|
|
||||||
time.sleep(3)
|
|
||||||
PWM.setMotorModel(0, 0, 0, 0) # Stop
|
|
||||||
|
|
||||||
|
|
||||||
def destroy():
|
|
||||||
PWM.setMotorModel(0, 0, 0, 0)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
try:
|
|
||||||
loop()
|
|
||||||
except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
|
|
||||||
destroy()
|
|
||||||
|
|
28
compLIB/Servo.py
Normal file
28
compLIB/Servo.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
from compLIB.PCA9685 import PCA9685
|
||||||
|
|
||||||
|
pwm = PCA9685(0x40, debug=True)
|
||||||
|
pwm.setPWMFreq(50)
|
||||||
|
|
||||||
|
|
||||||
|
class Servo:
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def set_position(channel: int, angle: int):
|
||||||
|
"""
|
||||||
|
Set position of servo connected to port
|
||||||
|
:param channel: channel between 0 and 7
|
||||||
|
:param angle: Angle of servo
|
||||||
|
:return: None
|
||||||
|
|
||||||
|
"""
|
||||||
|
angle = abs(angle)
|
||||||
|
|
||||||
|
if channel == 0:
|
||||||
|
pwm.setServoPulse(8 + channel, 2500 - int(angle / 0.09))
|
||||||
|
elif channel < 8:
|
||||||
|
pwm.setServoPulse(8 + channel, 500 - int(angle / 0.09))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def setup_position():
|
||||||
|
pwm.setServoPulse(8, 1500)
|
||||||
|
pwm.setServoPulse(9, 1500)
|
3
copy.sh
Executable file
3
copy.sh
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
scp -r compLIB pi@10.20.85.225:/home/pi/compLIB
|
Reference in a new issue