Python, RPi and GPIO - control engine - python

On my Raspberry Pi I have code written in Python that control engine on my vehicle. I control engine by GPIO. It works but the problem is that when I set io to go and then I set io to change direction it stops. Why it cannot do two things in one time?
This is my code:
import RPi.GPIO as io
import time
import serial
class TankManager:
pLeft = 0
pRight = 0
turnBarrel = 0
liftBarrel = 0
def __init__(self):
io.setmode(io.BCM)
def goahead(self, speed):
if(speed > 25) : speed = 25
io.setup(12, io.OUT)
TankManager.pLeft = io.PWM(12, 2.2)
TankManager.pLeft.start(1)
io.setup(13, io.OUT)
TankManager.pRight = io.PWM(13, 2.2)
TankManager.pRight.start(1)
io.setup(20, io.OUT)
io.output(20, False)
io.setup(21, io.OUT)
io.output(21, False)
return
def gostop(self):
if 'pLeft' in globals():
TankManager.pLeft.stop()
if 'pRight' in globals():
TankManager.pRight.stop()
io.cleanup();
return
def turnright(self):
io.setup(12, io.OUT)
TankManager.pLeft = io.PWM(12, 2.2)
TankManager.pLeft.start(1)
io.setup(21, io.OUT)
io.output(21, False)
return
def turnbarrelstop(self):
if 'turnBarrel' in globals():
TankManager.turnBarrel.stop()
io.cleanup();
return
And for example when I make turnbarrelstop the tank stop barrel but it stop going too. Maybe the reason is that I call io.cleanup() ? And it stop all GPIO signals?
I want to stop barrel but without stop going tank.

Do not call io.cleanup(). I would recommend do not call it in gostop() function too. And use it only if you are exiting the program.
You just need to change (level or PWM whatever applicable) of the specific io PIN.

Related

Stepper motor on raspberry pi callibration issues in python script

I am writing python a script in which I run a stepper motor over the GPIO pins of a raspberry pi and a leadshine driver. The script works by itself, and I have callibrated the stepper by making it run 50 times back and forth at different speeds using the stepper_run function by itself. And this works perfectly. My goal is to run a scanner timed with the stepper motor, using a subprocess call to a scanimage command.
The problem is that steps start to go slightly out of sync (say 100 steps on 12000) when I do other things in the script simultaneously, or right before/after I run the stepper. It is as if the python script isn't able to count its own pulses properly because it is busy doing something else?
Stepper motor definition:
def stepper_run(steps, speed, direction, delay):
'''
wrapper to run stepper
'''
steps = int(steps * (resolution/200))
speed = (speed / (resolution/200))
GPIO.output(ENA, GPIO.HIGH)
print('ENA set to LOW - Controller Enabled')
time.sleep(delay) # pause due to a possible change direction
set_direction(direction)
print('DIR set to LOW - Moving at ' + str(speed))
print('Controller PUL being driven.')
for x in range(steps):
GPIO.output(PUL, GPIO.HIGH)
time.sleep(speed)
GPIO.output(PUL, GPIO.LOW)
time.sleep(speed)
GPIO.output(ENA, GPIO.LOW)
print('ENA set to LOW - Controller Disabled')
#time.sleep(.5) # pause for possible change direction
return
Calling the stepper:
def canoscanlide400(currentposition):
'''
EDIT THIS DEFINITION TO MAKE THE SCANNER SEQUENCE
'''
#STEP1
stepper_run(12190, 0.00059, True, 0.32)
#STEP2
stepper_run(11740, 0.000462, False, 0.32)
#RETURN TO 0
stepper_run(450, 0.000485, False, 0.32)
return currentposition
The function that calls the scanner:
def scan(filename,device,fileformat,dpi,xsize,ysize):
'''
creates two files to hold the image and errors, respectively
takes 6 arguments: filename, device, fileformat, resolution in dpi, x size and y size for the scanner
'''
with open(filename,'w+') as write_handle:
with open('err.txt','a+') as ferr:
out=subprocess.Popen(['scanimage', '-d', device, '--resolution='+dpi, '-x '+xsize, '-y '+ysize, '--format='+fileformat, '--mode=Color'],stdout=write_handle,stderr=ferr)
And finally this is how I call everything:
if (device and 'no scanners' not in device and 'some other error' not in device):
print (device)
time.sleep(5)
for i in range (10):
scan(filename,device,fileformat,dpi,xsize,ysize)
currentposition = canoscanlide400(currentposition)
print (currentposition)
time.sleep(5)

Python: While loop updating LCD display

I'm fairly new to Python although I do have some understanding of programming.
I am currently using Python 3 on a Raspberry Pi with an LCD display connected to it.
I can output to the display using the PIL library and the examples that came with the display.
What I am trying to do is display a value that updates over a period of time.
To break this down I created a while loop that displays a number, sleeps for 3 seconds, increments the number and then runs back through the loop checking the integer is not greater than 10.
However, the screen never updates the integer. To make sure it’s incrementing and testing correctly I put a print statement to the console and can see it incrementing.
I'm assuming it’s something to do with the while loop not refreshing the display but can't figure it out. Sample code below. Any help appreciated.
#!/usr/bin/python
# -*- coding: UTF-8 -*-
#import chardet
import os
import sys
import time
import logging
import spidev as SPI
sys.path.append("..")
from lib import LCD_2inch4
from PIL import Image,ImageDraw,ImageFont
# Raspberry Pi pin configuration:
RST = 27
DC = 25
BL = 18
bus = 0
device = 0
i = 0
logging.basicConfig(level=logging.DEBUG)
try:
# display with hardware SPI:
disp = LCD_2inch4.LCD_2inch4()
# Initialize library.
disp.Init()
# Clear display.
disp.clear()
# Create blank image for drawing.
image1 = Image.new("RGB", (disp.width, disp.height ), "WHITE")
draw = ImageDraw.Draw(image1)
logging.info("draw point")
while i <10:
test_var = "some text"
draw.rectangle([(0,65),(140,100)],fill = "WHITE")
draw.text((5, 68), test_var, fill = "BLACK")
draw.text((5,150), str(i), fill = "BLACK")
draw = ImageDraw.Draw(image1)
image1=image1.rotate(0)
disp.ShowImage(image1)
time.sleep(3)
i= i+1
print(i)
disp.clear()
disp.module_exit()
logging.info("quit:")
except IOError as e:
logging.info(e)
except KeyboardInterrupt:
disp.module_exit()
logging.info("quit:")
exit()

pygame program on boot being killed with no errors

I have a program that is being executed on reboot via crontab. The script and programs work as expected if I run the script from terminal manually myself, but on running the script on boot its as if my RoverDriver.py program is being killed for no reason with no errors.
#reboot sleep 15 && sh /home/pi/Desktop/Rover-Driver/launcher.sh >/home/pi/Desktop/Rover-Driver/logs/cronlog 2>&1
The shell script is:
cd /
cd /home/pi/Desktop/Rover-Driver
sudo python3 bluetooth.py
cd /
The bluetooth.py program checks to see if our bluetooth wireless controller is connected to the pi, if so start the driver program
import pexpect
import time
attempts = 0
while attempts < 30:
child = pexpect.spawn('bluetoothctl')
child.sendline('paired-devices')
output = child.read_nonblocking(size = 200, timeout = -1).decode('utf-8')
target = 'Xbox Wireless Controller'
if output.find(target > -1:
print("Target Found")
print(pexpect.run('python RoverDriver.py'))
break
else:
print("No target found")
attempts = attempts + 1
time.sleep(1)
The RoverDiver.py is:
import pyfirmata
import pygame
import time
from pygame.locals import *
pygame.init()
# controller setup
joysticks = []
for i in range(pygame.joystick.get_count()):
joysticks.append(pygame.joystick.Joystick(i))
joysticks[-1].init()
controller = joysticks[0]
board = pyfirmata.ArduinoMega('/dev/ttyACM0')
# setting pins
onboard_led = board.get_pin('d:13:o')
l_motor_pin = board.get_pin('d:11:p')
r_motor_pin = board.get_pin('d:12:p')
motor_toggle_pin = board.get_pin('d:24:o')
# constantly updates statuses for example if reading analog input from potentiometer
it = pyfirmata.util.Iterator(board)
it.start()
motor_toggle_pin.write(0)
l_motor_pin.write(.49804)
r_motor_pin.write(.49804)
print("Have not entered while loop yet")
while(1):
pygame.event.pump()
# puts rover in "stop" state if no input, avoids rover from "running away"
motor_toggle_pin.write(0)
l_motor_pin.write(.49804)
r_motor_pin.write(.49804)
if(controller.get_button(11)):
print("Exiting...")
exit()
# divider ensure only half power given unless "A" button pressed down
divider = 0.125
reverse = False
right_power = controller.get_axis(4)
left_power = controller.get_axis(5)
# "A" button pressed, give full power
if(controller.get_button(0)):
divider = 0.25
right_power = divider * (right_power + 1)
left_power = divider * (left_power + 1)
# Bumpers are pressed, go reverse. Must be doing both to avoid breaking bot
if(controller.get_button(6) and controller.get_button(7)):
left_power = 0.5 - left_power
right_power = 0.5 - right_power
reverse = True
else:
left_power = 0.5 + left_power
right_power = 0.5 + right_power
# send motors their values
motor_toggle_pin.write(1)
l_motor_pin.write(left_power)
r_motor_pin.write(right_power)
print(f"L Power:{left_power} |R Power:{right_power}")
# avoid cpu overloading
time.sleep(.05)
# after exiting while loop, "turn off" motors
motor_toggle_pin.write(0)
l_motor_pin.write(.49804)
r_motor_pin.write(.49804)
print("End.")
I am expecting a rather large blob of text in the logs (because of the print statement of power levels), or at least the before/after print statements of the while loop however all i get is this:
Target Found.
b'pygame 1.9.4post1\r\nHello from the pygame community. https://www.pygame.org/contribute.html\r\n'
I know that its formatted that way because I am not decoding it. I am hypothesizing it has something to do with pygame but not sure what?
EDIT: To anyone who comes across this post. I switched my controls completely and no longer even rely on pygame. I switched to connecting to the pi via sockets and sending command strings over. This still needed to be setup on boot so I tried using crontab (unsuccessfully again) and instead found out about systemd which works beautifully.

python, cv2.imshow(), raspberryPi and a black screen

Currently trying write code with a GUI which will allow for toggling on/off image processing. Ideally the code will allow for turning on/off window view, real time image processing (pretty basic), and controlling an external board.
The problem I'm having revolves around the cv2.imshow() function. A few months back I made a push to increase processing rates by switching from picamera to cv2 where I can perform more complex computations like background subtraction without having to call python all the time. using the bcm2835-v4l2 package, I was able to pull images directly from the picamera using cv2.
fast forward 6 months and while trying to update the code, I find that the function cv2.imshow() does not display correctly anymore. I thought it might be a problem with bcm2835-v4l2 but tests using matplotlib show that the connection is fine. it appears to have everything to do with cv2.imshow() or so I guess.
I am actually creating a separate thread using the threading module for image capture and I am wondering if this could be the culprit. I don't think so though as typing in the commands
import cv2
camera = cv2.VideoCapture(0)
grabbed,frame = camera.read()
cv2.imshow(frame)
produces the same black screen
Down below is my code I am using (on the RPi3) and some images show the error and what is expected.
as for reference here are the details about my system
Raspberry pi3
raspi stretch
python 3.5.1
opencv 3.4.1
Code
import cv2
from threading import Thread
import time
import numpy as np
from tkinter import Button, Label, mainloop, Tk, RIGHT
class GPIOControllersystem:
def __init__(self,OutPinOne=22, OutPinTwo=27,Objsize=30,src=0):
self.Objectsize = Objsize
# Build GUI controller
self.TK = Tk() # Place TK GUI class into self
# Variables
self.STSP = 0
self.ShutdownVar = 0
self.Abut = []
self.Bbut = []
self.Cbut = []
self.Dbut = []
# setup pi camera for aquisition
self.resolution = (640,480)
self.framerate = 60
# Video capture parameters
(w,h) = self.resolution
self.bytesPerFrame = w * h
self.Camera = cv2.VideoCapture(src)
self.fgbg = cv2.createBackgroundSubtractorMOG2()
def Testpins(self):
while True:
grabbed,frame = self.Camera.read()
frame = self.fgbg.apply(frame)
if self.ShutdownVar ==1:
break
if self.STSP == 1:
pic1, pic2 = map(np.copy,(frame,frame))
pic1[pic1 > 126] = 255
pic2[pic2 <250] = 0
frame = pic1
elif self.STSP ==1:
time.sleep(1)
cv2.imshow("Window",frame)
cv2.destroyAllWindows()
def MProcessing(self):
Thread(target=self.Testpins,args=()).start()
return self
def BuildGUI(self):
self.Abut = Button(self.TK,text = "Start/Stop System",command = self.CallbackSTSP)
self.Bbut = Button(self.TK,text = "Change Pump Speed",command = self.CallbackShutdown)
self.Cbut = Button(self.TK,text = "Shutdown System",command = self.callbackPumpSpeed)
self.Dbut = Button(self.TK,text = "Start System",command = self.MProcessing)
self.Abut.pack(padx=5,pady=10,side=RIGHT)
self.Bbut.pack(padx=5,pady=10,side=RIGHT)
self.Cbut.pack(padx=5,pady=10,side=RIGHT)
self.Dbut.pack(padx=5,pady=10,side=RIGHT)
Label(self.TK, text="Controller").pack(padx=5, pady=10, side=RIGHT)
mainloop()
def CallbackSTSP(self):
if self.STSP == 1:
self.STSP = 0
print("stop")
elif self.STSP == 0:
self.STSP = 1
print("start")
def CallbackShutdown(self):
self.ShutdownVar = 1
def callbackPumpSpeed(self):
pass
if __name__ == "__main__":
GPIOControllersystem().BuildGUI()
Using matplotlib.pyplot.imshow(), I can see that the connection between the raspberry pi camera and opencv is working through the bcm2835-v4l2 connection.
However when using opencv.imshow() the window result in a blackbox, nothing is displayed.
Update: so while testing I found out that when I perform the following task
import cv2
import matplotlib
camera = cv2.VideoCapture(0)
grab,frame = camera.read()
matplotlib.pyplot.imshow(frame)
grab,frame = camera.read()
matplotlib.pyplot.imshow(frame)
update was solved and not related to the main problem. This was a buffering issue. Appears to have no correlation to cv2.imshow()
on a raspberry you should work with
from picamera import PiCamera
checkout pyimagesearch for that

Script uses too many cpu power when run as a service on a Raspberry pi

I have this code snippet running on a raspberry pi. It basically take pictures of people coming in and out of my room.
import RPi.GPIO as GP
import os
import socket
def opencallback(channel):
print(GP.input(channel))
if GP.input(channel):
global closeEvent
closeEvent = 1
else:
global openEvent
openEvent = 1
def transmit(message):
s = socket.create_connection((host, port))
s.send(message)
s.close()
def capture(cam, gpiolist, quick):
GP.output(cam1, gpiolist[0])
GP.output(cam2, gpiolist[1])
GP.output(cam3, gpiolist[2])
if quick:
cmd = "raspistill -o capture_%d.jpg -t 2" % cam
else:
cmd = "raspistill -o capture_%d.jpg" % cam
os.system(cmd)
# init
GP.setwarnings(False)
GP.setmode(GP.BOARD)
cam1 = 7
cam2 = 11
cam3 = 12
doorIn = 40
ledOut = 38
GP.setup(cam1, GP.OUT) # camera Mux1
GP.setup(cam2, GP.OUT) # camera Mux2
GP.setup(cam3, GP.OUT) # camera Mux3
GP.setup(ledOut, GP.OUT) # LED OUT GPIO 20
GP.setup(doorIn, GP.IN) # Door detector in GPIO 21
GP.add_event_detect(doorIn, GP.BOTH, callback=opencallback)
GP.output(ledOut, False)
openEvent = 0
closeEvent = 0
host = '192.168.1.111'
port = 13579
# main
while True:
if openEvent == 1:
transmit("2-01")
capture(2, (False, True, False), True) # front cam
transmit("2-03")
openEvent = 0
else:
pass
if closeEvent == 1:
transmit("2-02")
GP.output(ledOut, True)
capture(3, (False, False, True), False)
GP.output(ledOut, False)
transmit("2-04")
closeEvent = 0
else:
pass
Usually, I run it simply by using a standard call through command line and it doesn't load out the system.
However, I recently converted it to a service using systemd/ systemctl because I wanted to load that script in the background when I boot the pi. Now, this script is gulping a whole processor core by itself (as reported by htop). I didn't change anything to the code itself during the transition and when I run it the old way, it is still working okay. Most of the time, it is simply running the while loop doing nothing and waiting for a callback from GPIO and then execute some functions and go back to the while pass behavior.
My question is: what is causing the difference in computing power consumption between the two execution methods? Is there a way to fix this?
The edge-detection/callback code is efficient, only being invoked when an event takes place. However, the top-level while True: loop is extremely inefficient.
Consider the following modifications:
try:
import Queue as queue # Python 2.x
except ImportError:
import queue # Python 3.x
eventQueue = queue.Queue()
def opencallback(channel):
eventQueue.put(GP.input(channel))
# ...your existing setup code here, specifically including:
GP.add_event_detect(doorIn, GP.BOTH, callback=opencallback)
while True:
event = eventQueue.get()
if event:
transmit("2-01")
capture(2, (False, True, False), True) # front cam
transmit("2-03")
else:
transmit("2-02")
GP.output(ledOut, True)
capture(3, (False, False, True), False)
GP.output(ledOut, False)
transmit("2-04")
Note that this is not related to systemd -- you would have the same CPU usage issues with any other invocation method as well.
Why not have the callbacks trigger the actions for open and close events directly? Just have the loop run a short time.sleep
def opencallback(channel):
print(GP.input(channel))
if GP.input(channel):
transmit("2-02")
GP.output(ledOut, True)
capture(3, (False, False, True), False)
GP.output(ledOut, False)
transmit("2-04")
closeEvent = 0
else:
transmit("2-01")
capture(2, (False, True, False), True) # front cam
transmit("2-03")

Categories

Resources