Code covered by the BSD License  

Highlights from
PhantomX Robot Turret Controller

image thumbnail

PhantomX Robot Turret Controller

by

 

12 Apr 2012 (Updated )

Control the Trossen Robotics PhantomX RoboTurret: http://www.youtube.com/watch?v=YLt_fZFXYRw

PhantomXMessagePort
classdef PhantomXMessagePort < handle
    %PHANTOMXMESSAGEPORT Holds the serial port, issues commands and keeps
    %track of the state of the turret
    %
    % To create a PhantomXMessagePort object with dedault parameters
    % h = PhantomXMessagePort();
    %
    % Or to create with specific parameters: port and the baudrate
    % h = PhantomXMessagePort('COM1',38400);
    %
    % To open the message port and to start listening for joint poses
    % h.OpenPort();
    %
    % To get the current pose values: pan and tilt
    % pan = h.pose(1);
    % tilt = h.pose(2);
    %
    % To send a command to move PhantomX to a specific pose: [pan tilt]
    % pand = 400;
    % tilt = 600;
    % h.Send(pan,tilt);
    %
    % To close the port after use
    % h.ClosePort();
    
    properties (SetAccess = protected)
        port = 'COM14';
        baudrate = 38400;
        serial_h
        
        running = true;

        portOpen = false;
        actualPose_h
        desiredPose_h
        pose
        
        serialReadCountDownMilliseconds = 10000;
        timerPeriod = 0.35;        
        runAsyncTimer
    end
    
    properties (Constant)
        PACKET_LENGTH = 11;
        MIN_PAN_STEP = 0;
        MAX_PAN_STEP = 1027;
        MIN_TILT_STEP = 160;
        MAX_TILT_STEP = 850;
    end
    
    methods
%% ..structors        
        function self = PhantomXMessagePort(port,baudrate)
            if nargin == 2
                self.port = port;
                self.baudrate = baudrate;
            end           
        end

        function delete(self)
            self.ClosePort();
        end
        
%% Send
        function Send(self,pan,tilt)
            [pan,tilt] = self.KeepInPanAndTiltBounds(pan,tilt);
            pppp = strpad(num2str(round(pan)),4);
            tttt = strpad(num2str(round(tilt)),4);
                    
            if self.portOpen
                cmd = [':',pppp,',',tttt,';'];
                fprintf(self.serial_h,cmd);
                display(['COMMAND ',cmd]);
            else
                display('Port is current closed. Command not sent.');
            end                
        end
        
%% Pose updating timer        
        function StartGetGurrentPoseTimer(self)
            self.runAsyncTimer = timer('TimerFcn', @(src,event)GetGurrentPose(self), 'name', 'RunAsync','Period', self.timerPeriod,'BusyMode','drop','ExecutionMode','fixedDelay');
            start(self.runAsyncTimer);  
        end
        
        function StopGetGurrentPoseTimer(self)
            if ~isempty(self.runAsyncTimer) && strcmp(self.runAsyncTimer.Running,'on')
                stop(self.runAsyncTimer);
            end
        end
                    
        function GetGurrentPose(self)
            %display('GetGurrentPose');
            if self.portOpen
                tic
                previousToc = toc;
                bytesAvailable = self.serial_h.BytesAvailable;
                while bytesAvailable < 2*self.PACKET_LENGTH                                        
                    pause(0.05);                    
                    if self.serialReadCountDownMilliseconds < toc * 1000
                        warning('Not getting data back from serial port. Closing port'); %#ok<WNTAG>
                        self.ClosePort();
                        break;
                    else
                        bytesAvailable = self.serial_h.BytesAvailable;
                    end
                    if round(previousToc) < round(toc)
                        display(['Waiting for data. So far waited ',num2str(toc),'secs']);
                        previousToc = toc;
                    end
                end
                
                if self.portOpen
                    % Get all the data available                    
                    dataStr = char(fread(self.serial_h,bytesAvailable)); %#ok<FREAD> % DONT CHANGE THIS BECAUSE IT DOES A DIFFERENT THING IF CHANGED
                    packet = dataStr(find(dataStr== ';',1,'last')-10:find(dataStr == ';',1,'last'));
                    %packet = fscanf(self.serial_h);
                    % Get the last packet
                    if ~strcmp(packet(1),':') || ~strcmp(packet(6),',') || ~strcmp(packet(11),';')
                        warning('A problem with this packet. Must be in the form :pppp,tttt;'); %#ok<WNTAG>                       
                    end
                    % Set the pose
                    self.pose(1) = round(str2double(packet(2:5)));
                    self.pose(2) = round(str2double(packet(7:10)));                   
                end                
            end
        end
                            
%% KeepInPanAndTiltBounds
% Fix the pan and tilt angles entered so they are within the movement
% bounds of the servos
        function [newPan,newTilt] = KeepInPanAndTiltBounds(self,pan,tilt)        
            newPan = pan;
            newTilt = tilt;
            if newPan < self.MIN_PAN_STEP
                newPan = self.MIN_PAN_STEP;
            elseif self.MAX_PAN_STEP < newPan
                newPan = self.MAX_PAN_STEP;
            end
            
            if newTilt < self.MIN_TILT_STEP
                newTilt = self.MIN_TILT_STEP;
            elseif self.MAX_TILT_STEP < newTilt
                newTilt = self.MAX_TILT_STEP;
            end
        end
        
%% OpenPort        
        function result = OpenPort(self)
            result = false;
            try
                if isempty(self.serial_h)
                    self.serial_h = serial(self.port,'BaudRate',self.baudrate);
                end
                if ~strcmp(get(self.serial_h,'Status'),'open')
                    fopen(self.serial_h);
                end
                    
                if strcmp(get(self.serial_h,'Status'),'open')
                    self.portOpen = true;
                    self.StartGetGurrentPoseTimer();
                    result = self.portOpen;
                else
                    warning('Port not opened'); %#ok<WNTAG>
                end
                
            catch ME_1
                display(ME_1);
            end            
            
        end
        
%% ClosePort        
        function ClosePort(self)
            self.StopGetGurrentPoseTimer();
            try      %#ok<TRYNC>
                fclose(self.serial_h);
%             catch ME_1
%                 display(ME_1);
            end
            self.portOpen = false;
        end            
    end    
end

Contact us