I'm new to ROS.
I'm trying to make my turtlebot move forward until it is within a minimal distance from an obstacle, then rotate until the path is clear, then move forward again and so on...
I wrote this code:
import rospy, sys
from stopper import Stopper
if __name__ == "__main__":
rospy.init_node("stopper_node", argv=sys.argv)
forward_speed = 0.5
angular_speed = 45
if rospy.has_param('~forward_speed'):
forward_speed = rospy.get_param('~forward_speed')
if rospy.has_param('~angular_speed'):
angular_speed = rospy.get_param('~angular_speed')
my_stopper = Stopper(forward_speed, angular_speed)
my_stopper.start_moving();
and this:
import rospy
import math
from geometry_msgs.msg import Twist
from sensor_msgs.msg import LaserScan
class Stopper(object):
def __init__(self, forward_speed, angular_speed):
self.forward_speed = forward_speed
self.angular_speed = angular_speed
self.min_scan_angle = -30 /180 * math.pi
self.max_scan_angle = 30 / 180 * math.pi
self.min_dist_from_obstacle = 1
self.keep_moving = True
self.keep_rotating = False
self.command_pub = rospy.Publisher("/cmd_vel_mux/input/teleop", Twist, queue_size=10)
self.laser_subscriber = rospy.Subscriber("scan",LaserScan, self.scan_callback, queue_size=1)
def start_moving(self):
print "started moving1"
rate = rospy.Rate(1)
rospy.loginfo("Starting to move")
while not rospy.is_shutdown() and self.keep_moving:
self.move_forward()
rate.sleep()
self.start_rotating()
def move_forward(self):
move_msg = Twist()
move_msg.linear.x = self.forward_speed
self.command_pub.publish(move_msg)
def start_rotating(self):
print "started rotating1"
rate = rospy.Rate(1)
rospy.loginfo("Starting to rotate")
while not rospy.is_shutdown() and self.keep_rotating:
self.rotate()
rate.sleep()
self.start_moving()
def rotate(self):
move_msg = Twist()
move_msg.angular.z = self.angular_speed * 2 * math.pi / 360
self.command_pub.publish(move_msg)
def scan_callback(self, scan_msg):
for dist in scan_msg.ranges:
print dist
if self.keep_moving and dist < self.min_dist_from_obstacle:
self.keep_moving = False
print "keep moving is now false"
self.keep_rotating = True
print "keep rotating is now true"
break
if self.keep_rotating and math.isnan(dist):
self.keep_rotating = False
print "keep rotating is now false"
self.keep_moving = True
print "keep moving is now true"
break
But even though I can't find any logical mistakes in it, it just does not work and occasionaly bumps into stuff. I am running it with the gazebo simulation
"turtlebot_world". I would love to get some help.
Thanks!
I have a solution with the bugs navigation algorithms, hope help you up:
with these repositories (agn_gazebo, bugs), you could bring up a Gazebo simulation with a bounded map and some obstacle and a mobile wheeled robot platform (Pioneer P3dx) which is equipped with a laser scanner (Hokuyo URG) for environmental perception.
USAGE:
After cloning from these repositories in ~/catkin_ws/src using:
git clone https://github.com/agn-7/agn_gazebo.git
git clone https://github.com/agn-7/bugs.git
Then build them with catkin_make in your catkin workspace.
After package building, you need to change the agn_gazebo/worlds/final.world file:
Open it and change all /home/agn/catkin_ws/src/... with your target path with Ctrl + F or Ctrl + H
I've opened an issue to make it as a dynamic path instead of static, but currently, I couldn't do it.
Then Bring up the simulator: roslaunch agn_gazebo gazebo.launch
Running any bugs algorithm with a position target:
rosrun bugs bug.py bug0 11 0
or
rosrun bugs bug.py bug1 11 0
or
rosrun bugs bug.py bug2 11 0
Okay, I've implemented something that should work pretty well.
I have 3 files that make the wander turtlebot work as you asked.
wander_bot.launch
Responsibility: This file is a launch file that will run the gazebo world and will store the configurable parameters.
turtlebot_node.py
Responsibility: This python file will initialize the ROS node and it will load the configurable parameters, and then it will run the code that makes the turtlebot move.
turtlebot_logic.py
Responsibility: This python file will listen to the laser, it will implement all the logic stuff to make the wander bot work.
wander_bot.launch
<launch>
<param name="/use_sim_time" value="true" />
<!-- Launch turtle bot world -->
<include file="$(find turtlebot_gazebo)/launch/turtlebot_world.launch"/>
<!-- Launch stopper node -->
<node name="wander_bot" pkg="wander_bot" type="turtlebot_node.py" output="screen">
<param name="forward_speed" type="double" value="0.2"/>
<param name="minimum_distance_from_obstacle" type="double" value="1.0"/>
<param name="rotation_speed" type="int" value="2"/>
<param name="minimum_angle" type="int" value="-30"/>
<param name="maximum_angle" type="int" value="30"/>
</node>
</launch>
turtlebot_node.py
#!/usr/bin/python
import rospy
import sys
from turtlebot_logic import RosTurtlebotLogic
def loadParams():
forwardSpeed = 0.2
rotationSpeed = 2
minDistanceFromObstacle = 1.0
minimumAngle = -30
maximumAngle = 30
if rospy.has_param('~forward_speed'):
forwardSpeed = rospy.get_param('~forward_speed')
if rospy.has_param('~rotation_speed'):
rotationSpeed = rospy.get_param('~rotation_speed')
if rospy.has_param('~minimum_distance_from_obstacle'):
minDistanceFromObstacle = rospy.get_param('~minimum_distance_from_obstacle')
if rospy.has_param('~minimum_angle'):
minimumAngle = rospy.get_param('~minimum_angle')
if rospy.has_param('~maximum_angle'):
maximumAngle = rospy.get_param('~maximum_angle')
return forwardSpeed, rotationSpeed, minDistanceFromObstacle, minimumAngle, maximumAngle
if __name__ == "__main__":
rospy.loginfo("Started program.")
rospy.init_node("stopper_node", argv=sys.argv)
forwardSpeed, rotationSpeed, minDistanceFromObstacle, minimumAngle, maximumAngle = loadParams()
rospy.loginfo("Finished import parameters.")
my_stopper = RosTurtlebotLogic(forwardSpeed, rotationSpeed, minDistanceFromObstacle, minimumAngle, maximumAngle)
my_stopper.startMoving()
turtlebot_logic.py
#!/usr/bin/python
import math
import rospy
from geometry_msgs.msg import Twist
from sensor_msgs.msg import LaserScan
class RosTurtlebotLogic(object):
def __init__(self, forwardSpeed, rotationSpeed, minDistanceFromObstacle, minimumAngle, maximumAngle):
self.forwardSpeed = forwardSpeed
self.rotationSpeed = rotationSpeed
self.minDistanceFromObstacle = minDistanceFromObstacle
# Keeps the current minimum distance from obstacle from laser.
self.minimumRangeAhead = 5
# In which direction to rotate, left or right.
self.rotationDirection = 0
self.minimumIndexLaser = 360 * (90 + minimumAngle) / 90
self.maximumIndexLaser = 360 * (90 + maximumAngle) / 90 - 1
self.keepMoving = True
self.commandPub = rospy.Publisher("/cmd_vel_mux/input/teleop", Twist, queue_size=10)
rospy.Subscriber("scan", LaserScan, self.scanCallback, queue_size=10)
def startMoving(self):
rate = rospy.Rate(10)
while(not rospy.is_shutdown()):
if(self.keepMoving):
if (self.minimumRangeAhead < self.minDistanceFromObstacle):
self.keepMoving = False
else:
if(self.minimumRangeAhead > self.minDistanceFromObstacle):
self.keepMoving = True
twist = Twist()
if(self.keepMoving):
twist.linear.x = self.forwardSpeed
else:
twist.angular.z = self.rotationDirection
self.commandPub.publish(twist)
rate.sleep()
def scanCallback(self, scan_msg):
minimum = 100
index = 0
# Find the minimum distance to obstacle and we keep the minimum distance and the index.
# We need the minimum distance in order to know if we can go forward or not.
# We need the index to know in which direction to rotate.
if(not math.isnan(scan_msg.ranges[self.minimumIndexLaser])):
minimum = scan_msg.ranges[self.minimumIndexLaser]
for i in range(self.minimumIndexLaser, self.maximumIndexLaser + 1):
if(not math.isnan(scan_msg.ranges[i]) and scan_msg.ranges[i] < minimum):
minimum = scan_msg.ranges[i]
index = i
self.minimumRangeAhead = minimum
if(index <= 359):
self.rotationDirection = self.rotationSpeed
else:
self.rotationDirection = -self.rotationSpeed
The laser looks at 180 degrees, the right angle is index 0
at ranges array, forward is index 359 at ranges array, and left is index 719 at ranges array, ranges array is coming from the subscriber:
rospy.Subscriber("scan", LaserScan, self.scanCallback, queue_size=10)
The callback function is scanCallback
Well, that kind of straight forward, I don't think that I need to explain the code, it's well documented and easy to understand, for any further questions please comment here.
Related
I'd like to be able to run the exact same run, given I didn't change any parameters of the simulation, in the autonomous driving simulator Carla. Before I paste my code, my logic is that I have to set a specific seed for any Random operation to be repeatable, set a specific seed for the traffic manager, and in general to work in synchronous_mode=True so the lag in my computer won't interrupt(?). As you'll see, I log the x,y,z location of the ego vehicle, and run the simulation twice. It is similar, but not the same. What can I do to make it repeatable (not in recording mode, actual live runs)?
Additional info: Carla 0.9.14 on Ubuntu 20.04, Python 3.8.
import random
import numpy as np
import sys
import os
try:
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/carla')
except IndexError:
pass
import carla
from agents.navigation.behavior_agent import BehaviorAgent # pylint: disable=import-error
seed = 123
N_vehicles = 50
camera = None
telemetry = []
random.seed(seed)
try:
# Connect the client and set up bp library and spawn points
client = carla.Client('localhost', 2000)
client.set_timeout(60.0)
world = client.get_world()
bp_lib = world.get_blueprint_library()
spawn_points = world.get_map().get_spawn_points()
settings = world.get_settings()
settings.synchronous_mode = True
settings.fixed_delta_seconds = 0.10
world.apply_settings(settings)
traffic_manager = client.get_trafficmanager()
traffic_manager.set_random_device_seed(seed)
traffic_manager.set_synchronous_mode(True)
# Spawn ego vehicle
vehicle_bp = bp_lib.find('vehicle.audi.a2')
# breakpoint()
vehicle = world.try_spawn_actor(vehicle_bp, random.choice(spawn_points))
# Move spectator behind vehicle to motion
spectator = world.get_spectator()
transform = carla.Transform(vehicle.get_transform().transform(carla.Location(x=-6,z=2.5)),vehicle.get_transform().rotation)
spectator.set_transform(transform)
world.tick()
# set the car's controls
agent = BehaviorAgent(vehicle, behavior="normal")
destination = random.choice(spawn_points).location
agent.set_destination(destination)
print('destination:')
print(destination)
print('current location:')
print(vehicle.get_location())
#Iterate this cell to find desired camera location
camera_bp = bp_lib.find('sensor.camera.rgb')
# Spawn camera
camera_init_trans = carla.Transform(carla.Location(z=2))
camera = world.spawn_actor(camera_bp, camera_init_trans, attach_to=vehicle)
# Callback stores sensor data in a dictionary for use outside callback
def camera_callback(image, data_dict):
data_dict['image'] = np.reshape(np.copy(image.raw_data), (image.height, image.width, 4))
# Get gamera dimensions and initialise dictionary
image_w = camera_bp.get_attribute("image_size_x").as_int()
image_h = camera_bp.get_attribute("image_size_y").as_int()
camera_data = {'image': np.zeros((image_h, image_w, 4))}
# Start camera recording
camera.listen(lambda image: camera_callback(image, camera_data))
# Add traffic to the simulation
SpawnActor = carla.command.SpawnActor
SetAutopilot = carla.command.SetAutopilot
FutureActor = carla.command.FutureActor
vehicles_list, batch = [], []
for i in range(N_vehicles):
ovehicle_bp = random.choice(bp_lib.filter('vehicle'))
npc = world.try_spawn_actor(ovehicle_bp, random.choice(spawn_points))
# add it if it was successful
if(npc):
vehicles_list.append(npc)
print(f'only {len(vehicles_list)} cars were spawned')
world.tick()
# Set the all vehicles in motion using the Traffic Manager
for idx, v in enumerate(vehicles_list):
try:
v.set_autopilot(True)
except:
pass
# Game loop
while True:
world.tick()
pose = vehicle.get_location()
telemetry.append([pose.x, pose.y, pose.z])
# keep following the car
transform = carla.Transform(vehicle.get_transform().transform(carla.Location(x=-6,z=2.5)),vehicle.get_transform().rotation)
spectator.set_transform(transform)
if agent.done():
print("The target has been reached, stopping the simulation")
break
control = agent.run_step()
control.manual_gear_shift = False
vehicle.apply_control(control)
finally:
# Stop the camera when we've recorded enough data
if(camera):
camera.stop()
camera.destroy()
settings = world.get_settings()
settings.synchronous_mode = False
settings.fixed_delta_seconds = None
world.apply_settings(settings)
traffic_manager.set_synchronous_mode(True)
if(vehicles_list):
client.apply_batch([carla.command.DestroyActor(v) for v in vehicles_list])
vehicle.destroy()
np.savetxt('telemetry.txt', np.array(telemetry), delimiter=',')
y-axis is the error between two runs, x-axis is the time index of the run
I am attempting to create a script in python that can play the chrome dino game, but i cant get NEAT to accept an image in the form of a numpy array as input. It doesnt work when i convert it to a list either. What can i do to fix this? Is there a config somewhere that i have to find?
Code:
import os
import time
import neat
import pickle
import pyautogui as pg
from PIL import ImageGrab, ImageOps, Image
import numpy as np
gen = 0
positions_standart = ((455, 450), (1242, 605))
positions_restart = ((779, 624), (949, 713))
def get_dead():
box = (positions_restart[0][0], positions_restart[0][1], positions_restart[1][0], positions_restart[1][1])
image = ImageGrab.grab(box)
grayscale = ImageOps.grayscale(image)
a = np.array(grayscale.getcolors())
return a.sum() == 47100
def get_image():
box = (positions_standart[0][0], positions_standart[0][1], positions_standart[1][0], positions_standart[1][1])
image = ImageGrab.grab(box)
grayscale = ImageOps.grayscale(image)
a = np.array(grayscale.getcolors())
a = np.array(image)
return grayscale, a
class Dino:
def jump(self):
pg.press("space")
def eval_genomes(genomes, config):
"""
runs the simulation of the current population of
birds and sets their fitness based on the distance they
reach in the game.
"""
global gen
gen += 1
# start by creating lists holding the genome itself, the
# neural network associated with the genome and the
# bird object that uses that network to play
nets = []
dinos = []
ge = []
for genome_id, genome in genomes:
genome.fitness = 0 # start with fitness level of 0
net = neat.nn.FeedForwardNetwork.create(genome, config)
nets.append(net)
dinos.append(Dino())
ge.append(genome)
score = 0
for x, dino in enumerate(dinos):
pg.click(455, 450)
print(f"Dino {x}")
dino.jump()
run = True
while run:
time.sleep(0.1)
ge[x].fitness += 0.1
# send bird location, top pipe location and bottom pipe location and determine from network whether to jump or not
gs = get_image()[1]
gs = gs.tolist()
output = nets[dinos.index(dino)].activate([gs])
if output[0] > 0.5: # we use a tanh activation function so result will be between -1 and 1. if over 0.5 jump
dino.jump()
print("jump")
### - Check Dead - ###
if (get_dead()):
run = False
print("dead")
# break if score gets large enough
#if score > 600:
# pickle.dump(nets[0],open("best.pickle", "wb"))
# break
def run(config_file):
"""
runs the NEAT algorithm to train a neural network to play flappy bird.
:param config_file: location of config file
:return: None
"""
config = neat.config.Config(neat.DefaultGenome, neat.DefaultReproduction,
neat.DefaultSpeciesSet, neat.DefaultStagnation,
config_file)
# Create the population, which is the top-level object for a NEAT run.
p = neat.Population(config)
# Add a stdout reporter to show progress in the terminal.
p.add_reporter(neat.StdOutReporter(True))
stats = neat.StatisticsReporter()
p.add_reporter(stats)
#p.add_reporter(neat.Checkpointer(5))
# Run for up to 50 generations.
winner = p.run(eval_genomes, 50)
# show final stats
print('\nBest genome:\n{!s}'.format(winner))
if __name__ == '__main__':
# Determine path to configuration file. This path manipulation is
# here so that the script will run successfully regardless of the
# current working directory.
local_dir = os.path.dirname(__file__)
config_path = os.path.join(local_dir, 'config-feedforward.txt')
run(config_path)
What am i doing wrong? Please help me.
I have a written a script that uses the code below and I would like to optimize rsi_high and rsi_low to get the best sharpe_ratio:
#
import numpy
import talib as ta
global rsi_high, rsi_low
rsi_high = 63
rsi_low = 41
def myTradingSystem(DATE, OPEN, HIGH, LOW, CLOSE, VOL, exposure, equity, settings):
''' This system uses trend following techniques to allocate capital into the desired equities'''
nMarkets = CLOSE.shape[1] # SHAPE OF NUMPY ARRAY
result, rsi_pos = numpy.apply_along_axis(rsicalc, axis=0, arr=CLOSE)
pos = numpy.asarray(rsi_pos, dtype=numpy.float64)
return pos, settings
def rsicalc(num):
# print rsi_high
try:
rsival = ta.RSI(numpy.array(num,dtype='f8'),timeperiod=14)
if rsival[14] > rsi_high: pos_rsi = 1
elif rsival[14] < rsi_low: pos_rsi = -1
else: pos_rsi = 0
except:
rsival = 0
pos_rsi = 0
return rsival, pos_rsi
def mySettings():
''' Define your trading system settings here '''
settings = {}
# Futures Contracts
settings['markets'] = ['CASH','F_AD', 'F_BO', 'F_BP', 'F_C', 'F_CC', 'F_CD',
'F_CL', 'F_CT', 'F_DX', 'F_EC', 'F_ED', 'F_ES', 'F_FC', 'F_FV', 'F_GC',
'F_HG', 'F_HO', 'F_JY', 'F_KC', 'F_LB', 'F_LC', 'F_LN', 'F_MD', 'F_MP',
'F_NG', 'F_NQ', 'F_NR', 'F_O', 'F_OJ', 'F_PA', 'F_PL', 'F_RB', 'F_RU',
'F_S', 'F_SB', 'F_SF', 'F_SI', 'F_SM', 'F_TU', 'F_TY', 'F_US', 'F_W',
'F_XX', 'F_YM']
settings['slippage'] = 0.05
settings['budget'] = 1000000
settings['beginInSample'] = '19900101'
settings['endInSample'] = '19931231'
settings['lookback'] = 504
return settings
# Evaluate trading system defined in current file.
if __name__ == '__main__':
import quantiacsToolbox
results = quantiacsToolbox.runts(__file__, plotEquity=False)
sharpe_ratio = results['stats']['sharpe']
I suspect that using something like scipy minimize function would do the trick, but I am having trouble understanding how to package my script so that it can be in a usable form.
I have tried putting everything in a function and then running all the code through a number of loops, each time incrementing values but there must be a more elegant way of doing this.
Apologies for posting all my code but I thought it would help if the responder wanted to reproduce my setup and for anyone who is new to quantiacs to see a real example who is faced with the same issue.
Thanks for your help in advance!
I have designed and created a program using Python 3 that reads unread messages in my Gmail inbox under two labels.
By using tkinter I have two lovely boxes that display the total messages in each label. One for sales of one particular product and the other for another.
They use the update loop to recheck each label every few seconds.
Then after the business day, I use a cleanup script in Gmail that flushes the inboxes two labels.
The program is for use on my team's sales floor. They can see daily, the number of sales, and get a real-time readout to the success of certain marketing campaigns. It has done wonders for morale.
Now I would like to implement some sounds when sales go up. A cliche bell ring, a "chhaaaching" perhaps, you get the drift.
So, I am currently tackling with my limited knowledge and have searched all throughout StackOverflow and other sites for an answer. My guess is that I need something like the following...
"if an integer value changes on the next loop from it's previous value, by an increment of 1 play soundA, or, play soundB if that value decreases by 1."
I can't for the life of me figure out what would be the term for 'increases by 1', I am also clueless on how to attach a sound to any changes made to the integer on the proceeding loop. Help!!
If I wasn't clear enough, I am more than happy to explain and go into this further.
Thank you so much guys.
Here is my code as it stands so far...
#! /usr/bin/python3
import imaplib
import email
import tkinter as tk
WIDTH = 1000
HEIGHT = 100
def update():
mail=imaplib.IMAP4_SSL('imap.gmail.com',993)
mail.login('email#gmail.com','MyPassword')
mail.select("Submissions")
typ, messageIDs = mail.search(None, "UNSEEN")
FirstDataSetSUBS = str(messageIDs[0], encoding='utf8')
if FirstDataSetSUBS == '':
info1['text'] = 'no submissions'
else:
SecondDataSetSUBS = FirstDataSetSUBS.split(" ")
nosubs = len(SecondDataSetSUBS)
nosubs = int(nosubs)
info1['text'] = '{} submission[s]'.format(nosubs)
subs.after(1000, update)
def update_2():
mail=imaplib.IMAP4_SSL('imap.gmail.com',993)
mail.login('email#gmail.com','MyPassword')
mail.select("Memberships")
typ, messageIDs = mail.search(None, "UNSEEN")
FirstDataSetMSGS = str(messageIDs[0], encoding='utf8')
if FirstDataSetMSGS == '':
info2['text'] = 'no memberships'
else:
SecondDataSetMSGS = FirstDataSetMSGS.split(" ")
memberships = len(SecondDataSetMSGS)
memberships = int(memberships)
info2['text'] = '{} membership[s]'.format(memberships)
membs.after(1000, update_2)
membs = tk.Tk()
subs = tk.Tk()
membs.title('memberships counter')
membs.configure(background="black")
subs.title('submissions counter')
subs.configure(background="black")
x = (subs.winfo_screenwidth()//5) - (WIDTH//5)
y = (subs.winfo_screenheight()//5) - (HEIGHT//5)
subs.geometry('{}x{}+{}+{}'.format(WIDTH, HEIGHT, x, y))
info1 = tk.Label(subs, text='nothing to display', bg="black", fg="green", font="Lucida_Console 40")
info1.pack()
x = (membs.winfo_screenwidth()//2) - (WIDTH//2)
y = (membs.winfo_screenheight()//2) - (HEIGHT//2)
membs.geometry('{}x{}+{}+{}'.format(WIDTH, HEIGHT, x, y))
info2 = tk.Label(membs, text='nothing to display', bg="black", fg="red", font="Lucida_Console 40")
info2.pack()
update()
update_2()
membs.mainloop
subs.mainloop()
for playing audio you can use pyaudio module
in ubuntu, install by pip3 install pyaudio include sudo if required
import pygame
pygame.init()
increased=0
inc_music=pygame.mixer.music
dec_music=pygame.mixer.music
inc_music.load("/home/pratik/Documents/pos.wav")
dec_music.load("/home/pratik/Documents/neg.wav")
def get_inc():
global increased
a=increased
return a
def pl():
global inc_music
global dec_music
while True:
increased=get_inc()
if increased == 1:
inc_music.play()
increased=increased-1
elif increased == -1:
dec_music.play()
increased=increased+1
here increased is a global variable. Make sure whenever your sales is increased it is set to +1 and whenever it is decreased it is set to -1 and call pl function in a separate thread by using threading library in the background. Since, it is a forever loop it will continuosly run in background and ring the bells.
from threading import Thread
th=Thread(target=pl)
th.setDaemon(True)
th.start()
While writing the above I assumed at a moment there is either an increase or a decrease in sales, both dont occour simultaneously. If they do, use another global variable decreased which is also initialised with 0 and decreased by -1 each time decrease in sales. And return both of them from get_inc() .
Below code produces a label that gets updated randomly, and plays the sound files located in "C:\Windows\Media\" based on the change:
import tkinter as tk
import random
from playsound import playsound
def sound(is_positive=True):
if is_positive:
playsound(r"C:\Windows\Media\chimes.wav", False)
else:
playsound(r"C:\Windows\Media\chord.wav", False)
def random_update():
_old = label['text']
_new = random.randint(1, 100)
if _new > _old: # use (_new - _old) == 1 for checking
sound() # increment of 1 exclusively
elif _new < _old: # use (_new - _old) == -1 for checking
sound(False) # decrement of 1 exclusively
label['text'] = _new
label.after(2000, random_update)
if __name__ == '__main__':
root = tk.Tk()
label = tk.Label(root, text=1)
label.after(2000, random_update)
label.pack()
root.mainloop()
playsound is not a built-in package so it needs to be installed separately. You can install using:
pip install playsound
or:
python -m pip install playsound
in the command prompt on windows.
I have problem with programmatic monitor rotation
import win32api as win32
import win32con
MY_SCREEN_NUMBER = 1
device = win32.EnumDisplayDevices(None,MY_SCREEN_NUMBER)
dm = win32.EnumDisplaySettings(device.DeviceName,win32con.ENUM_CURRENT_SETTINGS)
dm.DisplayOrientation = win32con.DMDO_180
dm.Fields = dm.Fields & win32con.DM_DISPLAYORIENTATION
win32.ChangeDisplaySettingsEx(device.DeviceName,dm)
Code rotating screen only in opposite direction, for example
if screen in win32con.DMDO_DEFAULT it can only rotate it in win32con.DMDO_180,
if screen in win32con.DMDO_90 only rotates in win32con.DMDO_270
otherwise it gives me -2 (DISP_CHANGE_BADMODE) error code
But i can successfully rotate it with windows graphical screen params settings
How do I rotate the screen correctly?
def rotateTo(degree):
import win32api as win32
import win32con
MY_SCREEN_NUMBER = 1
device = win32.EnumDisplayDevices(None,MY_SCREEN_NUMBER)
dm = win32.EnumDisplaySettings(device.DeviceName,win32con.ENUM_CURRENT_SETTINGS)
newDisplayOrientationInWin32Format = degree/90
currentDisplayOrientationInWin32Format = dm.DisplayOrientation
if(newDisplayOrientationInWin32Format + currentDisplayOrientationInWin32Format) % 2 == 1 : #test the new resolution on the perpendicular to the previous
tmp = dm.PelsHeight
dm.PelsHeight=dm.PelsWidth
dm.PelsWidth=tmp
dm.DisplayOrientation = newDisplayOrientationInWin32Format
return win32.ChangeDisplaySettingsEx(device.DeviceName,dm)
I checked https://msdn.microsoft.com/en-us/library/ms812499.aspx and found C example, i need to swap height and width, but they don't test the new resolution on the perpendicular to the previous. I updated code with this test and it start working in any possible screen orientation for me.