I know I asked a similar question before (Formatting a return value from a serial device), but this time around my question is different. I am reading a value from an Arduino, that looks something like this:
value = b'446.45 mV\r\n'
What I need from this, is simply 446.45. My code below works to extract this value, but every once and a while it will decide to not work. I am calling this value many times, up to 10,000 or more. It is frustrating when I get the error: "ValueError: could not convert string to float: '' " when I am on the 9000th iteration of my data collection. Does anyone know what my issue might be?
value = ser2.readline() # gives something like: b'446.45 mV\r\n'
val_str = str(value)
count = val_str.count('.') #count number of decimal points
if count != 1: #make sure there is only one decimal point
val_str = val_str[:6] #keep two decimal points
w = val_str.strip("b")
x = w.strip("mV\\r\\n")
y = float(x) # usually gives: 446.45
I think it is because your device gives different output due to serial port or cable corruption and your program cannot translate it to float.
Unfortunately you did not provide all the data, so I could not test the solution, but this is the best I could think of.
my_str = b'446.45 mV\r\n'
def separate(value):
value = value.decode("utf8") # decoding the value (it is better to use my_str.decode() instead of str(my_str))
value = value.split('m')[0] # removing all the letter that go after m
return float(value) # returning the separated value
separate(my_str)
Assuming you are sending analog Data from your Arduino to Python I highly recommend to send the raw 10-Bit (or sometimes 12-Bit) integers. This will make conversion much easier.
If you have your Arduino doing something like this:
Serial.println(analogRead(some_port));
then the Arduino will send the int data in ascii-bytes.
You can then grab those by doing something like this in python:
value = ser2.readline()
int_value = str(int(value))
# Here you can then calculate voltages based on that
voltage = 5/1023 * int_value
Related
Having a lot of problems with everything today it seems, first time asking a question and I can't even get my code on here correctly!
Essentially what I'm hoping to do, is to import data from a csv file and use it to select and display images using pygame e.g.
screen.blit(row[0],(0,0))
Where row[0] is Rat1 in the csv file, which has been defined in my code as:
Rat1 = pygame.image.load('Rat1.jpg').convert()
However this throws up "argument 1 must be pygame.Surface, not str", which is fair enough, but I'm really struggling to find a way around this and have found some rather bizarre goings on, bizarre to me at least.
I'm new to this, so the best way I can think to get around this, is to change the row[0] in the csv file to 1, and then to import that to my program and create an integer variable from it, e.g.
x = row[0]
int(x)
if x == 1:
x = Rat1
and then plug x in to pygame, e.g.
screen.blit(x,(0,0))
This works if I just have x = Rat1 as a global variable, however doing it as above doesn't change x to = 1, it stays as row[x] so it just doesn't like it.
It boils down to this happening when I tried to test it a bit...
import csv
out = open("CSVTest.csv","rb")
data = csv.reader(out)
data = [row for row in data]
out.close()
print row[0] #this causes it to print a 1, so I know
#it's working and reading as it should
x = row[0] #make a variable
int(x) #doesn't throw up an error, so I assume it
#has changed the csv string to an integer
print x #prints a 1 again
if x == 1:
print "hello?" #doesn't print, so clearly doesn't
#recognise x as an integer
if x == 49: #I'm getting desperate now, ASCII 1?!
print "hello?!" #No joy
So what on earth is it, it doesn't seem to be your standard string, as won't convert obviously in to an integer.
I've tried pygame.image.fromstring(), where the answer probably lies, but I can't get it to work.
Can anyone point out what is wrong with it all and how I can easily call data from a csv file and at least get it recognised as an integer or even better, inserted in to a bit of pygame code and displayed?
I've read things from csv files and displayed images with pygame without a hitch, but getting the two to mate seems tough, beyond me certainly.
Any help is much appreciated!
int() is the Python standard built-in function to convert a string into an integer value. You call it with a string containing a number as the argument, and it returns the number converted to an actual integer:
print int("1") + 1
The above prints 2.
If you know the structure of your list (that it simply contains lists, only one level), you could do this:
T2 = [map(int, x) for x in T1]
Or...
Try this.
x = "1"
x is a string because it has quotes around it, but it has a number in it.
x = int(x)
Since x has the number 1 in it, I can turn it in to a integer.
To see if a string is a number, you can do this.
def is_number(var):
try:
if var == int(var):
return True
except Exception:
return False
x = "1"
y = "test"
x_test = is_number(x)
print(x_test)
It should print to IDLE True because x is a number.
y_test = is_number(y)
print(y_test)
It should print to IDLE False because y in not a number.
I have the following code which compares the input value that comes as a string with the one the function constracts. Basically checks the if the number the user enters is correct. The function works but only for 2 decimal points but the user is allowed to enter 2 to 4 decimal digits... How can I construct the right value?
def check_currency(self, amount):
amount = amount.replace("+", "")
amount = amount.replace("-", "")
sInput = amount.replace(",", ".")
locale.setlocale(locale.LC_ALL, self.LANG)
result = locale.currency(float(sInput), symbol=False, grouping=True)
if (amount == result):
return True
else:
return False
PS: The self.LANG get the respective value based on the system that the code runs on.
You aren't missing anything. locale.currency formats numbers according to the values in the dict returned by locale.localeconv() and that's what it's supposed to do. Naturally, 'frac_digits' is typically 2 since... well... you know.
Regarding what to do:
First, you can check 'int_frac_digits' in localeconv() - maybe it's good enough for you.
If not, since locale.currency is located in a Python source module, you can rig... I mean, override its logic. Looking at the source, the simplest method appears to be to replace locale.localeconv() with a wrapper.
Be wary though since such a change will be global. If you don't want it to affect other code using locale, alter local copies of the entities (or the entire module) or make a changed entity e.g. require an additional parameter to behave differently.
On a conceptual note: locale is actually correct - for its purpose - in not allowing to alter the representation. Its task is to format information of a few types according to the local convention - so whatever culture you user pertains to, they will see information in the way they are used to. If you alter the format in any way - that wouldn't any longer be "the local convention"! In fact, by requiring 3 decimal digits, you are already making assumptions about the local convention - which may not stand. E.g. in a decent share of currencies, even small sums can numerically be in the thousands.
def check_currency(self, amount):
amount = amount.replace("+", "")
amount = amount.replace("-", "")
sInput = amount.replace(",", ".")
length = len(amount)
decimals = len(sInput[sInput.find(".")+1:])
locale.setlocale(locale.LC_ALL, self.LANG)
if not sInput:
return "Empty Value"
if decimals<=2:
digit = decimals
result = locale.format('%%.%if' % digit, abs(Decimal(sInput)), grouping=True, monetary=True)
if decimals>2:
sInput = amount.replace(".", "")
digit = 0
result = locale.format('%%.%if' % digit, abs(Decimal(sInput)), grouping=True, monetary=True)
if (amount == result):
return True
else:
return False
I changed the function as you see above and it works perfect !! You can check the code above for anyone who might need it :)
Thank you again
No clue why this is happening. I must be missing something obvious.
I'm trying to make a counter print out something like SMPTE code (hours:minutes:seconds:frames (assuming 24fps)).
Code thus far:
import time
s_time = time.time()
def format_time():
t = time.time() - s_time
if t < 1:
print '00:00:00:%02d' % int(t/0.041666666666666664)
elif t < 60:
t = str(t).split('.')
print '00:00:%02d:%02d' % (int(t[0]), int(int(t[1][:4])/0.041666666666666664) )
while True:
format_time()
All seems well initially, until the duration surpasses 1 second and the elif branch is entered. Seconds print out fine, but the frames print out the full multi-digit result of the calculation. Given that the formatting operator is specifying %02d, just like it does in the first if branch (which behaves as expected), why is it not obeying in the second branch? I'm at a loss trying to figure out why it is still printing the full result rather than the truncated version.
You are trying to get the integer part and the fractional part of the float to print your result. It is a good practice to use operators and functions on numeric data directly instead of adding a heavy overhead by converting the float into str and back to number.
Use the math module modf function for that. It will also simplify your algorithm.
import time
import math
s_time = time.time()
def format_time():
t = time.time() - s_time
if t < 60:
f,i = math.modf(t)
print '00:00:%02d:%02d' % (i, f/0.041666666666666664)
while True:
format_time()
PS: for your code error, in your elif block, you are passing t as an integer with a huge value instead of passing the 0.xxxxx value of it. This error wouldn't occur if you keep using the math functions of floats.
I expect you want something like this:
hours = int(t)/3600
minutes = (int(t)/60)%60
seconds = int(t)%60
frames = (t-int(t))*24
print '%02d:%02d:%02d:%02d' % (hours, minutes, seconds, frames)
%02d means: print the integer and if it's shorter than 2 digits, prefix it with zeroes.
it doesn't limit the formatted string to two digits.
edit: one way of getting the first 2 (rounded) digits of a number n would be:
n = 13900
print round(n/10**math.floor(math.log10(n)-1))
or if you don't care about rounding, just cut the string...
I'm toying around with writing creating a serial code generator/validator, but I can't seem to get how to do a proper check.
Here's my generator code:
# Serial generator
# Create sequences from which random.choice can choose
Sequence_A = 'ABCDEF'
Sequence_B = 'UVWQYZ'
Sequence_C = 'NOPQRS'
Sequence_D = 'MARTIN'
import random
# Generate a series of random numbers and Letters to later concatenate into a pass code
First = str(random.randint(1,5))
Second = str(random.choice(Sequence_A))
Third = str(random.randint(6,9))
Fourth = str(random.choice(Sequence_B))
Fifth = str(random.randint(0,2))
Sixth = str(random.choice(Sequence_C))
Seventh = str(random.randint(7,8))
Eighth = str(random.choice(Sequence_D))
Ninth = str(random.randint(3,5))
serial = First+Second+Third+Fourth+Fifth+Sixth+Seventh+Eighth+Ninth
print serial
I'd like to make a universal check so that my validation code will accept any key generated by this.
My intuition was to create checks like this:
serial_check = raw_input("Please enter your serial code: ")
# create a control object for while loop
control = True
# Break up user input into list that can be analyzed individually
serial_list = list(serial_check)
while control:
if serial_list[0] == range(1,5):
pass
elif serial_list[0] != range(1,5):
control = False
if serial_list[1] == random.choice('ABCDEF'):
pass
elif serial_list[1] != random.choice('ABCDEF'):
control = False
# and so on until the final, where, if valid, I would print that the key is valid.
if control == False:
print "Invalid Serial Code"
I'm well aware that the second type of check won't work at all, but it's a place holder because I've got no idea how to check that.
But I thought the method for checking numbers would work, but it doesn't either.
The expression `range(1, 5)' creates a list of numbers from 1 to 4. So in your first test, you're asking whether the first character in your serial number is equal to that list:
"1" == [1, 2, 3, 4]
Probably not...
What you probably want to know is whether a digit is in the range (i.e. from 1 to 5, I assume, not 1 to 4).
Your other hurdle is that the first character of the serial is a string, not an integer, so you would want to take the int() of the first character. But that will raise an exception if it's not a digit. So you must first test to make sure it's a digit:
if serial_list[0].isdigit() and int(serial_list[0]) in range(1, 6):
Don't worry, if it's not a digit, Python won't even try to evaluate the part after and. This is called short-circuiting.
However, I would not recommend doing it this way. Instead, simply check to make sure it is at least "1" and no more than "5", like this:
if "1" <= serial_list <= "5":
You can do the same thing with each of your tests, varying only what you're checking.
Also, you don't need to convert the serial number to a list. serial_check is a string and accessing strings by index is perfectly acceptable.
And finally, there's this pattern going on in your code:
if thing == other:
pass
elif thing != other:
(do something)
First, because the conditions you are testing are logical opposites, you don't need elif thing != other -- you can just say else, which means "whatever wasn't matched by any if condition."
if thing == other:
pass
else:
(do something)
But if you're just going to pass when the condition is met, why not just test the opposite condition to begin with? You clearly know how to write it 'cause you were putting it in the elif. Put it right in the if instead!
if thing != other:
(do something)
Yes, each of your if statements can easily be cut in half. In the example I gave you for checking the character range, probably the easiest way to do it is using not:
if not ("1" <= serial_list <= "5"):
Regarding your python, I'm guessing that when your wrote this:
if serial_list[0] == range(1,5):
You probably meant this:
if 1 <= serial_list[0] <= 5:
And when you wrote this:
if serial_list[1] == random.choice('ABCDEF'):
You probably meant this:
if serial_list[1] in 'ABCDEF':
There are various other problems with your code, but I'm sure you'll improve it as you learn python.
At a higher level, you seem to be trying to build something like a software activation code generator/validator. You should know that just generating a string of pseudo-random characters and later checking that each is in range is an extremely weak form of validation. If you want to prevent forgeries, I would suggest learning about HMAC (if you're validating on a secure server) or public key cryptography (if you're validating on a user's computer) and incorporating that into your design. There are libraries available for python that can handle either approach.
My friend was given this free google website optimizer tshirt and came to me to try and figure out what the front logo meant.
t-shirt
So, I have a couple of guesses as to what it means, but I was just wondering if there is something more.
My first guess is that each block represents a page layout, and the logo "You should test that" just means that you should use google website optimizer to test which is the best layout. I hope that this isn't the answer, it just seems to simple and unsatisfying.
Well, I've spent the past hour trying to figure out if there is any deeper meaning, but to no avail. So, I'm here hoping that someone might be able to help.
I did though write a program to see if the blocks represent something in binary. I'll post the code below. My code tests every permutation of reading a block as 4 bits, and then tries to interpret these bits as letters, hex, and ip addresses.
I hope someone knows better.
#This code interprets the google t-shirt as a binary code, each box 4 bits.
# I try every permutation of counting the bits and then try to interpret these
# interpretations as letters, or hex numbers, or ip addresses.
# I need more interpretations, maybe one will find a pattern
import string
#these represent the boxes binary codes from left to right top to bottom
boxes = ['1110', '1000', '1111', '0110', '0011', '1011', '0001', '1001']
#changing the ordering
permutations = ["1234", "1243", "1324", "1342", "1423", "1432",
"2134", "2143", "2314", "2341", "2413", "2431",
"3124", "3142", "3214", "3241", "3412", "3421",
"4123", "4132", "4213", "4231","4312", "4321"]
#alphabet hashing where 0 = a
alphabet1 = {'0000':'a', '0001':'b', '0010':'c', '0011':'d',
'0100':'e', '0101':'f', '0110':'g', '0111':'h',
'1000':'i', '1001':'j', '1010':'k', '1011':'l',
'1100':'m', '1101':'n', '1110':'o', '1111':'p'}
#alphabet hasing where 1 = a
alphabet2 = {'0000':'?', '0001':'a', '0010':'b', '0011':'c',
'0100':'d', '0101':'e', '0110':'f', '0111':'g',
'1000':'h', '1001':'i', '1010':'j', '1011':'k',
'1100':'l', '1101':'m', '1110':'n', '1111':'o'}
hex = {'0000':'0', '0001':'1', '0010':'2', '0011':'3',
'0100':'4', '0101':'5', '0110':'6', '0111':'7',
'1000':'8', '1001':'9', '1010':'a', '1011':'b',
'1100':'c', '1101':'d', '1110':'e', '1111':'f'}
#code to convert from a string of ones and zeros(binary) to decimal number
def bin_to_dec(bin_string):
l = len(bin_string)
answer = 0
for index in range(l):
answer += int(bin_string[l - index - 1]) * (2**index)
return answer
#code to try and ping ip addresses
def ping(ipaddress):
#ping the network addresses
import subprocess
# execute the code and pipe the result to a string, wait 5 seconds
test = "ping -t 5 " + ipaddress
process = subprocess.Popen(test, shell=True, stdout=subprocess.PIPE)
# give it time to respond
process.wait()
# read the result to a string
result_str = process.stdout.read()
#For now, need to manually check if the ping worked, fix later
print result_str
#now iterate over the permuation and then the boxes to produce the codes
for permute in permutations:
box_codes = []
for box in boxes:
temp_code = ""
for index in permute:
temp_code += box[int(index) - 1]
box_codes.append(temp_code)
#now manipulate the codes using leter translation, network, whatever
#binary
print string.join(box_codes, "")
#alphabet1
print string.join( map(lambda x: alphabet1[x], box_codes), "")
#alphabet2
print string.join( map(lambda x: alphabet2[x], box_codes), "")
#hex
print string.join( map(lambda x: hex[x], box_codes), "")
#ipaddress, call ping and see who is reachable
ipcodes = zip(box_codes[0:8:2], box_codes[1:8:2])
ip = ""
for code in ipcodes:
bin = bin_to_dec(code[0] + code[1])
ip += repr(bin) + "."
print ip[:-1]
#ping(ip[:-1])
print
print
t-shirt.
I emailed the Website Optimizer Team, and they said "There's no secret code, unless you find one. :)"
I think Google are just trying to drive their point home - here are a bunch of different representations of the same page, test them, see which is best.
Which block do you like best?
I think it's simply a design, nothing secret, or mysterious.
What if it doesn't mean anything, what if it is just a neat design they came up with?
It says: "You are getting closer".
Well, I can't see an immediate pattern. But if you are testing IP, why not take two blocks of 4 as a single binary number.
Probably it's a base 4 notation?
I would try that, but I don't have any approach to this.
It reminded me of cellular automata:
http://www.wolframalpha.com/input/?i=rule+110
Anyone going that direction?