Raspberry + Sensor to Plotly HOW? Python - python

save my life.
PYTHON+RASPI!
I have some problems. I have raspberry pi 3 + Ultrasound Sensor HC-SR04. I am reading distance from it and want to use live-data chart in plot.ly but can't figure out how :/ I have found working code for distance calculation written in python readadc.py.:
import RPi.GPIO as GPIO
import time
import signal
import sys
# use Raspberry Pi board pin numbers
GPIO.setmode(GPIO.BCM)
# set GPIO Pins
pinTrigger = 23
pinEcho = 24
def close(signal, frame):
print("\nTurning off ultrasonic distance detection...\n")
GPIO.cleanup()
sys.exit(0)
signal.signal(signal.SIGINT, close)
# set GPIO input and output channels
GPIO.setup(pinTrigger, GPIO.OUT)
GPIO.setup(pinEcho, GPIO.IN)
while True:
# set Trigger to HIGH
GPIO.output(pinTrigger, True)
# set Trigger after 0.01ms to LOW
time.sleep(0.00001)
GPIO.output(pinTrigger, False)
startTime = time.time()
stopTime = time.time()
# save start time
while 0 == GPIO.input(pinEcho):
startTime = time.time()
# save time of arrival
while 1 == GPIO.input(pinEcho):
stopTime = time.time()
# time difference between start and arrival
TimeElapsed = stopTime - startTime
# multiply with the sonic speed (34300 cm/s)
# and divide by 2, because there and back
distance = (TimeElapsed * 34300) / 2
print ("Distance: %.1f cm" % distance)
time.sleep(1)
In this picture i have my distance values
Now I need to make connection to plotly. I have made it, i am connecting, but how to send values for drawing? I cant understand.. Here is my first part of code for plotly connection:
import plotly.plotly as py
from plotly.graph_objs import Scatter, Layout, Figure
import time
import readadc
username = 'here_i_write_my_username'
api_key = 'here_i_write_my_api'
stream_token = 'here_i_write_my_token'
py.sign_in(username, api_key)
trace1 = Scatter(
x=[],
y=[],
stream=dict(
token=stream_token,
maxpoints=200
)
)
layout = Layout(
title='Raspberry Pi Streaming Sensor Data'
)
fig = Figure(data=[trace1], layout=layout)
print py.plot(fig, filename='Raspberry Pi Streaming Example Values')
And i have no idea what to do next? How to send only 1 row data without X and Y ? I was trying something like this but it don't work. Can somebody help to end the code?
Not working try, plot nothing, empty chart:
sensor_pin = 24
readadc.initialize()
i = 0
stream = py.Stream(stream_token)
stream.open()
#the main sensor reading loop
while True:
sensor_data = readadc.readadc(sensor_pin,readadc.pinEcho)
stream.write({'x': i, 'y': sensor_data})
i += 1
# delay between stream posts
time.sleep(0.5)

Nevermind. I've done . Everything works just fine

Related

Variables in callback function wont update even when the loop reiterates

The task I am currently working on is:
A robot that is installed with a LIDAR sensor and placed in an enclosed warehouse. The robot initially is placed at any random position in the environment. My task is to guide the robot around the warehouse using the values from the sensor, such as wall following etc.
The problem I am facing currently is that I need the robot to start at a position before it does the wall following task. This position is such that the robot first needs to get close to the nearest wall and place itself parallel to the wall, ready to begin the wall following.
I created two '.py' files, a server file and a client file.
The client file calls the server file to do the wall search task. Once the task is complete the rest of the code in the client file is to begin the wall following. I included the code with the problems in it.
msg.ranges[360] (value of front laser range) is the variable that I need help with.
# The lidar sensor has a range form 0 to 180 degress with index range 0-720. The laser at 360 is the front laser or the laser with 0 angle.
# The laser at 0 and 719 are at -90 and 90 angle.
#! /usr/bin/env python
import rospy
from geometry_msgs.msg import Twist
from sensor_msgs.msg import LaserScan
from rosject.srv import findwall, findwallResponse #custom service message
def callback(msg):
r = list(msg.ranges)
minimum_value = min(r)
print(minimum_value)
index_minimum = r.index(minimum_value)
ray_angle = msg.angle_min + (index_minimum * msg.angle_increment)
#The distance and angle of an obstacle with respect to the laser scanner device must be calculated using
#The fields angle_min and angle_increment: ray_angle
print(ray_angle)
#Logic for duration of rotation
countdown_sec1 = 0
if ray_angle < 0:
twist_instance.angular.z = 0.2 #angular velocity in radians/second
else:
twist_instance.angular.z = -0.2
rotation_duration = (abs(ray_angle)/0.2) - 1
while countdown_sec1 <= rotation_duration:
pub.publish(twist_instance)
rate.sleep()
countdown_sec1 = countdown_sec1 + 1
#Once the robot faces the wall it is stopped
twist_instance.angular.z = 0
twist_instance.linear.x = 0
pub.publish(twist_instance)
rate.sleep()
print('front distance',msg.ranges[360]) #once stopped, I print the range of the front laser facing the wall
#This is where I faced the problem. the value that prints for the front laser is incorrect. I am unable to understand why.
#The following code is just to move the robot forward until it's within a certain distance from the wall.
difference = 0.3
forward_duration = round(difference/0.1)
countdown_sec2 = 0
twist_instance.linear.x = 0.1
twist_instance.angular.z = 0
while countdown_sec2 <= forward_duration:
pub.publish(twist_instance)
rate.sleep()
countdown_sec2 = countdown_sec2 + 1
twist_instance.linear.x = 0
pub.publish(twist_instance)
print('final distance', msg.ranges[360]) #Even here once the task is complete the the final value remains the same and incorrect.
# I let the callback run again and even then the value for the front laser does not change
def my_callback(request):
print('i am working boy')
my_response = findwallResponse()
my_response.wallfound = True
return my_response
if __name__ == '__main__':
rospy.init_node('findwall_node')
pub = rospy.Publisher('/cmd_vel', Twist, queue_size=1)
sub = rospy.Subscriber('/scan', LaserScan, callback)
twist_instance = Twist()
rate = rospy.Rate(1)
my_service = rospy.Service('/find_wall', findwall, my_callback)
rospy.spin()
Where am I going wrong, why wont the value for msg.ranges[360] not change when the loop is run again by rospy.spin()?
msg won't change as you're still inside callback(msg). In your code, callback(msg) will be called everytime sub will receive a LiDAR scan message.
I suggest that you separate the code that receives the message from the code that waits and publishes, as you will lose laser scan messages if your node is still processing a msg.
Here is a way to do it in ROS1:
#!/usr/bin/env python
import rospy
from std_msgs.msg import Int64, String
class MyNode:
# CLASS_VARIABLES
def __init__(self, start_value=0):
# INSTANCE_VARIABLES
self.counter = start_value
pass
def counter_callback(self, msg):
counter_data = msg.data
self.counter += counter_data
if __name__ == "__main__":
rospy.init_node("my_node")
rate = rospy.Rate(2)
node = MyNode()
sub = rospy.Subscriber("mynode_pub_topic", Int64, node.counter_callback)
string_pub = rospy.Publisher("mynode_pub_topic", String, queue_size=10)
string_instance = String()
while not rospy.is_shutdown():
string_instance.data = str(node.counter)
string_pub.publish(string_instance)
rate.sleep()
Other improvements could be to use publisher and subscribers as class attributes, as it is now done in ROS2.

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()

Can't seem to get uasyncio working in a micropython script for a PyBoard

I am designing a new time/score keeper for an air hockey table using a PyBoard as a base. My plan is to use a TM1627 (4x7seg) for time display, rotary encoder w/ button to set the time, IR and a couple 7segs for scoring, IR reflector sensors for goallines, and a relay to control the fan.
I'm getting hung up trying to separate the clock into its own thread while focusing on reading the sensors. Figured I could use uasyncio to split everything up nicely, but I can't figure out where to put the directives to spin off a thread for the clock and eventually the sensors.
On execution right now, it appears the rotary encoder is assigned the default value, no timer is started, the encoder doesn't set the time, and the program returns control to REPL rather quickly.
Prior to trying to async everything, I had the rotary encoder and timer working well. Now, not so much.
from rotary_irq_pyb import RotaryIRQ
from machine import Pin
import tm1637
import utime
import uasyncio
async def countdown(cntr):
# just init min/sec to any int > 0
min = sec = 99
enableColon = True
while True:
# update the 4x7seg with the time remaining
min = abs(int((cntr - utime.time()) / 60))
sec = (cntr - utime.time()) % 60
#print(str(), str(sec), sep=':' )
enableColon = not enableColon # alternately blink the colon
tm.numbers(min, sec, colon = enableColon)
if(min + sec == 0): # once both reach zero, break
break
await uasyncio.sleep(500)
X1 = pyb.Pin.board.X1
X2 = pyb.Pin.board.X2
Y1 = pyb.Pin.board.Y1
Y2 = pyb.Pin.board.Y2
button = pyb.Pin(pyb.Pin.board.X3, pyb.Pin.IN)
r = RotaryIRQ(pin_num_clk=X1,
pin_num_dt=X2,
min_val=3,
max_val=10,
reverse=False,
range_mode=RotaryIRQ.RANGE_BOUNDED)
tm = tm1637.TM1637(clk = Y1, dio = Y2)
val_old = val_new = 0
while True:
val_new = r.value()
if(val_old != val_new):
val_old = val_new
print(str(val_new))
if(button.value()): # save value as minutes
loop = uasyncio.get_event_loop()
endTime = utime.time() + (60 * val_new)
loop.create_task(countdown(endTime))
r.close() # Turn off Rotary Encoder
break
#loop = uasyncio.get_event_loop()
#loop.create_task(countdown(et))
#loop.run_until_complete(countdown(et))
I'm sure it's something simple, but this is the first non-CLI python script I've done, so I'm sure there are a bunch of silly mistakes. Any assistance would be appreciated.

Raspberry Pi 3 + temperature sensor + servo motor

I have raspberry pi 3 and trying to create smart green house model. This model should open window if temperature is too hight.
I am new writing codes in Python, found several examples: 1. for temperature sensor and 2. for servo motor to rotating.
Could anyone help me with servo motor? I would like to move servo for example to 30° if temperature is 20°C, if it is 21°C move 40° servo and so on.
I have Python code:
import sys
import Adafruit_DHT
import time
import wiringpi
sensor_args = { '11': Adafruit_DHT.DHT11,
'22': Adafruit_DHT.DHT22,
'2302': Adafruit_DHT.AM2302 }
if len(sys.argv) == 3 and sys.argv[1] in sensor_args:
sensor = sensor_args[sys.argv[1]]
pin = sys.argv[2]
else:
print('usage: sudo ./Adafruit_DHT.py [11|22|2302] GPIOpin#')
print('example: sudo ./Adafruit_DHT.py 2302 4 - Read from an AM2302
connected to GPIO #4')
sys.exit(1)
humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
if humidity is not None and temperature is not None:
print('Temp={0:0.1f}* Humidity={1:0.1f}%'.format(temperature, humidity))
else:
print('Failed to get reading. Try again!')
sys.exit(1)
temp=temperature
text_file = open("output.txt", "w")
text_file.write("%s" %(temp))
text_file.close()
wiringpi.wiringPiSetupGpio()
wiringpi.pinMode(18,wiringpi.GPIO.PWM_OUTPUT)
wiringpi.pwmSetMode(wiringpi.GPIO.PWM_MODE_MS)
wiringpi.pwmSetClock(192)
wiringpi.pwmSetRange(2000)
delay_period = 0.01
while temp==20.0:
for pulse in range(50,250,1):
wiringpi.pwmWrite(18,50)
time.sleep(delay_period)
for pulse in range(250,50,-1):
wiringpi.pwmWrite(18,pulse)
time.sleep(delay_period)
Part about servo motor ir example I found on the internet. I need to replace "while" to "if". I tried by myself, but rotor all the time spin to the same angle.
Can anyone help me with this little part of code?
Second question, how can I run this command in terminal "sudo python servo.py 11 17" on raspberry pi automatically in every 10 mminutes and when raspberry pi is turned on?
Thanks for your help!
The pulse is how you are controlling the position of the servo in your code:
wiringpi.pwmWrite(18,pulse)
See this example:
https://learn.adafruit.com/adafruits-raspberry-pi-lesson-8-using-a-servo-motor?view=all
Depending on your servo, a pulse value of 100 move the servo all the way left (closed in this example), and 200 all the way to the right (open in this example). You need to find these values by reading the datasheet or by experimentation. Once you have these, here is how you would set the position of the servo:
min_servo_val = 100
max_servo_val = 200
wiringpi.pwmWrite(18, min_servo_val) # Move all the way left
time.sleep(1) # Wait a second
wiringpi.pwmWrite(18, max_servo_val) # Move all the way right
Now you can either write a function that translates temperature to a servo position between min_servo_val and max_servo_val, or use a simple if statement. Here is an example of a function to translate temp into a pulse (servo position):
def get_servo_position(temp):
min_servo_val = 100 # Pulse value at which window is all the way closed closed
max_servo_val = 200 # Pulse value at which window is all the way open
full_closed_temp = 20.0 # Temperature at which window is completely closed
full_open_temp = 26.0 # Temperature at which window is completely open
if temp <= full_closed_temp:
return min_servo_val
elif temp >= full_open_temp:
return max_servo_val
else:
return ((temp - full_closed_temp) / (full_open_temp - full_closed_temp)) * (max_servo_val - min_servo_val) + min_servo_val
Now you can do:
print get_servo_position(19) # 100 all the way closed
print get_servo_position(22) # 133.3, or 33% of the way between min_servo_val and max_servo_val
print get_servo_position(25) # 183.3, or 83% of the way between min_servo_val and max_servo_val
print get_servo_position(27) # 200 all the way open
Now you need a loop that checks the temperature every ten minutes and adjusts the servo position. Something like this:
while True:
humidity, temp = Adafruit_DHT.read_retry(sensor, pin) # Get temperature.
position = get_servo_position(temp) # Get the servo position
wiringpi.pwmWrite(18,position) # Move to the position
time.sleep(10*60) # Wait 10 minutes
Putting it all together, your script should look something like this:
import sys
import Adafruit_DHT
import time
import wiringpi
dht_pin = 17 # GPIO conencted to DHT
servo_pin = 18 # GPIO connected to servo
dht_sensor = Adafruit_DHT.DHT11 # Put your sensor here, or set it from command line args
min_servo_val = 100 # Pulse value at which window is all the way closed closed
max_servo_val = 200 # Pulse value at which window is all the way open
full_closed_temp = 20.0 # Temperature at which window is completely closed
full_open_temp = 26.0 # Temperature at which window is completely open
def get_servo_position(temp):
if temp <= full_closed_temp:
return min_servo_val
elif temp >= full_open_temp:
return max_servo_val
else:
return ((temp - full_closed_temp) / (full_open_temp - full_closed_temp)) * (max_servo_val - min_servo_val) + min_servo_val
def main_loop():
while True:
humidity, temp = Adafruit_DHT.read_retry(dht_sensor, dht_pin) # Get temperature.
position = get_servo_position(temp) # Get the servo position
wiringpi.pwmWrite(18,position) # Move to the position
time.sleep(10*60) # Wait 10 minutes
if __name__ == '__main__':
# If you need to get command line arguments, do it below, otherwise just set the pins and other settings at the top of this script.
# For example...
# dht_pin = sys.argv[1]
# servo_pin = sys.argv[2]
# Set up servo
wiringpi.wiringPiSetupGpio()
wiringpi.pinMode(18,wiringpi.GPIO.PWM_OUTPUT)
wiringpi.pwmSetMode(wiringpi.GPIO.PWM_MODE_MS)
wiringpi.pwmSetClock(192)
wiringpi.pwmSetRange(2000)
# Enter main loop
main_loop()
Note that I left out command line arg parsing. If you need those you can add them right after if __name__ == '__main__':
Finally, making a script run on startup is a well covered topic:
Start shell script on Raspberry Pi startup

Terminating Sonic Pi with PyOSC

I am using the Pyosc library to send code from python to Sonic Pi on a Raspberry Pi.
The following code sends my code to Sonic Pi.
code = SOME SONIC PI CODE
oscmsg = OSC.OSCMessage()
oscmsg.setAddress("/run-code")
oscmsg.append(code)
c.send(oscmsg)
How do I terminate this code and send new code? What is the address/command for terminating the current code that is playing?
It's all written on the Sonic Pi github wiki page.
Therefore the address/command you're looking for is /stop-all-jobs.
This might answer even more questions.
# do this first:
# pip install pyosc
import OSC
import time
def sendCmd(cmd,par = None):
oscmsg = OSC.OSCMessage()
oscmsg.append('MY_PYTHON_GUI')
oscmsg.setAddress(cmd)
if par:
oscmsg.append(par)
c.send(oscmsg)
c = OSC.OSCClient()
c.connect(('127.0.0.1', 4557)) # connect to SuperCollider
#change these:
MYPATH = "/Users/you/path/"
# currentSong = MYSONG + ".txt"
# song = open( currentSong, 'r').read()
# MYSONG = "cloudbeat"
song = """
# music by Pit Noack
# http://www.maschinennah.de/sonic-pi-codeschnipsel-compus-loop/
use_bpm 80
live_loop :compus do
with_fx :ixi_techno, phase: [0.125, 0.25, 0.5, 1, 2].choose do
sample :loop_compus, beat_stretch: (ring 4, 8)[tick], amp: 4
sleep (ring 4, 8)[look]
end
end
"""
sendCmd("/stop-all-jobs")
sendCmd("/start-recording")
sendCmd("/run-code", song)
# the recording time should be calculated
time.sleep(3)
sendCmd("/stop-all-jobs")
# wait for reverb tail, etc
time.sleep(1)
sendCmd("/stop-recording")
time.sleep(0.1)
# sendCmd("/save-recording", MYPATH + MYSONG + ".wav")
sendCmd("/save-recording", MYPATH + "song.wav")

Categories

Resources