####################  configure.rb -- brent@mbari.org  #####################
# $Source: /home/cvs/ESP/gen2/software/esp/admin/configure.rb,v $
#    Copyright (C) 2003 MBARI
#    MBARI Proprietary Information. All rights reserved.
# $Id: configure.rb,v 1.109 2005/11/02 02:53:59 scholin Exp $
#
#  Common, One-Time configuration for entire ESP instrument
#  reads in all common utilites
#  Defines all motor axis
#  Must never cause any actuators to move
#
############################################################################

#system libraries
require 'valve'
require 'shaft'
require 'syringe'
require 'gripper'
require 'thermal'
require 'camera'

## see miscellenous utilities below

#write TIFF images to the log directory if none specified
PuckCamera = Camera.new :binning=>4, :suffix=>".tif",
                        :dir=>"/var/log/#{ENV['USER']}"

class Sampler  #sampler needs count<->PSI unit conversions
  #these will likely need to be modified when pressure sensors are serviced
  #               first is scale, last is the bias at 0
  IntakeScaleAndBias = [0.863977, 52.3283]  
  OutletScaleAndBias = [1.016226, 49.5828]
end

class Clamp < Slide
  def closed?
    rawPosition >= at(:close).raw - config.maxPositionErr
  end
end

###  Collection Clamp  ###
:CCconfig.denotes I2C::Servo::Configuration.default.with \
  :encoder=>:negative, :home=>:negative,
  :homeDirection=>false,
  :maxPositionErr => 20,
  :gain => I2C::Servo::PIDgain.new(2600,240,400),
  :maxSpeed => 100, :minSpeed => 30,
  :acceleration=>10,
  :maxCurrent => 300,
  :maxSettling => 30


:CC.denotes Clamp.new ("Collection Clamp",
   I2C::Servos[:collection], 1, CCconfig, 30).with AxisMap.new (
     0=>:home, -1000=>:open, 20000=>:close
   )
   

###  Collection Syringe  ###
:CSconfig.denotes I2C::Servo::Configuration.default.with \
  :encoder=>:negative, :home=>:negative,
  :homeDirection=>false,
  :maxPositionErr => 20,
  :gain => I2C::Servo::PIDgain.new(3500, 1000, 3000),
  :maxSpeed => 100, :minSpeed => 10,
  :acceleration=>5,
  :maxCurrent =>150,
  :maxSettling => 64

zero=-8869
:CS.denotes Syringe.new ("Collection Syringe", 
                            I2C::Servos[:collection], 0, CSconfig, 160).
  scale (:ml, AxisMap.new (0=>:home, zero-50=>:empty, zero=>0, 71629=>10
  ))

:CSfast.denotes CSconfig.dup.with :maxSpeed=>700, :maxPositionErr=>60
:CSpressurize.denotes CSfast.dup
    

###  Processing Clamp  ###
:PCconfig.denotes I2C::Servo::Configuration.default.with \
  :encoder=>:negative, :home=>:negative,
  :homeDirection=>false,
  :maxPositionErr => 20,
  :gain => I2C::Servo::PIDgain.new(2600,240,400),
  :maxSpeed => 100, :minSpeed => 30,
  :acceleration=>10,
  :maxCurrent => 300,
  :maxSettling => 30

:PC.denotes Clamp.new ("Processing Clamp", 
   I2C::Servos[:processing], 1, PCconfig, 30).with AxisMap.new (
     0=>:home, -1000=>:open, 20000=>:close
   )


###  Processing Syringe  ###
:PSconfig.denotes I2C::Servo::Configuration.default.with \
  :encoder=>:negative, :home=>:negative,
  :homeDirection=>false,
  :maxPositionErr => 10,
  :gain => I2C::Servo::PIDgain.new(3500, 200, 0),
  :maxSpeed => 100, :minSpeed => 5,
  :acceleration=>5,
  :maxCurrent =>100,
  :maxSettling => 3*32


zero=-9731
:PS.denotes Syringe.new ("Processing Syringe", 
                            I2C::Servos[:processing], 0, PSconfig, 160).
  scale (:ml, AxisMap.new (0=>:home, zero-30=>:empty, zero=>0, 71210=>2.5))
  
:PSfast.denotes PSconfig.dup.with :maxSpeed=>300


###  Manipulator Elbow  ###
:ElbowConfig.denotes I2C::Servo::Configuration.default.with \
  :encoder=>:negative, :home=>:negative,
  :homeDirection=>true,
  :maxPositionErr => 100,
  :gain => I2C::Servo::PIDgain.new(700,80,150),
  :maxSpeed => 700, :minSpeed => 10,
  :acceleration=>15,
  :maxCurrent => 300,
  :maxSettling => 128

:ElbowSlow.denotes ElbowConfig.dup.with :maxSpeed=>250

:Elbow.denotes Slide.new("Elbow", 
  I2C::Servos[:manipulator], 1, ElbowConfig, 30, 200).with AxisMap.new (
    -42000=>:drop, -15305=>:elevator, 0=>:home, 3964=>:collection,  
    -38723=>:flush, -52403=>:processing, -29000=>:bolt
  )


###  Manipulator Forearm  ###
:ForearmConfig.denotes I2C::Servo::Configuration.default.with \
  :encoder=>:negative, :home=>:negative,
  :homeDirection=>true,
  :maxPositionErr => 100,
  :gain => I2C::Servo::PIDgain.new(350, 80, 200),
  :maxSpeed => 500, :minSpeed => 5,
  :acceleration=>50,
  :maxCurrent =>400,
  :maxSettling => 8*32

:Forearm.denotes Slide.new ("Forearm",
  I2C::Servos[:manipulator], 0, ForearmConfig, 10, 60).with AxisMap.new (
    0=>:home, 2060=>[:retract, :retracted],
    -12700=>:collection, -12625=>:processing, -12400=>:elevator, -12800=>:elplace, -12608=>:flush
  )
:MFplace.denotes ForearmConfig.dup.with :maxCurrent=>200
:MFretract.denotes ForearmConfig.dup.with :maxPositionErr=>200

### Manipulator Hand  ###
:Hand.denotes Gripper.new "Hand", I2C::Servos[:manipulator], 1, 10


###  Storage Carousel  ###
:SCconfig.denotes I2C::Servo::Configuration.default.with \
  :encoder=>:negative, :home=>:negative,
  :homeDirection=>false,
  :maxPositionErr => 15,
  :gain => I2C::Servo::PIDgain.new(2000,500,500),
  :maxSpeed => 75, :minSpeed => 10,
  :acceleration=>5,
  :maxCurrent => 1500,
  :maxSettling => 64


:SC.denotes Slide.new ("Storage Carousel",
  I2C::Servos[:storage], 1, SCconfig, 30).with AxisMap.new (
    0=>:home, -711=>1, 3280=>2, 7277=>3, 11284=>4,
    15288=>5, 19314=>6, 23380=>7
  )


###  Storage Elevator  ###
:SEconfig.denotes I2C::Servo::Configuration.default.with \
  :encoder=>:negative, :home=>:negative,
  :homeDirection=>true,
  :maxPositionErr => 50,
  :gain => I2C::Servo::PIDgain.new(1000,50,400),  #was 2000,75,400
  :maxSpeed => 150, :minSpeed => 15,
  :acceleration=>20,
  :maxCurrent => 1000,
  :thresholdOffset => -727,
  :maxSettling => 4*32

seInch=2054        #counts/inch
sePuck=0.62*seInch #counts/puck
seBottom=-331      #plunger top just contacting bottom of puck stack
seTop=-29595       #plunger top flush with top plate
:SE.denotes Scale.new ("Storage Elevator", 
                            I2C::Servos[:storage], 0, SEconfig, 30, sePuck/50).
  scale ([" Pucks below Top Plate", "%.2f"], AxisMap.new (
    0=>:home, 550=>[:lowerLimit, :down, :retract], -30700=>[:upperLimit,:up],
    seTop=>["Top Plate", :top, 0], seTop+sePuck=>1, seBottom=>:bottom
  ))
Elevator = SE
:SEplace.denotes SEconfig.dup.with :threshold=>:positive, :thresholdOffset=>1000
:SEseal.denotes SEplace.dup.with :thresholdOffset=>-1200, :maxSettling =>8*32
:SEpick.denotes SEplace.dup.with :thresholdOffset=>-250

###  Sample Syringe  ###
:SSconfig.denotes I2C::Servo::Configuration.default.with \
  :encoder=>:negative, :home=>:negative,
  :homeDirection=>false,
  :maxPositionErr => 200,
  :gain => I2C::Servo::PIDgain.new(480, 25, 125),
  :maxSpeed => 300, :minSpeed => 30,
  :acceleration=>20,
  :maxCurrent =>600,
  :maxSettling => 64

zero=-5844
:SS.denotes Processor = Syringe.new ("Sampler Syringe", 
  I2C::Servos[:sampler], 0, SSconfig, 160).scale ([:ml,"%.2f"], AxisMap.new (
    0=>:home, zero-50=>:empty, zero=>0, 105303=>25
  ))
  
:SSfast.denotes SSconfig.dup.with :maxSpeed=>500, :maxPositionErr=>300
:SSexhale.denotes SSfast.dup.with :acceleration=>8
:SSinhale.denotes SSconfig.dup.with :acceleration=>5
:SSslow.denotes SSinhale.dup.with :maxSpeed=>170


#######  ROTARY VALVE CONFIGURATION  ###

###  Collection Syringe Valve  ###
csvConfig = I2C::Shaft::Configuration.default.
      with :slow=>57, :lash=>2

:CSV.denotes Shaft.new("Collection Syringe Valve",
  I2C::Shafts[:collection], 0, csvConfig).with AxisMap.new (
    22=>[:air,7],86=>[:CTV,8],150=>[:CSR,1],214=>[:waste2,2],
    277=>[:air2,3],340=>[:CBV,4],405=>[:waste1,:waste,5],471=>[:flush,6]
  )
CSVclosed = CSV.between :waste, :air

###  Collection Bottom Valve  ###
cbvConfig = I2C::Shaft::Configuration.default.
      with :slow=>45, :lash=>2
:CBV.denotes Shaft.new("Collection Bottom Valve", 
  I2C::Shafts[:collection], 1, cbvConfig).with AxisMap.new (
    289=>[:waste2,1],375=>[:SSV,2],463=>[:CSV,3],35=>[:waste1,4],
    122=>[:PRV,5], 205=>[:PSV,6] 
)


###  Collection Top Valve  ###
ctvConfig = I2C::Shaft::Configuration.default.
      with :slow=>48, :lash=>2
:CTV.denotes Shaft.new("Collection Top Valve",
  I2C::Shafts[:collection], 2, ctvConfig).with AxisMap.new (
    57=>[:intake,1], 189=>[:air,2], 319=>[:spare,3], 446=>[:CSV,4]
  )

###  Spare Collection Valve  ###
#extraConfig = csvConfig.dup
#:SpareCollectionValve.denotes Shaft.new("Spare Collection Valve",
# I2C::Shafts[:collection], 3, extraConfig).with AxisMap.new (
#    23=>[:arbitrary,1],89=>[:random,2]
#  )
 
###  Processing Syringe Valve  ###
psvConfig = I2C::Shaft::Configuration.default.
      with :slow=>57, :lash=>2
:PSV.denotes Shaft.new("Processing Syringe Valve",
  I2C::Shafts[:processing], 0, psvConfig).with AxisMap.new (
    419=>[:air,1],485=>[:PML,2],37=>[:PTV,3],101=>[:PBV,4],
    165=>[:PSR,5], 228=>[:waste1 ,6], 293=>[:waste2, 7], 357=>[:CBV, 8]  
  )
PSVclosed = PSV.between :waste, :air

###  Processing Bottom Valve  ###
pbvConfig = I2C::Shaft::Configuration.default.
      with :slow=>50, :lash=>1
:PBV.denotes Shaft.new("Processing Bottom Valve",
  I2C::Shafts[:processing], 1, pbvConfig).with AxisMap.new (
    416=>[:air,:air1,2],502=>[:waste2,3],74=>[:spare1,4],158=>[:spare2,5],
    244=>[:waste1,6], 329=>[:PSV ,1] 
  )

###  Processing Top Valve  ###
ptvConfig = I2C::Shaft::Configuration.default.
      with :slow=>42, :lash=>1
:PTV.denotes Shaft.new("Processing Top Valve",
  I2C::Shafts[:processing], 2, ptvConfig).with AxisMap.new (
    393=>[:mixing,2], 12=>[:PRVmixing,3], 133=>[:PRV,4], 265=>[:puck,1]
  )

###  Processing Reagent Valve  ###
prvConfig = I2C::Shaft::Configuration.default.
      with :slow=>48, :lash=>2
:PRV.denotes Shaft.new("Processing Reagent Valve",
  I2C::Shafts[:processing], 3, prvConfig).with AxisMap.new (
    352=>[:spare,1],415=>[:ab1,2],480=>[:abwash,3],32=>[:ab2,4],
    97=>[:waste2,5], 158=>[:CBV ,6], 223=>[:PRFlush,7], 289=>[:Air,8]  
  )
PRVclosed = PRV.between :waste, :air

###  Sampler Syringe Valve  ###
ssvConfig = I2C::Shaft::Configuration.default.
      with :near=>15, :slow=>38, :lash=>2

:SSV.denotes Shaft.new("Sampler Syringe Valve", 
  I2C::Shafts[:sampler], 0, ssvConfig).with AxisMap.new (
    353=>[:CBV,2],477=>[:exhaust,3],94=>[:air,:spit,4],221=>[:plug,1]
#28=>[78],284=>76,226=>[12],43=>45,299=>43
  )
SSVclosed = SSV.between :CBV, :exhaust


###  SOLENOID VALVE CONFIGURATION  ###

pulseWidth=0.02  #minimum pulse (secs) width for ALL solenoid valves

:SamplerValves.denotes Solenoid::Valves.
  new I2C::Solenoids[:sampler], pulseWidth
:CollectionValves.denotes Solenoid::Valves.
  new I2C::Solenoids[:collection], pulseWidth
:ProcessingValves.denotes Solenoid::Valves.
  new I2C::Solenoids[:processing], pulseWidth

outerValve = Valve::NormallyClosed.new

:Intake.denotes Valve.new("Outer Intake", SamplerValves, 6, outerValve)
:Exhaust.denotes Valve.new("Outer Exhaust", SamplerValves, 7, outerValve)

$manifoldElement = Valve::ManifoldElement.new
def reagentValve name, controller, number
#define a new valve in a Reagents manifold
  v=Valve.new (name, controller, number, $manifoldElement)
  v.intern="Reagents[#{name.inspect}]"
  v
end


### Collection Series Manifold ###

collectionSeries = [
  reagentValve(:lysis, CollectionValves,0),
  reagentValve(:fix,   CollectionValves,1),
  reagentValve(:AqMeOH,CollectionValves,2),
  reagentValve(:diluent, CollectionValves,3),
  reagentValve(4,CollectionValves,4),
  reagentValve(5, CollectionValves,5),
  reagentValve(:kill, CollectionValves,6),
  reagentValve(:flush, CollectionValves,7)  ]
:CSR.denotes Valve::Manifold.new :Collection, collectionSeries, :air


### Processing Series Manifold ###

processingSeries = [
  reagentValve(:sig1, ProcessingValves,0),
  reagentValve(:sig2, ProcessingValves,1),
  reagentValve(:sig3, ProcessingValves,2),
  reagentValve(:conjugate, ProcessingValves,3),
  reagentValve(:sub1, ProcessingValves,4),
  reagentValve(:sub2, ProcessingValves,5),
  reagentValve(:wash, ProcessingValves,6),
  reagentValve(:flush, ProcessingValves,7)  ]
:PSR.denotes Valve::Manifold.new :Processing, processingSeries, :air



###  THERMAL PAD CONFIGURATION  ###

:CollectionPuckHeatConfig.denotes I2C::Thermal::Configuration.default.
    with :heating=>I2C::Thermal::PIDgain.new(2000,0,0)

CH=Thermal.new("Collection Puck Heater",
   I2C::Thermals[:collection], CollectionPuckHeatConfig).
    scale ([:C, '%.2f'], AxisMap.new 1001=>0, 7801=>100)
:CollectionPuckHeater.denotes CH

:ProcessingPuckHeatConfig.denotes I2C::Thermal::Configuration.default.
    with :heating=>I2C::Thermal::PIDgain.new(2000,0,0)

PH=Thermal.new("Processing Puck Heater",
   I2C::Thermals[:processing], ProcessingPuckHeatConfig).
    scale ([:C, '%.2f'], AxisMap.new 1001=>0, 7801=>100)
:ProcessingPuckHeater.denotes PH


####  UTILITIES  ####

#these must be read in after all axes are defined above
require 'core'

ESP.configure  #configure all defined axes

begin  #load all "post configuration" utilities and protocols here

  require 'misc'  #miscellenous utilites
  require 'puckmoves'
  require 'samplepass'
  require 'wcr'
  require 'samplelys'
  require 'lyfil'
  require 'sh2'
    
rescue Exception =>loadErr
  Log.recordException loadErr
end
