Exemplo n.º 1
0
#myroomba.enable_map(enable=True, enableMapWithText=False, roomOutline=False, rssiMap=True, rssiMapGoodSignal=-30, rssiMapBadSignal=-70, auto_rotate=False, mapSize="(1100,1370,-100,-240,0,0)", mapPath="/dataDisk/htdocs/roomba", iconPath="/dataDisk/Roomba980-Python/roomba/res/")  #enable live maps, class default is
myroomba.enable_map(
    enable=True,
    enableMapWithText=False,
    roomOutline=False,
    auto_rotate=False,
    mapSize="(1100,1370,-100,-250,0,0)",
    mapPath="{{htdocs_path}}roomba",
    iconPath="/opt/roomba/res/")  #enable live maps, class default is no maps

if broker is not None:
    myroomba.set_mqtt_client(
        mqttc, brokerFeedback
    )  #if you want to publish Roomba data to your own mqtt broker (default is not to) if you have more than one roomba, and assign a roombaName, it is addded to this topic (ie brokerFeedback/roombaName)
#finally connect to Roomba - (required!)
myroomba.connect()

print("<CMTRL C> to exit")
print("Subscribe to /roomba/feedback/# to see published data")

try:
    if mqttc is not None:
        mqttc.loop_forever()
    else:
        while True:
            #print("Roomba Data: %s" % json.dumps(myroomba.master_state, indent=2))
            time.sleep(5)

except (KeyboardInterrupt, SystemExit):
    print("System exit Received - Exiting program")
    myroomba.disconnect()
Exemplo n.º 2
0
def main():

    #----------- Local Routines ------------

    def create_html(myroomba,mappath="."):
        '''
        Create html files for live display of roomba maps - but only if they
        don't already exist
        NOTE add {{ for { in html where you need variable substitution
        '''
        #default css and html
        css =   '''\
                body {
                    background-color: white;
                    margin: 0;
                    color: white;
                    padding: 0;
                    }
                img,video {
                    width: auto;
                    max-height:100%;
                    }
                '''
        html = '''\
                <!DOCTYPE html>
                <html>
                <head>
                <link href="style.css" rel="stylesheet" type="text/css">
                </head>
                <script>

                function refresh(node)
                {{
                   var times = 1000; // gap in Milli Seconds;

                   (function startRefresh()
                   {{
                      var address;
                      if(node.src.indexOf('?')>-1)
                       address = node.src.split('?')[0];
                      else
                       address = node.src;
                      node.src = address+"?time="+new Date().getTime();

                      setTimeout(startRefresh,times);
                   }})();

                }}

                window.onload = function()
                {{
                  var node = document.getElementById('img');
                  refresh(node);
                  // you can refresh as many images you want just repeat above steps
                }}
                </script>

                <body>
                <img id="img" src="{}map.png" alt="Roomba Map Live" style="position:absolute;top:0;left:0"/>
                </body>
                </html>
                '''.format(myroomba.roombaName)
                
        def write_file(fname, data, mode=0o666):
            if not os.path.isfile(fname):
                log.warn("{} file not found, creating".format(fname))
                try:
                    with open(fname , "w") as fn:
                        fn.write(textwrap.dedent(data))
                    os.chmod(fname, mode)
                except (IOError, PermissionError) as e:
                    log.error("unable to create file {}, error: {}".format(fname, e))
                    
        #check if style.css exists, if not create it
        css_path = '{}/style.css'.format(mappath)
        write_file(css_path, css)
                
        #check if html exists, if not create it
        html_path = '{}/{}roomba_map.html'.format(mappath, myroomba.roombaName)
        write_file(html_path, html, 0o777)

    def setup_logger(logger_name, log_file, level=logging.DEBUG, console=False):
        try: 
            l = logging.getLogger(logger_name)
            formatter = logging.Formatter('[%(asctime)s][%(levelname)5.5s](%(name)-20s) %(message)s')
            if log_file is not None:
                fileHandler = logging.handlers.RotatingFileHandler(log_file, mode='a', maxBytes=10000000, backupCount=10)
                fileHandler.setFormatter(formatter)
            if console == True:
                #formatter = logging.Formatter('[%(levelname)1.1s %(name)-20s] %(message)s')
                streamHandler = logging.StreamHandler()
                streamHandler.setFormatter(formatter)

            l.setLevel(level)
            if log_file is not None:
                l.addHandler(fileHandler)
            if console == True:
              l.addHandler(streamHandler)
                 
        except Exception as e:
            print("Error in Logging setup: %s - do you have permission to write the log file??" % e)
            sys.exit(1)

    arg = parse_args()  #note: all options can be included in the config file
    
    if arg.debug:
        log_level = logging.DEBUG
    else:
        log_level = logging.INFO

    #setup logging
    setup_logger('Roomba', arg.log, level=log_level,console=arg.echo)
    
    #log = logging.basicConfig(level=logging.DEBUG, 
    #    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')

    log = logging.getLogger('Roomba')

    log.info("*******************")
    log.info("* Program Started *")
    log.info("*******************")
    
    log.debug('Debug Mode')

    log.info("Roomba.py Version: %s" % Roomba.__version__)

    log.info("Python Version: %s" % sys.version.replace('\n',''))

    if HAVE_MQTT:
        import paho.mqtt
        log.info("Paho MQTT Version: %s" % paho.mqtt.__version__)

    if HAVE_CV2:
        log.info("CV Version: %s" % cv2.__version__)

    if HAVE_PIL:
        import PIL #bit of a kludge, just to get the version number
        log.info("PIL Version: %s" % PIL.__version__)

    log.debug("-- DEBUG Mode ON -")
    log.info("<CNTRL C> to Exit")
    log.info("Roomba MQTT data Interface")
    
    group = None
    options = vars(arg) #use args as dict

    if arg.blid is None or arg.password is None:
        get_passwd = Password(arg.roomba_ip,file=arg.configfile)
        roombas = get_passwd.get_roombas()
    else:
        roombas = {arg.roomba_ip: {"blid": arg.blid,
                                   "password": arg.password,
                                   "roomba_name": arg.roomba_name}}
                                   
    roomba_list = []
    for addr, info in roombas.items():
        log.info("Creating Roomba object {}, {}".format(addr, info.get("roomba_name", addr)))
        #get options from config (if they exist) this overrides command line options.
        for opt, value in options.copy().items():
            config_value = info.get(opt)
            if config_value is None:
               options[opt] = value
            elif value is None or isinstance(value, str):
                options[opt] = config_value
            else:
                options[opt] = literal_eval(str(config_value))
                
        # minnimum required to connect on Linux Debian system
        # myroomba = Roomba(address, blid, roombaPassword)
        myroomba =  Roomba(addr,
                           blid=arg.blid,
                           password=arg.password,
                           topic=arg.topic,
                           roombaName=arg.roomba_name,
                           webport=arg.webport)
                           
        if arg.webport:
            arg.webport+=1
                    
        if arg.exclude:
            myroomba.exclude = arg.exclude
            
        #set various options
        myroomba.set_options(raw=arg.raw,
                             indent=arg.indent,
                             pretty_print=arg.pretty_print,
                             max_sqft=arg.max_sqft)
            
        if arg.mappath and arg.mapsize and arg.drawmap:
            # auto create html files (if they don't exist)
            create_html(myroomba, arg.mappath)
            # enable live maps, class default is no maps
            myroomba.enable_map(enable=True,
                                mapSize=arg.mapsize,
                                mapPath=arg.mappath,
                                iconPath=arg.iconpath,
                                roomOutline=arg.room_outline,
                                floorplan=arg.floorplan)
                                
        if arg.broker is not None:
            # if you want to publish Roomba data to your own mqtt broker
            # (default is not to) if you have more than one roomba, and
            # assign a roombaName, it is addded to this topic
            # (ie brokerFeedback/roombaName)
            myroomba.setup_mqtt_client(arg.broker,
                                       arg.port,
                                       arg.user,
                                       arg.broker_password,
                                       arg.broker_feedback,
                                       arg.broker_command,
                                       arg.broker_setting)
             
        roomba_list.append(myroomba)   
        
    
    loop = asyncio.get_event_loop()
    loop.set_debug(arg.debug)
    
    group = asyncio.gather(*[myroomba.async_connect() for myroomba in roomba_list])
    
    if not group:
        for myroomba in roomba_list:
            myroomba.connect()            #start each roomba connection individually
    
    try:
        loop.run_forever()
            
    except (KeyboardInterrupt, SystemExit):
        log.info("System exit Received - Exiting program")
        for myroomba in roomba_list:
                myroomba.disconnect()
        log.info('Program Exited')
        
    finally:
        pass
Exemplo n.º 3
0
class PublishMission:
    def __init__(self):
        rospy.init_node("mission_publisher", anonymous=True)

        config_path = rospy.get_param("~config")

        try:
            with open(config_path) as f:
                content = f.read()
                config = yaml.load(content, Loader=yaml.FullLoader)
                rospy.logdebug(f"Configuration dict: {content}")
        except Exception as e:
            while True:
                rospy.logerr("Configuration file is broken or not readable!")
                rospy.logerr(e)
                rospy.sleep(5)

        self.myroomba = Roomba(config["roomba"]["IP"],
                               config["roomba"]["blid"],
                               config["roomba"]["password"])
        self.myroomba.connect()
        time.sleep(5)
        while not self.myroomba.roomba_connected:
            #print(1)
            time.sleep(1)
        print("Roomba connected")
        rospy.Service("send_command", Command, self.send_command)
        self.pub_mission = rospy.Publisher("mission", Mission, queue_size=10)

    def send_command(self, req):
        if req.command == "Start":
            self.myroomba.send_command("start")
            return ("Starting cleaning")
        elif req.command == "Stop":
            self.myroomba.send_command("stop")
            return ("Stop cleaning")
        elif req.command == "Home":
            self.myroomba.send_command("dock")
            return ("Going back home")
        else:
            return ("Wrong command")

    def get_msg_data(self, data, data_state, data_error):
        miss_msg = Mission()
        miss_msg.name = data["name"]
        miss_msg.batteryPercentage = str(data["batPct"])
        miss_msg.mission_cycle = data["cleanMissionStatus"]["cycle"]
        miss_msg.mission_phase = data["cleanMissionStatus"]["phase"]
        miss_msg.current_state = data_state
        miss_msg.error = data_error
        miss_msg.mission_notReady = str(data["cleanMissionStatus"]["notReady"])
        miss_msg.robotPositionXY[0] = data["pose"]["point"]["x"]
        miss_msg.robotPositionXY[1] = data["pose"]["point"]["y"]
        miss_msg.robotPositionAngle = data["pose"]["theta"]
        miss_msg.audio = str(data["audio"]["active"])
        return (miss_msg)

    def spin(self):
        rate = rospy.Rate(1)
        while not rospy.is_shutdown():
            #data = {"name": "robot", "batPct": 100, "cleanMissionStatus": {"cycle": "none", "phase": "charge", "error": 0, "notReady": 0}, "pose": {"point": {"x": 100, "y": 20},"theta": -28}, "audio": {"active": True}}
            #data_state = "Charging"
            data_state = self.myroomba.current_state
            data1 = self.myroomba.master_state
            data_error = self.myroomba.error_message
            data = data1["state"]["reported"]
            mission_msg = self.get_msg_data(data, data_state, data_error)
            self.pub_mission.publish(mission_msg)
            rate.sleep()