I'm trying to build my first dronekit python program, and I'm doing some tests with some examples but I couldn't connect to my UAV(Iris+). I plugged the usb radio(3DR 915 MHz) and I put vehicle = connect('/dev/ttyUSB0', wait_ready=True). Actually I have no idea which string I should put in. Thanks in advance guys, I need some help!
My code:
print "Start simulator (SITL)"
from dronekit_sitl import SITL
sitl = SITL()
sitl.download('copter', '3.3', verbose=True)
sitl_args = ['-I0', '--model', 'quad', '--home=-35.363261,149.165230,584,353']
sitl.launch(sitl_args, await_ready=True, restart=True)
# Import DroneKit-Python
from dronekit import connect, VehicleMode
import time
# Connect to the Vehicle.
print "Connecting to vehicle on: '/dev/ttyUSB0'"
vehicle = connect('/dev/ttyUSB0', wait_ready=True)
# Get some vehicle attributes (state)
print "Get some vehicle attribute values:"
print " GPS: %s" % vehicle.gps_0
print " Battery: %s" % vehicle.battery
print " Last Heartbeat: %s" % vehicle.last_heartbeat
print " Is Armable?: %s" % vehicle.is_armable
print " System status: %s" % vehicle.system_status.state
print " Mode: %s" % vehicle.mode.name # settable
# Close vehicle object before exiting script
vehicle.close()
# Shut down simulator
sitl.stop()
print("Completed")
Best place for getting dk support now is probably here: https://discuss.dronekit.io/c/python
In answer, I have not tried this on Linux. I suspect the connection string is correct, but you may have to also set the baud rate using baud=57600
Related
One of the goal of the project I'm working with is making Pepper robot patrolling hospital wards "autonomously". So I downloaded some basic application to start with navigation (https://github.com/aldebaran/naoqi_navigation_samples). The "explore" application is critical since it is needed by the other two (places and patrol). I tried to launch "explore" on Choregraphe, but the robot does not move (so it does not explore neither creates a map, obviously) and the application ends by saying the final sentence. In particular the block "Get map" gives an error. So, the application starts correctly but it does not work properly.
I saved "explore" as a robot application and tried in both autonomous life and not autonomous life.
I can not understand where I'm wrong: could you help me please?
Make sure the charging flap is not open when you run. Also try this code, it will create a map
#! /usr/bin/env python
# -*- encoding: UTF-8 -*-
"""Example: Use explore method."""
import qi
import argparse
import sys
import numpy
from PIL import Image
def main(session):
"""
This example uses the explore method.
"""
# Get the services ALNavigation and ALMotion.
navigation_service = session.service("ALNavigation")
motion_service = session.service("ALMotion")
# Wake up robot
motion_service.wakeUp()
# Explore the environement, in a radius of 2 m.
radius = 5.0
error_code = navigation_service.explore(radius)
if error_code != 0:
print ("Exploration failed.")
return
# Saves the exploration on disk
path = navigation_service.saveExploration()
print ("Exploration saved at path: \"" + path + "\"")
# Start localization to navigate in map
navigation_service.startLocalization()
# Come back to initial position
navigation_service.navigateToInMap([0., 0., 0.])
# Stop localization
navigation_service.stopLocalization()
# Retrieve and display the map built by the robot
result_map = navigation_service.getMetricalMap()
map_width = result_map[1]
map_height = result_map[2]
img = numpy.array(result_map[4]).reshape(map_width, map_height)
img = (100 - img) * 2.55 # from 0..100 to 255..0
img = numpy.array(img, numpy.uint8)
Image.frombuffer('L', (map_width, map_height), img, 'raw', 'L', 0, 1).show()
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--ip", type=str, default="127.0.0.1",
help="Robot IP address. On robot or Local Naoqi: use '127.0.0.1'.")
parser.add_argument("--port", type=int, default=9559,
help="Naoqi port number")
args = parser.parse_args()
session = qi.Session()
try:
session.connect("tcp://" + args.ip + ":" + str(args.port))
except RuntimeError:
print ("Can't connect to Naoqi at ip \"" + args.ip + "\" on port " + str(args.port) +".\n"
"Please check your script arguments. Run with -h option for help.")
sys.exit(1)
main(session)
I am currently working on Softbanks' robot Pepper and I try to use Watson speech-to-text solution on Pepper's audio buffers remote streaming by using websocket protocol.
I used the answer to that former question NAO robot remote audio problems to find a way to access remotly pepper's audio buffers and that project https://github.com/ibm-dev/watson-streaming-stt to learn how to use websocket protocole to use watson streaming stt.
However, after I open my websocket application, I start sending buffers to watson and after a few sendings, I receive error: 'Unable to transcode from audio/l16;rate=48000;channel=1 to one of: audio/x-float-array; rate=16000; channels=1'
Each time I'm trying to send Pepper's audio buffer to watson, it is unable to understand it.
I compared data I send with data sent in watson streaming stt example (using pyaudio streaming from microphone instead of Pepper's buffer streaming) and I don't see any difference. Both time I'm pretty sure that I am sending a string containing raw chunks of bytes. Which is what Watson asks for in it documentation.
I try to send chunks of 8192 bytes with a sample rate of 48kHz and I can easily convert Pepper's audio buffer in hexa so I don't understand why Watson can't transcode it.
Here is my code:
# -*- coding: utf-8 -*-
#!/usr/bin/env python
import argparse
import base64
import configparser
import json
import threading
import time
from optparse import OptionParser
import naoqi
import numpy as np
import sys
from threading import Thread
import ssl
import websocket
from websocket._abnf import ABNF
CHANNELS = 1
NAO_IP = "172.20.10.12"
class SoundReceiverModule(naoqi.ALModule):
"""
Use this object to get call back from the ALMemory of the naoqi world.
Your callback needs to be a method with two parameter (variable name, value).
"""
def __init__( self, strModuleName, strNaoIp):
try:
naoqi.ALModule.__init__(self, strModuleName );
self.BIND_PYTHON( self.getName(),"callback" );
self.strNaoIp = strNaoIp;
self.outfile = None;
self.aOutfile = [None]*(4-1); # ASSUME max nbr channels = 4
self.FINALS = []
self.RECORD_SECONDS = 20
self.ws_open = False
self.ws_listening = ""
# init data for websocket interfaces
self.headers = {}
self.userpass = "" #userpass and password
self.headers["Authorization"] = "Basic " + base64.b64encode(
self.userpass.encode()).decode()
self.url = ("wss://stream.watsonplatform.net//speech-to-text/api/v1/recognize"
"?model=fr-FR_BroadbandModel")
except BaseException, err:
print( "ERR: abcdk.naoqitools.SoundReceiverModule: loading error: %s" % str(err) );
# __init__ - end
def __del__( self ):
print( "INF: abcdk.SoundReceiverModule.__del__: cleaning everything" );
self.stop();
def start( self ):
audio = naoqi.ALProxy( "ALAudioDevice", self.strNaoIp, 9559 );
self.nNbrChannelFlag = 3; # ALL_Channels: 0, AL::LEFTCHANNEL: 1, AL::RIGHTCHANNEL: 2; AL::FRONTCHANNEL: 3 or AL::REARCHANNEL: 4.
self.nDeinterleave = 0;
self.nSampleRate = 48000;
audio.setClientPreferences( self.getName(), self.nSampleRate, self.nNbrChannelFlag, self.nDeinterleave ); # setting same as default generate a bug !?!
audio.subscribe( self.getName() );
#openning websocket app
self._ws = websocket.WebSocketApp(self.url,
header=self.headers,
on_open = self.on_open,
on_message=self.on_message,
on_error=self.on_error,
on_close=self.on_close)
sslopt={"cert_reqs": ssl.CERT_NONE}
threading.Thread(target=self._ws.run_forever, kwargs = {'sslopt':sslopt}).start()
print( "INF: SoundReceiver: started!" );
def stop( self ):
print( "INF: SoundReceiver: stopping..." );
audio = naoqi.ALProxy( "ALAudioDevice", self.strNaoIp, 9559 );
audio.unsubscribe( self.getName() );
print( "INF: SoundReceiver: stopped!" );
print "INF: WebSocket: closing..."
data = {"action": "stop"}
self._ws.send(json.dumps(data).encode('utf8'))
# ... which we need to wait for before we shutdown the websocket
time.sleep(1)
self._ws.close()
print "INF: WebSocket: closed"
if( self.outfile != None ):
self.outfile.close();
def processRemote( self, nbOfChannels, nbrOfSamplesByChannel, aTimeStamp, buffer ):
"""
This is THE method that receives all the sound buffers from the "ALAudioDevice" module"""
print "receiving buffer"
# self.data_to_send = self.data_to_send + buffer
# print len(self.data_to_send)
#self.data_to_send = ''.join( [ "%02X " % ord( x ) for x in buffer ] ).strip()
self.data_to_send = buffer
#print("buffer type :", type(data))
#print("buffer :", buffer)
#~ print( "process!" );
print( "processRemote: %s, %s, %s, lendata: %s, data0: %s (0x%x), data1: %s (0x%x)" % (nbOfChannels, nbrOfSamplesByChannel, aTimeStamp, len(buffer), buffer[0],ord(buffer[0]),buffer[1],ord(buffer[1])) );
if self.ws_open == True and self.ws_listening == True:
print "sending data"
self._ws.send(self.data_to_send, ABNF.OPCODE_BINARY)
print "data sent"
#print self.data_to_send
aSoundDataInterlaced = np.fromstring( str(buffer), dtype=np.int16 );
#
aSoundData = np.reshape( aSoundDataInterlaced, (nbOfChannels, nbrOfSamplesByChannel), 'F' );
# print "processRemote over"
# processRemote - end
def on_message(self, ws, msg):
print("message")
data = json.loads(msg)
print data
if "state" in data:
if data["state"] == "listening":
self.ws_listening = True
if "results" in data:
if data["results"][0]["final"]:
self.FINALS.append(data)
# This prints out the current fragment that we are working on
print(data['results'][0]['alternatives'][0]['transcript'])
def on_error(self, ws, error):
"""Print any errors."""
print(error)
def on_close(self, ws):
"""Upon close, print the complete and final transcript."""
transcript = "".join([x['results'][0]['alternatives'][0]['transcript']
for x in self.FINALS])
print("transcript :", transcript)
self.ws_open = False
def on_open(self, ws):
"""Triggered as soon a we have an active connection."""
# args = self._ws.args
print "INF: WebSocket: opening"
data = {
"action": "start",
# this means we get to send it straight raw sampling
"content-type": "audio/l16;rate=%d;channel=1" % self.nSampleRate,
"continuous": True,
"interim_results": True,
# "inactivity_timeout": 5, # in order to use this effectively
# you need other tests to handle what happens if the socket is
# closed by the server.
"word_confidence": True,
"timestamps": True,
"max_alternatives": 3
}
# Send the initial control message which sets expectations for the
# binary stream that follows:
self._ws.send(json.dumps(data).encode('utf8'))
# Spin off a dedicated thread where we are going to read and
# stream out audio.
print "INF: WebSocket: opened"
self.ws_open = True
def version( self ):
return "0.6";
def main():
"""initialisation
"""
parser = OptionParser()
parser.add_option("--pip",
help="Parent broker port. The IP address or your robot",
dest="pip")
parser.add_option("--pport",
help="Parent broker port. The port NAOqi is listening to",
dest="pport",
type="int")
parser.set_defaults(
pip=NAO_IP,
pport=9559)
(opts, args_) = parser.parse_args()
pip = opts.pip
pport = opts.pport
# We need this broker to be able to construct
# NAOqi modules and subscribe to other modules
# The broker must stay alive until the program exists
myBroker = naoqi.ALBroker("myBroker",
"0.0.0.0", # listen to anyone
0, # find a free port and use it
pip, # parent broker IP
pport) # parent broker port
"""fin initialisation
"""
global SoundReceiver
SoundReceiver = SoundReceiverModule("SoundReceiver", pip) #thread1
SoundReceiver.start()
try:
while True:
time.sleep(1)
print "hello"
except KeyboardInterrupt:
print "Interrupted by user, shutting down"
myBroker.shutdown()
SoundReceiver.stop()
sys.exit(0)
if __name__ == "__main__":
main()
I would be thankful if anyone had any idea on how to bypass that error or on what to try to get useful info. I first believed that I was sending "wrong" data to watson however after lots of attempts I have no clue on how to fix that problem.
Thank you a lot,
Alex
I have installed dronekit and dronekit sitl and created the hello.py example and I get the following eror I am a novice so sorry if its obvious. This is the output I am running on a raspberry 3 under debian with python 2.7 . Here is the code
print "Start simulator (SITL)"
import dronekit_sitl
sitl = dronekit_sitl.start_default()
connection_string = sitl.connection_string()
# Import DroneKit-Python
from dronekit import connect, VehicleMode
# Connect to the Vehicle.
print("Connecting to vehicle on: %s" % (connection_string,))
vehicle = connect(connection_string, wait_ready=True)
# Get some vehicle attributes (state)
print "Get some vehicle attribute values:"
print " GPS: %s" % vehicle.gps_0
print " Battery: %s" % vehicle.battery
print " Last Heartbeat: %s" % vehicle.last_heartbeat
print " Is Armable?: %s" % vehicle.is_armable
print " System status: %s" % vehicle.system_status.state
print " Mode: %s" % vehicle.mode.name # settable
# Close vehicle object before exiting script
vehicle.close()
# Shut down simulator
sitl.stop()
print("Completed")
And here is the output I get:
python hellp.py
Start simulator (SITL)
Starting copter simulator (SITL)
SITL already Downloaded and Extracted.
Ready to boot.
Traceback (most recent call last):
File "hellp.py", line 3, in <module>
sitl = dronekit_sitl.start_default()
File "/home/gus/.local/lib/python2.7/site-packages/dronekit_sitl/__init__.py", line 341, in start_default
sitl.launch(sitl_args, await_ready=True, restart=True)
File "/home/gus/.local/lib/python2.7/site-packages/dronekit_sitl/__init__.py", line 271, in launch
p = Popen([self.path] + args, cwd=wd, shell=sys.platform == 'win32', stdout=PIPE, stderr=PIPE)
File "/usr/lib/python2.7/subprocess.py", line 390, in __init__
errread, errwrite)
File "/usr/lib/python2.7/subprocess.py", line 1024, in _execute_child
raise child_exception
OSError: [Errno 8] Exec format error
Thanks so much in advance for any help
As you are running SITL on ARM, this might be the issue. You might have installed packages directly by apt-get. You can try to build the SITL on the pi itself and try run after that.
Heyho
I want to repeat a program after runnning a task. At the start of the program I ask some questions, than the code jumps into the task. If the task is done the questions sholud ask again..
Each Question reads some infos at the serial port. If i get the infos ten times ich will restart the programm.. but the window closes and i must start the file..
What can i do?
import serial
import struct
import datetime
print("\n")
print("This tool reads the internal Bus ")
print("-----------------------------------------------------------------------")
COM=input("Check your COM Port an fill in with single semicolon (like: 'COM13' ): ")
ser = serial.Serial(
port=COM,
baudrate=19200,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS
)
print("\n")
print("Please choose an option: ")
print("Polling of measured values and the operating status (1)")
print("Reading Parameter memory (2)")
print("Reading Fault memory (3)")
print("EXIT (4)")
print("\n")
i=input("Reading: ")
while(i==1):
count=0
while (count<10):
print(file.name)
print(ser.isOpen())
print ("connected to: "+ ser.portstr)
data = "\xE1\x14\x75\x81"
ser.write(data)
a=(map(hex,map(ord,ser.read(46))))
with open("RS485_Reflex.txt",mode='a+') as file:
file.write(str(datetime.datetime.now()))
file.write(", Values: ,")
file.write(str(a))
file.write("\n")
print(a)
count=count+1
else:
i=0
loop=1
#-----------------------------------------------------------------------
while(i==2):
count=0
while (count<10):
print(file.name)
print(ser.isOpen())
print ("connected to: "+ ser.portstr)
data = "\xE1\x13\x00\x00\x74\x81"
ser.write(data)
a=(map(hex,map(ord,ser.read(11))))
with open("RS485_Reflex.txt",mode='a+') as file:
file.write(str(datetime.datetime.now()))
file.write(", Parameters: , ")
file.write(str(a))
file.write("\n")
print(a)
count=count+1
else:
i=0
#---------------------------------------------------------------------
while(i==3):
count=0
while (count<10):
print(file.name)
print(ser.isOpen())
print ("connected to: "+ ser.portstr)
data = "\xE1\x12\x00\x00\x73\x81"
ser.write(data)
a=(map(hex,map(ord,ser.read(11))))
with open("RS485_Reflex.txt",mode='a+') as file:
file.write(str(datetime.datetime.now()))
file.write(", Fault: , ")
file.write(str(a))
file.write("\n")
print(a)
count=count+1
else:
i=0
#----------------------------------------------------------------------
while(i==4):
file.close()
ser.close()
sys.exit(0)
file.close()
ser.close()
First, you should use If/Elif/Else statements instead of while loops.
while(i==1):
should be
if(i==1)0:
This is a simple program I wrote that you can follow:
# setup a simple run_Task method (prints number of times through the loop already)
def run_task(count):
print "Ran a certain 'task'", count,"times"
# count is a variable that will count the number of times we pass through a loop
count = 0
# loop through 10 times
while(count<10):
# ask questions
q1 = raw_input("What is your name?")
q2 = raw_input("What is your favorite color?")
# run a 'task'
run_task(count)
And again, asking for help. But, before I start, here will be a lot of text, so please sorry for that.
I have about 500~ IP addresses with devices 2x categories in .xlsx book
I want:
telnet to device. Check device (by authentication prompt) type 1 or type 2.
If device is type 1 - get it firmware version in 2x partitions
write in excel file:
column 1 - IP address
column 2 - device type
column 3 - firmware version
column 4 - firmware version in reserve partition.
If type 2 - write in excel file:
column 1 - IP address
column 2 - device type
If device is down, or device type 3(unknown) - write in excel file:
column 1 - IP address
column 2 - result (EOF, TIMEOUT)
What I have done: I'm able to telnet to device, check device type, write in excel with 2 columns (in 1 column IP addresses, in 2 column is device type, or EOF/TIMEOUT results)
And, I'm writing full logs from session to files in format IP_ADDRESS.txt to future diagnosis.
What I can't understand to do? I can't understand how to get firmware version, and put it on 3,4 columns.
I can't understand how to work with current log session in real time, so I've decided to copy logs from main file (IP_ADDRESS.txt) to temp.txt to work with it.
I can't understand how to extract information I needed.
The file output example:
Trying 10.40.81.167...
Connected to 10.40.81.167.
Escape character is '^]'.
####################################
# #
# RADIUS authorization disabled #
# Enter local login/password #
# #
####################################
bt6000 login: admin
Password:
Please, fill controller information at first time (Ctrl+C to abort):
^C
Controller information filling canceled.
^Cadmin#bt6000# firmware info
Active boot partition: 1
Partition 0 (reserved):
Firmware: Energomera-2.3.1
Version: 10117
Partition 1 (active):
Firmware: Energomera-2.3.1_01.04.15c
Version: 10404M
Kernel version: 2.6.38.8 #2 Mon Mar 2 20:41:26 MSK 2015
STM32:
Version: bt6000 10083
Part Number: BT6024
Updated: 27.04.2015 16:43:50
admin#bt6000#
I need values - after "Energomera" words, like 2.3.1 for reserved partition, and 2.3.1_01.04.15c for active partition.
I've tried to work with string numbers and excract string, but there was not any kind of good result at all.
Full code of my script below.
import pexpect
import pxssh
import sys #hz module
import re #Parser module
import os #hz module
import getopt
import glob #hz module
import xlrd #Excel read module
import xlwt #Excel write module
import telnetlib #telnet module
import shutil
#open excel book
rb = xlrd.open_workbook('/samba/allaccess/Energomera_Eltek_list.xlsx')
#select work sheet
sheet = rb.sheet_by_name('IPs')
#rows number in sheet
num_rows = sheet.nrows
#cols number in sheet
num_cols = sheet.ncols
#creating massive with IP addresses inside
ip_addr_list = [sheet.row_values(rawnum)[0] for rawnum in range(sheet.nrows)]
#create excel workbook with write permissions (xlwt module)
wb = xlwt.Workbook()
#create sheet IP LIST with cell overwrite rights
ws = wb.add_sheet('IP LIST', cell_overwrite_ok=True)
#create counter
i = 0
#authorization details
port = "23" #telnet port
user = "admin" #telnet username
password = "12345" #telnet password
#firmware ask function
def fw_info():
print('asking for firmware')
px.sendline('firmware info')
px.expect('bt6000#')
#firmware update function
def fw_send():
print('sending firmware')
px.sendline('tftp server 172.27.2.21')
px.expect('bt6000')
px.sendline('firmware download tftp firmware.ext2')
px.expect('Updating')
px.sendline('y')
px.send(chr(13))
ws.write(i, 0, host)
ws.write(i, 1, 'Energomera')
#if eltek found - skip, write result in book
def eltek_found():
print(host, "is Eltek. Skipping")
ws.write(i, 0, host)
ws.write(i, 1, 'Eltek')
#if 23 port telnet conn. refused - skip, write result in book
def conn_refuse():
print(host, "connection refused")
ws.write(i, 0, host)
ws.write(i, 1, 'Connection refused')
#auth function
def auth():
print(host, "is up! Energomera found. Starting auth process")
px.sendline(user)
px.expect('assword')
px.sendline(password)
#start working with ip addresses in ip_addr_list massive
for host in ip_addr_list:
#spawn pexpect connection
px = pexpect.spawn('telnet ' + host)
px.timeout = 35
#create log file with in IP.txt format (10.1.1.1.txt, for example)
fout = open('/samba/allaccess/Energomera_Eltek/{0}.txt'.format(host),"wb")
#push pexpect logfile_read output to log file
px.logfile_read = fout
try:
index = px.expect (['bt6000', 'sername', 'refused'])
#if device tell us bt6000 - authorize
if index == 0:
auth()
index1 = px.expect(['#', 'lease'])
#if "#" - ask fw version immediatly
if index1 == 0:
print('seems to controller ID already set')
fw_info()
#if "Please" - press 2 times Ctrl+C, then ask fw version
elif index1 == 1:
print('trying control C controller ID')
px.send(chr(3))
px.send(chr(3))
px.expect('bt6000')
fw_info()
#firmware update start (temporarily off)
# fw_send()
#Eltek found - func start
elif index == 1:
eltek_found()
#Conn refused - func start
elif index == 2:
conn_refuse()
#print output to console (test purposes)
print(px.before)
px.send(chr(13))
#Copy from current log file to temp.txt for editing
shutil.copy2('/samba/allaccess/Energomera_Eltek/{0}.txt'.format(host), '/home/bark/expect/temp.txt')
#EOF result - skip host, write result to excel
except pexpect.EOF:
print(host, "EOF")
ws.write(i, 0, host)
ws.write(i, 1, 'EOF')
#print output to console (test purposes)
print(px.before)
#Timeout result - skip host, write result to excel
except pexpect.TIMEOUT:
print(host, "TIMEOUT")
ws.write(i, 0, host)
ws.write(i, 1, 'TIMEOUT')
#print output to console (test purposes)
print(px.before)
#Copy from current log file to temp.txt for editing
shutil.copy2('/samba/allaccess/Energomera_Eltek/{0}.txt'.format(host), '/home/bark/expect/temp.txt')
#count +1 to correct output for Excel
i += 1
#workbook save
wb.save('/samba/allaccess/Energomera_Eltek_result.xls')
Have you have any suggestions or ideas, guys, how I can do this?
Any help is greatly appreciated.
You can use regular expressions
example:
>>> import re
>>>
>>> str = """
... Trying 10.40.81.167...
...
... Connected to 10.40.81.167.
...
... Escape character is '^]'.
...
...
...
... ####################################
... # #
... # RADIUS authorization disabled #
... # Enter local login/password #
... # #
... ####################################
... bt6000 login: admin
... Password:
... Please, fill controller information at first time (Ctrl+C to abort):
... ^C
... Controller information filling canceled.
... ^Cadmin#bt6000# firmware info
... Active boot partition: 1
... Partition 0 (reserved):
... Firmware: Energomera-2.3.1
... Version: 10117
... Partition 1 (active):
... Firmware: Energomera-2.3.1_01.04.15c
... Version: 10404M
... Kernel version: 2.6.38.8 #2 Mon Mar 2 20:41:26 MSK 2015
... STM32:
... Version: bt6000 10083
... Part Number: BT6024
... Updated: 27.04.2015 16:43:50
... admin#bt6000#
... """
>>> re.findall(r"Firmware:.*?([0-9].*)\s", str)
['2.3.1', '2.3.1_01.04.15c']
>>> reserved_firmware = re.search(r"reserved.*\s*Firmware:.*?([0-9].*)\s", str).group(1)
>>> reserved_firmware
'2.3.1'
>>> active_firmware = re.search(r"active.*\s*Firmware:.*?([0-9].*)\s", str).group(1)
>>> active_firmware
'2.3.1_01.04.15c'
>>>