Can't control any servo with my RaspberryPi 2 - python

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

Related

Python OpenGL glRotatef - looking for the correct multiplier

I am using gluLookAt with a camera whose coordinates are xCam, yCam and zCam. The coordinates of the object the camera is looking at are xPos, yPos, and zPos. There are variables named mouseturnX and mouseturnY, which measure the deviation of the mouse from the middle of the screen in the x-axis and the y-axis. The variable camdist describes the distance between camera and the object it looks at.
The code of the cameraposition is this:
xCam = sin(mouseturnX)*camdist+xPos
yCam = mouseturnY+yPos
zCam = cos(mouseturnX)*camdist+zPos
I now made a polygon object, which I rotate with:
glRotatef(mouseturnX,0,1,0)
Usually it should only show me the backside of the object, it does not matter which position the camera has. But now it does not turn correctly. I tried it with other rotation-axises, there it works fine, but with the y-axis it just does not want to work. I tried changing the camdist from positive to negative, the mouseturnX in the glRotatef function from positive to negative and back to positive again. It just does not work. I used glPushMatrix before the rotation command and glPopMatrix after it. One line before the rotation command I used the translate function to set a fixpoint for the polygon.
Edit: The polygon actually spins, but not in the right amount. It seems like I have to multiply the rotation of the polygon with something.
I found the multiplicator by trying. It is 56.5. It is not perfect, but it works.

change multiple kivy properties without intermediate event dispatch

I'm using a simple NumericProperties and looking for a way to (quasi-)simultaneously change two property values without an intermediate event dispatch.
Here is a minimal example (all are NumericProperty).
motor: offset + delta
Imagine this is some kind of devices (say a motor attached to a larger CNC machinery). The motor physically moves whenever the value changes, say on an "on_motor" event. The user usually moves the motor by updating the "delta" value, while the "offset" value is some calibration.
Once in a while the motor needs recalibration. It needs to update the "offset" value without physically changing the motor (and giving a new "delta" value). An assignment like
(offset, delta) = (offset + delta, 0)
would provide all correct values, except inbetween this assignment on_motor is called with the intermediate values that would correspond to
offset = offset + delta # motor changes by the relative amount +delta
delta = 0 # motor changes by the relative amount -delta
Is there a more general way to have two assignments of properties atomically (without intermediate change events?)
Should i try to unbind the motor NumericProperty from the offset EventDispatcher, at least during calibration ?
If all three of those values are Properties, then an event will be generated for every change to offset or delta, and a resulting event will be generated by the motor property each time. So, even if you simultaneously change offset and delta, two separate events will be generated.
If you have a method on_motor() that responds to changes to the motor Property, you could create a BooleanProperty, maybe named isCalibrating. Then in your on_motor() you could have (at the start of that method):
if self.isCalibrating:
return
Then you could just set isCalibrating to True during calibration.

Raspberry pi servo doesn't stop

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.

Turn led on in function with different args. Python

I can’t seem to wrap my head around how to do this. I tried searching but it just returns how to turn on a led with a raspberry pi. So here I am. I am trying to make a function so that I can check multiple values and if they match turn a led on. I guess my major issue is when it is true the led turns on, but if the next function shares the same led it will turn it off. If that makes sense.
#
def turnon(led,x)
if x == updating_x:
turn led # from led, on
else:
turn led # from led, off
while True:
#led 1
turnon(1,20)
#led 1
turnon(1,50)
#led 2
turnon(2,10)
So say updating_x=20 so the led #1 would turn on but then the next function that has the same LED would turn it off. I thought about changing it to this
if x == updating_x:
turn led # from led, on
time.sleep()
turn led off
else:
pass
But it is somewhat time critical and I will want the multiple leds to turn on together and not just one after the other. I don’t want to get caught just sleeping if the value change true for another led.
FYI, the plan is 60ish leds with around 70 different check values
Any ideas on the right way to do this? and Thanks!
Edit:
Sorry I will try and explain it better. So with the example I gave, I want led 1 to turn on if the update_x == 20 or 50. (if update_x = 20 now) In the loop, it runs the first function which is true so the led turns on. But the second function will be false so it turns the led off, although it is still true for the first function. The problem is that I want to keep the led on until the first function returns false.
Ignore the second bit with the time.sleep in it, just an idea but won't work for what I want.
writing this I had an idea of having the x variables I want to work in a list and using that list in the function parameters, if that works. In the end there will be around 60 leds with about 5 values to turn each one on, 60 lists sounds like a pain.

Using PsychoPy changing origin coordinate

I am trying to make a program that gets Pen coordinate from wacom tablet which I manage to figure out using this:
data = display.Display().screen().root.query_pointer()._data
X = data["root_x"]-cfg['winpos'][0]-(cfg['width']/2)
Y = cfg['height']-(data["root_y"]-cfg['winpos'][1])-(cfg['height']/2)
print "Pen Position is: ", X, Y
but problem is that Psychopy has origin coordinate for screen at the centre please refer to pic:
and i am using a wacom INTUOS PTZ1230 12" 12" tablet which i want (0, 0) to start from regular monitor origin from top refer to second pic.
very long to read but all i need is to change my coordinate system in python using psychopy. thanks any bit helps
Experimenters generally present their stimuli symetrically around the center of the screen so, although top left and bottom left are (both) more conventional for the origin, the center of the screen makes most sense for scientists.
The window does have atributes viewScale and viewPos though. Although they aren't designed quite for this purpose I think you could use viewPos to shift the origin.
Jon

Categories

Resources