So I'm trying to use a servo (Doman s0306d) with the pi camera, tried running this script I found to test the motor, it starts running but doesn't stop unless I manually unplug it from the breadboard.
import RPi.GPIO as IO # calling for header file for GPIO’s of PI
import time # calling for time to provide delays in program
IO.setwarnings(False) # do not show any warnings
IO.setmode (IO.BCM) # programming the GPIO by BCM pin numbers. (like PIN29 as‘GPIO5’)
IO.setup(19,IO.OUT) # initialize GPIO19 as an output
p = IO.PWM(19,50) # GPIO19 as PWM output, with 50Hz frequency
p.start(7.5) # generate PWM signal with 7.5% duty cycle
time.sleep(4)
for x in range(0,5): # execute loop forever
p.ChangeDutyCycle(7.5) # change duty cycle for getting the servo position to 90º
time.sleep(1) # sleep for 1 second
p.ChangeDutyCycle(12.5) # change duty cycle for getting the servo position to 180º
time.sleep(1) # sleep for 1 second
p.ChangeDutyCycle(2.5) # change duty cycle for getting the servo position to 0º
time.sleep(1) # sleep for 1 second
p.ChangeDutyCycle(0)
p.stop()
IO.cleanup()
Any ideas ? Thank you.
[EDIT] The servo you are using is a "continuous" servo - so you need to give it the zero speed or "STOP" setting pulse width of 1500us (according to the website http://www.domanrchobby.com/content/?150.html). I haven't used PWM on the pi but if the percentages are of the 50Hz pulse rate (20ms interval) then that should be your 7.5% centre value. You need to make sure the servo gets that pulse before your code exits.
[Original] You are setting the duty cycle to 0 when you exit, which will probably mean the servo doesn't get any pulses. Some servos will stop sometime after they don't get pulses, but some servos (particularly digital servos, but not all) will continue to try achieve the setting from the last pulse they received. Suggest you leave the setting at the mid range 7.5 which you know the servo can achieve and delay for a little while before cleaning up.
Related
I have a friend setting up an irrigation system at his house. He is telling me it won't detect moisture after the first run-through, regardless of whether there is moisture or not. In his own words:
"I’m trying to figure out how to make my program restarts the detection process. Like say my sensor is in soil and it detects water then after a certain period I need it to run again. My problems is that when I run it again and it’s sitting in a cup of water, it’s doesn’t detect the water. I read something about maybe checking the state of the sensor but I couldn’t get anywhere.
Also would I would the delay function to continuously run it in intervals."
He sent me his code today, and I would like to help him, although I am new to Python. Here is the code.
#!/usr/bin/python
import RPi.GPIO as GPIO
import time
#GPIO SETUP
channel = 20
GPIO.setmode(GPIO.BCM)
GPIO.setup(channel, GPIO.IN)
def callback(channel):
if GPIO.input(channel)==0:
print (" Water Detected!")
else:
print ( 'NO Water Detected!')
GPIO.add_event_detect(channel, GPIO.FALLING, bouncetime=300) # let us know when the pin goes HIGH or LOW
GPIO.add_event_callback(channel, callback) # assign function to GPIO PIN, Run function on change
# infinite loop
while True:
time.sleep(1)
import RPi.GPIO as GPIO # Import Raspberry Pi GPIO library
from time import sleep # Import the sleep function from the time module
GPIO.setwarnings(False) # Ignore warning for now
GPIO.setmode(GPIO.BOARD) # Use physical pin numbering
GPIO.setup(3, GPIO.OUT, initial=GPIO.LOW) # Set pin 8 to be an outputpin and set initial value to low (off)
while True: # Run forever
GPIO.output(3, GPIO.HIGH) # Turn on
sleep(1) # Sleep for 1 second
GPIO.output(3, GPIO.LOW) # Turn off
sleep(1) # Sleep for 1 second
I am attempting to make a simple python script that uses a moisture sensor on GOIP 21 and will output text on a display.
What I have:
Raspberry Pi 4 4GB
Arducam 1602 16x2 LCD Display Module Based on HD44780
KeeYees 5 Pcs High Sensitivity Soil Moisture Sensor Module with Female to Female Jump Wires, Sensor Module Watering System Manager for Arduino TE215
Breadboard 830
It's only a learning attempt, after I figure this out I plan on buying better sensors and actually having them display accurate percentages. For not a simple moisture detected vs no-detected is okay with me.
My code seems to work for outputting to the console, however when I try to output to the LCD, it gives some weird characters and stops. Not sure what to do as i'm not a python wiz (you'd think id be more like php, but nah lol).
Here is my code
#!/usr/bin/python
import RPi.GPIO as GPIO
import time
import sys
sys.path.append('/home/pi/lcd')
import lcd
#GPIO SETUP
moist1 = 21
GPIO.setmode(GPIO.BCM)
GPIO.setup(moist1, GPIO.OUT)
def callback(moist1):
if GPIO.input(moist1):
lcd.GPIO.cleanup()
lcd.lcd_init()
lcd.lcd_byte(lcd.LCD_LINE_1, lcd.LCD_CMD)
lcd.lcd_string("Water Is Good", 2)
lcd.lcd_byte(lcd.LCD_LINE_2, lcd.LCD_CMD)
lcd.lcd_string("Don't Add", 2)
lcd.GPIO.cleanup()
else:
lcd.GPIO.cleanup()
lcd.lcd_init()
lcd.lcd_byte(lcd.LCD_LINE_1, lcd.LCD_CMD)
lcd.lcd_string("Add Water Now!", 2)
lcd.lcd_byte(lcd.LCD_LINE_2, lcd.LCD_CMD)
lcd.lcd_string("!!!!!!!!!!!!!!", 2)
lcd.GPIO.cleanup()
GPIO.add_event_detect(moist1, GPIO.BOTH, bouncetime=300) # let us know when the pin goes HIGH or LOW
GPIO.add_event_callback(moist1, callback) # assign function to GPIO PIN, Run function on change
# infinite loop
while True:
time.sleep(1)
I can't figure out what I am doing wrong. Please let me know if you see it. Thanks
I'm using a Raspberry Pi 2 and a breadboard to make a morse code interpreter. The circuit is a simple button that lights up an LED when pressed. How could I use functions to count how long the button is held down?
You haven't given sufficient details of your circuit to pin this down to your particular use case, so I'll suggest the following (on which I'll base my code):
Connect the LED (with series resistor) to GPIO 12
Connect a 10k resistor between GPIO 11 and the 3.3V rail (acts as a pull-up)
Connect the push-button between GPIO 11 and Ground (0V).
I'd then write the code to monitor the pin and log the time for each press into a list. You can read out the values in the same order which allows you to process the times and interpret the code from them.
import RPi.GPIO as GPIO
import time
# set up an empty list for the key presses
presses = []
# set up the GPIO pins to register the presses and control the LED
GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.OUT)
GPIO.setup(11, GPIO.IN)
# turn LED off initially
GPIO.output(12, False)
while True:
# wait for input to go 'low'
input_value = GPIO.input(11)
if not input_value:
# log start time and light the LED
start_time = time.time()
GPIO.output(12, True)
# wait for input to go high again
while not input_value:
input_value = GPIO.input(11)
else:
# log the time the button is un-pressed, and extinguish LED
end_time = time.time()
GPIO.output(12, False)
# store the press times in the list, as a dictionary object
presses.append({'start':start_time, 'end':end_time})
You'll finish up with a list that looks something like this:
[{start:123234234.34534, end:123234240.23482}, {start:123234289.96841, end:123234333.12345}]
The numbers you see here are in units of seconds (this is your system time, which is measured in seconds since the epoch).
You can then use a for loop to run through each item in the list, subtract each end time from the start time, and of course subtract the start of the next press from the end of the previous one, so that you can assemble characters and words based on the gaps between presses. Have fun :-)
I am having the problem, that I am not able to control any of my servos I have. I have two servos, one is a normal servo used in model planes and the second one is a micro sized servo.
I wired both of them separately (The signal cable to a GPIO pin and the other two cables first directly to the board and after to a external power source).
When I try to run them via the similar python code
...
GPIO.setmode(GPIO.BCM)
GPIO.setup(11, GPIO.OUT)
pwm = GPIO.PWM(11, 50)
pwm.start(2)
timelib.sleep(2)
pwm.ChangeDutyCycle(3)
timelib.sleep(2)
...
the servos sometimes just turn for a bit but then stop on one side. After that you can still hear the servo making noises like it is trying to run further. After it turned to the end I can not make it work or make it turn in any way. It will just stay there whatever input I will make. It will just turn to the same end again if I am manually turn them back to the start position. I can not figure it out what I am doing wrong or where I need to change my way of doing it.
Does anyone have any tips or had a similar problem?
I'm thankful for every further tip and further step I will make.
Thanks in advance!
The servos position is controlled by the pulsewidth of a 50 Hz PWM signal. Hence, we need to turn the PWM sequence on at 50 Hz. Note that for a 50 Hz signal, the Period of the signal is 1/50=.02 seconds, or 20 milliseconds. Keep this Period in mind as we will come back to it later. We start by creating a PWM object on Pin 11 with a 50 Hz signal with the command:
pwm=GPIO.PWM(11,50)
We can now start the pwm sequence by giving a command to specify the DutyCycle of the signal. Before we do this, we need to talk a little bit about how servos work. A typical servo wants to see a frequency of 50 Hz on the control line. The position it moves to depends on the pulse width of the signal. Most servos behave roughly as such, but you will need to tweak these numbers for your particular servo. Typically, the servo will go to the full left position when it sees a pulse width of 1 millisecond, it will go the middle position when it sees a pulse width of 1.5 millisecond, and it will go to the full right position when it sees a pulse width of 2 millisecond. Note however, that on the Raspberry Pi we do not specify a pulse width, but we specify a DutyCycle. So, we can use the following relationship:
DutyCycle =PulseWidth/Period
Remember that Period = 1/frequency, so:
DutyCycle = PulseWidth/(1/frequency) = PulseWidth * frequency
The PulseWidth that will give us a full left position is 1 milllisecond. We now calculate the applied DutyCycle to give us the desired position:
DutyCycle = PulseWidth*frequency=.001 *50 = .05 = 5%
So, for a 50 Hz signal, if we set the DutyCycle to 5, then we should see the servo move to the full left position. Similarly, if we set DutyCycle to 7.5, we should get the middle position, and if we set it to 10 we should be in the full right position. You can get all the intermediate positions by linearly scaling between 5 and 10. Note that these values will vary between brands, and between individual servos, so play around with your servo to get it calibrated. We are now ready to apply a command to position the servo. If we want the servo in the full left position, we should set the DutyCycle to 5%. We do that with the command:
pwm.start(5)
This will start the PWM signal, and will set it at 5%. Remember, we already specified the 50 Hz signal when we created the pwm object in our earlier commands. Now if we want to change the position, we can change the DutyCycle. For example, if we want to go to the middle position, we want a DutyCycle of 7.5, which we can get with the command:
pwm.ChangeDutyCycle(7.5)
Now if we want the full right position, we want a duty cycle of 10, which we would get with the command:
pwm.ChangeDutyCycle(10)
Remember, it is not DutyCycle that actually controls servo position, it is PulseWidth. We are creating DutyCycles to give us the desired PulseWidth.
Now, play around with your particular servo and then find the specific DutyCycles that lead to full left and full right positions. For my servo, I find that full left is at DutyCycle=2, and full right is at DutyCycle=12. With these values, I can create a linear equation that will give me any angle I want between 0 and 180. This will make the Raspberry Pi behave much more like the simple and intuitive operation of the Arduino.
To do the linear equation I need two points. Well, I know that for a desired angle of 0, I should apply a DutyCycle of 2. This would be the point (0,2). Now I also know that for a desired angle of 180, I should apply a DutyCycle of 12. This would be the point (180,12). We now have two points and can calculate the equation of the line. (Remember, play with your servo . . . your numbers might be slightly different than mine, but the methodology below will work if you use your two points)
Remember slope of a line will be:
m=(y2-y1)/(x2-x1)=(12-2)/180-0)=10/180 = 1/18
We can now get the equation of the line using the point slope formula.
y-y1=m(x-x1)
y-2=1/18*(x-0)
y = 1/18*x + 2
Putting in our actual variables, we get
DutyCycle = 1/18* (DesiredAngle) + 2
Now to change to that position, we simply use the command:
pwm.ChangeDutyCycle(DutyCycle)
See more at: http://www.toptechboy.com/raspberry-pi/raspberry-pi-lesson-28-controlling-a-servo-on-raspberry-pi-with-python/#sthash.LRmf7708.dpuf
Alternately, you can use my library which hides most of the pwm and GPIO board complexity. Sample code:
from RaspberryMotors.motors import servos
s1 = servos.servo(11) #create the servo objects , connected to GPIO board pin #11
s1.setAngleAndWait(45) # move S1 position of 45 degrees
s1.shutdown() #will clean up the GPIO board as well`
You can view download the code or the library via any of the two links:
https://github.com/vikramdayal/RaspberryMotors or
https://pypi.org/project/RaspberryMotors/#description
I am looking for pointers/tips on how to generate a synthesized sound signal on the BeagleBone akin to watch the tone() function would return on a Arduinos. Ultimately, I'd like to connect a piezo or a speaker on a GPIO pin and hear a sound wave out of it. Any pointers?
This is how I managed to solve this question on the Beaglebone using Python and PyBBIO:
#!/usr/bin/python
# Circuit:
# * A Piezo is connected to pin 12 on header P8. - GPIO1_12
# * A LED is connected to pin 14 on header P8. - GPIO0_26
# * A button is connected to pin 45 on header P8. - GPIO2_6
# Use a pull-down resistor (around 10K ohms) between pin 45 and ground.
# 3.3v for the other side of the button can be taken from pins 3 or 4
# on header P9. Warning: Do not allow 5V to go into the GPIO pins.
# * GND - pin 1 or 2, header P9.
def setup(): # this function will run once, on startup
pinMode(PIEZO, OUTPUT) # set up pin 12 on header P8 as an output - Piezo
pinMode(LED, OUTPUT) # set up pin 14 on header P8 as an output - LED
pinMode(BUTTON, INPUT) # set up pin 45 on header P8 as an input - Button
def loop(): # this function will run repeatedly, until user hits CTRL+C
if (digitalRead(BUTTON) == HIGH):
# was the button pressed? (is 3.3v making it HIGH?) then do:
buzz()
delay(10) # don't "peg" the processor checking pin
def delay(j): #need to overwrite delay() otherwise, it's too slow
for k in range(1,j):
pass
def buzz(): #this is what makes the piezo buzz - a series of pulses
# the shorter the delay between HIGH and LOW, the higher the pitch
limit = 500 # change this value as needed;
# consider using a potentiometer to set the value
for j in range(1, limit):
digitalWrite(PIEZO, HIGH)
delay(j)
digitalWrite(PIEZO, LOW)
delay(j)
if j==limit/2:
digitalWrite(LED, HIGH)
digitalWrite(LED, LOW) # turn it off
run(setup, loop)
Check out this page. From userland (e.g. python) you can use set a pin to high or low by writing to the correct sysfs file in /sys/class/gpio.
The GPIO pins of the AM3359 are low-voltage and with insufficient driver strength to directly drive any kind of transducer. You would need to build a small circuit with a op-amp, transistor or FET to do this.
Once you've done this, you'd simply set up a timer loop to change the state of the GPIO line at the required frequency.
By far the quickest and easiest way of getting audio from this board is with a USB Audio interface.