Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows Build Script and Associated Documentation Per Platform #18

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
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
69 changes: 61 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,69 @@ This package also supports most of FCL's object shapes, including:

## Installation

First, install [octomap](https://github.com/OctoMap/octomap), which is necessary using OcTree. For Ubuntu, using `sudo apt-get install liboctomap-dev`
Second, install FCL using the instructions provided [here](https://github.com/flexible-collision-library/fcl).
If you're on Ubuntu 17.04 or newer, you can install FCL using `sudo apt-get install libfcl-dev`.
Otherwise, just compile FCL from source -- it's quick and easy, and its dependencies are all easily installed via `apt` or `brew`.

In order to install the Python wrappers for FCL, simply run
```shell
pip install python-fcl
### Linux

First install needed dependencies:

```bash
sudo apt-get install liboctomap-dev libfcl-dev
```

Then install for your particular Python version:

```bash
pip3 install python-fcl
```

### MacOS

First install needed dependencies:

```bash
brew install fcl eigen octomap libccd
```

Then install for your particular Python version:

```bash
pip3 install python-fcl
```

### Windows

**Using Prebuilt Wheel**

```bash
pip install python-fcl-win32
```

**Building From Source**

Building on Windows requires:

* Python3 (e.g. Not tested using Python2)
* Cython
* CMake
* MSVC (Visual Studio 16 2019)

> Since the build script places artifacts in `C:\Program Files (x86)`, it is
***required*** to run it using an "Administrator PowerShell" prompt.

```bash
# Run using Administrator PowerShell prompt. WILL FAIL WITHOUT PROPER ACCESS

git clone https://github.com/BerkeleyAutomation/python-fcl
cd python-fcl

# Use CMake to compile/install all dependencies along with installing python-fcl
requirements/build_win32.ps1
```

Running the above script will download, build, and install FCL and any needed
dependencies.

# Usage Examples

## Objects

### Collision Objects
Expand Down
100 changes: 50 additions & 50 deletions example/example.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
from __future__ import print_function
import numpy as np
import fcl

def print_collision_result(o1_name, o2_name, result):
print 'Collision between {} and {}:'.format(o1_name, o2_name)
print '-'*30
print 'Collision?: {}'.format(result.is_collision)
print 'Number of contacts: {}'.format(len(result.contacts))
print ''
print('Collision between {} and {}:'.format(o1_name, o2_name))
print('-'*30)
print('Collision?: {}'.format(result.is_collision))
print('Number of contacts: {}'.format(len(result.contacts)))
print()

def print_continuous_collision_result(o1_name, o2_name, result):
print 'Continuous collision between {} and {}:'.format(o1_name, o2_name)
print '-'*30
print 'Collision?: {}'.format(result.is_collide)
print 'Time of collision: {}'.format(result.time_of_contact)
print ''
print('Continuous collision between {} and {}:'.format(o1_name, o2_name))
print('-'*30)
print('Collision?: {}'.format(result.is_collide))
print('Time of collision: {}'.format(result.time_of_contact))
print()

def print_distance_result(o1_name, o2_name, result):
print 'Distance between {} and {}:'.format(o1_name, o2_name)
print '-'*30
print 'Distance: {}'.format(result.min_distance)
print 'Closest Points:'
print result.nearest_points[0]
print result.nearest_points[1]
print ''
print('Distance between {} and {}:'.format(o1_name, o2_name))
print('-'*30)
print('Distance: {}'.format(result.min_distance))
print('Closest Points:')
print(result.nearest_points[0])
print(result.nearest_points[1])
print()

# Create simple geometries
box = fcl.Box(1.0, 2.0, 3.0)
Expand All @@ -48,10 +49,10 @@ def print_distance_result(o1_name, o2_name, result):
#=====================================================================
# Pairwise collision checking
#=====================================================================
print '='*60
print 'Testing Pairwise Collision Checking'
print '='*60
print ''
print('='*60)
print('Testing Pairwise Collision Checking')
print('='*60)
print()

req = fcl.CollisionRequest(enable_contact=True)
res = fcl.CollisionResult()
Expand All @@ -74,10 +75,10 @@ def print_distance_result(o1_name, o2_name, result):
#=====================================================================
# Pairwise distance checking
#=====================================================================
print '='*60
print 'Testing Pairwise Distance Checking'
print '='*60
print ''
print('='*60)
print('Testing Pairwise Distance Checking')
print('='*60)
print()

req = fcl.DistanceRequest(enable_nearest_points=True)
res = fcl.DistanceResult()
Expand All @@ -100,10 +101,10 @@ def print_distance_result(o1_name, o2_name, result):
#=====================================================================
# Pairwise continuous collision checking
#=====================================================================
print '='*60
print 'Testing Pairwise Continuous Collision Checking'
print '='*60
print ''
print('='*60)
print('Testing Pairwise Continuous Collision Checking')
print('='*60)
print()

req = fcl.ContinuousCollisionRequest()
res = fcl.ContinuousCollisionResult()
Expand All @@ -118,10 +119,10 @@ def print_distance_result(o1_name, o2_name, result):
#=====================================================================
# Managed collision checking
#=====================================================================
print '='*60
print 'Testing Managed Collision and Distance Checking'
print '='*60
print ''
print('='*60)
print('Testing Managed Collision and Distance Checking')
print('='*60)
print('')
objs1 = [fcl.CollisionObject(box, fcl.Transform(np.array([20,0,0]))), fcl.CollisionObject(sphere)]
objs2 = [fcl.CollisionObject(cone), fcl.CollisionObject(mesh)]
objs3 = [fcl.CollisionObject(box), fcl.CollisionObject(sphere)]
Expand All @@ -143,26 +144,26 @@ def print_distance_result(o1_name, o2_name, result):
#=====================================================================
cdata = fcl.CollisionData()
manager1.collide(cdata, fcl.defaultCollisionCallback)
print 'Collision within manager 1?: {}'.format(cdata.result.is_collision)
print ''
print('Collision within manager 1?: {}'.format(cdata.result.is_collision))
print()

cdata = fcl.CollisionData()
manager2.collide(cdata, fcl.defaultCollisionCallback)
print 'Collision within manager 2?: {}'.format(cdata.result.is_collision)
print ''
print('Collision within manager 2?: {}'.format(cdata.result.is_collision))
print()

##=====================================================================
## Managed internal (n^2) distance checking
##=====================================================================
ddata = fcl.DistanceData()
manager1.distance(ddata, fcl.defaultDistanceCallback)
print 'Closest distance within manager 1?: {}'.format(ddata.result.min_distance)
print ''
print('Closest distance within manager 1?: {}'.format(ddata.result.min_distance))
print()

ddata = fcl.DistanceData()
manager2.distance(ddata, fcl.defaultDistanceCallback)
print 'Closest distance within manager 2?: {}'.format(ddata.result.min_distance)
print ''
print('Closest distance within manager 2?: {}'.format(ddata.result.min_distance))
print()

#=====================================================================
# Managed one to many collision checking
Expand All @@ -171,20 +172,19 @@ def print_distance_result(o1_name, o2_name, result):
rdata = fcl.CollisionData(request = req)

manager1.collide(fcl.CollisionObject(mesh), rdata, fcl.defaultCollisionCallback)
print 'Collision between manager 1 and Mesh?: {}'.format(rdata.result.is_collision)
print 'Contacts:'
print('Collision between manager 1 and Mesh?: {}'.format(rdata.result.is_collision))
print('Contacts:')
for c in rdata.result.contacts:
print '\tO1: {}, O2: {}'.format(c.o1, c.o2)
print ''
print('\tO1: {}, O2: {}'.format(c.o1, c.o2))
print()

#=====================================================================
# Managed many to many collision checking
#=====================================================================
rdata = fcl.CollisionData(request = req)
manager3.collide(manager2, rdata, fcl.defaultCollisionCallback)
print 'Collision between manager 2 and manager 3?: {}'.format(rdata.result.is_collision)
print 'Contacts:'
print('Collision between manager 2 and manager 3?: {}'.format(rdata.result.is_collision))
print('Contacts:')
for c in rdata.result.contacts:
print '\tO1: {}, O2: {}'.format(c.o1, c.o2)
print ''

print('\tO1: {}, O2: {}'.format(c.o1, c.o2))
print()
131 changes: 131 additions & 0 deletions requirements/build_win32.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<#
***************************************************************************
Run using Administrator PowerShell prompt. WILL FAIL WITHOUT PROPER ACCESS
This is because the script places build artifacts in C:\Program Files (x86)
***************************************************************************

This script builds fcl and it's dependencies for python-fcl on Windows.

It downloads, builds, installs, and then deletes:
* fcl
* libccd
* eigen
* octomap
#>

# Ensure that paths are constant between runs
pushd $PSScriptRoot

# Create a directory that encapsulates all Git repos
mkdir fcl; cd fcl


#------------------------------------------------------------------------------
# Eigen
Write-Host "Building Eigen"
git clone https://gitlab.com/libeigen/eigen.git
cd eigen
mkdir build; cd build
cmake -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 16 2019" -DBUILD_SHARED_LIBS=ON ..
cmake --build . --config Release --target install
Write-Host "Done"
cd ../..


# ------------------------------------------------------------------------------
# LibCCD
Write-Host "Building LibCCD"
git clone https://github.com/danfis/libccd
cd libccd
mkdir build; cd build
cmake -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 16 2019" -DBUILD_SHARED_LIBS=ON ..
cmake --build . --config Release --target install
Write-Host "Done"
cd ../..

# FCL won't be able to find libccd unless it is named "ccd" exactly
Rename-Item "C:\Program Files (x86)\libccd" ccd


# ------------------------------------------------------------------------------
# Octomap
Write-Host "Building Octomap"
git clone https://github.com/OctoMap/octomap
cd octomap
mkdir build; cd build
cmake -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 16 2019" -DBUILD_SHARED_LIBS=ON ..

# Build Octomap (won't install for some reason)
cmake --build . --config Release --target install

# Now rebuild, which installs correctly
cmake --build . --config Release --target install
Write-Host "Done"
cd ../../

# FCL won't be able to find octomap unless it is named "octomap" exactly
Rename-Item "C:\Program Files (x86)\octomap-distribution" octomap


# ------------------------------------------------------------------------------
# FCL
Write-Host "Building FCL"
git clone https://github.com/flexible-collision-library/fcl
cd fcl

# Checkout specific version 0.5.0 (only one compatible with python-fcl)
git checkout 7075caf32ddcd5825ff67303902e3db7664a407a
mkdir build; cd build

# Fiddle with build file to help fcl find LibCCD and Octomap
# Also tells compiler to dynamically link with C runtime (matches Cython)
$build_script_modification = @"
find_package(ccd QUIET)
find_package(octomap QUIET)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL$<$<CONFIG:Debug>:Debug>")
"@
$filePath = "../CMakeLists.txt"
$lineNumber = 11
$fileContent = Get-Content $filePath
$fileContent[$lineNumber-1] = $build_script_modification
$fileContent | Set-Content $filePath

# Now perform actual build
cmake -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 16 2019" ..
cmake --build . --config Release --target install
Write-Host "Done"
cd ../../


# ------------------------------------------------------------------------------
# Python-FCL
cd ../

# Delete compilation directory since it is no longer needed
del -Force -Recurse fcl

cd ../

$fcl_dir = './fcl'
Write-Host "Copying dependent DLLs"
ls "C:/Program Files (x86)/octomap/bin/*.dll" | cp -destination $fcl_dir
cp "C:/Program Files (x86)/ccd/bin/ccd.dll" $fcl_dir

Start-Sleep -s 5

# Now build Cython extension
python setup-win32.py install
Write-Host "Successfully built python-fcl"


# Now delete all of the installed dependencies (after building python-fcl)
Write-Host "Removing build directories for Eigen, LibCCD, FCL, and Octomap"
rmdir -r 'C:\Program Files (x86)\Eigen3'
rmdir -r 'C:\Program Files (x86)\ccd'
rmdir -r 'C:\Program Files (x86)\fcl'
rmdir -r 'C:\Program Files (x86)\octomap'

Write-Host "All done!"

# Make sure to return the cwd to wherever it was before the build
popd
Loading