{"id":29902918,"url":"https://github.com/downflux/go-orca","last_synced_at":"2025-11-04T09:06:18.771Z","repository":{"id":37015746,"uuid":"383269100","full_name":"downflux/go-orca","owner":"downflux","description":"Golang implementation of the Optimal Reciprocal Collision Avoidance (ORCA) algorithm","archived":false,"fork":false,"pushed_at":"2022-10-20T08:17:42.000Z","size":210003,"stargazers_count":42,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-06-21T19:52:59.151Z","etag":null,"topics":["collision-avoidance","golang"],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/downflux/go-orca","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/downflux.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-07-05T21:32:52.000Z","updated_at":"2024-03-16T14:41:16.000Z","dependencies_parsed_at":"2022-08-18T22:00:34.790Z","dependency_job_id":null,"html_url":"https://github.com/downflux/go-orca","commit_stats":null,"previous_names":["downflux/orca"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/downflux/go-orca","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/downflux%2Fgo-orca","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/downflux%2Fgo-orca/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/downflux%2Fgo-orca/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/downflux%2Fgo-orca/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/downflux","download_url":"https://codeload.github.com/downflux/go-orca/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/downflux%2Fgo-orca/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268257513,"owners_count":24221062,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-01T02:00:08.611Z","response_time":67,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["collision-avoidance","golang"],"created_at":"2025-08-01T16:17:29.835Z","updated_at":"2025-11-04T09:06:18.728Z","avatar_url":"https://github.com/downflux.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# go-orca\nGolang implementation of the Optimal Reciprocal Collision Avoidance (ORCA)\nalgorithm\n\n## Disclaimer\n\nThis project is under active development and is not yet feature complete, and\nmay contain bugs. We welcome contributions in the form of new issues and pull\nrequests.\n\nThis project was created after endlessly consulting the canonical implementation\n[github.com/snape/RVO2](https://github.com/snape/RVO2) and follows the general\nshape of the reference. General improvements lie in abstracting away some code\nand documenting a number of assumptions the reference implementation makes.\n\n## Background\n\nORCA is useful for local collision avoidance in large systems.  This repository\naims to be an implementation of the ORCA algorithm with much improved\ndocumentation and API.\n\nMore prosaic documentation of this library will be made available at\n[blog.downflux.com](https://blog.downflux.com) soon.\n\n## Installation\n\n```bash\n$ go version\n\ngo version go1.17.4 linux/amd64\n```\n\n## Updating\n\n```bash\n$ go get -u ./...\n$ go mod tidy\n```\n\n## Demo\n\n```bash\n$ go run \\\n  github.com/downflux/go-orca/examples/generator --mode=line | go run \\\n  github.com/downflux/go-orca/examples --frames=1500 \u003e demo.gif\n```\n\n![ORCA demo](examples/output/animation.gif)\n\n## Profiling\n\n**N.B.**: WSL does not profile correctly. See\n[golang/go#22366](https://github.com/golang/go/issues/22366).\n\n```bash\n$ go test -v \\\n  github.com/downflux/go-orca/... \\\n  -bench . \\\n  -benchmem -cpu 1,2,4,8,16,32,64\n\n$ go test -v \\\n  github.com/downflux/go-orca/orca \\\n  -bench BenchmarkStep/N=1000000 \\\n  -benchmem \\\n  -cpuprofile cpu.out\n  -memprofile mem.out\n\n$ go tool pprof -tree -nodecount=10 cpu.out\n```\n\nSee [pprof](https://github.com/google/pprof/blob/master/README.md) for more\ninformation.\n\n### Sample Metrics\n\n```bash\n$ go test github.com/downflux/go-orca/orca -bench .\ngoos: linux\ngoarch: amd64\npkg: github.com/downflux/go-orca/orca\ncpu: Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz\nBenchmarkStep/PoolSize=1/N=1000-8                    223           5444871 ns/op\nBenchmarkStep/PoolSize=2/N=1000-8                    363           3433878 ns/op\nBenchmarkStep/PoolSize=4/N=1000-8                    429           2475249 ns/op\nBenchmarkStep/PoolSize=8/N=1000-8                    646           2115339 ns/op\nBenchmarkStep/PoolSize=16/N=1000-8                   835           1728687 ns/op\nBenchmarkStep/PoolSize=32/N=1000-8                   724           1764201 ns/op\nBenchmarkStep/PoolSize=64/N=1000-8                   804           1728317 ns/op\nBenchmarkStep/PoolSize=1/N=10000-8                     7         172579943 ns/op\nBenchmarkStep/PoolSize=2/N=10000-8                    10         103194960 ns/op\nBenchmarkStep/PoolSize=4/N=10000-8                    21          65091548 ns/op\nBenchmarkStep/PoolSize=8/N=10000-8                    27          54601893 ns/op\nBenchmarkStep/PoolSize=16/N=10000-8                   26          51649538 ns/op\nBenchmarkStep/PoolSize=32/N=10000-8                   33          49275545 ns/op\nBenchmarkStep/PoolSize=64/N=10000-8                   33          49198270 ns/op\nBenchmarkStep/PoolSize=1/N=100000-8                    1        25395613600 ns/op\nBenchmarkStep/PoolSize=2/N=100000-8                    1        14673700700 ns/op\nBenchmarkStep/PoolSize=4/N=100000-8                    1        9807954000 ns/op\nBenchmarkStep/PoolSize=8/N=100000-8                    1        8083196700 ns/op\nBenchmarkStep/PoolSize=16/N=100000-8                   1        7842262700 ns/op\nBenchmarkStep/PoolSize=32/N=100000-8                   1        7965633400 ns/op\nBenchmarkStep/PoolSize=64/N=100000-8                   1        8314680600 ns/op\nPASS\nok      github.com/downflux/go-orca/orca        113.571s\n```\n\n### Performance\n\nPerformance metrics shoud be compared against [Granberg][1], [Snape et al.][2],\nand [van den Berg et al.][3]. We estimate that there is about another 50%\noptimization achievable in the current implementation of the ORCA algorithm.\n\n## Example\n\n```golang\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/downflux/go-geometry/nd/vector\"\n\t\"github.com/downflux/go-kd/kd\"\n\t\"github.com/downflux/go-kd/point\"\n\t\"github.com/downflux/go-orca/agent\"\n\t\"github.com/downflux/go-orca/orca\"\n\n\tv2d \"github.com/downflux/go-geometry/2d/vector\"\n\tokd \"github.com/downflux/go-orca/kd\"\n)\n\n// Define a K-D tree point which satisfies ORCA's P interface as well.\n//\n// Ensure the point is mutable, as we will be updating the point velocities.\ntype a struct {\n\t// r is the collision radius of the agent.\n\tr float64\n\n\t// s is the max speed of the agent.\n\ts float64\n\n\t// p is the current position of the agent.\n\tp v2d.V\n\n\t// v is the current veloicty of the agent.\n\tv v2d.V\n\n\t// t is the target velocity of the agent.\n\tt v2d.V\n}\n\nfunc (a *a) P() v2d.V   { return a.p }\nfunc (a *a) V() v2d.V   { return a.v }\nfunc (a *a) T() v2d.V   { return a.t }\nfunc (a *a) R() float64 { return a.r }\nfunc (a *a) S() float64 { return a.s }\n\ntype p a\n\nfunc (p *p) A() agent.A  { return (*a)(p) }\nfunc (p *p) P() vector.V { return vector.V((*a)(p).P()) }\n\n// Check interface fulfilment.\n//\n// Ensure that our point fulfills the ORCA K-D tree data point interface.\nvar (\n\t_ okd.P = \u0026p{}\n\n\t// These checks are technically unnecessary (okd.P is a superset of\n\t// point.P), but we're adding the check here to facilitate the reader's\n\t// understanding of the underlying types being used in this example.\n\t_ point.P = \u0026p{}\n\t_ agent.A = \u0026a{}\n)\n\nfunc main() {\n\t// Construct some agents.\n\tagents := []point.P{\n\t\t\u0026p{\n\t\t\tr: 1,\n\t\t\t// Max speed just means the agent has the capability to\n\t\t\t// move this fast, but the goal of ORCA is to minimize\n\t\t\t// the difference to the target velocity instead.\n\t\t\ts: 10,\n\t\t\tp: *v2d.New(0, 0),\n\t\t\tv: *v2d.New(0, 1),\n\t\t\tt: *v2d.New(0, 1),\n\t\t},\n\t\t\u0026p{\n\t\t\tr: 1,\n\t\t\ts: 10,\n\t\t\tp: *v2d.New(0, 5),\n\t\t\tv: *v2d.New(0, -1),\n\t\t\tt: *v2d.New(0, -1),\n\t\t},\n\t}\n\n\t// Create a K-D tree which tracks agent-agent proximity.\n\t//\n\t// N.B.: This tree will need to be rebalanced if velocities are updated,\n\t// which takes a non-trivial amount of time. This additional time is not\n\t// accounted for in the ORCA performance tests. In the course of a\n\t// simulation, we would expect multiple other (user-defined) steps to\n\t// occur, and so have exposed the tree rebalance call.\n\tt, _ := kd.New(agents)\n\n\t// Simulate one loop. Step() is a pure function and does not mutate any\n\t// state -- the caller will need to manually set the position and\n\t// velocity vectors. Or not, im_a_sign_not_a_cop.jpg.\n\t//\n\t// Note that we are manually casting the base K-D tree into the\n\t// ORCA-specific K-D tree.\n\tmutations, _ := orca.Step(orca.O{\n\t\tT: okd.Lift(t),\n\t\t// Pick a sensible value for the lookhead -- this depends on how\n\t\t// fast the agents are travelling per tick.\n\t\tTau:      10,\n\t\tF:        func(a agent.A) bool { return true },\n\t\tPoolSize: 2,\n\t})\n\tfor _, m := range mutations {\n\t\ta := m.A.(*a)\n\t\tfmt.Printf(\n\t\t\t\"input velocity for agent at position %v is %v, but output velocity is %v\\n\",\n\t\t\ta.P(),\n\t\t\ta.V(),\n\t\t\tm.V,\n\t\t)\n\t}\n}\n```\n\n## TODO\n\nWe have not yet implemented generating velocity objects for polygonal obstacles.\nThe current implementation only adjusts trajectory for other circular agents.\n\n[1]: https://arongranberg.com/astar/docs_beta/local-avoidance.html\n[2]: https://www.intel.com/content/www/us/en/developer/articles/technical/reciprocal-collision-avoidance-and-navigation-for-video-games.html\n[3]: http://emotion.inrialpes.fr/fraichard/safety2010/10-vandenberg-etal-icraw.pdf\n[4]: https://github.com/snape/RVO2\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdownflux%2Fgo-orca","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdownflux%2Fgo-orca","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdownflux%2Fgo-orca/lists"}