DynamiKontrol Python API¶

DynamiKontrol is a API for controlling DynamiKontrol module as motors, LEDs or so on. You can find our modules at https://dk.m47rix.com. Please contact us matrix.ai.solution@gmail.com
Installation¶
Install Python¶
First download and install Python from here:
https://www.python.org/downloads
or use Anaconda:
Install DynamiKontrol Package in pip¶
To install DynamiKontrol package via pip, simply execute in terminal:
pip install -U DynamiKontrol
This installs the latest version from pypi.
dynamikontrol package¶
Submodules¶
dynamikontrol.LED module¶
- class dynamikontrol.LED.LED(module)[source]¶
Bases:
object
LED submodule class.
from dynamikontrol import Module import time module = Module() module.led.blink(color='r') # blink red module.led.toggle(color='g') # toggle green while True: module.led.on(color='y') # turn on yellow time.sleep(0.1) module.led.off(color='y') # turn off yellow time.sleep(0.1) module.disconnect()
- Parameters
module (object) – Module object.
- blink(color='all', on_delay=0.256, off_delay=0.256)[source]¶
Blink the LED light periodically.
- Parameters
color (str, optional) – Color of the LED light.
r
,y
org
. Defaults toall
.on_delay (float, optional) – Delay time for turned-on status.
on_delay
must be between0.0
to65.0
in second. Defaults to0.256
.off_delay (float, optional) – Delay time for turned-off status.
off_delay
must be between0.0
to65.0
in second. Defaults to0.256
.
- off(color='all')[source]¶
Turn off the LED light
- Parameters
color (str, optional) – Color of the LED light.
r
,y
org
. Defaults toall
.
dynamikontrol.Module module¶
- class dynamikontrol.Module.Module(serial_no=None, debug=False)[source]¶
Bases:
object
Module class.
from dynamikontrol import Module module = Module(serial_no) # specify the module by serial number # Print module serial number print('Serial number: %s' % (module.get_serial_no(),) module.disconnect()
- Parameters
serial_no (str) – Specify serial number of the module.
debug (bool) – print debug messages.
- disconnect()[source]¶
Close the connection of the module. Must include
module.disconnect()
at the end of the code so that module can close connection properly.
- get_fw_version()[source]¶
Get firmware version of the connected module.
- Returns
Device firmware version.
- Return type
str
- get_serial_no()[source]¶
Get serial number of the connected module.
- Returns
Serial number.
- Return type
str
dynamikontrol.Motor module¶
- class dynamikontrol.Motor.BLDC(module)[source]¶
Bases:
object
BLDC(Speed) motor submodule class.
from dynamikontrol import Module import time module = Module() module.motor.speed(1000) time.sleep(5) module.motor.stop() module.disconnect()
- Parameters
module (object) – Module object.
- get_speed(func, unit='rpm')[source]¶
Get speed of the motor asynchronously.
from dynamikontrol import Module import time module = Module() module.motor.speed(4000, period=10) def get_speed_cb(speed): print('Current Speed', speed) for i in range(60): time.sleep(0.5) module.motor.get_speed(func=get_speed_cb) module.disconnect()
- Parameters
func (function) – Callback function when getting speed from the motor.
unit (str, optional) – Speed unit must be one of
rpm
,deg/s
andrad/s
. Defaults to'rpm'
.
- speed(speed, period=None, unit='rpm', func=None, args=(), kwargs={})[source]¶
Control speed of the motor.
- Parameters
speed (int) – If
speed > 0
spins along clockwise, otherwise spins along counter clockwise.period (int, optional) – Control period.
period
must be between0.0
to65.0
in second. Defaults toNone
.unit (str, optional) – Speed unit must be one of
rpm
,deg/s
andrad/s
. Defaults to'rpm'
.func (function, optional) – Callback function when motor has been stopped. Defaults to
None
.args (tuple, optional) – args for callback function. Defaults to
()
.kwargs (dict, optional) – kwargs for callback function. Defaults to
{}
.
- class dynamikontrol.Motor.Servo(module)[source]¶
Bases:
object
Servo(Angle) motor submodule class.
from dynamikontrol import Module import time module = Module() module.motor.angle(0) time.sleep(2) while True: module.motor.angle(45) time.sleep(2) def cb(string): print(string) module.motor.angle(-45, func=cb, args=('hello',)) # print 'hello' when motor stopped at -45 degree. time.sleep(2) module.disconnect()
- Parameters
module (object) – Module object.
- angle(angle, period=None, func=None, args=(), kwargs={})[source]¶
Control the angle of motor.
- Parameters
angle (int) – If
angle > 0
moves along clockwise, otherwise moves along counter clockwise.angle
must be between-85
to85
in degrees.period (float, optional) – Control period.
period
must be between0.0
to65.0
in second. Defaults toNone
.func (function, optional) – Callback function when motor has been stopped. Defaults to
None
.args (tuple, optional) – args for callback function. Defaults to
()
.kwargs (dict, optional) – kwargs for callback function. Defaults to
{}
.
dynamikontrol.Switch module¶
- class dynamikontrol.Switch.Switch(module)[source]¶
Bases:
object
Switch submodule class.
from dynamikontrol import Module import time module = Module() def callback(string, angle): print(string) module.motor.angle(angle) module.switch.press(callback, ('Switched to on', 85,)) module.switch.release(callback, ('Switched to off', 0,)) while True: time.sleep(1) module.disconnect()
- Parameters
module (object) – Module object.
- off(func, args=(), kwargs={}, ch=0)[source]¶
Define callback function when switch is set to
off
status.- Parameters
func (function) – Callback function.
args (tuple, optional) – args. Defaults to
()
.kwargs (dict, optional) – kwargs. Defaults to
{}
.ch (int, optional) – Switch channel number. Must be
0
or1
. Defaults to0
.
- on(func, args=(), kwargs={}, ch=0)[source]¶
Define callback function when switch is set to
on
status.- Parameters
func (function) – Callback function.
args (tuple, optional) – args. Defaults to
()
.kwargs (dict, optional) – kwargs. Defaults to
{}
.ch (int, optional) – Switch channel number. Must be
0
or1
. Defaults to0
.
dynamikontrol.Timer module¶
- class dynamikontrol.Timer.Timer[source]¶
Bases:
object
General timer class.
from dynamikontrol import Module, Timer import time t1 = Timer() t2 = Timer() module = Module() t1.callback_at(func=module.led.toggle, args=('r',), at='2021-03-02 19:46:30', interval=0.1) t2.callback_after(func=module.led.toggle, args=('g',), after=1, interval=0.1) time.sleep(5) t1.stop() t2.stop() module.disconnect()
- callback_after(func, args=(), kwargs={}, after=0, interval=None)[source]¶
Call the callback function after specific time.
- Parameters
func (function) – Callback function.
args (tuple, optional) – args. Defaults to
()
.kwargs (dict, optional) – kwargs. Defaults to
{}
.after (int, optional) – Callback delay time in seconds. Defaults to
0
.interval (int, optional) – Callback interval time in seconds. Defaults to
None
.
- callback_at(func, args=(), kwargs={}, at=None, interval=None)[source]¶
Call the callback function at specific time.
- Parameters
func (function) – Callback function.
args (tuple, optional) – args. Defaults to
()
.kwargs (dict, optional) – kwargs. Defaults to
{}
.at (datetime str, optional) – Callback time in datetime str. e.g)
2021-03-04 21:57:30
. Defaults toNone
.interval ([type], optional) – Callback interval time in seconds. Defaults to
None
.
Module contents¶
Face Tracking Camera¶
Face tracking algorithm is not included in DynamiKontrol package. So we use Mediapipe face tracking solution for face tracking and OpenCV for streaming webcam.
Explanation¶
Let’s define x1
, x2
are top left point and bottom right point of face bounding box, then cx
would be center point of the face. Mediapipe face tracking solution returns relative coordinates of the input image, so range of cx
would be 0.0 to 1.0. For instance, if your face is located in exact center of the image, cx
is 0.5.
cx = (x1 + x2) / 2 # center of the face
if cx < 0.4: # left -> clockwise
angle += ANGLE_STEP
module.motor.angle(angle)
elif cx > 0.6: # right -> counter clockwise
angle -= ANGLE_STEP
module.motor.angle(angle)
If cx < 0.4
, face is located in the left of the image, camera should move to left, and it means the motor should move to clockwise(+). Otherwise vice versa.
Source Code¶
import cv2
import mediapipe as mp
from dynamikontrol import Module
ANGLE_STEP = 1
module = Module()
mp_drawing = mp.solutions.drawing_utils
mp_face_detection = mp.solutions.face_detection
face_detection = mp_face_detection.FaceDetection(
min_detection_confidence=0.7)
cap = cv2.VideoCapture(0)
angle = 0 # motor current angle
while cap.isOpened():
ret, img = cap.read()
if not ret:
break
img = cv2.flip(img, 1) # mirror image
results = face_detection.process(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
if results.detections:
for detection in results.detections:
mp_drawing.draw_detection(img, detection)
x1 = detection.location_data.relative_bounding_box.xmin # left side of face bounding box
x2 = x1 + detection.location_data.relative_bounding_box.width # right side of face bounding box
cx = (x1 + x2) / 2 # center of the face
if cx < 0.4: # left -> clockwise
angle += ANGLE_STEP
module.motor.angle(angle)
elif cx > 0.6: # right -> counter clockwise
angle -= ANGLE_STEP
module.motor.angle(angle)
cv2.putText(img, '%d deg' % (angle), org=(10, 30), fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=1, color=255, thickness=2)
break
cv2.imshow('Face Cam', img)
if cv2.waitKey(1) == ord('q'):
break
cap.release()
face_detection.close()
module.disconnect()
Lunch Roulette¶
A Machine select your lunch menu with no worries.
Source Code¶
from dynamikontrol import Module
import time, random
module = Module()
direction = 1 # initial direction, clockwise
start_time = time.time()
stop_time = 5 # stop after 5 seconds
stop_angle = random.randint(-80, 80) # random angle
while True:
if time.time() - start_time > stop_time:
module.motor.angle(angle=stop_angle)
print(f'Motor stopped at {stop_angle} degree')
break
direction = direction * -1 # change direction
module.motor.angle(angle=direction * 80)
time.sleep(0.6)
module.led.blink()
module.disconnect()
Dial GUI¶
Simple dial GUI example using PyQt5.
Source Code¶
Install PyQt5
pip install PyQt5
from dynamikontrol import Module
from PyQt5.QtWidgets import *
import sys
class Dial(QWidget):
def __init__(self, module):
QWidget.__init__(self)
self.module = module
self.dial = QDial()
self.dial.setRange(-150, 150)
self.dial.setNotchesVisible(True)
self.dial.valueChanged.connect(self.dialMoved)
layout = QGridLayout()
layout.addWidget(self.dial)
self.setLayout(layout)
self.setGeometry(500, 500, 500, 500)
def dialMoved(self):
self.module.motor.angle(self.dial.value())
print(f'Dial value {self.dial.value()}')
if __name__ == '__main__':
app = QApplication(sys.argv)
screen = Dial(Module())
screen.show()
sys.exit(app.exec_())
Thermometer¶
Simple IoT analogue thermometer using weather API. It is around 13 degrees Celsius in the image below.
You can download a graduated ruler from this link.
https://github.com/TheMatrixGroup/DynamiKontrol/raw/master/examples/thermometer.pdf
Source Code¶
from dynamikontrol import Module
import requests, time
from datetime import datetime
module = Module()
# weather of Seoul, Korea
lat = 37.566536 # latitude
lon = 126.977966 # longitude
url = f'https://fcc-weather-api.glitch.me/api/current?lat={lat}&lon={lon}'
while True:
res = requests.get(url).json()
temp = res['main']['temp']
print(f'{datetime.now()} temperature {temp} degree')
angle = int(temp * 10 / 3)
module.motor.angle(angle)
time.sleep(60)
module.disconnect()
IoT Door Lock¶
You can build IoT smart door lock system that can be integrated in the mobile app and the web app.
In this example, we use Flask web framework. You can also use Node.js and other languages and frameworks.
Source Code¶
Server door_lock.py
from dynamikontrol import Module
from flask import Flask, request, render_template
module = Module()
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/change', methods=['POST'])
def change():
is_locked = request.form['is_locked']
if is_locked == 'true':
module.motor.angle(85)
module.led.off(color='r')
module.led.on(color='g')
else:
module.motor.angle(-45)
module.led.off(color='g')
module.led.on(color='r')
return {'result': True}
if __name__ == '__main__':
app.run()
module.disconnect()
Client templates/index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<title>IoT Door Lock System</title>
</head>
<body>
<div class="d-flex justify-content-center mt-5">
<h5>IoT Door Lock System</h5>
</div>
<div class="d-flex justify-content-center">
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" id="lockSwitch">
<label class="custom-control-label" for="lockSwitch">Lock the Door</label>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
$(function() {
$('#lockSwitch').change(function(e) {
$.ajax({
method: 'POST',
url: '/change',
data: { is_locked: this.checked }
})
.done(function(msg) {
console.log(msg);
});
});
})
</script>
</body>
</html>