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 time
|
||||
|
||||
SINGLE_ENDED = 0x84
|
||||
ADDRESS = 0x48
|
||||
|
||||
bus = smbus.SMBus(1)
|
||||
|
||||
|
||||
class Adc:
|
||||
def __init__(self):
|
||||
# Get I2C bus
|
||||
self.bus = smbus.SMBus(1)
|
||||
class ADC:
|
||||
|
||||
# I2C address of the device
|
||||
self.ADDRESS = 0x48
|
||||
@staticmethod
|
||||
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"""
|
||||
COMMAND_SET = self.ADS7830_CMD | ((((channel << 2) | (channel >> 1)) & 0x07) << 4)
|
||||
self.bus.write_byte(self.ADDRESS, COMMAND_SET)
|
||||
while (1):
|
||||
value1 = self.bus.read_byte(self.ADDRESS)
|
||||
value2 = self.bus.read_byte(self.ADDRESS)
|
||||
command = SINGLE_ENDED | ((((channel << 2) | (channel >> 1)) & 0x07) << 4)
|
||||
bus.write_byte(ADDRESS, command)
|
||||
|
||||
while "Koka is great":
|
||||
value1 = bus.read_byte(ADDRESS)
|
||||
value2 = bus.read_byte(ADDRESS)
|
||||
if value1 == value2:
|
||||
break;
|
||||
break
|
||||
|
||||
voltage = value1 / 255.0 * 3.3 # calculate the voltage value
|
||||
voltage = round(voltage, 2)
|
||||
|
||||
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
|
||||
from Command import COMMAND as cmd
|
||||
import atexit
|
||||
|
||||
GPIO.setwarnings(False)
|
||||
Buzzer_Pin = 17
|
||||
|
@ -9,15 +8,17 @@ GPIO.setup(Buzzer_Pin, GPIO.OUT)
|
|||
|
||||
|
||||
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__':
|
||||
B = Buzzer()
|
||||
B.run('1')
|
||||
time.sleep(3)
|
||||
B.run('0')
|
||||
def exit():
|
||||
Buzzer.set(0)
|
||||
|
||||
atexit.register(exit)
|
|
@ -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
|
||||
from PCA9685 import PCA9685
|
||||
import atexit
|
||||
|
||||
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:
|
||||
def __init__(self):
|
||||
self.pwm = PCA9685(0x40, debug=True)
|
||||
self.pwm.setPWMFreq(50)
|
||||
class Motor(object):
|
||||
|
||||
def duty_range(self, duty1, duty2, duty3, duty4):
|
||||
if duty1 > 4095:
|
||||
duty1 = 4095
|
||||
elif duty1 < -4095:
|
||||
duty1 = -4095
|
||||
@staticmethod
|
||||
def power(port: int, percent: int):
|
||||
"""
|
||||
Set specified motor to percentage power
|
||||
: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:
|
||||
duty2 = 4095
|
||||
elif duty2 < -4095:
|
||||
duty2 = -4095
|
||||
# bottom left motor is inverted - REEEEEEEEEEEE
|
||||
if port == 1:
|
||||
forward = not forward
|
||||
|
||||
if duty3 > 4095:
|
||||
duty3 = 4095
|
||||
elif duty3 < -4095:
|
||||
duty3 = -4095
|
||||
adjusted_speed = int(min(max(0, percent), 100) * MOTOR_PERCENTAGE_MULT)
|
||||
|
||||
if duty4 > 4095:
|
||||
duty4 = 4095
|
||||
elif duty4 < -4095:
|
||||
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))
|
||||
if forward:
|
||||
pwm.setMotorPwm(port * 2, 0)
|
||||
pwm.setMotorPwm(port * 2 + 1, adjusted_speed)
|
||||
else:
|
||||
self.pwm.setMotorPwm(0, 4095)
|
||||
self.pwm.setMotorPwm(1, 4095)
|
||||
pwm.setMotorPwm(port * 2, adjusted_speed)
|
||||
pwm.setMotorPwm(port * 2 + 1, 0)
|
||||
|
||||
def left_Lower_Wheel(self, duty):
|
||||
if duty > 0:
|
||||
self.pwm.setMotorPwm(3, 0)
|
||||
self.pwm.setMotorPwm(2, duty)
|
||||
elif duty < 0:
|
||||
self.pwm.setMotorPwm(2, 0)
|
||||
self.pwm.setMotorPwm(3, abs(duty))
|
||||
else:
|
||||
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)
|
||||
@staticmethod
|
||||
def all_off():
|
||||
"""
|
||||
Turns of all motors
|
||||
:return:
|
||||
"""
|
||||
for i in range(0, MOTOR_COUNT):
|
||||
Motor.power(i, 0)
|
||||
|
||||
|
||||
PWM = Motor()
|
||||
|
||||
|
||||
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()
|
||||
atexit.register(Motor.all_off())
|
||||
|
|
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)
|
|
@ -103,4 +103,4 @@ if __name__ == '__main__':
|
|||
ultrasonic.run()
|
||||
except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
|
||||
PWM.setMotorModel(0, 0, 0, 0)
|
||||
ultrasonic.pwm_S.setServoPwm('0', 90)
|
||||
ultrasonic.pwm_S.setServoPwm('0', 90)
|
|
@ -1 +1 @@
|
|||
__version__ = "0.0.1"
|
||||
__version__ = "0.0.1"
|
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