Python NRF24 convert Payload - python

since some days I try to connect an Arduino with a Raspberry by an NRF24 module.
By the examples i got some working code in C (#raspberry) but I want to use python due to the web app.
The problem is I can't interpret the msq send by the Arduino. The Arduino should send 8 times uint32_t in one payload. After receive in Raspberry I got 8 times 4 uint8_t.
Arduino MSG:
uint32_t SendMsg[8] = {222, micros(), 10, 20, 30, 40, 50, 60};
Raspberry RCV:
Received: [222, 0, 0, 0, 24, 22, 97, 210, 10, 0, 0, 0, 20, 0, 0, 0, 30, 0, 0, 0, 40, 0, 0, 0, 50, 0, 0, 0, 60, 0, 0, 0]
The Raspberry "destroy" the int32 to 4 times int8 ... how I may combine them again?
The RCV is a list of int.
Here the complete code:
Raspberry:
import RPi.GPIO as GPIO
from lib_nrf24 import NRF24
import time
import spidev
GPIO.setmode(GPIO.BCM)
pipes = [0xAB, 0xCD, 0xAB, 0xCD, 0x71]
radio = NRF24(GPIO, spidev.SpiDev())
radio.begin(0, 22)
radio.setPayloadSize(32)
radio.setChannel(77)
radio.setDataRate(NRF24.BR_1MBPS)
radio.setPALevel(NRF24.PA_MIN)
radio.setAutoAck(True)
radio.enableDynamicPayloads()
radio.enableAckPayload()
radio.openReadingPipe(1,pipes)
radio.printDetails()
radio.startListening()
while(1):
# ackPL = [1]
while not radio.available(0):
time.sleep(1 / 100)
receivedMessage = []
radio.read(receivedMessage, radio.getDynamicPayloadSize())
print("Received: {}".format(receivedMessage))
Arduino
//Send.ino
#include<SPI.h>
#include<RF24.h>
// ce, csn pins
RF24 radio(6, 10);
uint32_t RcvMsg[8] = {0, 0, 0, 0, 0, 0, 0, 0};
void setup(void){
radio.begin();
radio.setPALevel(RF24_PA_MAX);
radio.setChannel(77);
radio.openWritingPipe(0xABCDABCD71LL);
radio.enableDynamicPayloads();
radio.powerUp();
}
void loop(void){
const char text[] = "Hello World is awe DOAs";
uint32_t SendMessage;
uint32_t SendMsg[8] = {222, micros(), 10, 20, 30, 40, 50, 60};
radio.write(&SendMsg, sizeof(SendMsg));
if ( radio.isAckPayloadAvailable() ) {
radio.read(&RcvMsg, sizeof(RcvMsg));
}
Serial.print(" SendMsg[0]: ");Serial.print(SendMsg[0]); Serial.print(" SendMsg[1]: ");Serial.print(SendMsg[1]); Serial.print(" SendMsg[2]: ");Serial.print(SendMsg[2]); Serial.print(" SendMsg[3]: ");Serial.print(SendMsg[3]); Serial.print(" SendMsg[4]: ");Serial.print(SendMsg[4]);Serial.print(" SendMsg[5]: ");Serial.print(SendMsg[5]);Serial.print(" SendMsg[6]: ");Serial.print(SendMsg[6]); Serial.print(" SendMsg[7]: ");Serial.println(SendMsg[7]);
Serial.print(" RcvMsg[0] : ");Serial.print(RcvMsg[0]);Serial.print(" RcvMsg[1] : ");Serial.print(RcvMsg[1]);Serial.print(" RcvMsg[2] : ");Serial.print(RcvMsg[2]);Serial.print(" RcvMsg[3] : ");Serial.print(RcvMsg[3]); Serial.print(" RcvMsg[4] : ");Serial.print(RcvMsg[4]);Serial.print(" RcvMsg[5] : ");Serial.print(RcvMsg[5]);Serial.print(" RcvMsg[6] : ");Serial.print(RcvMsg[6]);Serial.print(" RcvMsg[7] : ");Serial.println(RcvMsg[7]);
delay(1000);
}

I found a solution:
#============================================================================#
#============================================================================#
# translate radio Msq from byte to int
#============================================================================#
def translate_from_radio(msg, size):
translated_msg=[]
for i in range (0, size, 4):
translated_msg.append(int.from_bytes([msg[i+3], msg[i+2], msg[i+1], msg[i]], byteorder='big'))
#print("Translate FROM Radio: " + str(msg) + " --> " + str(translated_msg))
return translated_msg
#============================================================================#
#============================================================================#
# Split the msg element in 4 bytes and add it to translated msg
#============================================================================#
def translate_to_radio(msg):
translated_msg=[]
for i in range (0, len(msg)):
x=msg[i].to_bytes(4, byteorder='big')
for g in reversed(x):
translated_msg.append(g)
#print("Translate TO Radio: " + str(msg) + " --> " + str(translated_msg))
return translated_msg

Related

Different number of incoming bytes from STM on Windows and Ubuntu

I have a code, which sending a message to usb device. It returns me the correct answer on Windows, but on ubuntu it gives wrong result. Why is that?
import hid
import time
try:
print("Opening the device")
h = hid.device()
h.open(0x0483, 0x5750) # TREZOR VendorID/ProductID
print("Manufacturer: %s" % h.get_manufacturer_string())
print("Product: %s" % h.get_product_string())
print("Serial No: %s" % h.get_serial_number_string())
print("Write the data")
time.sleep(0.05)
h.write(([1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]))
d = h.read(19)
print(d)
except IOError as ex:
print(ex)
print("You probably don't have the hard-coded device.")
print("Update the h.open() line in this script with the one")
print("from the enumeration list output above and try again.")
print("Done")
result on Windows:
Opening the device
Manufacturer: STMicroelectronics
Product: STM32 Custom Human interface
Serial No: 00000000001A
Write the data
[2, 1, 255, 0, 0, 1, 0, 0, 0, 0, 0, 2, 1, 2, 0, 1, 0, 0, 1]
Done
result on Ubuntu:
sudo python3 main.py
Opening the device
Manufacturer: STMicroelectronics
Product: STM32 Custom Human interface
Serial No: 00000000001A
Write the data
Read the data
[2, 1]
Done

How do I translate Decode(Packet) function in C++?

I am learning depth ai and I found this example on their repo. https://github.com/luxonis/depthai-experiments/tree/master/gen2-road-segmentation. I started translating this code in C++ to be consistent with the project I am putting together. I run into this function named "Decode"
def decode(packet):
data = np.squeeze(toTensorResult(packet)["L0317_ReWeight_SoftMax"])
class_colors = [[0, 0, 0], [0, 255, 0], [255, 0, 0], [0, 0, 255]]
class_colors = np.asarray(class_colors, dtype=np.uint8)
indices = np.argmax(data, axis=0)
output_colors = np.take(class_colors, indices, axis=0)
return output_colors
Adding more detail regarding the problem.
DepthAI offers a lot of examples in their core repo
https://github.com/luxonis/depthai-core
I used some of those example to start shaping the segmentation script since its a feature that I don't find written in C++ between all of the examples.
Here is my progress so far.
#include <chrono>
#include "depthai-core/examples/utility/utility.hpp"
#include <depthai/depthai.hpp>
#include "slar.hpp"
using namespace slar;
using namespace std;
using namespace std::chrono;
static std::atomic<bool> syncNN{true};
void slar_depth_segmentation::segment(int argc, char **argv, dai::Pipeline &pipeline,
cv::Mat frame,
dai::Device *device_unused) {
// blob model
std::string nnPath("/Users/alessiograncini/road-segmentation-adas-0001.blob");
if (argc > 1) {
nnPath = std::string(argv[1]);
}
printf("Using blob at path: %s\n", nnPath.c_str());
// in
auto camRgb = pipeline.create<dai::node::ColorCamera>();
auto imageManip = pipeline.create<dai::node::ImageManip>();
auto mobilenetDet = pipeline.create<dai::node::MobileNetDetectionNetwork>();
// out
auto xoutRgb = pipeline.create<dai::node::XLinkOut>();
auto nnOut = pipeline.create<dai::node::XLinkOut>();
auto xoutManip = pipeline.create<dai::node::XLinkOut>();
// stream names
xoutRgb->setStreamName("camera");
xoutManip->setStreamName("manip");
nnOut->setStreamName("segmentation");
//
imageManip->initialConfig.setResize(300, 300);
imageManip->initialConfig.setFrameType(dai::ImgFrame::Type::BGR888p);
// properties
camRgb->setPreviewSize(300, 300);
camRgb->setBoardSocket(dai::CameraBoardSocket::RGB);
camRgb->setResolution(dai::ColorCameraProperties::SensorResolution::THE_1080_P);
camRgb->setInterleaved(false);
camRgb->setColorOrder(dai::ColorCameraProperties::ColorOrder::RGB);
//
mobilenetDet->setConfidenceThreshold(0.5f);
mobilenetDet->setBlobPath(nnPath);
mobilenetDet->setNumInferenceThreads(2);
mobilenetDet->input.setBlocking(false);
// link
camRgb->preview.link(xoutRgb->input);
imageManip->out.link(mobilenetDet->input);
//
if (syncNN) {
mobilenetDet->passthrough.link(xoutManip->input);
} else {
imageManip->out.link(xoutManip->input);
}
//
mobilenetDet->out.link(nnOut->input);
// device
dai::Device device(pipeline);
// queues
auto previewQueue = device.getOutputQueue("camera", 4, false);
auto detectionNNQueue = device.getOutputQueue("segmentation", 4, false);
// fps
auto startTime = steady_clock::now();
int counter = 0;
float fps = 0;
auto color = cv::Scalar(255, 255, 255);
// main
while (true) {
auto inRgb = previewQueue->get<dai::ImgFrame>();
auto inSeg = detectionNNQueue->get<dai::NNData>();
//?
auto segmentations = inSeg->getData();
//
counter++;
auto currentTime = steady_clock::now();
auto elapsed = duration_cast<duration<float>>(currentTime - startTime);
if(elapsed > seconds(1)) {
fps = counter / elapsed.count();
counter = 0;
startTime = currentTime;
}
// testing if mat is a good replacement for
// the input array as in "decode" the inSeg data is manipulated
// cv::Mat img(500, 1000, CV_8UC1, cv::Scalar(70));
// slar_depth_segmentation::draw(segmentations, frame);
std::stringstream fpsStr;
fpsStr << std::fixed << std::setprecision(2) << fps;
cv::imshow("camera window", inRgb->getCvFrame());
//cv::imshow("camera window", frame);
int key = cv::waitKey(1);
if (key == 'q' || key == 'Q') {
break;
}
}
}
void slar_depth_segmentation::draw(cv::InputArray data, cv::OutputArray frame) {
cv::addWeighted(frame, 1, data, 0.2, 0, frame);
}
//https://jclay.github.io/dev-journal/simple_cpp_argmax_argmin.html
void slar_depth_segmentation::decode( cv::InputArray data) {
vector <int> class_colors [4] =
{{0,0,0},{0,255,0},{255, 0, 0}, {0, 0, 255}};
}
I can successfully play the camera using this script - but as you can tell the only part of the segmentation that is translated is the draw method, that is a function equivalent for both py and c++ since it's part of the openCV library.
I am getting stuck in trying to write the equivalent of the decode method. Thanks
[edit]
Any suggestion regarding this follow up??
C++
cv::InputArray slar_depth_segmentation::decode(std::vector<std::uint8_t> data) {
// reshape or np.squeeze
data.resize(1, 1);
// create a vector array
std::vector<std::vector<int>> classColors{
{0, 0, 0},
{0, 255, 0},
{255, 0, 0},
{0, 0, 255}};
double minVal;
double maxVal;
cv::minMaxIdx(
data,
&minVal,
&maxVal);
// get max value of class colors
auto output_colors = classColors[&maxVal, 0];
return output_colors;
}
Py
def decode(packet):
data = np.squeeze(toTensorResult(packet)["L0317_ReWeight_SoftMax"])
class_colors = [[0, 0, 0], [0, 255, 0], [255, 0, 0], [0, 0, 255]]
class_colors = np.asarray(class_colors, dtype=np.uint8)
indices = np.argmax(data, axis=0)
output_colors = np.take(class_colors, indices, axis=0)
return output_colors
#I think you are looking for the
cv::argmax # function.
cv::argmax # returns the index of the maximum value in an array.
cv::argmax # is available in OpenCV 3.4.3 and later.

How to run rust function in python program

I'm working with a xorcipher app to benchmark both python and rust function but I don't know how to add the rust function to python code can anyone help I need the save the output in buf I'm including my rust code
use std::convert::TryInto;
/*
Apply a simple XOR cipher using they specified `key` of size
`key_size`, to the `msg` char/byte array of size `msg_len`.
Writes he ciphertext to the externally allocated buffer `buf`.
*/
#[no_mangle]
pub unsafe fn cipher(msg: *const i8, key: *const i8, buf: *mut i8, msg_len: usize, key_len: usize)
{
let mut i: isize = 0;
while i < msg_len.try_into().unwrap() {
let key_len_i8: i8 = key_len.try_into().unwrap();
*buf.offset(i) = *msg.offset(i) ^ (*key.offset(i) % key_len_i8);
i = i + 1;
}
}
Let's say your rust code is named rs_cipher.rs.
If you compile it with this command
rustc --crate-type dylib rs_cipher.rs
you obtain a native dynamic library for your system.
(of course, this can also be done with cargo and the crate-type = ["cdylib"] option)
Here is a python code that loads this library, finds the function and calls it (see the comments for these different stages).
import sys
import os
import platform
import ctypes
import traceback
# choose application specific library name
lib_name='rs_cipher'
# determine system system specific library name
if platform.system().startswith('Windows'):
sys_lib_name='%s.dll'%lib_name
elif platform.system().startswith('Darwin'):
sys_lib_name='lib%s.dylib'%lib_name
else:
sys_lib_name='lib%s.so'%lib_name
# try to load native library from various locations
# (current directory, python file directory, system path...)
ntv_lib=None
for d in [os.path.curdir,
os.path.dirname(sys.modules[__name__].__file__),
'']:
path=os.path.join(d, sys_lib_name)
try:
ntv_lib=ctypes.CDLL(path)
break
except:
# traceback.print_exc()
pass
if ntv_lib is None:
sys.stderr.write('cannot load library %s\n'%lib_name)
sys.exit(1)
# try to find native function
fnct_name='cipher'
ntv_fnct=None
try:
ntv_fnct=ntv_lib[fnct_name]
except:
# traceback.print_exc()
pass
if ntv_fnct is None:
sys.stderr.write('cannot find function %s in library %s\n'%
(fnct_name, lib_name))
sys.exit(1)
# describe native function prototype
ntv_fnct.restype=None # no return value
ntv_fnct.argtypes=[ctypes.c_void_p, # msg
ctypes.c_void_p, # key
ctypes.c_void_p, # buf
ctypes.c_size_t, # msg_len
ctypes.c_size_t] # key_len
# use native function
msg=(ctypes.c_int8*10)()
key=(ctypes.c_int8*4)()
buf=(ctypes.c_int8*len(msg))()
for i in range(len(msg)):
msg[i]=1+10*i
for i in range(len(key)):
key[i]=~(20*(i+2))
sys.stdout.write('~~~~ first initial state ~~~~\n')
sys.stdout.write('msg: %s\n'%[v for v in msg])
sys.stdout.write('key: %s\n'%[v for v in key])
sys.stdout.write('buf: %s\n'%[v for v in buf])
sys.stdout.write('~~~~ first call ~~~~\n')
ntv_fnct(msg, key, buf, len(msg), len(key))
sys.stdout.write('msg: %s\n'%[v for v in msg])
sys.stdout.write('key: %s\n'%[v for v in key])
sys.stdout.write('buf: %s\n'%[v for v in buf])
(msg, buf)=(buf, msg)
for i in range(len(buf)):
buf[i]=0
sys.stdout.write('~~~~ second initial state ~~~~\n')
sys.stdout.write('msg: %s\n'%[v for v in msg])
sys.stdout.write('key: %s\n'%[v for v in key])
sys.stdout.write('buf: %s\n'%[v for v in buf])
sys.stdout.write('~~~~ second call ~~~~\n')
ntv_fnct(msg, key, buf, len(msg), len(key))
sys.stdout.write('msg: %s\n'%[v for v in msg])
sys.stdout.write('key: %s\n'%[v for v in key])
sys.stdout.write('buf: %s\n'%[v for v in buf])
Running this python code shows this result
~~~~ first initial state ~~~~
msg: [1, 11, 21, 31, 41, 51, 61, 71, 81, 91]
key: [-41, -61, -81, -101]
buf: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
~~~~ first call ~~~~
msg: [1, 11, 21, 31, 41, 51, 61, 71, 81, 91]
key: [-41, -61, -81, -101]
buf: [-42, -56, -70, -124, -2, -16, -110, -36, -122, -104]
~~~~ second initial state ~~~~
msg: [-42, -56, -70, -124, -2, -16, -110, -36, -122, -104]
key: [-41, -61, -81, -101]
buf: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
~~~~ second call ~~~~
msg: [-42, -56, -70, -124, -2, -16, -110, -36, -122, -104]
key: [-41, -61, -81, -101]
buf: [1, 11, 21, 31, 41, 51, 61, 71, 81, 91]
Note that I replaced these two lines in your rust code
let key_len_i8: i8 = key_len.try_into().unwrap();
*buf.offset(i) = *msg.offset(i) ^ (*key.offset(i) % key_len_i8);
by these
let key_len_isize: isize = key_len.try_into().unwrap();
*buf.offset(i) = *msg.offset(i) ^ (*key.offset(i % key_len_isize));
because the offset on key was going out of bounds.
Maybe, instead of dealing with pointer arithmetic and unsigned/signed conversions, should you build usual slices from the raw pointers and use them in the safe way?
#[no_mangle]
pub fn cipher(
msg_ptr: *const i8,
key_ptr: *const i8,
buf_ptr: *mut i8,
msg_len: usize,
key_len: usize,
) {
let msg = unsafe { std::slice::from_raw_parts(msg_ptr, msg_len) };
let key = unsafe { std::slice::from_raw_parts(key_ptr, key_len) };
let buf = unsafe { std::slice::from_raw_parts_mut(buf_ptr, msg_len) };
for i in 0..msg_len {
buf[i] = msg[i] ^ key[i % key_len];
}
}

Print firebase data from arduino to 7 segment display

I am trying to get my firebase data and display it to my 7-segment using Arduino and I am getting the help of a python script to send data to the serial monitor. While it detects the Serial.available() inside the loop but I don't know how could I get that particular value and display its first digit to my 7-segment
Currently for the test I am just trying to display 1 if there is data matches inside serial monitor and arduino
Adruino:
#define A PA0
#define B PA1
#define C PA2
#define D PA3
#define E PA4
#define F PA5
#define G PA6
int a = 2;
void setup() {
Serial.begin(9600);
pinMode(A, OUTPUT);
pinMode(B, OUTPUT);
pinMode(C, OUTPUT);
pinMode(D, OUTPUT);
pinMode(E, OUTPUT);
pinMode(F, OUTPUT);
pinMode(G, OUTPUT);
}
void loop() {
if(Serial.available()){
// Serial.println("0 1 2 3 4 5 6 7 8 9");
// sevenSeg(1, 1, 1, 1, 1, 1, 0); // 0
// delay(500);
if(Serial.readString() == Serial.readString()){
sevenSeg(0, 0, 0, 1, 1, 0, 0); // 1
delay(500);
}
}else{
sevenSeg(1, 1, 1, 1, 1, 1, 0);
}// 0
}
void sevenSeg (int g, int f, int e, int d, int c, int b, int a)
{
digitalWrite(A, a);
digitalWrite(B, b);
digitalWrite(C, c);
digitalWrite(D, d);
digitalWrite(E, e);
digitalWrite(F, f);
digitalWrite(G, g);
}
Python Script:
import pyrebase
import argparse
import datetime
import time
import math
import serial
from serial import Serial
time_str = datetime.datetime.now().strftime("%Y%b%d_%I:%M:%S%p").upper()
ap = argparse.ArgumentParser()
ap.add_argument("-t", "--temp", help="Patient temperature at time of reading") #
ap.add_argument("-r", "--heart", help="Patient heart rate at the time of reading")
args = vars(ap.parse_args())
#firebase configuration
firebaseConfig = {
"apiKey": "",
"authDomain": "heartrate-firebase.firebaseapp.com",
"databaseURL": "https://heartrate-firebase-default-rtdb.firebaseio.com/",
"projectId": "heartrate-firebase",
"storageBucket": "heartrate-firebase.appspot.com",
"messagingSenderId": "851991577466",
"appId": "1:851991577466:web:daaf323d9af64fd3318cc3",
}
firebase = pyrebase.initialize_app(firebaseConfig)
db = firebase.database()
if args.get("temp", None) is not None:
data = {"Temperature": args.get("temp", None)}
db.child("Temperature").child(time_str).set(data)
if args.get("heart", None) is not None:
data = {"HeartRate": args.get("heart", None)}
db.child("HeartRate").child(time_str).set(data)
user = db.child("HeartRate").get()
for x in user.each():
date = db.child("HeartRate").child(x.key()).child("HeartRate").get()
print("Heart Rate: " + date.val())
userTemp = db.child("Temperature").get()
for x in userTemp.each():
date = db.child("Temperature").child(x.key()).child("Temperature").get()
# date = db.child("Temperature").get()
print("Temperature: " + date.val())
with serial.Serial('COM4', 9600, timeout=5) as ser:
time.sleep(2)
ser.write((date.val() + '\n').encode())
time.sleep(1)
y = ser.read(ser.inWaiting())
print(y)
# ser.close()
All I end up with is displaying 0. Any help or ideas are greatly appreciated. Thanks.
the problem was I was receiving 2\r\n from the database so to remove \r\n I used strip() to remove \r\n and it worked.

Controlling many servos using Arduino and Python over serial continuously

I've been working on this piece of code to control a large array of servos on Arduino using Python.
The code works, but I've seen some strange behavior surrounding timing.
Between each update to the servos, I need a sleep command.
If I don't insert a sleep, the program will work the first time I run it, but if the Python code gets stopped, then I try to connect over serial with Python again, the Arduino is non responsive.
What could be happening to the serial port and how could I prevent this from happening?
Also, am I parsing the data coming into the Arduino the most efficient way possible using memcpy? Or is there a better or more standard way to do this?
I've read about using serialEvent, is there a benefit to using that command for parsing serial data in this situation?
//ARDUINO CODE
#include <Servo.h>
int servoPins[] = {9, 10};
//int servoPins[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38};
//int servoPins[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34};
const int numServos = sizeof(servoPins)/sizeof(int);
Servo servos[numServos];
char serialData[numServos * 3];
char tempData[3];
void setup() {
Serial.begin(9600);
Serial.println("Ready");
for (int i=0; i < numServos; i++) {
servos[i].attach(servoPins[i]);
//servos[i].write(20);
}
}
void loop() {
if (Serial.available()) {
Serial.readBytesUntil('\0', serialData, numServos * 3);
for (int i=0; i < numServos; i++) {
memmove(tempData, serialData + i * 3, 3);
servos[i].write(atoi(tempData));
}
}
}
#PYTHON CODE
""" Control n servos on n arduinos over serial
"""
import glob
import platform
import serial
from time import sleep
import sys
'''
Servo
Id number, angle for servo, Arduino port servo is on
For now the port is used as an index, so please number them going from 0-n
'''
class Servo:
id_num = 0
angle = 0
port = 0
def __init__(self, id_num, angle, port):
self.id_num = id_num
self.angle = angle
self.port = port
'''
ServoDriver
-Stores a list of servos
-Open ports to Arduinos
-Stores a list of those ports
-Creates a map of which servos are on which ports
-Provides a way to update the angle of all servos on all ports
'''
class ServoDriver:
def __init__(self, servos):
self.ports = self.open_ports()
self.servos = servos
# looks for all devices that have the same name pattern as an Arduino and opens them
def open_ports(self):
# find arduinos
# note: currently this is Mac only
devices = glob.glob('/dev/tty.usbmodem*')
print devices
if len(devices) == 0:
print "No Arduinos found"
sys.ext(1)
ports = []
for device in devices:
try:
# connect to serial port
ports.append(serial.Serial(device, 9600))
except:
print 'Failed to open port'
sys.ext(1)
# need a short delay right after serial port is started for the Arduino to initialize
sleep(2)
return ports
# update the angle of all servos on all ports
def update(self, servos):
debug = True
servo_data = []
for p in self.ports:
servo_data.append('')
for servo_update in servos:
for servo_stored in self.servos:
if servo_stored.id_num == servo_update.id_num:
this_port = servo_stored.port
break
# constrain servo angles to avoid damaging servos
if servo_update.angle > 135:
servo_update.angle = 135
else if servo_update.angle < 45:
servo_update.angle = 45
# append angle to the datum for this port
servo_data[this_port] = servo_data[this_port] + str(servo_update.angle).zfill(3)
for servo_datum in servo_data:
# append null byte for arduino to recognize end of data
servo_datum = servo_datum + "\0"
# send data to the Arduinos
for port,servo_datum in zip(self.ports,servo_data):
port.write(servo_datum)
def close_ports(self):
print 'closing ports'
for port in self.ports:
port.close()
# generates values for making a servo sweep back and forth
def servo_iter():
l = []
#for i in range(0,1):
l.append(40)
#for i in range(0,1):
l.append(80)
for pos in l:
yield pos
def servo_iter_2(total):
for i in range(0,total):
yield i
if __name__ == "__main__":
# create a list of servos with mappings to ports
# if you have the wrong number of servos it acts weird
#num_servos = 32
num_servos = 2
servos = []
servos.append(Servo(0, 40, 0))
servos.append(Servo(1, 40, 0))
'''
servos.append(Servo(2, 40, 0))
servos.append(Servo(3, 40, 0))
servos.append(Servo(4, 40, 0))
servos.append(Servo(5, 40, 0))
servos.append(Servo(6, 40, 0))
servos.append(Servo(7, 40, 0))
servos.append(Servo(8, 40, 0))
servos.append(Servo(9, 40, 0))
servos.append(Servo(10, 40, 0))
servos.append(Servo(11, 40, 0))
servos.append(Servo(12, 40, 0))
servos.append(Servo(13, 40, 0))
servos.append(Servo(14, 40, 0))
servos.append(Servo(15, 40, 0))
servos.append(Servo(16, 40, 0))
servos.append(Servo(17, 40, 0))
servos.append(Servo(18, 40, 0))
servos.append(Servo(19, 40, 0))
servos.append(Servo(20, 40, 0))
servos.append(Servo(21, 40, 0))
servos.append(Servo(22, 40, 0))
servos.append(Servo(23, 40, 0))
servos.append(Servo(24, 40, 0))
servos.append(Servo(25, 40, 0))
servos.append(Servo(26, 40, 0))
servos.append(Servo(27, 40, 0))
servos.append(Servo(28, 40, 0))
servos.append(Servo(29, 40, 0))
servos.append(Servo(30, 40, 0))
servos.append(Servo(31, 40, 0))
servos.append(Servo(32, 40, 0))
'''
#if len(servos) != num_servos:
# print 'wrong number of servos'
# sys.ext(1)
# comment out the next two lines if you only have 1 arduino
#servos.append(Servo(2, 40, 1))
#servos.append(Servo(3, 40, 1))
#servos.append(Servo(4, 40, 2))
#servos.append(Servo(5, 40, 2))
angles = []
for i in range(0,len(servos)):
angles.append(40)
try:
# instantiate a driver
# must happen inside try-finally
driver = ServoDriver(servos)
iter1 = False
if iter1:
pos = servo_iter()
else:
pos = servo_iter_2(len(servos))
while True:
try:
x = pos.next()
except StopIteration:
if iter1:
pos = servo_iter()
else:
pos = servo_iter_2(len(servos))
x = pos.next()
# create a list of servos with ids and angles to update positions of servos
if iter1:
for servo in servos:
servo.angle = x
else:
for i,servo in zip(angles,servos):
servo.angle = i
# call the driver with the list of servos
driver.update(servos)
sleep(0.5)
for i in range(0, len(servos)):
if i == x:
angles[i] = 80
else:
angles[i] = 40
# close the serial port on exit, or you will have to unplug the arduinos to connect again
finally:
driver.close_ports()
I think the right answer here was to add a delay to the Arduino.
Your Arduino will reset every time you make a serial connection over usb. If you want a temporary disable, you can insert a 10 microfarad capacitor between ground and reset. This will keep it from auto-reseting, and can be easily removed for program uploading.

Categories