I am using the following code to read sensor data, process it and publish some feedback to a different topic, /scans_freespace.
#!/usr/bin/env python
import rospy
from rospy.core import is_shutdown
from sensor_msgs.msg import LaserScan
from sweep_bot.msg import Space
from sweep_bot.msg import SpaceArray
class FreeSpace :
def __init__(self) :
rospy.loginfo('starting')
self.scans = ()
self.regions = {}
self.publisher = self.subscriber = ''
def callbackScans(self, data) :
self.scans = data.ranges
self.regions = {
'starboard_aft' : self.scans[0:135],
'starboard_abeam_aft' : self.scans[136:271],
'starboard_abeam_bow' : self.scans[272:407],
'starboard_bow' : self.scans[408:543],
'port_aft' : self.scans[949:1084],
'port_abeam_aft' : self.scans[814:949],
'port_abeam_bow' : self.scans[679:814],
'port_bow' : self.scans[544:679],
}
def publish(self) :
self.getSomeData('port_bow')
def getSomeData(self, region) :
rospy.loginfo("Checking region: %s", region)
rospy.loginfo("Checking scans: %s", self.scans)
return self.scans[region]
if __name__ == '__main__' :
rospy.init_node('space_identifier')
rate = rospy.Rate(10)
spacer = FreeSpace()
subscriber = rospy.Subscriber("scans", LaserScan, spacer.callbackScans)
publisher = rospy.Publisher("scans_freespace", SpaceArray, queue_size=10)
while not rospy.is_shutdown() :
spacer.publish()
rate.sleep()
As the code shows, I am calling the getSomeData() function from my publish() function passing a single string argument. getSomeData() receives the argument as expected but the global variables which are populated from the callbackScan() function are empty.
The output from the script is as follow:
[INFO] [1629830370.246796, 0.000000]: starting
[INFO] [1629830370.253719, 0.000000]: Checking region: port_bow
[INFO] [1629830370.256151, 0.000000]: Checking scans: ()
Traceback (most recent call last):
File "/home/sisko/catkin_ws/src/sweepbot/Sweeper/sweep_bot/src/freespace.py", line 49, in <module>
spacer.publish()
File "/home/sisko/catkin_ws/src/sweepbot/Sweeper/sweep_bot/src/freespace.py", line 31, in publish
self.getSomeData('port_bow')
File "/home/sisko/catkin_ws/src/sweepbot/Sweeper/sweep_bot/src/freespace.py", line 37, in getSomeData
return self.scans[region]
TypeError: tuple indices must be integers, not str
Ironically, the code did work until I attempted to update my output.
What am I missing?
There are a few things wrong here. However, your error is because you do not properly initialize your message fields. This in turn causes issue when publish() is called before a LaserScan message is received. As well, ranges is a std_msg/Float32[] so even if it was assigned correctly in the callback you'd have another error when trying to index a float list with a string. It is a little unclear as to what you want to do, but looking at the key names getSomeData() should look something more like this:
def getSomeData(self, region) :
rospy.loginfo("Checking region: %s", region)
rospy.loginfo("Checking scans: %s", self.scans)
return self.regions[region] if region in self.regions else None
Another point to make is if you're hoping to publish the results of this function out via the publish() function, you need to actually define a publisher inside your class with the correct type.
Related
The following code does work on Pyomo 5.7.0, but does not work on Pyomo 5.7.3 and above anymore. The Error is "ValueError: Error retrieving immutable Param value (battery.n_time_steps)" (full traceback at the end) when trying to build the time_steps set.
import pyomo.environ as pyo
def test_param_pyomo5_7():
def create_battery():
block = pyo.Block()
block.n_time_steps = pyo.Param(within=pyo.NonNegativeIntegers, doc='Number of time steps')
block.time_steps = pyo.RangeSet(1, block.n_time_steps, doc='Time steps')
return block
def create_model() -> pyo.AbstractModel:
model = pyo.AbstractModel()
model.battery = create_battery()
return model
data = {
None: {
'battery': {
'n_time_steps': {None: 24},
},
}
}
model = create_model()
instance = model.create_instance(data=data)
The full traceback is:
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\PyomoModel.py:697: in create_instance
instance.load( data,
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\PyomoModel.py:734: in load
self._load_model_data(dp,
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\PyomoModel.py:787: in _load_model_data
self._initialize_component(modeldata, namespaces, component_name, profile_memory)
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\PyomoModel.py:825: in _initialize_component
declaration.construct(data)
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\block.py:2207: in construct
obj.construct(data.get(name, None))
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\disable_methods.py:116: in construct
return base.construct(self, data)
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\set.py:2792: in construct
args = tuple(value(arg) for arg in args)
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\set.py:2792: in <genexpr>
args = tuple(value(arg) for arg in args)
pyomo\core\expr\numvalue.pyx:153: in pyomo.core.expr.numvalue.value
???
pyomo\core\expr\numvalue.pyx:138: in pyomo.core.expr.numvalue.value
???
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\param.py:853: in __call__
return self[None]
..\..\opt\Miniconda3\envs\tesca_optimizer\lib\site-packages\pyomo\core\base\indexed_component.py:577: in __getitem__
return self._getitem_when_not_present(index)
There was an inconsistency in how blocks were initialized from dictionary data in Pyomo<5.7.2, which was fixed in 5.7.2 (PR #1703). The correct data dictionary requires "indices" for all components (even scalar components). Your data dictionary is missing the None key (implicit index) for the data associated with the scalar Block battery. The following data dictionary will work in recent versions of Pyomo:
data = {
None: {
'battery': {
None: {
'n_time_steps': {None: 24},
},
},
}
}
I have provided the following python code,but the problem is that when it doesnot receive any input, it start showing error. how can i modify the code in a way that this error dosnot appear:
#!/usr/bin/env python from roslib import message import rospy import sensor_msgs.point_cloud2 as pc2 from sensor_msgs.msg import PointCloud2, PointField import numpy as np import ros_numpy from geometry_msgs.msg import Pose
#listener def listen():
rospy.init_node('listen', anonymous=True)
rospy.Subscriber("/Filtered_points_x", PointCloud2, callback_kinect)
def callback_kinect(data):
pub = rospy.Publisher('lidar_distance',Pose, queue_size=10)
data_lidar = Pose()
xyz_array = ros_numpy.point_cloud2.pointcloud2_to_xyz_array(data)
print(xyz_array)
mini_data = min(xyz_array[:,0])
print("mini_data", mini_data)
data_lidar.position.x = mini_data
pub.publish(data_lidar)
print("data_points", data_lidar.position.x)
height = int (data.height / 2)
middle_x = int (data.width / 2)
middle = read_depth (middle_x, height, data) # do stuff with middle
def read_depth(width, height, data) :
if (height >= data.height) or (width >= data.width) :
return -1
data_out = pc2.read_points(data, field_names= ('x','y','z'), skip_nans=True, uvs=[[width, height]])
int_data = next(data_out)
rospy.loginfo("int_data " + str(int_data))
return int_data
if __name__ == '__main__':
try:
listen()
rospy.spin()
except rospy.ROSInterruptException:
pass
the following is the error that i mentioned:
[[ 7.99410915 1.36072445 -0.99567264]]
('mini_data', 7.994109153747559)
('data_points', 7.994109153747559)
[INFO] [1662109961.035894]: int_data (7.994109153747559, 1.3607244491577148, -0.9956726431846619)
[]
[ERROR] [1662109961.135572]: bad callback: <function callback_kinect at 0x7f9346d44230>
Traceback (most recent call last):
File "/opt/ros/kinetic/lib/python2.7/dist-packages/rospy/topics.py", line 750, in _invoke_callback
cb(msg)
File "/home/masoumeh/catkin_ws/src/yocs_velocity_smoother/test4/distance_from_pointcloud.py", line 27, in callback_kinect
mini_data = min(xyz_array[:,0])
ValueError: min() arg is an empty sequence
The code is still receiving input, but specifically it’s receiving an empty array. You’re then trying to splice the empty array, causing the error. Instead you should check that the array has elements before the line min(xyz_array[:,0]). It can be as simple as:
if xyz_array == []:
return
As another note, you’re creating a publisher in the callback. You shouldn’t do this as a new publisher will be created every time it gets called. Instead create it as a global variable.
I am trying to send a file across the network using Twisted with the LineReceiver protocol. The issue I am seeing is that when I read a binary file and try to send the chunks they simply don't send.
I am reading the file using:
import json
import time
import threading
from twisted.internet import reactor, threads
from twisted.protocols.basic import LineReceiver
from twisted.internet import protocol
MaximumMsgSize = 15500
trySend = True
connectionToServer = None
class ClientInterfaceFactory(protocol.Factory):
def buildProtocol(self, addr):
return WoosterInterfaceProtocol(self._msgProcessor, self._logger)
class ClientInterfaceProtocol(LineReceiver):
def connectionMade(self):
connectionToServer = self
def _DecodeMessage(self, rawMsg):
header, body = json.loads(rawMsg)
return (header, json.loads(body))
def ProcessIncomingMsg(self, rawMsg, connObject):
# Decode raw message.
decodedMsg = self._DecodeMessage(rawMsg)
self.ProccessTransmitJobToNode(decodedMsg, connObject)
def _BuildMessage(self, id, msgBody = {}):
msgs = []
fullMsgBody = json.dumps(msgBody)
msgBodyLength = len(fullMsgBody)
totalParts = 1 if msgBodyLength <= MaximumMsgSize else \
int(math.ceil(msgBodyLength / MaximumMsgSize))
startPoint = 0
msgBodyPos = 0
for partNo in range(totalParts):
msgBodyPos = (partNo + 1) * MaximumMsgSize
header = {'ID' : id, 'MsgParts' : totalParts,
'MsgPart' : partNo }
msg = (header, fullMsgBody[startPoint:msgBodyPos])
jsonMsg = json.dumps(msg)
msgs.append(jsonMsg)
startPoint = msgBodyPos
return (msgs, '')
def ProccessTransmitJobToNode(self, msg, connection):
rootDir = '../documentation/configs/Wooster'
exportedFiles = ['consoleLog.txt', 'blob.dat']
params = {
'Status' : 'buildStatus',
'TaskID' : 'taskID',
'Name' : 'taskName',
'Exports' : len(exportedFiles),
}
msg, statusStr = self._BuildMessage(101, params)
connection.sendLine(msg[0])
for filename in exportedFiles:
with open (filename, "rb") as exportFileHandle:
data = exportFileHandle.read().encode('base64')
params = {
ExportFileToMaster_Tag.TaskID : taskID,
ExportFileToMaster_Tag.FileContents : data,
ExportFileToMaster_Tag.Filename : filename
}
msgs, _ = self._BuildMessage(MsgID.ExportFileToMaster, params)
for m in msgs:
connection.sendLine(m)
def lineReceived(self, data):
threads.deferToThread(self.ProcessIncomingMsg, data, self)
def ConnectFailed(reason):
print 'Connection failed..'
reactor.callLater(20, reactor.callFromThread, ConnectToServer)
def ConnectToServer():
print 'Connecting...'
from twisted.internet.endpoints import TCP4ClientEndpoint
endpoint = TCP4ClientEndpoint(reactor, 'localhost', 8181)
deferItem = endpoint.connect(factory)
deferItem.addErrback(ConnectFailed)
netThread = threading.Thread(target=reactor.run, kwargs={"installSignalHandlers": False})
netThread.start()
reactor.callFromThread(ConnectToServer)
factory = ClientInterfaceFactory()
protocol = ClientInterfaceProtocol()
while 1:
time.sleep(0.01)
if connectionToServer == None: continue
if trySend == True:
protocol.ProccessTransmitJobToNode(None, None)
trySend = False
Is there something I am doing wrong?file is sent, it's when the write is multi part or there are more than one file it struggles.
If a single write occurs then the m
Note: I have updated the question with a crude piece of sample code in the hope it makes sense.
_BuildMessage returns a two-tuple: (msgs, '').
Your network code iterates over this:
msgs = self._BuildMessage(MsgID.ExportFileToMaster, params)
for m in msgs:
So your network code first tries to send a list of json encoded data and then tries to send the empty string. It most likely raises an exception because you cannot send a list of anything using sendLine. If you aren't seeing the exception, you've forgotten to enable logging. You should always enable logging so you can see any exceptions that occur.
Also, you're using time.sleep and you shouldn't do this in a Twisted-based program. If you're doing this to try to avoid overloading the receiver, you should use TCP's native backpressure instead by registering a producer which can receive pause and resume notifications. Regardless, time.sleep (and your loop over all the data) will block the entire reactor thread and prevent any progress from being made. The consequence is that most of the data will be buffered locally before being sent.
Also, your code calls LineReceiver.sendLine from a non-reactor thread. This has undefined results but you can probably count on it to not work.
This loop runs in the main thread:
while 1:
time.sleep(0.01)
if connectionToServer == None: continue
if trySend == True:
protocol.ProccessTransmitJobToNode(None, None)
trySend = False
while the reactor runs in another thread:
netThread = threading.Thread(target=reactor.run, kwargs={"installSignalHandlers": False})
netThread.start()
ProcessTransmitJobToNode simply calls self.sendLine:
def ProccessTransmitJobToNode(self, msg, connection):
rootDir = '../documentation/configs/Wooster'
exportedFiles = ['consoleLog.txt', 'blob.dat']
params = {
'Status' : 'buildStatus',
'TaskID' : 'taskID',
'Name' : 'taskName',
'Exports' : len(exportedFiles),
}
msg, statusStr = self._BuildMessage(101, params)
connection.sendLine(msg[0])
You should probably remove the use of threading entirely from the application. Time-based events are better managed using reactor.callLater (your main-thread loop effectively generates a call to ProcessTransmitJobToNode once hundred times a second (modulo effects of the trySend flag)).
You may also want to take a look at https://github.com/twisted/tubes as a better way to manage large amounts of data with Twisted.
I am a starter in using python. I am showing a section of the code I was working on. I was trying to communicate python to an arduino using pyserial and blinking a LED. I want to use the value returned by the function send_data to be used as an input for function delay_for_goodant. But when I run the code, I get the error
global name data not defined.
Any suggestions to get rid of this?
def openthedoor(set_accepted_list):
if(((len(set_accepted_list)) >0) & (set_forbidden_list == set()):
print"yes,open the gate"
use_door(1)
else:
print"no,close the gate"
use_door(0)
set_for_comparison = set(set_accepted_list & set_list_ant_id)
list_for_comparison = list(set_for_comparison)
return set_for_comparison,list_for_comparison
def establishing_connection():
print ser.read();
ser.write('1')
last_action = -1
def use_door(activate):
global last_action
if(last_action != activate):
send_data(activate)
last_action = activate
def send_data(data):
if (data ==0):
print "manga"
return True
else:
print "muringa"
return False
def delay_for_goodant(data):
print "thenga"
global ser
try:
if (ser == None):
ser = serial.Serial("COM1",9600,timeout = 0)
print "reconnect"
if send_data(data) is True:
ser.write('0')
time.sleep(0)
incoming_data = ser.readline()
print "python is telling arduino to keep the LED dim"
else:
ser.write('1')
time.sleep(0.7)
incoming_data2 = ser.readline()
print "python is telling the arduino to keep the LED bright"
except IOError:
ser = None
I call these functions in later parts of the code as. Am i doing a mistake here? What i am trying to do here is if data ==0, i want to ser.write('1').
establishing_connection()
set_for_comparison,list_for_comparison = openthedoor(set_accepted_list)
activate = use_door()
data = send_data(activate)
arabica = delay_for_goodant(data)
Also the value inside the function delay_for_goodant is not printed.
This is what i get, when i run the code:
True
muringa
Traceback (most recent call last):
File "door_code_final_calib_dig_2.py", line 352, in <module>
arabica = delay_for_goodant(data)
NameError: name 'data' is not defined
I am trying to get Chapel to return an integer to Python. I'd like to call it with python call.py.
call.py
import os
from pych.extern import Chapel
currentloc = os.path.dirname(os.path.realpath(__file__))
#Chapel(sfile=os.path.join(currentloc + '/response.chpl'))
def flip_bit(v=int):
return int
if __name__=="__main__":
u = 71
w = flip_bit(u)
print(w)
And response.chpl
export
proc flip_bit(v: int) :int {
v = -v;
return v;
}
This returns the error
/tmp/temp-7afvL9.chpl:2: In function 'flip_bit':
/tmp/temp-7afvL9.chpl:3: error: illegal lvalue in assignment
g++: error: /tmp/tmpvmKeSi.a: No such file or directory
Traceback (most recent call last):
File "call.py", line 15, in <module>
w = flip_bit(u)
File "/home/buddha314/.virtualenvs/pychapel/local/lib/python2.7/site-packages/pych/extern.py", line 212, in wrapped_f
raise MaterializationError(self)
pych.exceptions.MaterializationError: Failed materializing ({'anames': ['v'],
'atypes': [<type 'int'>],
'bfile': None,
'dec_fp': '/home/buddha314/pychapel/tmp/response.chpl',
'dec_hs': '7ecfac2d168f3423f7104eeb38057ac3',
'dec_ts': 1502208246,
'doc': None,
'efunc': None,
'ename': 'flip_bit',
'lib': 'sfile-chapel-7ecfac2d168f3423f7104eeb38057ac3-1502208246.so',
'module_dirs': [],
'pfunc': <function flip_bit at 0x7fa4d72bd938>,
'pname': 'flip_bit',
'rtype': <type 'int'>,
'sfile': '/home/buddha314/pychapel/tmp/response.chpl',
'slang': 'chapel',
'source': None}).
UPDATE
Based on Lydia's response, I did
export
proc flip_bit(v: int) :int {
var w: int;
w = -v;
return w;
}
And that worked! WOO-HOOO!!!!
UPDATE 2
Based on Brad's comments, this also works
export
proc flip_bit(in v: int) :int {
return -v;
}
Perhaps he can add a comment on benefits of each approach.
It looks like your issue is that you're trying to modify the argument before returning it. Chapel's default argument intent for integers is const in ( see the Chapel spec http://chapel.cray.com/docs/latest/language/spec.html, section 13.5 ), which means it can't be modified within the body of the function and is a copy of the value passed to it. If you store the result in a local variable and return that instead, that should solve your compilation failure and give you the behavior you desire.