MrYsLab / PyMata

A Python client class library for Interaction with Standard Firmata
GNU Affero General Public License v3.0
95 stars 40 forks source link

piezo_beep #37

Closed ghost closed 6 years ago

ghost commented 6 years ago

Hi, I can use my loudspeaker with the piezo_beep, but I don't know why it doesn't work with very short tones. It works with as short as 50ms, but for shorter ones is not precise at all. What should I do? Thank you!

MrYsLab commented 6 years ago

@franjmt89 The FirmataPlus sketch code is using the standard Arduino tones library. I am not set up to measure the duration, but would you know if you use the Arduino tone library directly, do you get any better precision?

ghost commented 6 years ago

I'm a very amateur user, so I'm not quite sure how to use the Arduino tone library. When I control the loudspeaker with the Arduino I can get a very precise tone duration. Right now this is how my code for the loudspeaker looks like:

def PlayTone(frequency, duration): global speakerPin board.play_tone(speakerPin, board.TONE_TONE, frequency, duration)

And with this I can get a the frequency I want, but duration smaller than 100ms is not working very well.

MrYsLab commented 6 years ago

Most likely, the timing loop within FirmataPlus is causing the issue when you are going below 100ms. The tone feature was added to support tone for s2a_fm users when using Scratch.

May I ask why you need to produce a tone with a duration below 100ms?

ghost commented 6 years ago

I need to use it as a cue for initiation of task.

MrYsLab commented 6 years ago

I just ran the following program with a duration of 10ms and I cannot perceive a difference in the lengths of the beeps. I used both Python 2.17 and 3.6.3 and both work the same. I am running on an Arduino Uno. Could you please try this program and let me know if you are still hearing a problem?

You may have to change the COM port to match your system and the pin for the buzzer.

import time
import sys
import signal

from PyMata.pymata import PyMata

BEEPER = 3  # pin that piezo device is attached to

# create a PyMata instance
board = PyMata("/dev/ttyACM0")

def signal_handler(sig, frm):
    print('You pressed Ctrl+C!!!!')
    if board is not None:
        board.reset()
    sys.exit(0)

signal.signal(signal.SIGINT, signal_handler)

for i in range(10):
    board.play_tone(BEEPER, board.TONE_TONE, 1000, 10)
    time.sleep(1)

board.close()
MrYsLab commented 6 years ago

I am closing this issue since I have not heard from you. If you are still having issues, you can leave a comment on this issue and I will receive it. I will reopen the issue if needed.

Kushal4092 commented 5 years ago

hi i tried to run the code above to for the play tone function, it did not work. Then i changed it to this in order for it run

BEEPER = 3 # pin that piezo device is attached to

create a PyMata instance

board = PyMata.Arduino("COM4") board.play_tone(BEEPER, board.TONE_TONE, 1000, 10) time.sleep(1)

board.close()

It still did not work. Please let know what i did wrong. I have changed the com thanks

MrYsLab commented 5 years ago

@Kushal4092 I just ran the example program https://github.com/MrYsLab/PyMata/blob/master/examples/piezo/piezo_beep.py and it works here.

Do you have FirmataPlus loaded onto your Arduino? Here are the instructions to do so: https://github.com/MrYsLab/pymata-aio/wiki/Uploading-FirmataPlus-to-Arduino

Is your piezo device a 5 volt device?

Here is an article on wiring up a piezo device and some sample code to drive it. It does not use Firmata but the tone library directly. Does this work for you?

Kushal4092 commented 5 years ago

This is what i got when trying to setup firmataplus Arduino: 1.8.2 (Windows 10), Board: "Arduino Leonardo"

C:\Program Files (x86)\Arduino\libraries\Firmata\examples\FirmataPlus32u4\FirmataPlus32u4.ino:44:29: fatal error: FirmataPlus32u4.h: No such file or directory

include

                         ^

compilation terminated.

exit status 1 Error compiling for board Arduino Leonardo.

This report would have more information with "Show verbose output during compilation" option enabled in File -> Preferences.

MrYsLab commented 5 years ago

@Kushal4092 I just downloaded and installed the latest version of the Arduino IDE. Next, I downloaded libraries.zip from https://github.com/MrYsLab/pymata-aio/blob/master/FirmataPlus/libraries.zip Then I unzipped this file into C:\Documents/Arduino directory: image

I then opened the Arduino IDE and selected Examples from the File menu and selected Examples/FirmataPlus32u4 and compiled.

image

Did you install the contents of libraries.zip into the correct directory on your computer?

Kushal4092 commented 5 years ago

now I did installed in the right directory but now its giving me printData("argc = ", argc); printDATA("x",0)

are these something that i need to worry about.

MrYsLab commented 5 years ago

@Kushal4092 Are those coming up as warnings when you compile/upload the sketch? If they are warnings, you can safely ignore them.

Kushal4092 commented 5 years ago

It works thanks. DO you know what is the unit of frequency in the function play_tone. for the duration its in milliseconds. thanks again

MrYsLab commented 5 years ago

I am glad that it works. The frequency is in hz. I will update the API documentation. Thanks.

Kushal4092 commented 5 years ago

for i in range(1): board.play_tone(BEEPER, board.TONE_TONE, 10, 30000) time.sleep(1) why does its last less than 3 sec when i set it to run for 30 sec

Kushal4092 commented 5 years ago

Also can I use pyfirmata instead of pymata and use playtone function. If so how is it possible? I found this function "connect_to_firmata("com3")" but not able to make it work. please help. Thanks

MrYsLab commented 5 years ago

@Kushal4092 It looks like you might have found a bug in the Arduino tone library. I ran some tests using Arduino sketches, and the duration parameter does not work as expected with the native sketches as well. I will update the code and documentation to remove the duration parameter for the next release.

I suggest you structure your code something like this:

import time
import sys
import signal

from PyMata.pymata import PyMata

BEEPER = 3  # pin that piezo device is attached to

# create a PyMata instance
board = PyMata("/dev/ttyACM0")

def signal_handler(sig, frm):
    print('You pressed Ctrl+C!!!!')
    if board is not None:
        board.reset()
    sys.exit(0)

signal.signal(signal.SIGINT, signal_handler)

# play a continuous tone, wait 30 seconds and then turn tone off
board.play_tone(BEEPER, board.TONE_TONE, 1000, 0)
time.sleep(30)
board.play_tone(BEEPER, board.TONE_NO_TONE, 1000, 0)

board.close()

For pyfirmata, you will need to contact its repository maintainer, since I do not maintain that repository.

Kushal4092 commented 5 years ago

When would the next update? Thanks

MrYsLab commented 5 years ago

On second thought, I will not be changing the code, since I do not want to change things for people that may be currently using the duration parameter. I do not wish to break their code. Instead, I will document the preferred way of controlling tone in a note in the wiki. That preferred way is to turn tone on with a continuous tone (duration 0), sleep, and then turn the tone off.

I should have a note completed in the next few days.

MrYsLab commented 5 years ago

I just updated the wiki. You can view it here: https://github.com/MrYsLab/PyMata/wiki/Preferred-Way-To-Control-A-Piezo-Tone-Device

Kushal4092 commented 5 years ago

Hi I have question regrading reading. I was trying to read an analog pin first then write it and read the written value and print. I have been getting 0 after writing it to the pin. Also what kind of value does it out put. for example voltage or different unit.

Kushal4092 commented 5 years ago

This my code import PyMata from PyMata.pymata import PyMata import time

port = 'COM4' board = PyMata(port)

A1 = i2c_config(self, pin_type = analog, data_pin = 1)

a1 = board.analog_read(pin=1)

print('a1 read before write: ' + str(a1))

time.sleep(5)

board.analog_write(pin=1,value=5)

a2=board.analog_read(pin=1)

print(a2)

board.close()

MrYsLab commented 5 years ago

Hi, The terminology that Arduino uses can be very confusing. The analog pins A0 and above are only analog inputs (they cannot be configured for analog output). To add to the confusion, the Ax pins can be configured to be digital inputs and outputs, and then the pin number designation changes. For example, A0 is identified as pin 14 if it is used in a digital mode. Analog output is actually not analog at all, but PWM. For the Uno only pins 3, 5, 6, 9, 10 and 11 can be configured as PWM pins. PWM is an output only mode. To make things more confusing, on the Uno, pin A4 is used for i2c data, and pin A5 is used for i2c clock. I hope that this makes things a little clearer, but if not, please feel free to ask any questions you might have.

Kushal4092 commented 5 years ago

Do u have Pymata3 API which i can use as a reference. like then one you had for pymata http://dawnrobotics.github.io/PyMata/PyMata.pymata.PyMata-class.html

MrYsLab commented 5 years ago

There are wiki pages for both PyMata and its API is defined here. and pymata-aio the pymata3 API defined here.

Examples can be found on the wiki page. To get you started here is a blink script using pymata3:

from pymata_aio.pymata3 import PyMata3
from pymata_aio.constants import Constants

BOARD_LED = 13
board = PyMata3()

def setup():
    board.set_pin_mode(BOARD_LED, Constants.OUTPUT)

def loop():
    print("LED On")
    board.digital_write(BOARD_LED, 1)
    board.sleep(1.0)
    print("LED Off")
    board.digital_write(BOARD_LED, 0)
    board.sleep(1.0)

if __name__ == "__main__":
    setup()
    while True:
        loop()

Notice that pymata3 sleep is used and not the standard library sleep. Also, if you are going to build an application using a blocking library, you may get some unexpected results. If you have any questions, please feel free to ask.

Kushal4092 commented 5 years ago

What does ANALOG mean when using set_pin_mode(a1,ANALOG)does it operate both ways as input and output

Kushal4092 commented 5 years ago

board.set_pin_mode(0,Constants.ANALOG) a1 = board.analog_read(pin=0)

print('a1 read before write: ' + str(a1))

let me know if its right , if not how can i fix it

MrYsLab commented 5 years ago

Here is an example of some code that will allow a potentiometer connected to pin A2 to control the brightness of an LED connected to pin 6. We need to set the mode for pin A2 to ANALOG because that triggers firmata (on the Arduino) to automatically report any value changes reported on that pin.

The pin mode for the LED is set to PWM. This is the way the Firmata protocol defines things internally, so pymata3 is consistent with this. When we write to the PWM pin, the command is analog_write. This is to be consistent with the way Arduino describes its PWM write commands.


from pymata_aio.pymata3 import PyMata3
from pymata_aio.constants import Constants

"""
Use a potentiometer connected to pin A2 to control
the brightness of an LED connected to pin 6

Pin6 is a PWM pin.
"""

# Led to control via PWM
LED = 6
POT = 2

# create a PyMata3 instance and name it board
board = PyMata3()

# set the pin mode for pin 6 to be PWM
board.set_pin_mode(LED, Constants.PWM)

# set the pin mode for pin a2 to be analog in.
# we set the pin mode so that firmata will automatically
# report any value changes for a2
board.set_pin_mode(POT, Constants.ANALOG)

# The pot will return a value between 0 and 1024.
# PWM outputs take a value of 0-256 so we will scale the value of the
# pot to match.

while True:
    try:
        pot_value = board.analog_read(POT)
        led_brightness = pot_value // 4

        board.analog_write(LED, led_brightness)
    except KeyboardInterrupt:
        board.shutdown()
MrYsLab commented 5 years ago

Here is an adaptation of your example:

from pymata_aio.pymata3 import PyMata3
from pymata_aio.constants import Constants

board = PyMata3()

ANALOG_PIN = 2  # this is A2

board.set_pin_mode(ANALOG_PIN, Constants.ANALOG)
# forever read the analog pin until control C is entered
while True:
    try:
        analog_value = board.analog_read(ANALOG_PIN)
        print('Analog read', analog_value)
    except KeyboardInterrupt:
        board.shutdown()
Kushal4092 commented 5 years ago

why does the the out put from pin 6 lower than the input? is it due to fact that it has different transistors on the arduino.

MrYsLab commented 5 years ago

What mode are you setting - digital or PWM? When you say a lower level, what levels are you seeing?

Kushal4092 commented 5 years ago

PWM which analog_write. the input to A2 is 0.8v and the output from pin 6 is 0.73v. I think the loss of voltage is caused due to the calculation. Also why does the program closes? I load the program and look at my reading and then stop it the program, then re-run the program and it stops, I got the run it again. What am i doing wrong?

MrYsLab commented 5 years ago

Can you copy the code here? I cannot tell why it may be stopping without looking at it.

Kushal4092 commented 5 years ago

from pymata_aio.pymata3 import PyMata3 from pymata_aio.constants import Constants # Led to control via PWM LED = 6 POT = 2

# create a PyMata3 instance and name it board board = PyMata3()

# set the pin mode for pin 6 to be PWM board.set_pin_mode(LED, Constants.PWM)

# set the pin mode for pin a2 to be analog in. # we set the pin mode so that firmata will automatically

# report any value changes for a2 board.set_pin_mode(POT, Constants.ANALOG)

# The pot will return a value between 0 and 1024. # PWM outputs take a value of 0-256 so we will scale the value of the # pot to match.

while True: try: pot_value = board.analog_read(POT) print(pot_value) led_brightness = pot_value // 4

   board.analog_write(LED, led_brightness)
    print(led_brightness)`
except KeyboardInterrupt:
    board.shutdown()
MrYsLab commented 5 years ago

Ok, that looks like my code. By the way, to copy a program here is to surround it with ``` before the first line of code and after the last line and the code will be formatted properly. like this:

some code

I don't think I understand. Are you saying that if you start the program, hit control C and restart it, the code stops by itself? Does it print out any exceptions?

Kushal4092 commented 5 years ago

yes I am just playing with the code. If I press ctrl+c its does not stop, i think i need to make the function keyboardInterrupt. but i stop it using IDE(pycharm) and rerun it gives me this pymata_aio Version 2.16 Copyright (c) 2015-2016 Alan Yorinks All rights reserved.

Using COM Port:com4

Initializing Arduino - Please wait... list index out of range Shutting down ...

Process finished with exit code 0

MrYsLab commented 5 years ago

PyCharm does not pass on the Control C to the running program. To stop a program running in PyCharm, press the red square on the left side of the dialog box. This generates a Control C that is sent to the program.: image To restart it, press the green triangle: image

Kushal4092 commented 5 years ago

The input voltage at A2 is 0.806v and the out to D6 is 0.79v do u whats is causing this error. I am using my DMM to to just see the change in voltage from input to output.

MrYsLab commented 5 years ago

It is probably due to 2 factors. The first is the accuracy of the Arduino ADC (analog input). There is a discussion of this in this article. If you scroll to the bottom of the page, the article quantifies this in terms of voltage.

The second is the fact that PWM is not a true analog ouput but a simulated one. This article might help to understand this.

Kushal4092 commented 5 years ago

Hi, I am trying to read the digital pin but it always give me 0 when I write 1. `from pymata_aio.pymata3 import PyMata3 from pymata_aio.constants import Constants import time

board = PyMata3() pin10 = 10 board.set_pin_mode(pin10, Constants.OUTPUT) timeout = time.time() + 5 board.digital_pin_write(pin10, value=1) while True: a = board.digital_read(pin10) b=board.analog_read(pin10) print("b = ", b) print(a) if time.time() > timeout: break `

MrYsLab commented 5 years ago

The Firmata protocol works differently than a straight Arduino sketch. There is some documentation here: https://github.com/firmata/protocol/blob/master/protocol.md#pin-state-query.

Essentially, with Firmata, when you set a pin as an output pin, if you write to it and then read it back, it will not accurately reflect the level that you wrote. The pin can be set up to be either an input pin or output pin but cannot be both. The mode is selected by the set_pin_mode call.

Also, you cannot do an analog_read on a digital pin, and pin 10 is a digital pin.

Let me know if that does not answer your question.

Kushal4092 commented 5 years ago

Hi, I am using Pymata3 https://htmlpreview.github.io/?https://github.com/MrYsLab/pymata-aio/blob/master/documentation/html/pymata3.m.html#header-classes

library and I am trying to read Rx from my arduino but it says I need to upload FirmataPlusRB. when I do that I get an error. When I upload FirmataPlusRBPixy its fine, but when I am trying to use the pixy_get_block I get empty [] and when I wait but a bit longer the program crashes and says Initializing Arduino - Please wait... Write exception Write exception Write exception

Shutting down ... Write exception

I was using StandardFirmata and It was working fine but I was not able to use the this function.

this is the Code: board.pixy_init(max_blocks=1, cb=None,cb_type=Constants.CB_TYPE_ASYNCIO) print(board.pixy_get_blocks())

MrYsLab commented 5 years ago

I have moved this issue over to the pymata-aio distribution and you may find it here: https://github.com/MrYsLab/pymata-aio/issues/88