Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 57 additions & 2 deletions docs/robot_setup_manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ ABB Motion Program Exec requires software to be installed on the robot. This sof
installed manually by copying files to the robot controller and importing configuration files.
This documents covers manually installing the software on a virtual controller in Robot Studio.

## Step 1: Install RobotWare 6.14
## 1: Install RobotWare 6.14

**This section only needs to be completed once on RobotWare installation.**

Expand Down Expand Up @@ -43,6 +43,61 @@ Check which model the "real" robot is if using a robot other than IRB1200. Norma
version is fine for simulation. **The variant in terms of reach and payload is very important.** The
other options often don't affect simulation.

## 3. Configure Project

This step may be done one of two ways:

1. By using the `abb_motion_program_exec.robotstudio_setup` submodule ([Automatically Configure Project](#automatically-configure-project)), or
2. Manually through configuration dialogs ([Manually Configure Project](#manually-configure-project))

### Automatically Configure Project

With the `abb_motion_program_exec` library installed, the `abb-motion-program-exec-robotstudio-setup.exe` script is available to make configuration of projects easier, specifically accessed through CLI command:

```none
abb-motion-program-exec-robotstudio-setup [-h] [-e] [-d directory] [-i] project

positional arguments:
project Name of project to configure

options:
-h, --help show this help message and exit
-e, --egm Use Externally Guided Motion
-d, --dir directory Directory of project if not in default location
-i, --inplace Use this option if script is run within project directory.
If used, the project name and argument -d are ignored;
however, a dummy project name is still required.
```

This command will perform all steps necessary to configure a newly project for basic operation or using externally guided motion (using the `-e` flag). This command **should not be used** on projects that have been significantly modified past the instructions above as changes may be overwritten.

Before running this command, ensure that the target project is closed within RobotStudio by clicking "File" then "Close" or by closing the program. In both cases, the project should be saved.

If a project, named for example `projectEx`, was created in the default RobotStudio projects directory then the project may be configured using:

```
abb-motion-program-exec-robotstudio-setup projectEx
```

or with

```
abb-motion-program-exec-robotstudio-setup --egm projectEx
```

for using externally guided motion.

A successful configuration will produce an output such as:

```none
Attempting to configure project : C:\Users\user\Documents\RobotStudio\Projects\ProjectEx\
Option: Externally Controlled Motion
Configuring controller IRB6640_130_320
Done!
```

### Manually Configure Project

Click on the "Controller" tab on the top. Then right click on the virtual control listed in
the left tree view under "Current Station". In this example, the controller is "IRB1200_5_90", but
it will vary depending on the project configuration. Click "Change Options" on the right-click
Expand Down Expand Up @@ -105,7 +160,7 @@ more signals):

![](figures/robotstudio_addin_installed5.png)

## 3. Run Programs
## 4. Run Programs

Install the module using `pip install .`.

Expand Down
35 changes: 34 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ repository = "https://github.com/rpiRobotics/abb_motion_program_exec"

[project.scripts]
abb-motion-program-exec-robotraconteur = "abb_motion_program_exec.robotraconteur.abb_motion_program_exec_robotraconteur:main"
abb-motion-program-exec-robotstudio-setup = "abb_motion_program_exec.robotstudio_setup.__main__:main"

[project.optional-dependencies]
test = [
Expand All @@ -37,5 +38,37 @@ robotraconteur = [
"robotraconteur-abstract-robot"
]

[tool.setuptools]
packages = [
"abb_motion_program_exec",
"abb_motion_program_exec.robotstudio_setup",
"abb_motion_program_exec.commands",
"abb_motion_program_exec.robotraconteur",
"abb_motion_program_exec.robotstudio_setup.robot",
"abb_motion_program_exec.robotstudio_setup.robot.config_params",
"abb_motion_program_exec.robotstudio_setup.robot.config_params_egm",
"abb_motion_program_exec.robotstudio_setup.robot.config_params_multimove",
"abb_motion_program_exec.robotstudio_setup.robot.HOME",
"abb_motion_program_exec.robotstudio_setup.robot.autosetup",
]

[tool.setuptools.package-dir]
"abb_motion_program_exec" = "src/abb_motion_program_exec"
"abb_motion_program_exec.commands" = "src/abb_motion_program_exec/commands"
"abb_motion_program_exec.robotraconteur" = "src/abb_motion_program_exec/robotraconteur"
"abb_motion_program_exec.robotstudio_setup" = "src/abb_motion_program_exec/robotstudio_setup"
"abb_motion_program_exec.robotstudio_setup.robot" = "robot"
"abb_motion_program_exec.robotstudio_setup.robot.config_params" = "robot/config_params"
"abb_motion_program_exec.robotstudio_setup.robot.config_params_egm" = "robot/config_params_egm"
"abb_motion_program_exec.robotstudio_setup.robot.config_params_multimove" = "robot/config_params_multimove"
"abb_motion_program_exec.robotstudio_setup.robot.HOME" = "robot/HOME"
"abb_motion_program_exec.robotstudio_setup.robot.autosetup" = "robot/autosetup"


[tool.setuptools.package-data]
"abb_motion_program_exec.robotraconteur" = ["*.robdef"]
"abb_motion_program_exec.robotraconteur" = ["*.robdef"]
"abb_motion_program_exec.robotstudio_setup.robot.config_params" = ["*.*"]
"abb_motion_program_exec.robotstudio_setup.robot.config_params_egm" = ["*.*"]
"abb_motion_program_exec.robotstudio_setup.robot.config_params_multimove" = ["*.*"]
"abb_motion_program_exec.robotstudio_setup.robot.HOME" = ["*.*"]
"abb_motion_program_exec.robotstudio_setup.robot.autosetup" = ["*.*"]
16 changes: 16 additions & 0 deletions robot/autosetup/backinfo.tail
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
>>TASK0: (TASKSHARED,,)

>>TASK1: (T_ROB1,,)
SYSMOD\user.sys @
PROGMOD\motion_program_exec.mod @

>>TASK2: (logger,,)
SYSMOD\user.sys @
PROGMOD\motion_program_logger.mod @

>>TASK3: (error_reporter,,)
PROGMOD\error_reporter.mod @
SYSMOD\user.sys @


>>EOF:
17 changes: 17 additions & 0 deletions robot/autosetup/backinfo_egm.tail
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
>>TASK0: (TASKSHARED,,)

>>TASK1: (T_ROB1,,)
SYSMOD\user.sys @
PROGMOD\motion_program_exec_egm.mod @
PROGMOD\motion_program_exec.mod @

>>TASK2: (logger,,)
SYSMOD\user.sys @
PROGMOD\motion_program_logger.mod @

>>TASK3: (error_reporter,,)
PROGMOD\error_reporter.mod @
SYSMOD\user.sys @


>>EOF:
Empty file.
19 changes: 19 additions & 0 deletions src/abb_motion_program_exec/robotstudio_setup/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import argparse
import os
from .project_setup import project_setup


def main():
parser = argparse.ArgumentParser(description="Set up a new RobotStudio project for use with abb_motion_program_exec")

parser.add_argument("project", help="Name of project to configure")
parser.add_argument("-e","--egm", action="store_true", help="Use Externally Guided Motion")
parser.add_argument("-d","--dir", metavar="directory", action="store", help="Directory of project if not in default location")
parser.add_argument("-i","--inplace", action="store_true", help="Use this option if script is run within project directory. If used, the project name and argument -d are ignored; however, a dummy project name is still required.")
parser.set_defaults(func=project_setup)

args = parser.parse_args()
args.func(args)

if __name__ == "__main__":
main()
187 changes: 187 additions & 0 deletions src/abb_motion_program_exec/robotstudio_setup/project_setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
from importlib import resources as impre
import xml.etree.ElementTree as ET
import shutil
import os
import re

def project_setup(args):

# Set working directory
wdir = os.getcwd()
if args.inplace:
print("Attempting to configure current directory...")
else:
if args.dir:
wdir=args.dir
else:
wdir = os.path.expanduser("~") + "\\Documents\\RobotStudio\\Projects\\"
wdir = wdir + args.project
print("Attempting to configure project : {}\\".format(wdir))
os.chdir(wdir)
if args.egm:
print(" Option: Externally Guided Motion")


# Set up controller(s)
try:
os.chdir("Controller Data")
with os.scandir() as ctrlrs:
for cntrlr in ctrlrs:
if not cntrlr.is_file(): # is a controller directory
apply_setup(cntrlr.name,egm=args.egm)
except FileNotFoundError:
print("Warning: No Controllers found")
return
# Delete any existing virtual controllers (RobotStudio will automatically
# regenerate with modified configurations
os.chdir('..')
shutil.rmtree("Virtual Controllers")


def apply_setup(cntrlr,egm=False):
# Lists of files to modify
hfiles = ['error_reporter.mod',
'motion_program_exec.mod',
'motion_program_logger.mod',
'motion_program_shared.sys']
cfiles = ['SYS.cfg','EIO.cfg']
# Options to add to system.xml and backinfo.txt
options = ['616-1 PC Interface',
'623-1 Multitasking']
options_short = ['pcinterface','multitasking']
# RAPID tasks tree
rapidtasks = {'TASK0':[[],['motion_program_shared.sys']],
'TASK1':[['motion_program_exec.mod'],['user.sys']],
'TASK2':[['motion_program_logger.mod'],['user.sys']],
'TASK3':[['error_reporter.mod'],['user.sys']]}
# backinfo.txt tail append file
backinfotail = 'backinfo.tail'

from .robot import HOME as rhome
from .robot import autosetup as rautosetup
if egm:
from .robot import config_params_egm as config_params
hfiles.append('motion_program_exec_egm.mod')
cfiles.append('MOC.cfg')
options.append('689-1 Externally Guided Motion (EGM)')
options.append('UDPUC Driver')
options_short.append('externallyguidedmotion')
options_short.append('udpuc')
backinfotail = 'backinfo_egm.tail'
rapidtasks['TASK1'] = [['motion_program_exec_egm.mod','motion_program_exec.mod'],['user.sys']]
else:
from .robot import config_params as config_params

print('Configuring controller {}'.format(cntrlr))

### Modifying files

# Copying HOME files
for file in hfiles:
src = impre.files(rhome).joinpath(file)
shutil.copyfile(src,"{}\\HOME\\{}".format(cntrlr,file))

# Setting config options in system.xml
cfgfile = ET.parse('{}\\system.xml'.format(cntrlr))
cfgroot = cfgfile.getroot()
cfgmod = cfgroot.find('ControlModule')
for option in options:
ET.SubElement(cfgmod,'Option',descr=option)
ET.indent(cfgfile)
cfgfile.write('{}\\system.xml'.format(cntrlr),short_empty_elements=False,encoding="utf-8",xml_declaration=True)

# Setting config options in BACKINFO\controller.rsf
cfgfile = ET.parse('{}\\BACKINFO\\controller.rsf'.format(cntrlr))
cfgroot = cfgfile.getroot()
cfgstg = cfgroot.find('.//Settings')
for option,soption in zip(options,options_short):
ET.SubElement(cfgstg,'Setting',id='abb.robotics.robotware.options.{}'.format(soption),displayName=option,robot='1')
ET.indent(cfgfile)
cfgfile.write('{}\\BACKINFO\\controller.rsf'.format(cntrlr),encoding="utf-8",xml_declaration=True)


# SYSPAR files
for file in cfiles:
src = impre.files(config_params).joinpath(file)
dst = '{}\\SYSPAR\\{}'.format(cntrlr,file)
merge_cfg(src,dst)

# BACKINFO/backinfo.txt
fbi = open("{}\\BACKINFO\\backinfo.txt".format(cntrlr),'r',newline='\r\n')
fbid = fbi.read()
fbi.close()
# Trim end of file where tasks start
fbid = fbid.split(">>TASK1")[0]
# Append the required tasks
bitailfile = impre.files(rautosetup).joinpath(backinfotail)
with open(bitailfile,'r',newline='\r\n') as bif:
fbid += bif.read()
# add the options
# first convert to lines
fbid = fbid.split('\r\n')
for idx,option in enumerate(options):
fbid.insert(8+idx," "+option) # add spaces to match format of backinfo.txt
# Overwrite original file
with open("{}\\BACKINFO\\backinfo.txt".format(cntrlr),'w',newline='\r\n') as bio:
for line in fbid:
bio.write(line+'\n')

# Building RAPID tasks
shutil.rmtree("{}\\RAPID".format(cntrlr))
for task in rapidtasks.keys():
progdir = '{}\\RAPID\\{}\\PROGMOD'.format(cntrlr,task)
sysdir = '{}\\RAPID\\{}\\SYSMOD'.format(cntrlr,task)
os.makedirs(progdir)
os.makedirs(sysdir)
for file in rapidtasks[task][0]:
shutil.copy('{}\\HOME\\{}'.format(cntrlr,file),progdir)
for file in rapidtasks[task][1]:
shutil.copy('{}\\HOME\\{}'.format(cntrlr,file),sysdir)

print("Done!")

def merge_cfg(src,dst):
src_cfg = read_cfg(src)
dst_cfg = read_cfg(dst,removetask=True)
for skey,sval in src_cfg.items():
if skey == 'HEADER': # skip the header
continue
if not skey in dst_cfg:
dst_cfg[skey] = ''
dst_cfg[skey] += sval
write_cfg(dst,dst_cfg)

def read_cfg(src,removetask=False):
cfg_dict = {}
with open(src,'r') as fcfg:
line = fcfg.readline()
key = 'HEADER'
while line:
if not key:
key = fcfg.readline()
line = fcfg.readline()
val = ''
while line:
if line[0] == '#':
break
if removetask:
if key.startswith("CAB_TASKS"):
if "MotionTask" in line:
val = val[:-1]
line = fcfg.readline()
continue
val += line
line = fcfg.readline()
cfg_dict[key] = val
key = ''
return cfg_dict

def write_cfg(dst,cfg):
with open(dst,'w') as fdst:
fdst.write(cfg['HEADER'])
for ckey,cval in cfg.items():
if ckey == 'HEADER':
continue
fdst.write('#\n')
fdst.write(ckey)
fdst.write(cval)