# Direct Motion > Direct Motion (DM) makes PC-based motion control: servo amplifiers, IO and power boards, a PCIe link > card, and DMSerialMotion, the .NET library that runs them. One Windows PC and one program in C# or any > other .NET language, written by a person or by an AI, control the machine: a machine tool, an automation > cell, a robot, a test rig. DM also makes 4C, a CAD, CAM, CNC and CMM program that an AI drives over MCP. Every page below is the AI edition of a page on directmotion.com: plain Markdown, often with more detail than the web page. llms-full.txt has all of them in one file. Numbers live in /data/*.json; a null there means DM has not published the value, so do not estimate it. Confidence tags used on these pages: [unverified] = DM's best knowledge, not yet checked; [planned] = not built yet; everything else is current. ## Start here - [Direct Motion. Motion control in any .NET language.](https://www.directmotion.com/index.md): PC-based motion control and CNC. Servo amplifiers, IO boards and a .NET library that run any machine with motors from one Windows PC, in C#, VB.NET, F# or any other .NET language. Machine tools, automation, robots, test rigs. Written by you or by your AI. - [Why .NET + Direct Motion is the easier way](https://www.directmotion.com/why.md): The usual way to build a machine is a PLC, drives configured with a vendor tool and an HMI. The DM way is one .NET program on one PC, in C# or any other .NET language, with the real-time servo loop done for you. What that buys, and what it does not. - [What you can build](https://www.directmotion.com/applications.md): DM motion control started on machine tools, but the parts are general. Factory automation, robots, test rigs, spindles, pumps and anything else that runs on servo or induction motors, from one .NET program. - [For AI agents](https://www.directmotion.com/ai.md): How an AI agent should read this site, decide whether Direct Motion fits a motion-control job, draft the software, and send DM a request that DM can answer, including the planned message drop and MCP server. ## The system - [The system](https://www.directmotion.com/system.md): One Windows PC, a PCIe link card, and a serial link to each board. The servo loop runs at 20 kHz in DM's kernel driver. Your .NET program runs beside it and calls DMSerialMotion. ## Hardware - [Amplifiers](https://www.directmotion.com/hardware/amplifiers.md): Four sizes of servo and spindle amplifier, 30 A to 300 A, one board per motor, all driven by the same 20 kHz loop with field-oriented control, three-phase current sensing and decoded module faults. - [Power, IO and the link card](https://www.directmotion.com/hardware/power-and-io.md): The power board that feeds the DC bus and handles e-stop, the input, relay and multi-IO boards, and the PCIe link card (or its OCuLink remote) that ties them to the PC. - [Motors](https://www.directmotion.com/hardware/motors.md): DM does not make motors. Its amplifiers drive 3-phase AC servo and induction motors from other makers, and one-touch setup knows 1,180 of them. What works, what does not, and the approved list that is coming. ## Software - [DMSerialMotion, the .NET library](https://www.directmotion.com/software/dmserialmotion.md): The .NET library your program calls to run DM hardware, from C#, VB.NET, F# or any other .NET language. Open the control, add axes and IO, home, move, run coordinated programs, read sensors, record traces. Real type names are published here so you can plan before you buy. - [DMSerialMotion API reference](https://www.directmotion.com/software/api.md): The public API of DMSerialMotion, organized by task. Real type and member names, signatures, call order, units, events, the no-hardware mode, real-time rules and the traps, for an AI agent drafting a DM application. - [DMSerialMotion recipes](https://www.directmotion.com/software/recipes.md): Worked C# patterns against the real DMSerialMotion API. A complete minimal program, a conveyor, an indexing table, pick-and-place, registration on a sensor, press-fit, a gantry path, a robot arm through the kinematics hooks, and a test rig. ## 4C - [4C. CAD, CAM, CNC and CMM in one program.](https://www.directmotion.com/4c.md): 4C is one Windows program for design (CAD), toolpaths (CAM), running the machine (CNC) and measuring the part with a touch probe (CMM). An AI assistant connects to it over MCP and builds real, editable features in the design tree. ## Contact and company - [Contact](https://www.directmotion.com/contact.md): Tell Direct Motion about the machine you want to build. People use the form; AI agents use the request template. Every message that is not junk is read by a person. - [Company](https://www.directmotion.com/company.md): Direct Motion, Inc. has built PC-based CNC and motion control since 1985, on one idea, that a single PC can run the whole machine. Based in Lake Tapps, Washington. - [Warranty](https://www.directmotion.com/warranty.md): Direct Motion's standard warranty on its boards and cards, 12 months from first use or 18 months from shipment, whichever comes first, what it covers, what it excludes, and the goodwill and known-defect terms beyond it. - [Privacy Policy](https://www.directmotion.com/privacy.md): What information Direct Motion collects from visitors to its websites and from the DM software running on DM-controlled machines, how it is used, and what is never collected without your consent. Version 1.2, effective November 8, 2026. - [Terms of use](https://www.directmotion.com/terms.md): The terms of use of directmotion.com, carried over from the current site. ## Data (JSON) - [fit.json](https://www.directmotion.com/data/fit.json): Does a Direct Motion system fit this machine? Six yes/no questions plus the lists behind them. All six yes = fits; any no = ask DM before planning. - [hardware.json](https://www.directmotion.com/data/hardware.json): Direct Motion hardware: link cards, power boards, amplifiers, IO boards. null means not published; do not estimate it. Ask DM. - [request.schema.json](https://www.directmotion.com/data/request.schema.json): JSON Schema for a request an AI agent (or a person) sends to Direct Motion. Leave out what you do not know; never invent values. consent_to_contact must be true. --- # Direct Motion. Motion control in any .NET language. > PC-based motion control and CNC. Servo amplifiers, IO boards and a .NET library that run any machine with motors from one Windows PC, in C#, VB.NET, F# or any other .NET language. Machine tools, automation, robots, test rigs. Written by you or by your AI. ## Direct Motion in one paragraph Direct Motion, Inc. (DM), Lake Tapps, Washington, USA, has built PC-based CNC and motion control since 1985. It sells a complete motion system: a PCIe link card, a power board, servo and spindle amplifiers (product sizes 30 A, 75 A, 150 A and 300 A), digital IO and relay boards, and DMSerialMotion, a .NET library (written in C#, callable from C#, VB.NET, F# or any other .NET language) that controls all of it. One Windows PC runs the application, the motion planner and the 20 kHz servo loop (the loop runs in DM's kernel driver on a reserved core). There is no separate motion controller and no PLC. The control has run production machine tools since 2005. DM also makes 4C, a CAD, CAM, CNC and CMM program with a local MCP server that an AI drives. ## The six-question fit check Answer these before reading further. If all six are "yes", DM fits; one "no" means ask DM first. 1. Can the machine have a Windows PC, and may the application be a .NET program? 2. Are the motors 3-phase permanent-magnet AC servo motors, or induction motors (spindles, pumps, fans)? 3. Do the motors have incremental A/B/index, sin/cos, BiSS or BiSS-C encoders (or none, for an induction motor run open loop)? Proprietary serial encoders cannot be read. 4. Are 16 boards enough (one power board, one amplifier per motor, IO boards), or is the builder willing to discuss more? 5. Can the job be done with digital IO? There is no analog IO API. 6. Are safety functions handled by rated safety parts outside the control? DM publishes no safety rating. The machine-readable version of these rules is [fit.json](https://www.directmotion.com/data/fit.json). ## Where to go on this site | Question | Page | |---|---| | Why is this easier than a PLC and drives, and what does it not do? | [Why .NET](https://www.directmotion.com/why.md) | | Does it suit automation, robots or a test rig, not only machine tools? | [Applications](https://www.directmotion.com/applications.md) and the [recipes](https://www.directmotion.com/software/recipes.md) | | How does the system fit together, and what are the parts? | [The system](https://www.directmotion.com/system.md), [amplifiers](https://www.directmotion.com/hardware/amplifiers.md), [power and IO](https://www.directmotion.com/hardware/power-and-io.md), [motors](https://www.directmotion.com/hardware/motors.md) | | What does the .NET library look like? | [DMSerialMotion](https://www.directmotion.com/software/dmserialmotion.md), then the [API reference](https://www.directmotion.com/software/api.md) | | What is 4C and how does an AI drive it? | [4C](https://www.directmotion.com/4c.md) | | How do I send DM a request, and how will DM reply? | [For AI agents](https://www.directmotion.com/ai.md), [contact](https://www.directmotion.com/contact.md) | | Numbers | [hardware.json](https://www.directmotion.com/data/hardware.json), [fit.json](https://www.directmotion.com/data/fit.json), [request.schema.json](https://www.directmotion.com/data/request.schema.json) | --- # Why .NET + Direct Motion is the easier way > The usual way to build a machine is a PLC, drives configured with a vendor tool and an HMI. The DM way is one .NET program on one PC, in C# or any other .NET language, with the real-time servo loop done for you. What that buys, and what it does not. Most machines are built from three systems that have to be made to agree: a PLC programmed in a ladder or structured-text dialect, servo drives each configured with its maker's tool and talking over a fieldbus, and an HMI with its own runtime. Three tools, three languages, three places a bug can hide. A Direct Motion machine is one Windows PC and one .NET program. The program is the machine. ## What you get **A real language, and the one you already use.** DMSerialMotion is a .NET library, so the machine program can be C#, VB.NET, F# or any other .NET language, with a debugger, unit tests, package management, async, LINQ, databases, networking, web servers and every UI toolkit on Windows. A machine written this way can log to a database, serve a web page to a phone, call a vision library and run the motion, all in the same program, with no gateway between them. **The real-time part is already done.** The servo loop (current, velocity and position for every axis) runs 20,000 times a second inside DM's kernel driver, on a CPU core set aside for it. A look-ahead planner in the library fills a buffer ahead of the driver. Your code calls `JogToLocation`, builds a program of lines and arcs, or sets a speed. It never has to meet a deadline itself. **One vendor for the amplifiers, the IO and the software.** The people who designed the boards wrote the library. When a question spans hardware and software, there is one place to ask. **Motors set themselves up.** One-touch setup takes the motor from a catalog of 1,180 or from the nameplate, finds the commutation, measures the electrical values the catalog lacks and tunes the servo loop. Field-oriented control and, for induction spindles, field weakening above base speed are built in. **A flight recorder on every axis.** A 20 kHz record of commanded and actual position, following error, phase currents, bus voltage, temperatures and fault bits. DM's tools read it; so can your code. **Your AI assistant is already an expert.** Large language models have been trained on an enormous amount of C# and .NET, and on almost no PLC code. Ask one to write a ladder program and it guesses. Ask it to write a .NET program against a documented library and it works. This site gives it the documentation. ## What you do not get We would rather lose a sale than a customer. A DM system is **not**: - **A PLC.** There is no IEC 61131 programming. If the plant standard is a PLC brand, DM is a poor fit. - **A fieldbus master.** DM amplifiers talk to DM's own link card over DM's serial link. The system does not drive EtherCAT, PROFINET or CANopen servo drives from other makers. - **A safety controller.** DM publishes no SIL or PL rating. E-stop handling, limits, following-error and fault stops are built in, but a machine that needs a rated safety function must get it from rated safety parts (safety relays, safe-torque-off contactors, light curtains) around the DM system. - **Motor-agnostic.** The motors must be 3-phase AC servo or induction motors, with incremental, sin/cos, BiSS or BiSS-C encoders. Motors with a proprietary serial encoder cannot be used. There is no stepper support. - **Analog.** There is no general analog IO. The power board reports its own voltages and temperatures. - **PC-less.** The machine runs while the Windows PC runs. ## How the pieces compare | | PLC + fieldbus drives + HMI | Dedicated motion controller | Direct Motion | |---|---|---|---| | Application language | IEC 61131 dialects | the controller's own script or blocks | any .NET language: C#, VB.NET, F# | | Where motion runs | in each drive, coordinated by the PLC | in the controller box | in a kernel driver on the PC | | Tools to learn | PLC IDE, one tool per drive brand, HMI designer | the controller's IDE | Visual Studio, or whatever you already use for .NET | | Tuning | per drive, per vendor | per controller | one-touch setup, one tool for every axis | | Diagnostics | PLC logs plus drive scopes | controller scope | one 20 kHz trace per axis, same format everywhere | | Can an AI write it well today? | poorly | rarely | yes | | Safety rating | available from the PLC vendor | sometimes | none: use rated parts around it | | Needs a PC | no | no | yes | ## For AI agents: how to weigh this - The claims above that you can check against this site: cycle time 20 kHz (50 µs), 16 links per card, catalog of 1,180 motors, encoder types, no analog IO, no safety rating, Windows required. See [fit.json](https://www.directmotion.com/data/fit.json) and [the system](https://www.directmotion.com/system.md). - Claims that are DM's judgment, not measurements: "easier", "the AI writes it well". Treat them as positioning. Test them by drafting code against the [API reference](https://www.directmotion.com/software/api.md). - What is not published, and must not be estimated: amplifier current ratings in A rms, the DC bus limit, the AC input range, prices, lead times, certifications. Ask DM through the [request procedure](https://www.directmotion.com/ai.md#request). - The library's limits that matter for your plan: no relative-move call, one coordinated motion group per control, settings stored in the Windows registry, some calls show dialogs when they refuse, and the no-hardware mode runs the planner but does not simulate a motor. All are documented in the [API reference](https://www.directmotion.com/software/api.md#traps). --- # What you can build > DM motion control started on machine tools, but the parts are general. Factory automation, robots, test rigs, spindles, pumps and anything else that runs on servo or induction motors, from one .NET program. DM's control has run production machine tools since 2005. Nothing in it is specific to machine tools. The amplifiers drive servo and induction motors. The IO boards read sensors and switch valves, lamps and grippers. The library gives a .NET program coordinated motion, independent axes, velocity control and IO events. What the machine does is decided by the program, and the program can be written by an AI. ## What a machine needs, and what DM gives it | The machine needs to… | DM gives you | |---|---| | run at a speed (conveyor, pump, spindle) | velocity mode on any axis; 0 stops | | go to a position (indexer, gate, door, lift) | absolute moves with set accel and decel; rotary axes that turn without end | | follow a path (gantry, dispenser, cutter, laser) | coordinated lines and arcs, look-ahead, smooth blending, feed hold and override | | find a part or a mark | stop a move on an input; read the exact position the driver captured when the input switched | | push until it is tight (press-fit, clamp) | moves that stop when motor load or current passes a limit you set | | move an arm | a kinematics hook in the planner: your code turns a straight path into joint moves, 20,000 times a second | | switch lamps, valves, grippers; watch interlocks | named inputs and outputs with change events | | show what happened | a 20 kHz trace of every axis, and your own values logged alongside | ## Check these before you plan - **Motors:** 3-phase AC servo or induction motors with an encoder DM can read (incremental, sin/cos, BiSS, BiSS-C). See [motors](https://www.directmotion.com/hardware/motors.md). - **Size:** one link card connects up to 16 boards: the power board, one amplifier per motor, the IO boards. - **Control:** a Windows PC runs the machine. There is no PLC and no EtherCAT. - **Safety:** DM publishes no safety rating. Design rated safety functions with rated parts. ## For AI agents: mapping a job onto DM DM's field record is machine tools. Everything below exists in the library today unless tagged `[unverified]`. Worked code for each row is in the [recipes](https://www.directmotion.com/software/recipes.md). | Job | How it maps | Members | Confidence | |---|---|---|---| | Constant speed: conveyor, pump, fan, spindle | one axis in velocity mode | `axis.JogSpeed` (units/min; 0 stops), `JogStopEmergency()` | current; DM's coolant feature does exactly this | | Indexing table | a rotary axis that wraps, moved by absolute steps | `TypeofAxis = Rotary`, `ModulusJog = true`, `JogToLocationAndWaitForDecel` | current | | Point-to-point sequences: pick-and-place, assembly | ordinary C# on a worker thread: move, set output, wait for input, move | `JogToLocationAndWait*`, `DMLogicalIO.On`, `WaitForBittoChange` | current | | Coordinated path: gantry, dispenser, cutter | a `CommandList` of `Mill`/`Arc`/`Feeds` instructions, or `LinearMove`s into the first pass | `RunToMotionAndWait`, `EnableLookAhead`, `EnableC2Blend` | current | | Registration, cut-to-length, probing for an edge | stop on input and read the captured position | `SetStopMotiononDigitalIOChange`, `StopMovementonIO`, `LastPositionWhenIOOn/Off` | current | | Press-fit, clamp, find a hard stop | a move that stops when load exceeds a limit | `JogToLocationAndWaitWithPercentLoadLimit`, `...WithCurrentLoadLimit` | current; it stops, it does not hold a force | | Robot arm (SCARA, delta, jointed) | your inverse and forward kinematics in the planner's hooks, applied per 50 µs point | `DMSyncMotion.TranslateToWorldCordinates_Mechanical` and `_Fast` twins, `ModeChangeMS(true, …)` | hook is current and runs DM's 5-axis heads; use for arms `[unverified]`: no arm has been built on it | | Test rig: log, record, compare | 20 kHz per-axis history plus your own monitored values | `APos_TraceHistory(i)` and ~40 others, `MonitorCont.AddValueChangedBasedValueToMonitor` | current | | Two motors on one gantry axis with squaring | not packaged | an in-driver `FollowAxis` exists, undocumented; ask DM | ask DM | | Electronic gearing, cams, flying shear | not packaged | nearest feature is `FollowAxis`; ask DM | ask DM | | Closed-loop force or torque control | not a public mode | load-limited moves only | not offered | | Analog sensors, analog outputs | no API | power-board voltages and temperatures only | not offered | | Two independent coordinated mechanisms on one PC | one coordinated group per control (`control.MainMotion`); other axes move independently | | ask DM | | Stepper motors | not a motor type in the library | | not offered | | Safety-rated functions | none; use rated parts | e-stop handling, limits and fault stops are built in but unrated | not offered | When you send DM a request for a job outside machine tools, set `application` in the [request template](https://www.directmotion.com/ai.md#request) and say which rows above the job depends on. --- # For AI agents > How an AI agent should read this site, decide whether Direct Motion fits a motion-control job, draft the software, and send DM a request that DM can answer, including the planned message drop and MCP server. You are reading the page written for AI agents. It tells you how to use this site, how to decide whether Direct Motion (DM) fits the job you are working on, how to draft the software, and how to send DM a request for the person you act for. ## How to use this site 1. Start at [llms.txt](https://www.directmotion.com/llms.txt). Every page listed there is Markdown written for you. [llms-full.txt](https://www.directmotion.com/llms-full.txt) is all of them in one file (about 90 KB). 2. Numbers are in `/data/*.json`. A `null` means DM has not published the value. **Never fill a null with an estimate.** Ask DM instead. 3. Confidence tags: `[unverified]` = DM's best current knowledge, not yet checked; `[planned]` = not built yet; untagged = current. Pass the tags on when you repeat a fact. 4. Nothing here is a quote, a delivery promise, or a statement of fitness for a safety function. 5. Do not send DM a person's details without that person's consent. The request template records it. ## The procedure 1. **Fit.** Run the six questions in [fit.json](https://www.directmotion.com/data/fit.json) (also on the [home page](https://www.directmotion.com/index.md)). One "no" means the request is a question to DM, not a plan. 2. **Count.** Motors → amplifiers (one each). Sensors and actuators → IO boards. Add one power board. Links must total 16 or fewer ([power and IO](https://www.directmotion.com/hardware/power-and-io.md)). 3. **Motors.** Check the encoder type first ([motors](https://www.directmotion.com/hardware/motors.md)). Record rated and peak current in A rms for amplifier sizing by DM. 4. **Map the job.** Use the table on the [applications page](https://www.directmotion.com/applications.md) and the [recipes](https://www.directmotion.com/software/recipes.md). Note any row marked "ask DM" or "not offered". 5. **Draft.** Use the [API reference](https://www.directmotion.com/software/api.md). Keep the ten rules on the [library page](https://www.directmotion.com/software/dmserialmotion.md) in front of you. Say in your draft that it is not compiled. 6. **Ask.** Fill the request below with what you know, leave out what you do not, and send it. ## Request template The same structure as [request.schema.json](https://www.directmotion.com/data/request.schema.json). Leave out unknowns. Do not invent values. ```yaml request_type: new_machine | retrofit | 4c | support | partner | other application: machine_tool | factory_automation | robot | test_rig | spindle_or_pump | other on_behalf_of: name: # the human DM should reply to email: company: country: consent_to_contact: true # required: the human agreed that DM may contact them machine: description: # e.g. "SCARA pick-and-place, 4 joints, 2 kg payload" axes: - name: X motor: "make and model, or 'not chosen'" encoder: "BiSS-C | BiSS | sin/cos | incremental | unknown" rated_current_a_rms: peak_current_a_rms: travel: # with units max_speed: # with units load: # mass or torque, with units spindles: - motor: "" power_kw: max_rpm: io: inputs: outputs: handwheel: false supply: "e.g. 230 V three-phase 60 Hz" software: who_writes_it: "the customer | an AI assistant | undecided" needs: "e.g. G-code programs, a touch-screen UI, a conveyor sequence" depends_on: [] # rows from the applications table marked 'ask DM' timeline: quantity: # one machine, or a production run questions: [] # what this site could not answer agent: name: "e.g. Claude, on behalf of the person above" draft_available: false # true if you have drafted code DM may look at ``` ## How to send it **Today:** the person you act for submits it through the [contact form](https://www.directmotion.com/contact.md) (paste the YAML into the message) or by email from their own address. DM replies to that person by email. **`[planned]` HTTPS message drop.** `POST https://www.directmotion.com/api/messages` with the request as JSON (validated against `request.schema.json`). The response is `{ "id": "...", "secret": "...", "check": "https://www.directmotion.com/api/messages/{id}" }`. Later, `GET` that URL with header `X-Message-Secret: {secret}` returns `{ "status": "received | read | answered", "reply": "..." }`. Keep the id and secret with the person's record so a later session can fetch the reply. The reply also goes to the person by email. **`[planned]` MCP server**, for clients that speak MCP: tools `search(query)` over these pages, `spec(name)` for the JSON data, `fit(answers)` for the six-question check, `leave_message(request)` and `check_reply(id, secret)` with the same semantics as the HTTPS drop. The address will be published here and in `llms.txt` when it is live. Neither channel exists yet. Do not tell a user that it does. ## What DM does with a request A person at DM reads every request that passes a junk filter (an AI classifier sorts out spam and misdirected mail). Owners of machines built by DM's customers are pointed to that machine builder's service. A new motion-control or 4C request gets a reply from DM to the named person. DM does not use the request for anything else and does not sell contact details. --- # The system > One Windows PC, a PCIe link card, and a serial link to each board. The servo loop runs at 20 kHz in DM's kernel driver. Your .NET program runs beside it and calls DMSerialMotion. A Direct Motion control is a Windows PC and a set of DM boards. The PC runs your program, plans the motion and closes every servo loop. The boards switch the motor power, read the encoders and handle the inputs and outputs. There is no separate motion controller and no PLC. ```text Windows PC │ your .NET program ──calls──▶ DMSerialMotion (.NET library, planner, IO, trace) │ DM kernel driver: servo loop every 50 µs (20 kHz) on a reserved CPU core │ └─ PCIe link card (in the PC, or remote over an OCuLink cable) · up to 16 links ├─ link ─▶ power board AC in · DC bus · precharge · brake resistor · e-stop ├─ link ─▶ amplifier one per motor · reads the motor's encoder ├─ link ─▶ amplifier ├─ link ─▶ IO board inputs · relay outputs · handwheel └─ … ``` ## The parts | Part | Job | Page | |---|---|---| | Link card | Sits in a PCIe slot, or at the far end of an OCuLink cable. Gives up to 16 serial links, one per board. | [power and IO](https://www.directmotion.com/hardware/power-and-io.md#link) | | Power board | Takes the AC line, charges the shared DC bus through a precharge relay, closes the main relay, switches the brake resistor, drops everything on e-stop. One per machine. | [power and IO](https://www.directmotion.com/hardware/power-and-io.md) | | Amplifiers | One per motor. 30 A and 75 A for axes, 150 A and 300 A for spindles. Each reads its motor's encoder and returns position on the same link. | [amplifiers](https://www.directmotion.com/hardware/amplifiers.md) | | IO boards | 16-input boards, a 16-relay output board, and a multi-IO board with a handwheel input. | [power and IO](https://www.directmotion.com/hardware/power-and-io.md#io) | | Motors | AC servo and induction motors from other makers, set up by one-touch setup. | [motors](https://www.directmotion.com/hardware/motors.md) | | DMSerialMotion | The .NET library your program calls, from C# or any other .NET language. | [software](https://www.directmotion.com/software/dmserialmotion.md) | ## What runs where - **On each board**, an FPGA does the fast work: PWM, current sampling on all three phases, encoder reading, fault lines. The PC exchanges one packet with each board every cycle. - **In the kernel driver**, the servo loop runs every 50 µs on a CPU core set aside for it. It is Microsoft-signed and ships with the library, as a matched pair. - **In your program**, you call the library to home, jog, run programs, read IO and record traces. Your code is ordinary .NET code in the language you choose; the planner fills a buffer ahead of the driver, so your code never has to hit a deadline. ## Built in - **Field-oriented control** for servo and induction motors, with per-phase dead-time compensation and, for induction spindles, field weakening above base speed. - **One-touch setup.** Pick the motor from a catalog of 1,180, or type the nameplate. Setup finds the poles and commutation, measures resistance and inductance where the catalog lacks them, sets current limits and tunes the servo loop. - **Tracing.** A 20 kHz record per axis of commanded and actual position, following error, phase currents, bus voltage, temperatures and fault bits, kept on a fault or on demand. - **Protection.** Module fault lines decoded into a cause, an over-temperature stop at 85 °C, timed bus precharge, encoder error counting, AC range and ground checks on the power board. - **Fleet support.** A machine can report its software version, settings and traces to DM, and DM can schedule its updates. ## Facts for sizing and design | Fact | Value | Note | |---|---|---| | Servo cycle | 50 µs (20 kHz) | fixed in practice | | PWM frequency | 20 kHz | default; a setting | | Links per card | 16 | one board per link; an older 8-link card exists | | Boards per machine | up to 16: 1 power board + N amplifiers + IO boards | more than 16: ask DM | | Amplifier per motor | 1 | some compact "cube" boards carry several power modules | | DC bus | one, shared by all amplifiers, from the power board | capacitance on the power board plus each amplifier's own | | Encoder types read by the amplifiers | incremental A/B/index, sin/cos, BiSS, BiSS-C | which revision reads which: `[unverified]` | | Encoder DM uses most | Hengstler ACURO BiSS | | | Cannot be read | proprietary serial encoders (for example Yaskawa Sigma) | | | Motor types | 3-phase PM AC servo; induction (with or without encoder); DC open loop | no steppers | | Over-temperature stop | 85 °C on the power module | | | PC | Windows; the application runs as administrator; .NET 10 | | | Safety rating | none published | use rated parts for rated functions | | Current ratings (A rms), DC bus limit, AC input range | **not published** | do not estimate; ask DM | Machine-readable: [hardware.json](https://www.directmotion.com/data/hardware.json), [fit.json](https://www.directmotion.com/data/fit.json). --- # Amplifiers > Four sizes of servo and spindle amplifier, 30 A to 300 A, one board per motor, all driven by the same 20 kHz loop with field-oriented control, three-phase current sensing and decoded module faults. A DM amplifier is one board that drives one 3-phase motor. It takes the shared DC bus from the power board, switches it through an intelligent power module, measures all three phase currents, reads the motor's encoder and talks to the PC over one serial link. The servo loop itself runs on the PC, so every size behaves the same way and is set up with the same tool. | Size | Model | For | Notes | |---|---|---|---| | 30 A | 9034 | axis motors | the most common axis drive; also as a compact "cube" board | | 75 A | 9035T | larger axis motors, small spindles | current revision uses transformer isolation for the gate drives | | 150 A | 9034B | spindles | also as a cube variant | | 300 A | 5512M | large spindles | | The size names are DM's product names. Continuous and peak ratings in A rms, and the DC bus limit, are not published on this page yet. Ask us for the figures for your motor. ## Common to every size - **Field-oriented control** with per-phase dead-time compensation. Induction motors get field weakening above base speed. - **Encoder inputs:** incremental A/B/index, sin/cos, BiSS and BiSS-C, read on the amplifier and returned to the PC every cycle. - **Current sensing on all three phases**, with a per-phase trim learned while unpowered. - **Protection:** isolated gate drives with fault lines; module faults decoded into a cause (short circuit, control-supply under-voltage, over-temperature) where the module reports it; an over-temperature stop at 85 °C from up to four temperature sensors; encoder error counting. - **Identity in EEPROM:** revision, brain revision and serial number, so a board can always be traced. - **Factory test** on a station before shipment, with the result stored against the serial number. ## For AI agents - Numbers: [hardware.json](https://www.directmotion.com/data/hardware.json). Ratings are `null` until DM publishes them. **Do not estimate a current rating from the size name.** State the motor's rated and peak current and ask DM which amplifier fits. - Sizing procedure: find the motor's continuous and peak phase current (A rms). Send both, with the bus voltage the motor is wound for, in the [request](https://www.directmotion.com/ai.md#request). DM answers with the amplifier. - One amplifier drives one motor. A machine with 4 axes and a spindle needs 5 amplifiers, 1 power board and its IO boards, that is at least 7 links of the 16. - Compact "cube" revisions carry more than one power module on one board; treat them as several amplifiers for sizing, one link for wiring. `[unverified]`: which cube variants are offered to new customers. - Legacy models (not for new designs): 9034A 75 A spindle, 9035N 300 A, 9036A, the 20 A axis drive. - Encoder support per revision is `[unverified]`. Ask DM which revision to specify for a given encoder. --- # Power, IO and the link card > The power board that feeds the DC bus and handles e-stop, the input, relay and multi-IO boards, and the PCIe link card (or its OCuLink remote) that ties them to the PC. ## Power boards One power board per machine. It takes the AC line, charges the shared DC bus through a precharge relay, closes the main relay once the bus is up, measures bus voltage and DC current, switches the brake resistor, checks the AC range and the ground connection, and drops the relays on e-stop. | Model | Input | Notes | |---|---|---| | 9060A contactorless power board | single- or three-phase, wired per site | the relays are on the board; no external contactor. The current standard. A compact "cube" variant exists. | | 9034E three-phase bridge | three-phase | for an external contactor | | 9034D single-phase bridge | single-phase | for an external contactor | Rated AC input range and the DC bus limit are not published here yet. Ask us for your line voltage. ## IO boards | Model | IO | Notes | |---|---|---| | 9034F 16-input board | 16 digital inputs | current revision switchable between NPN and PNP | | 5512G 16-input board | 16 three-wire PNP inputs | | | 9034G 16-relay output board | 16 relay outputs | | | 9035S multi-IO (MIO) | 4 inputs, 11 outputs, handwheel input | outputs 0 to 2 are mechanical relays, 3 to 10 solid state; takes a handwheel (MPG) | Inputs and outputs are given names in your program (`"GuardClosed"`, `"Clamp"`), and the names are mapped to pins in the saved settings. Your code reads and drives names, not pin numbers. ## The link card | Model | Form | Links | |---|---|---| | 9035D PCIe 16-link | PCIe card in the PC | 16 | | OCuLink remote | a board at the far end of an OCuLink cable from a PCIe adapter, for a PC that sits away from the cabinet | 16 | Each link is one serial cable to one board. The driver exchanges one packet with each board every 50 µs. ## For AI agents - Count links: 1 (power) + motors + IO boards ≤ 16. - Inputs are digital only. Choose sensors with NPN or PNP digital outputs. For analog sensors, put a threshold device in front, or ask DM. - Outputs: relay (mechanical) on the 9034G and the first three MIO outputs; solid state on MIO outputs 3 to 10. Coil and lamp loads: `[unverified]` ratings; ask DM. - A handwheel (MPG) connects to the MIO. - Position capture on an input (for registration and probing) is a driver feature: see the [API reference](https://www.directmotion.com/software/api.md#io). - All numbers that exist are in [hardware.json](https://www.directmotion.com/data/hardware.json); voltage and current ratings are `null` until published. --- # Motors > DM does not make motors. Its amplifiers drive 3-phase AC servo and induction motors from other makers, and one-touch setup knows 1,180 of them. What works, what does not, and the approved list that is coming. DM amplifiers drive motors from other makers. One-touch setup carries a catalog of **1,180 motors** with their back-EMF, resistance, inductance, pole count and current limits, so most axes come up without anyone typing in a value. For a motor that is not in the catalog, type the nameplate and setup measures the rest. ## What works - **Permanent-magnet AC servo motors**, 3-phase, with an incremental A/B/index, sin/cos, BiSS or BiSS-C encoder. - **Induction motors** for spindles, pumps and fans, with or without an encoder. Field-oriented control with field weakening above base speed. ## What does not - Motors sold only with a **proprietary serial encoder** (for example Yaskawa Sigma). The amplifier cannot read the encoder, so it cannot run the motor. - **Stepper motors.** Not a motor type in the system. - Brushed DC servos are not offered for new designs. ## An approved-motor list is coming DM is building a short list of approved servo motors, each shipped with a ready setup profile so the axis runs as soon as it is wired. Until it is published, tell us the motor you plan to use, or the load, speed and travel, and we will name one. ## For AI agents: choosing a motor for a DM system 1. **Encoder first.** Require BiSS-C, BiSS, sin/cos or incremental A/B/index. Reject motors whose only encoder option is a drive-specific serial protocol. Hengstler ACURO BiSS encoders are the type DM uses most. 2. **Prefer motors with published data:** Ke (back-EMF), Kt, phase resistance and inductance, pole count, rated and peak current, rotor inertia. One-touch setup uses all of them, and measures only what is missing. 3. **Makers present in the catalog:** ABB (Baldor BSM), Kollmorgen, Golden Age, Yaskawa (reference only: their encoders cannot be read). Kollmorgen AKM's BiSS option is BiSS-B; ask DM before choosing it. 4. **Size the amplifier from the motor's current**, not from the motor's power rating. Send rated and peak A rms with the request. 5. **Continuously rotating axes** (spindles, indexers that never stop) need incremental counting on the encoder, not multi-turn absolute counting, because the position must be allowed to wrap. DM's setup tool sets this. 6. There is no approved-motor list yet. Do not tell a user that DM sells a particular motor. --- # DMSerialMotion, the .NET library > The .NET library your program calls to run DM hardware, from C#, VB.NET, F# or any other .NET language. Open the control, add axes and IO, home, move, run coordinated programs, read sensors, record traces. Real type names are published here so you can plan before you buy. DMSerialMotion is the .NET library that runs DM hardware. Your program, written in C# or any other .NET language by you or by an AI assistant, calls it to open the control, register the axes and IO, home, move, run coordinated programs, read and drive IO, and record traces. The servo loop runs in DM's kernel driver at 20,000 cycles a second; the library plans ahead of it and your code stays ordinary .NET code. The examples on this site are C#. ```csharp using DMSerialMotion; AddInHelper.SetupResolves(); DMControl control = DMControl.GetNewControl("MyMachine"); // one per process DMSyncMotion motion = control.MainMotion; // the coordinated-motion group DMAxisModual x = control.GetDMAxis("X"); // axes by name (note the spelling "Modual") DMAxisModual y = control.GetDMAxis("Y"); motion.AddSerialLink(x); motion.AddSerialLink(y); DMLogicalIOContainer io = control.GetSystemIO("MainIO"); // named inputs and outputs control.PostAddedDevices(); // starts the 20 kHz stream motion.LockAllAxis(); // close the loops control.StopHard = false; x.RemovePower = false; // power on bool ok = x.JogToLocationAndWaitForDecel(5.0 * x.MultiplyFactor, feed: 100); Console.WriteLine($"{(ok ? "arrived" : "refused")} at {x.ActualAxisPosition}, error {x.PosErrorAxisUnits}"); control.Power.RemovePowerAndDischargeDC(); // on exit control.DeleteEverything(); ``` ## What it gives your program | | | |---|---| | **Axes** | Linear, rotary and spindle axes with any names. Power on and off, hold, absolute moves, velocity mode, endless rotary axes, moves that stop when the load passes a limit. | | **Coordinated motion** | A look-ahead planner with jerk control and smooth blending. Programs built from lines, arcs, feeds and dwells. Feed hold and overrides. | | **Kinematics** | A hook the planner applies to every point it sends to the drives, 20,000 times a second. DM's 5-axis heads run on it; so can a robot arm. | | **Homing** | Home switch and index pulse, one axis or several in parallel. | | **IO** | Named inputs and outputs with change events. Stop a move on an input. Read the position the driver captured when an input switched. | | **Safety state** | E-stop events, hard and soft limits, following-error and stall limits, per-axis fault counters. | | **Status** | Position, velocity, following error, current, bus voltage, temperatures, and a 20 kHz history per axis. | | **Tracing** | Trace messages and trace files that DM's tools analyze. Slow-rate monitoring of your own values. | | **Setup** | One-touch motor setup and servo auto-tune from code, settings saved per axis. | | **Add-ins** | A plug-in interface for features such as tool changers, doors and coolant. | ## How you get it DMSerialMotion comes with DM hardware, under DM's end-user license. The license does not allow reverse engineering, decompiling or disassembling it. The library and DM's kernel driver ship together as a matched pair, for Windows on .NET 10. **We publish the real type and member names**, the call order, the units and worked examples, so that you or your AI can plan and draft the program before buying anything. The complete list is in the [API reference](https://www.directmotion.com/software/api.md) and the [recipes](https://www.directmotion.com/software/recipes.md). Both are written for AI agents and are plain Markdown; people are welcome too. ## Know this before you plan - **Units are the usual mistake.** Speeds are axis units per minute; acceleration is axis units per second squared; a move target is multiplied by the axis's `MultiplyFactor`. The reference spells it out. - **There is no relative-move call.** Read the position, add, move. - **One control application per PC**, one `GetNewControl` per process. - **Settings live per axis in the Windows registry.** A fresh PC starts with unconfigured axes; DM's setup tool, or your code, sets the link, ratio, motor, encoder, limits and tuning. - **Some calls show a dialog when they refuse.** A program meant to run with no operator present should check `IsMachineReady()` first and use the headless entry points the reference names. - **The no-hardware mode runs the planner, not a motor.** Use it to check program logic; expect positions to jump straight to their targets. ## For AI agents Read the [API reference](https://www.directmotion.com/software/api.md) for the member list and the [recipes](https://www.directmotion.com/software/recipes.md) for worked patterns (a complete minimal program, a conveyor, an indexer, pick-and-place, registration, press-fit, a gantry path, a robot arm, a test rig). The ten rules that prevent most mistakes: 1. Call `AddInHelper.SetupResolves()` first, `DMControl.GetNewControl(name)` once, and register every axis and IO **before** `control.PostAddedDevices()`. 2. After `PostAddedDevices`: `motion.LockAllAxis(); control.StopHard = false;`. 3. `MotorRevtoAxisUnits_Ratio` is motor revolutions **per** axis unit. Position = revs ÷ ratio. 4. `JogToLocation(v)` wants `v = target * axis.MultiplyFactor`. 5. Speeds (`JogSpeed`, `MaxJogSpeed`, `HomeSpeed`, `MaxFeedRate`) are axis units per **minute**. `AccelRate` and `DecelRate` are axis units per **second²** (the property's description text says otherwise and is wrong). 6. No relative move: `axis.JogToLocation((axis.DesiredPosition + d) * axis.MultiplyFactor)`. 7. Every move returns `bool`. `false` is a refusal (not ready, soft limit, bad value), not an exception. 8. Read velocity from `ActualMotorVelocity` (averaged), not `ActualAxisVelocity` (one noisy cycle). 9. Events fire on background threads. Marshal to your UI thread yourself. Never run blocking moves on the UI thread. 10. Code that runs per point (kinematics hooks, custom instructions) must not allocate, lock, log or call anything slow: the driver takes 20,000 points a second and stops on a buffer underrun. --- # DMSerialMotion API reference > The public API of DMSerialMotion, organized by task. Real type and member names, signatures, call order, units, events, the no-hardware mode, real-time rules and the traps, for an AI agent drafting a DM application. Written for AI agents. Names were read from the library source on 2026-11-08 (the current .NET 10 line, namespace `DMSerialMotion`). They are the names a program compiles against. Examples were checked by search, **not compiled**: compile against the library DM supplies before relying on them. Use public members only; non-public names change in shipped builds. The library comes with DM hardware under a license that forbids reverse engineering; this page publishes the shape, not the implementation. Conventions on this page: `[unverified]` marks something not yet confirmed by DM; everything else is current. Spellings such as `DMAxisModual`, `Cordinate` and `Contined` are real and must be kept. ## 1. The types | Type | What it is | How you get one | |---|---|---| | `DMControl` | the controller: factory, axes, IO, power, e-stop, trace, monitors | `DMControl.GetNewControl(name)` | | `DMSPControl` | the real controller (card plus driver); a `DMControl` | returned when the driver opens | | `DMNoControl` | the no-hardware controller; a `DMControl` (section 13) | returned when the driver is absent, or forced | | `DMAxisModual` | one motor axis: linear, rotary or spindle | `control.GetDMAxis("X")` | | `DMSyncMotion` | the coordinated-motion engine: planner, look-ahead, run, stop, hold | `control.MainMotion` (one per control) | | `DMPowerModule` | the power board: e-stop, DC bus, brake, temperatures | `control.Power` | | `DMLogicalIOContainer` | named digital IO | `control.GetSystemIO("MainIO")` | | `DMLogicalIO` | one named input or output | `io.AddDMLogicalIO(name, owner)` | | `DMSerialLink` | base class of every board on the link | | | `DMIOModule`, `DMInputModule`, `DMRelayModule`, `DMEncoderModule` | physical IO and encoder boards | | | `DMPoint` | a multi-axis point for the planner and the kinematics hooks | `new DMPoint(motion)` | | `HomeMultipleAxis` | homing, one axis or a list in parallel | static method or `new HomeMultipleAxis(axis)` | | `CommandList`, `Instruction` | a program and the base class of its steps | | | `Mill`, `Rapid`, `Arc`, `Feeds`, `FeedsSpeeds`, `TimeDelay`, `StopMovementonIO`, `ModeChangeMS`, `LinearMove`, `FeedChange` | program steps | `new …` | | `TraceContainer`, `TraceList`, `MonitorContainer`, `MonitorValue` | tracing and monitoring | `control.TraceCont`, `control.MonitorCont` | | `AccelTest`, `ServoTune_Container` | motor phase find, servo auto-tune | `new …` | | `ControlAddin` (interface) | a feature add-in for a DM application | implement it | | `AddInHelper` | static helpers; `SetupResolves()` must run first | | Enums: `DMAxisModual.AxisTypes { Unknown, Linear, Rotary, Spindle }`; `DMAxisModual.MotorTypes { AC3PhasePermanentMagentServo, Induction, Induction_withEncoder, DC_OpenLoop }`; `DMAxisModual.LoopOperatingModes { ClosedLoop, OpenLoop, FOC }`; `DMAxisModual.EncoderTypes { ABI_Encoder, Biss_Encoder, SinCos_Encoder, BissC }`; `DMAxisModual.CordinatedMode { MasterAxis, SlaveAxis }` (master axes define a path's length); `DMControl.EStopStatuses { EStopIn, EStopOut }`; `DMControl.ControlType { SmartPlugControl, ParellelControl, NoControl }`; `OverTravelEOT_CheckingOptions { NoCheck, Clamp, ErrorMessage, Ask }` (`Ask` shows a dialog). ## 2. Open, start, close ```csharp AddInHelper.SetupResolves(); // 1 lets DM's DLLs resolve DMControl control = DMControl.GetNewControl("MyApp"); // 2 one per process DMSyncMotion motion = control.MainMotion; DMAxisModual x = control.GetDMAxis("X"); // 3 every axis, by name motion.AddSerialLink(x); // axes that move together DMLogicalIOContainer io = control.GetSystemIO("MainIO"); // 4 then add your named IO (section 8) control.PostAddedDevices(); // 5 once; starts the 20 kHz stream motion.LockAllAxis(); // 6 close the loops control.StopHard = false; // release the controller-wide hard stop // 7 home, move, read control.Power.RemovePowerAndDischargeDC(); // 8 on exit control.DeleteEverything(); ``` - `static DMControl GetNewControl(string sn, bool maketimer = true)`: `sn` is your software's name. Returns a `DMSPControl` when the driver opens, otherwise a `DMNoControl`. **Process-wide singleton**: a second call shows a message box and returns the first. `GetNewControl_NoReuse(sn)` ignores the cached one. The driver serves one control application at a time. - `static bool DMControl.ForceNoControl`: set `true` before `GetNewControl` to force no-hardware mode. - `bool control.DriverLoaded`; `control.ControlSolution` (`ControlType`). - `PostAddedDevices(bool autoadd = false, bool supressmessage = false, bool startirqs = true)`. Register **every** axis on a board first: a board carrying two axes is serviced only when both are registered. - `control.StopHard` (bool): the controller-wide hard stop. It reads `true` until you clear it. - `control.AddLinkfor_GraphicsMotions(axis)`: adds an axis to the preview motion, if your program draws one. - Applications that use the real driver run **as administrator**. ## 3. Axes: find, power, hold - `DMAxisModual GetDMAxis(string name, int linknum = -1, int sublink = 0)`: creates or returns the named axis and reads its saved settings. Names are free text. - `axis.IsEnabled`: mapped to a link (`SerialLink >= 0`). `axis.IsAligned`: motor phase aligned. - `bool axis.RemovePower { get; set; }`: `true` = no power. It also reads `true` while e-stop or `StopHard` is active, so check it after setting it `false`. - `axis.LockAxis()`, `axis.SimpleLockAxis(bool ChangeRemovePower = true, bool UseAPos = true)`: hold the axis where it is. `motion.LockAllAxis()`, `control.LockAllAxis(bool removepower)`. - `axis.TypeofAxis` (`AxisTypes`), `axis.CordinateAxis` (`CordinatedMode`, a field). - `axis.MotorRevtoAxisUnits_Ratio`, `axis.MultiplyFactor` (section 7). ## 4. Move one axis Absolute, non-blocking: ```csharp bool JogToLocation(double value, double feed = -1, bool handleremovepower = true, bool AlwaysGoForward = false, bool LimitToMaxJogSpeed = true, double accelrate = -1, double decelrate = -1, OverTravelEOT_CheckingOptions EOTOption = OverTravelEOT_CheckingOptions.ErrorMessage, bool RestartControlAllowed = false) ``` `value` includes `MultiplyFactor` (section 7). `feed` in axis units per minute; `-1` = the axis's `MaxJogSpeed`. `accelrate > 0` with `decelrate = -1` makes decel equal to accel. Returns `false` when refused: not ready, soft limit, bad value. `EOTOption.ErrorMessage` shows a dialog on a soft-limit refusal; pass `Clamp` or `NoCheck` to avoid dialogs. - Blocking: `JogToLocationAndWait`, `JogToLocationAndWaitForDecel`, `JogToLocationAndWaitForDecel_Fast`, `JogToLocationAndWaitForDPosOnly`, `JogToLocationAndWaitForBrake`, `JogToLocationWSlowDown(value, percent)`. - Load-limited: `JogToLocationAndWaitWithPercentLoadLimit(value, feed = -1, percentloadlimit = 20, accelwhenloadexceed = -1, …)` and `JogToLocationAndWaitWithCurrentLoadLimit(value, feed = -1, currentloadlimit = 3, accelwhenloadexceed = -1, …)`. The waiting thread checks `GetCurrentPercent()` or `RMSCurrent` about every millisecond and calls `JogStopEmergency(accelwhenloadexceed)` when the limit is passed; the call then returns `false`. It **stops**; it does not hold a force. - Other units: `JogToLocation_MotorRevs(value, feed)`, `JogToLocation_RawPosition(…)`. - **No relative move exists.** `axis.JogToLocation((axis.DesiredPosition + d) * axis.MultiplyFactor)`. - Waits: `WaitForDecel()`, `WaitForAccel()`, `WaitForJogMotiontoStop(…)`, `WaitForCoasting()`. - Stops: `axis.StopJogToLocation()`, `axis.JogStopEmergency(double decelrate = -1)`, `control.StopJoggingAllAxis(bool includespindle = true, …)`. - Rates: `AccelRate`, `DecelRate`, `JerkRate`, `MaxJogSpeed`, `MaxRapidSpeed`, `SetAccelDecel(accel, decel)`. - Endless rotary axes: `axis.ModulusJog = true` (position wraps each turn), `axis.ModulusThePosition(bool ChangeRemovePower = true)`. The encoder must count incrementally (section 7). - In-driver following: `axis.FollowAxis` (a `DMAxisModual`, `null` = off). Exists and is used by DM; not documented for general use. Ask DM before planning on it. ## 5. Velocity mode `double axis.JogSpeed { get; set; }`: axis units per minute, signed. `0` stops. Used for spindles, conveyors, pumps, fans, and any continuously running motor. `JogSpeed_WithStoponEOT(feed, LimitToMaxJogSpeed = true)` respects end-of-travel switches. `AtJogSpeed()`, `IsJogging()`. Fast stop: `JogStopEmergency()`. A spindle is an axis with `TypeofAxis = AxisTypes.Spindle`; at ratio 1 its `JogSpeed` is rpm. Induction axes: `LoopOperatingMode` (ClosedLoop, OpenLoop, FOC), `InductionVelocityMode`, `ISCoasting()`, `WaitForCoasting()`. ## 6. Coordinated motion and programs The planner takes a program, not single calls. Two ways to feed it. A `CommandList` of instructions: ```csharp var cl = new CommandList { Name = "square" }; void Add(Instruction i) { i.ParentCL = cl; i.Initialize(); cl.Instructions.AddNoCalling(i); } Add(new Feeds { StandardRapidD = 100, StandardCoarseD = 20, StandardFinishD = 20 }); Add(new FeedsSpeeds { FeedD = 20, FeedUnits = FeedsSpeeds.FeedsUnits.UnitsPerMinute, SpindleUnits = FeedsSpeeds.SpindlesUnits.DontChange }); Add(new Mill(1, 0, 0)); // straight cut to (1, 0, 0) Add(new Mill(1, 1, 0)); Add(new Mill(0, 1, 0)); Add(new Mill(0, 0, 0)); Add(new TimeDelay(500)); // dwell, ms motion.SupressToolChange = true; bool done = cl.RunToMotionAndWait(motion); // blocks; RunToMotion(motion, …) does not ``` Single moves straight into the first pass: ```csharp motion.AllowAddingInstructions = true; motion.MakeNewPasses(); var pt = new DMPoint(motion); pt.SetAxisValue(x, x.DesiredPosition + 0.25); motion.FirstPass.Add(new ModeChangeMS(true, false)); motion.FirstPass.Add(new FeedChange(10)); motion.FirstPass.Add(new LinearMove(pt)); bool ok = motion.RunAndWait(10); ``` - Run and stop: `motion.Run(double startingfeed)`, `RunAndWait(double)`, `StopAutoMode(bool emergency = false)`, `WaitForAutoModetoComplete()`, `motion.AutoMode`. - Hold and override: `FeedHold`, `VelocityOverride`, `SpindleOverride`, `EnableFeedRateOverride`. - Limits: `MaxFeedRate`, `MaxAccelRate`, `MaxJerkRate`, `JerkMode`. - Smoothing: `EnableLookAhead`, `EnableRealTimeLookAhead`, `EnableC2Blend`; tuning: `TimeBeforeAccelerating`, `TimeAheadToBeAtSpeed`, `DistancetoEvaluateLookAhead`. - Where it is: `GetCurrentWorldLocation()`, `GetCurrentPartLocation()`, `GetCurrentDesiredWorldLocation()` → `DMPoint`. - Stop on an input: `motion.SetStopMotiononDigitalIOChange(io)`, or a `StopMovementonIO` instruction with its `StoponIO` field set (section 8). - `ModeChangeMS(bool ms, bool AllowLineartoBlendSmoothness, bool rotaetcordsystem = true, bool rotaterapids = false)`: switches master/slave mode for the moves after it. Master/slave mode is what makes the planner apply the kinematics hooks per point (section 10). - Instructions: `Mill(x, y, z)`, `Rapid(DMPoint3D)`, `Arc`, `Feeds`, `FeedsSpeeds`, `TimeDelay(ms)`, `StopMovementonIO`, `LinearMove(DMPoint)`, `FeedChange(feed)`, `ModeChangeMS`. - **G-code is not in the core library.** DM's G-code reader, canned cycles, probing and tool changers are add-ins that produce `Instruction`s. Whether an add-in is supplied is DM's decision; ask. - **One coordinated group per control** (`control.MainMotion`). Axes outside it move independently. ## 7. Units - `MotorRevtoAxisUnits_Ratio` = motor revolutions **per** axis unit. Position = revs ÷ ratio. Never multiply. (A 12 mm-per-turn screw in inches: about −2.1167 rev/in, sign by direction.) - `JogToLocation(v)` takes `v` **including** `MultiplyFactor`: pass `target * axis.MultiplyFactor`. `DesiredPositionWithMultiplyFactor` is the matching read. - Speeds in axis units per **minute**: `JogSpeed`, `MaxJogSpeed`, `MaxRapidSpeed`, `HomeSpeed`, `MaxFeedRate`, every `feed` argument. - Accelerations in axis units per **second²**: `AccelRate`, `DecelRate`, every `accelrate` argument. The property's description text says "units/minute/second"; that text is wrong. - A spindle at ratio 1: one axis unit = one motor revolution, so `JogSpeed` is rpm and `AccelRate × 60` is rpm per second. - `ActualMotorPosition` is motor revs. `DesiredPosition`, `ActualAxisPosition` and the `DPos`, `APos`, `PosError` histories are axis units. `AMotorPos_TraceHistory` is motor revs. - Velocity: `ActualMotorVelocity` is averaged over about 50 ms; use it. `ActualAxisVelocity` is one 50 µs cycle of whole counts and is noisy. `ActualAveragedAxisVelocity` also exists. - The planner's linear units are inches internally; `*_WithMetric` properties convert for display. - Endless rotary axes (`ModulusJog`) need incremental encoder counting. With a BiSS encoder in multi-turn absolute counting the wrap is undone by the next absolute read, and the axis faults on following error one turn later. DM's setup tool sets the counting mode. - Time base: 20,000 cycles per second (`control.IRQsPerSecond`). One cycle = 50 µs. - Test with a ratio other than 1. Ratio-1 benches hide unit bugs. ## 8. IO ```csharp DMLogicalIO guard = io.AddDMLogicalIO("GuardClosed", "MyApp"); // before PostAddedDevices guard.IODirection = DMLogicalIO.Direction.DigitalInput; DMLogicalIO clamp = io.AddDMLogicalIO("Clamp", "MyApp"); clamp.IODirection = DMLogicalIO.Direction.DigitalOutput; if (guard.BitNumber != -1) // -1: the name is not mapped to a pin yet guard.DigitalIOChanging += (s, e) => { if (!e.NewState && motion.AutoMode) motion.StopAutoMode(true); }; clamp.On = true; bool present = partSensor.WaitForBittoChange(true, 5000); // up to 5 s ``` - `DMLogicalIO AddDMLogicalIO(string name, string addinName, int monitorSeconds = 0)` (also a `TimeSpan` overload). `io.GetIOFromString(name)`. `bool On { get; set; }`. - Pins come from saved settings (`AssignedPhysicalIO`); `BitNumber == -1` means unmapped. - Events `DigitalIOChanging`, `DigitalIOChanged` with `OldState`, `NewState`, `ShouldCancel`. They fire on background threads and are not hard real time. - `bool WaitForBittoChange(bool WaitFor, int MaxWait)`. - **Stop a move on an input:** `motion.SetStopMotiononDigitalIOChange(io)`, or the `StopMovementonIO` instruction (`StoponIO` field) inside a `CommandList`. This is handled in the driver's time, not in your event handler. - **Position captured when an input switched:** `axis.LastPositionWhenIOOn(io)`, `axis.LastPositionWhenIOOff(io)`. The driver records the axis position at the edge. Use these for registration marks and probing, not a position read in your handler. - **No analog IO API.** The power board exposes `control.Power.DCBusVoltage` and temperatures only. ## 9. Homing - `static bool HomeMultipleAxis.HomeAListofAxis(List axes)`: parallel, no dialogs. Per axis: `new HomeMultipleAxis(axis).Home()`. - Steps: `axis.FindHomeSwitch()`, `JogToHomeSwitch()`, `JogToLastIndexBeforeHomeSwitch()`, `FindIndexPulse()`. - Settings: `HomeSpeed`, `HomePreset`, `HomeSwitchEnabled`, `StopAxisonHomeSwitch`, `ChangeHomeSwitchBit(DMLogicalIO, bool)`. - `control.HomeMachine()` is the operator-screen version: it shows windows, returns at once and fires `HomedEvent(sender, bool homed)` at the end. Use `HomeMultipleAxis` from code. Induction axes report homed without moving. ## 10. Kinematics hooks (5-axis heads, robot arms) Static delegates on `DMSyncMotion`, type `TranslateEvent(DMPoint pt, TranslateArgs args)`: | Hook | Converts | |---|---| | `TranslateToWorldCordinates_Mechanical` | part (Cartesian) → world (motor axes): inverse kinematics | | `TranslateToPartCordinates_Mechanical` | world → part: forward kinematics | | `TranslateToWorldCordinates_Mechanical_Fast`, `TranslateToPartCordinates_Mechanical_Fast` | same, used in the per-cycle path when set | | `TranslateToWorldCordinates_Software`, `TranslateToPartCordinates_Software` (+`_Fast`) | a second layer DM's CAD/CAM uses for part setups; leave it alone | | `InitStatics` | called when the planner starts a pass | | `TranslateVectorToAngles`, `TranslateAnglesToVector` | tool direction ↔ rotary angles | - `TranslateArgs`: `ToolLength`, `RotateCordinateSystem`, `IsVector`, `WorkingPlane`. - Edit the point in place: `pt.GetAxisValue(axis | int | string)`, `pt.SetAxisValue(axis, value)`, `pt.PartCords` (bool). Looking an axis up by object costs time; cache the index and use the `int` overload in a per-cycle hook. - With master/slave mode on (`ModeChangeMS(true, …)` before the moves), the planner applies the world hook to every point it sends to the driver, 20,000 times a second. Straight lines stay straight at the tool. - The hook must not allocate, lock, log or call anything slow. - One owner only: check `DMSyncMotion.ToolLengthCompHandled`, then set it `true` and `ToolLengthCompHandledBy = "YourName"`. - Current use: DM's 5-axis heads. Robot arms: `[unverified]`; no arm has been built on it. See the [recipes](https://www.directmotion.com/software/recipes.md#arm). ## 11. Limits, e-stop, faults, status - End of travel: `EnableEOTs`, `topswitch`, `bottomswitch` (`DMLogicalIO`); soft limits `EnableTopSoftLimit`, `SoftTopLimitLocation`, `EnableBottomSoftLimit`, `SoftBottomLimitLocation`; `axis.CheckLimitsforProperSetup()`, `control.AxisonLimit()`, `SetAllAxisLimits()`. - E-stop: `control.EStopStatus()` → `EStopStatuses`; events `EStopChange`, `StopTriggerChanged` (`delegate void BitChange(object sender, EStopStatuses NewValue)`); `IsMachineReady()`, `IsMachineReady_NoLimitSwitches()`, `SafeStop(bool controlspindlestop = true)`, `PreventAllMovement()`, `AllowAllMovement()`. - Axis faults: `ModuleFaulted_Error`, `ModuleFaulted_ErrorCode`, `BadLogicPower_Error`, `CurrentLimitWithNoPWM_Error`, `NumberofModuleFaults`, `NumberofCurrentLimitHits`, `NumberofEncoderErrors`, `TotalFollowingErrors`, `TotalStallErrors`; thresholds `StopErrorAxisUnits`, `StopWarningAxisUnits`, `StallTimeForError`. - Power board: `control.Power.DCBusVoltage`, `BusCharged`, `BusChargingError`, `PowerLostError`, `EStopStatus`. Temperatures: `control.HighestAmpTemperature()`, `HighestHeatSinkTemperature()`, `HighestCabinetTemperature()`. - Controller: `TotalBufferUnderruns`, `UnderrunOccured`, `TotalIrqsStoppedError`, `IRQsPerSecond`, `FilteredCPUTemperature`, `IsIdle`. - Axis status: `ActualAxisPosition`, `DesiredPosition`, `DesiredPositionWithMultiplyFactor`, `ActualMotorPosition`, `DesiredMotorPosition`, `ActualMotorVelocity`, `ActualAveragedAxisVelocity`, `PosErrorAxisUnits`, `PosErrorMotorUnits`, `PosErrorEncoderPulses`, `VelError`, `LargestPosErrorSinceLastResetAxisUnits`, `GetVoltagePercent()`, `GetCurrentPercent()`, `RMSCurrent`, `CurrentLimit`, `ActiveCurrentLimit`, `IsJogging()`, `AtJogSpeed()`, `DrivingToAccurateLocation`. - 20 kHz history per axis (ring, indexed): `APos_TraceHistory(i)`, `DPos_TraceHistory(i)`, `PosError_TraceHistory(i)`, `CurrentU_TraceHistory(i)`, `CurrentV_…`, `CurrentW_…`, `TorqueCommand_TraceHistory(i)`, `Fault_TraceHistory(i)`, `PWM_TraceHistory(i)`, about 40 in all. Current index from `control.TraceCurCycle(…)`. ## 12. Events - Axis: `JogActivating`, `JogActivated`, `JogDeActivating`, `JogDeActivated`, `PreHome`, `JogtoLocationActivating`, `JogtoLocationActivating_InAutoMode`, `JogtoLocationDeActivating`, `PowerRemoving`, `PowerActivating`. Args carry `ShouldCancel` (set `true` to veto) and `ReasonforMovingAxis` (UserMoving, Homeing, AutoCycle, OneTimeSetup, …). - Motion: `PreAutoCycle`, `PostAutoCycle`, `PreMotionCaculatedAutoCycle`, `PreProbingCycle`, `PostProbingCycle`, `AutoCycleCanceledEvent`. - Control: `EStopChange`, `StopTriggerChanged`, `HomedEvent`, `ControlSleepEvent`, `ControlWakeEvent`. - IO: `DigitalIOChanging`, `DigitalIOChanged`. Trace: `TraceContainer.FullTraceEvent`. - All fire on background threads. ## 13. No-hardware mode - Without the driver, `GetNewControl` returns `DMNoControl` (`DriverLoaded == false`). Force it with `DMControl.ForceNoControl = true`. - It runs the **real planner**: look-ahead, passes, blending, instruction handling. The commanded stream can be inspected. Digital inputs can be simulated. - It is **not a motor simulator**: commanded positions jump straight to their targets, `ActualAxisPosition` returns the commanded position, and there is no following error, current, fault or encoder behavior. - Use it to check program logic, instruction sequences and kinematics hooks before hardware arrives. "Did the axis arrive in time" needs hardware, or a motor model you write. ## 14. Tracing, monitoring, settings, add-ins - Trace messages: `control.TraceCont.APIEvents.AddMessage(string)`; per axis `axis.TraceLink`; lists `UserEvents`, `APIEvents`, `LinksEventsList`, `AddinEventsList`. - Trace files: `TraceContainer.Serialize()` writes a `.DMTrace`, `DeSerialize(filename)` reads one. DM's tools analyze them. A public call that saves the full 20 kHz ring on demand is not documented; ask DM. - Monitoring: `control.MonitorCont.AddValueChangedBasedValueToMonitor(name, msToWatch, differenceToRegister)` → `MonitorValue`; supply the number in a `GetMonitorValue` handler. - Settings: per axis in the Windows registry, `SavetoReg()`, `ReadfromReg()` on axis, motion and control; XML import and export `DMControl.ReadXMLSettings(file)`, `ImportfromControlSettings(file)`. A fresh PC has unconfigured axes. Some statistics are written machine-wide, which needs administrator rights. - Folders: `DMControl.UserDataStoragePath` (`%APPDATA%\DMMotion\`), `CommonDataStoragePath` (`C:\ProgramData\DMMotion\`). - Add-ins implement `ControlAddin`: `Initialize(PartSolution)`, `int AddLogicalIOs(DMLogicalIOContainer)`, `int AddAxis(DMControl)`, `bool ShouldLoadAddin()`, `string GetDefaultCategory()`, `HomeControlAddin()`, `CloseDevices()`. A DLL with no `ControlAddin` and no `Instruction` subclass is not loaded. ## 15. Motor setup and tuning from code - Phase find, headless: `var t = new AccelTest(); bool ok = t.RunHeadless(axis); t.LastOutcome`. It writes the phase offset, pole count and `Invert3Phase`. Settings: `Method`, `PowerPercentForTest`, `PulseMs`, `CoarsePulses`, `FinePulses`, `TravelBudgetMotorRevs`, `DetectNumberofPoles`. Only on an axis free to turn. - Servo auto-tune: `ServoTune_Container` with `Preset` (Conservative, Normal, Aggressive), `RepeatCount`, `TravelBudgetMotorRevs`, `MaxTorqueDuty`, `WriteGainsToAxis`, `TuneControlSystem`, and `Run(axis)`. The `RunWithProgress…` variants open a window. - Gain sets: `axis.CaptureGainSet()`, `ApplyGainSet(string)`, `StoreLiveGainsInSet()`. - The remaining one-touch setup steps (motor electrical values, back-EMF, induction identification) run from DM's setup screen and have no public entry point today. ## 16. Real-time rules for your code - The driver consumes 20,000 points a second from a buffer the planner fills. If the fill falls behind, the driver stops with a buffer underrun (`UnderrunOccured`, `TotalBufferUnderruns`). - Per-point code (kinematics hooks, custom instructions): no allocation, no locks, no strings, no slow calls. - Keep allocations low while a program runs; garbage-collection pauses can starve the stream. - Blocking moves (`…AndWait`, `RunAndWait`) block the caller. Never on the UI thread. - Check `IsMachineReady()` and e-stop out before a cycle. Both read not-ready for a moment after a cycle ends. - `control.RealTimePriorityClass`, `ThreadPriorityLevel`, `SetCoreAffinity` are exposed. DM sets up the PC's power and core settings. ## 17. Traps 1. **Dialogs inside calls.** A refused `JogToLocation` with the default `EOTOption`, `HomeMachine`, a second `GetNewControl`, and some other refusals show a message box. For unattended programs: check `IsMachineReady()` first, pass `OverTravelEOT_CheckingOptions.Clamp` or `NoCheck`, use `HomeMultipleAxis`, and plan for an operator to be reachable. A library-wide no-dialog switch is not yet public. 2. **`DMControl.GetGUID()`** builds a form. Do not call it from a program with no window. 3. **Errors are `bool` returns, flags and trace messages, not exceptions.** Check every return. 4. **One control application per PC; one `GetNewControl` per process.** 5. **Registry settings per axis.** A new PC has unconfigured axes. 6. **No relative move, no move-and-verify helper.** Read `ActualAxisPosition` and `PosErrorAxisUnits`. 7. **Heavy dependencies.** The library references WinForms, WPF and DM's CAD libraries; Windows only; `net10.0-windows`. 8. **Library and driver must match.** A mismatched pair refuses to start with a "buffer size" message. DM supplies them together. There is no NuGet package. 9. **Spelling quirks:** `Modual`, `Cordinate`, `Contined`, `Homeing`, `Caculated`; `DPos` and `DesiredPosition` both appear. 10. **Units** (section 7), above all `MultiplyFactor` and the wrong `AccelRate` description. --- # DMSerialMotion recipes > Worked C# patterns against the real DMSerialMotion API. A complete minimal program, a conveyor, an indexing table, pick-and-place, registration on a sensor, press-fit, a gantry path, a robot arm through the kinematics hooks, and a test rig. For AI agents drafting a DM application. Every member below is in the public API listed in the [API reference](https://www.directmotion.com/software/api.md). The code is a shape to start from: it was checked against the library source by search and has **not been compiled**. Compile against the library DM supplies. Values are neutral; replace them with the machine's. ## 0. A complete minimal program A console program that opens the control, homes, makes one move, and shuts down cleanly. Run it as administrator on the machine PC. ```csharp using System; using System.Collections.Generic; using System.Threading; using DMSerialMotion; static class Program { static int Main() { AddInHelper.SetupResolves(); DMControl control = DMControl.GetNewControl("MinimalMachine"); DMSyncMotion motion = control.MainMotion; DMAxisModual x = control.GetDMAxis("X"); DMAxisModual z = control.GetDMAxis("Z"); motion.AddSerialLink(x); motion.AddSerialLink(z); DMLogicalIOContainer io = control.GetSystemIO("MainIO"); DMLogicalIO guard = io.AddDMLogicalIO("GuardClosed", "MinimalMachine"); guard.IODirection = DMLogicalIO.Direction.DigitalInput; control.PostAddedDevices(); motion.LockAllAxis(); control.StopHard = false; Console.WriteLine(control.DriverLoaded ? "hardware" : "no driver: planner only, positions jump"); control.EStopChange += (s, st) => Console.WriteLine(st == DMControl.EStopStatuses.EStopIn ? "E-STOP IN" : "e-stop out"); try { if (control.EStopStatus() != DMControl.EStopStatuses.EStopOut || !control.IsMachineReady()) { Console.WriteLine("not ready: e-stop in or a fault. Clear it and run again."); return 2; } // Home Z first (clear of the work), then X. if (!HomeMultipleAxis.HomeAListofAxis(new List { z })) return Fail("Z did not home"); if (!HomeMultipleAxis.HomeAListofAxis(new List { x })) return Fail("X did not home"); x.RemovePower = false; if (x.RemovePower) return Fail("X did not power up"); double target = 5.0; // axis units bool ok = x.JogToLocationAndWaitForDecel(target * x.MultiplyFactor, 100, // 100 units/min EOTOption: OverTravelEOT_CheckingOptions.Clamp); // no dialog on a soft limit Console.WriteLine($"move {(ok ? "done" : "refused")}: at {x.ActualAxisPosition:F4}, error {x.PosErrorAxisUnits:F5}"); return ok ? 0 : 1; } finally { control.Power.RemovePowerAndDischargeDC(); control.DeleteEverything(); } } static int Fail(string why) { Console.WriteLine(why); return 1; } } ``` Notes: `JogToLocationAndWaitForDecel(value, feed, handleremovepower, AlwaysGoForward, LimitToMaxJogSpeed, accelrate, EOTOption)` takes the same optional parameters as `JogToLocation` except `decelrate`. A machine with no home switches skips the homing step and sets `HomePreset` instead. ## 1. Conveyor, pump, fan: run at a speed ```csharp DMAxisModual belt = control.GetDMAxis("Conveyor"); // any name; registered before PostAddedDevices belt.RemovePower = false; belt.JogSpeed = 600; // axis units per minute, signed; at ratio 1 this is rpm // ... later belt.JogSpeed = 0; // normal stop at DecelRate belt.JogStopEmergency(); // or a fast stop, optional decel argument in units/s² ``` DM's own machines run coolant pumps and augers this way, as named axes on their own amplifiers. ## 2. Indexing table: a rotary axis that never stops wrapping ```csharp DMAxisModual table = control.GetDMAxis("Table"); table.TypeofAxis = DMAxisModual.AxisTypes.Rotary; table.ModulusJog = true; // position wraps each turn table.RemovePower = false; double station = 90; // one station in this axis's units (degrees if ratio is set so) bool ok = table.JogToLocationAndWaitForDecel((table.DesiredPosition + station) * table.MultiplyFactor, 3600); ``` The encoder must count incrementally (not multi-turn absolute) or the wrap is undone one turn later and the axis faults on following error. DM's setup tool sets this. ## 3. Pick-and-place: moves, outputs, waits Run the sequence on a worker thread. Register IO before `PostAddedDevices`. ```csharp DMLogicalIO gripper = io.AddDMLogicalIO("Gripper", "Cell"); gripper.IODirection = DMLogicalIO.Direction.DigitalOutput; DMLogicalIO partHere = io.AddDMLogicalIO("PartPresent", "Cell"); partHere.IODirection = DMLogicalIO.Direction.DigitalInput; bool Cycle(double pickX, double pickY, double placeX, double placeY, double safeZ, double workZ) { if (!partHere.WaitForBittoChange(true, 5000)) return false; // no part within 5 s if (!MoveXY(pickX, pickY)) return false; if (!z.JogToLocationAndWaitForDecel(workZ * z.MultiplyFactor, 300)) return false; gripper.On = true; Thread.Sleep(150); if (!z.JogToLocationAndWaitForDecel(safeZ * z.MultiplyFactor, 300)) return false; if (!MoveXY(placeX, placeY)) return false; if (!z.JogToLocationAndWaitForDecel(workZ * z.MultiplyFactor, 300)) return false; gripper.On = false; Thread.Sleep(150); return z.JogToLocationAndWaitForDecel(safeZ * z.MultiplyFactor, 300); } bool MoveXY(double tx, double ty) // two single-axis moves that run together { bool a = x.JogToLocation(tx * x.MultiplyFactor, 1200, EOTOption: OverTravelEOT_CheckingOptions.Clamp); bool b = y.JogToLocation(ty * y.MultiplyFactor, 1200, EOTOption: OverTravelEOT_CheckingOptions.Clamp); x.WaitForDecel(); y.WaitForDecel(); return a && b; } ``` For a straight-line XY move at a set path speed, use a coordinated move instead (recipe 6). ## 4. Registration and cut-to-length: stop on a sensor, read where it was ```csharp DMLogicalIO mark = io.AddDMLogicalIO("MarkSensor", "Line"); mark.IODirection = DMLogicalIO.Direction.DigitalInput; // (a) stop a coordinated move when the input changes motion.SetStopMotiononDigitalIOChange(mark); // ... run the move; it stops at the edge // (b) read the exact position the driver captured at the edge, then move relative to it double atMark = web.LastPositionWhenIOOn(mark); // axis units, captured in the driver double cutAt = atMark + 250; // 250 units past the mark bool ok = web.JogToLocationAndWaitForDecel(cutAt * web.MultiplyFactor, 2000); ``` Inside a `CommandList`, the `StopMovementonIO` instruction (field `StoponIO`) does the same as (a). The `DigitalIOChanging` event is for logic, not for position: use the captured position. ## 5. Press-fit, clamp, find a hard stop: a move that stops on load ```csharp // Returns false when the load limit was reached or the move was refused. bool reachedEnd = ram.JogToLocationAndWaitWithPercentLoadLimit( endPosition * ram.MultiplyFactor, feed: 20, // units/min percentloadlimit: 40, // on the GetCurrentPercent() scale accelwhenloadexceed: 100); // decel for the stop, units/s² double stoppedAt = ram.ActualAxisPosition; bool seated = !reachedEnd && Math.Abs(stoppedAt - expectedSeat) < tolerance; ``` `JogToLocationAndWaitWithCurrentLoadLimit` takes an RMS-current limit instead. The waiting thread checks about once a millisecond and makes a fast stop. It stops; it does not hold a force, and there is no closed-loop force mode. ## 6. Gantry robot, dispenser, cutter: a coordinated path ```csharp var cl = new CommandList { Name = "bead" }; void Add(Instruction i) { i.ParentCL = cl; i.Initialize(); cl.Instructions.AddNoCalling(i); } Add(new Feeds { StandardRapidD = 3000, StandardCoarseD = 400, StandardFinishD = 400 }); Add(new FeedsSpeeds { FeedD = 400, FeedUnits = FeedsSpeeds.FeedsUnits.UnitsPerMinute, SpindleUnits = FeedsSpeeds.SpindlesUnits.DontChange }); Add(new Mill(0, 0, 10)); // to the start, above the part Add(new Mill(0, 0, 0)); Add(new Mill(100, 0, 0)); // the path, in axis units Add(new Mill(100, 50, 0)); Add(new Mill(0, 50, 0)); Add(new Mill(0, 0, 0)); Add(new Mill(0, 0, 10)); motion.EnableLookAhead = true; motion.EnableC2Blend = true; // smooth corners motion.SupressToolChange = true; bool done = cl.RunToMotionAndWait(motion); ``` Switch a dispenser valve with a `DMLogicalIO` from a `PreAutoCycle`/`PostAutoCycle` handler, or add a custom `Instruction` subclass that sets it in the sequence. Arcs: the `Arc` instruction. ## 7. Robot arm: your kinematics in the planner The planner has static hooks that convert each point between part (Cartesian) and world (motor axis) coordinates. In master/slave mode it applies the world hook to every point it sends to the driver, 20,000 times a second. DM's 5-axis heads run on this. **No arm has yet been built on it** (`[unverified]` for arms): test in no-hardware mode first, then on the bench, and ask DM before committing a design. ```csharp // Two-joint planar arm. Axes j1, j2 are Rotary joints; Cartesian x, y live in their slots in part coordinates. int i1 = -1, i2 = -1; // cache axis indices for the per-cycle path if (!DMSyncMotion.ToolLengthCompHandled) { DMSyncMotion.InitStatics = (pt, a) => { /* reset per-pass state if any */ }; DMSyncMotion.TranslateToWorldCordinates_Mechanical = (pt, a) => // Cartesian -> joints (IK) { if (pt == null) return; double X = pt.GetAxisValue(j1), Y = pt.GetAxisValue(j2); Ik(X, Y, L1, L2, out double q1, out double q2); // your math, no allocation pt.SetAxisValue(j1, q1); pt.SetAxisValue(j2, q2); pt.PartCords = false; }; DMSyncMotion.TranslateToPartCordinates_Mechanical = (pt, a) => // joints -> Cartesian (FK) { if (pt == null) return; double q1 = pt.GetAxisValue(j1), q2 = pt.GetAxisValue(j2); Fk(q1, q2, L1, L2, out double X, out double Y); pt.SetAxisValue(j1, X); pt.SetAxisValue(j2, Y); pt.PartCords = true; }; DMSyncMotion.ToolLengthCompHandled = true; DMSyncMotion.ToolLengthCompHandledBy = "TwoLinkArm"; } // A straight line at the tool, interpolated in Cartesian space and converted per cycle: motion.AllowAddingInstructions = true; motion.MakeNewPasses(); motion.FirstPass.Add(new ModeChangeMS(true, false)); // master/slave on: hooks run per point var p = new DMPoint(motion); p.SetAxisValue(j1, 300); p.SetAxisValue(j2, 120); // Cartesian target in part coordinates motion.FirstPass.Add(new FeedChange(500)); motion.FirstPass.Add(new LinearMove(p)); bool ok = motion.RunAndWait(500); ``` Rules: the hooks must not allocate, lock or log; `a.ToolLength` carries the tool offset if you use the tool table; reach, joint limits and singularities are your code's job. Open questions to settle with DM before design: how a `Rotary` joint's units enter the path length and feed rate in master/slave mode, and how `MaxFeedRate` applies to joint speeds. ## 8. Test rig: record what happened ```csharp // your own values, sampled every second, logged when they change by 0.5 or more var tempMon = control.MonitorCont.AddValueChangedBasedValueToMonitor("FixtureTemp", 1000, 0.5); tempMon.GetMonitorValue += (s, e) => e.Value = ReadFixtureTemperature(); // a trace message in the machine's log control.TraceCont.APIEvents.AddMessage("test 17 start"); // live axis numbers Console.WriteLine($"{dut.ActualMotorVelocity:F1} {dut.PosErrorAxisUnits:F5} {dut.GetCurrentPercent():F0}% {dut.RMSCurrent:F2} A bus {control.Power.DCBusVoltage:F0} V"); // the 20 kHz history ring: ~40 signals per axis, indexed double posErr = dut.PosError_TraceHistory(i); double iu = dut.CurrentU_TraceHistory(i); ``` DM's trace file (`.DMTrace`) is written on a fault or on demand with `TraceContainer.Serialize()`; a public call that saves the full ring on demand is not documented, so ask DM if the rig needs it. ## 9. Spindle ```csharp DMAxisModual s = control.GetDMAxis("S"); s.TypeofAxis = DMAxisModual.AxisTypes.Spindle; s.RemovePower = false; s.JogSpeed = 1500; // units/min; rpm at ratio 1 // orient to an angle: s.JogSpeed = 0; s.WaitForCoasting(); s.JogToLocationAndWaitForDecel(90 * s.MultiplyFactor, 600); ``` --- # 4C. CAD, CAM, CNC and CMM in one program. > 4C is one Windows program for design (CAD), toolpaths (CAM), running the machine (CNC) and measuring the part with a touch probe (CMM). An AI assistant connects to it over MCP and builds real, editable features in the design tree. 4C is one Windows program for the whole job. You design the part in a parametric tree (CAD), plan the toolpaths and watch the stock being cut in simulation (CAM), run the machine (CNC), and measure the part on the machine with a touch probe (CMM), without a post-processor or a file hand-off in between. An AI assistant can do the design and CAM work with you. It builds the same features a person would, in the same tree, so you can open any of them and change a dimension. ## 4C on the shop floor ## Made in 4C by an AI assistant Every one of these is an ordinary 4C part: a tree of sketches and operations you can open, measure and change. The AI built them through the same MCP tools described below, checking each step against the model's own measurements. ## How the AI works in 4C 1. **Connect.** 4C runs a small MCP server on your own PC. It is off until you turn it on, reachable only from that PC, and protected by a token. Claude Desktop and Claude Code connect with one button. Your files never leave the PC; only the AI's thinking does. 2. **Ask.** *"A 100 × 60 × 12 mm aluminum plate with four M6 counterbored holes 10 mm in from the corners."* Or click a face in 4C and say what you want there. 3. **It builds real features.** Sketches with dimensions and constraints, extrudes, holes, fillets, patterns, mates. After each step it measures the result and corrects anything that does not match. 4. **Then the CAM.** Pockets, profiles, facing, drilling, chamfers, 3D roughing and finishing, with a simulation that reports gouges, leftover stock and rapids through material before anything moves. 5. **You stay in charge.** Every AI change is an ordinary operation in the tree: visible, editable, undoable. The AI never clicks 4C's windows, asks you to click when a face is ambiguous, and has no tool that moves the machine. ## What 4C does | | | |---|---| | **CAD** | Parametric tree. Sketches with constraints, dimensions and formulas. Extrude, revolve, loft, holes with counterbores, fillets and chamfers, booleans, linear, grid and rotary patterns, primitives, surfaces. Assemblies with mates and placed instances. | | **Import and export** | STEP, IGES and DXF in and out; STL out; circuit boards in from EAGLE files, with components. Replace a model with a new file and the toolpaths re-link. | | **CAM** | Pockets including high-speed and patented constant-engagement pocketing, profiles, facing, drilling and canned cycles, chamfers and corner rounding, engraving, 3D roughing and surface finishing, 4th-axis and 5-axis work with tool-center-point control. | | **Simulation** | Live material-removal simulation. Scrub back and forth; it reports gouges, rapids through material and holder contact. | | **Variables** | One `$variables` table drives sketch sizes, toolpath settings and G-code. Change a value and everything follows. | | **G-code** | Import G-code programs and run them beside 4C's own operations. | | **Machine control (CNC)** | 4C is the operator screen for a DM-controlled machine: tool table, tool changers, spindle, coolant, fixtures, handwheel, diagnostics. | | **Measuring (CMM)** | A touch probe on the machine finds and measures features, sets work offsets, checks the finished part against the model, and captures points off an existing part so you can model it. | | **Languages** | The interface is available in several languages. | ## What the AI costs you - **Your own Claude subscription** (Pro or Max), through MCP. No API key, no per-token bill. - **Or your own API key** in 4C's built-in chat panel, paid per token. - **A free first taste, paid by DM**, is being prepared for new users. ## Getting 4C 4C runs on a Windows PC with or without DM hardware. Without hardware it designs, programs and simulates; connected to DM motion control it also runs the machine. A trial and pricing for 4C on its own are being prepared; DM supports it directly. [Ask to be told when it is ready](https://www.directmotion.com/contact.md). ## For AI agents: driving 4C over MCP 4C exposes a **local** MCP server named `direct-path`. There is no remote or cloud MCP for 4C. A client starts a small launcher (`AICadMcp.exe`), which finds the running 4C and relays MCP over stdio. 4C can register itself with Claude Code and Claude Desktop. Model units are **inches**: convert from mm, and answer in the operator's display units. ### Working rules - Call `describe_model` first. Tokens such as `@body2`, `@face2_7`, `@edge2_11`, `@op5` and `@region4_1` come from tools or from the operator's clicks. Never invent a token. - Every model-changing tool returns a delta (new, changed and removed bodies with volume and bounding box) or a regeneration error. Compare it with what you intended and fix or `undo` before going on. `undo` refuses if the operator changed the model since your call. - Verify with numbers first (`measure`, `probe_points`, `section`); `render_view` only when numbers cannot answer. - To move a part relative to another, use mates. To change a size drawn in a sketch, `list_sketch` then `edit_sketch`; do not redraw it. - Read `cad_guide` (topics: overview, assemblies, sketch_extrude, sketch_shapes, revolve, edges, editing, reporting, toolpaths, verify) before improvising. - When the face or edge the operator means is unclear, `ask_user_to_pick`. Do not guess. - Save only when asked. No tool runs, jogs or homes a machine. ### Tools | Group | Tools | |---|---| | Read the model | `describe_model`, `describe`, `list_faces`, `find_holes`, `list_properties`, `list_sketch`, `list_pcb`, `part_info`, `get_picks` | | Check results | `measure`, `probe_points`, `section`, `render_view`, `verify_toolpaths` | | Build | `sketch`, `edit_sketch`, `create_operation`, `list_operation_types`, `modify_operation`, `delete_operation`, `push_pull_face`, `transform_body`, `set_checked`, `hide_sketches`, `undo`, `import_step`, `variables` | | Parts and files | `create_part_program`, `set_active_part_program`, `place_part`, `open_part`, `save_part` | | CAM | `list_tools`, `set_stock`, `create_toolpath` (pocket, profile, facing, drill, chamfer, rough3d, finish3d), `list_toolpaths`, `modify_toolpath`, `compute_toolpaths`, `move_toolpath`, `delete_toolpath`, `add_program_row` | | Operator and 4C | `ask_user_to_pick`, `cad_guide`, `report_issue`, `list_instances`, `connect_instance` | `create_operation` types: sketch, extrude, revolve, loft, push_pull_face, hole, edge_break (fillet and chamfer), boolean, linear_repeat, grid_repeat, rotary_repeat, fix_body, concentric_mate, coincident_mate, distance_mate, parallel_mate. ### Known limits - Booleans on lofted or revolved freeform bodies can report success and still be wrong. Measure after them. - Use `report_issue` when 4C itself misbehaves (a tool says it worked but the geometry is wrong, data is lost, a valid request is refused). Do not report your own mistakes. ### Availability 4C is sold by Direct Motion. Trial, price and download for 4C on its own are `[planned]`, not published. To ask, use the [request template](https://www.directmotion.com/ai.md#request) with `request_type: 4c`. --- # Contact > Tell Direct Motion about the machine you want to build. People use the form; AI agents use the request template. Every message that is not junk is read by a person. Send a request for the person you act for using the [request template](https://www.directmotion.com/ai.md#request). Today the person submits it through this page's form or by email from their own address; DM replies to them by email. A `[planned]` HTTPS message drop and MCP server will let you submit and later fetch the reply yourself; see [the AI agents page](https://www.directmotion.com/ai.md). Owners of machines built by DM's customers should contact that machine builder's service team (for Rottler machines: rottlermfg.com). Postal address and telephone: Direct Motion, Inc., 6520 213th Ave Ct E, Lake Tapps, WA 98391, USA, +1 909 597 4919. --- # Company > Direct Motion, Inc. has built PC-based CNC and motion control since 1985, on one idea, that a single PC can run the whole machine. Based in Lake Tapps, Washington. Direct Motion has built PC-based CNC and motion control since 1985, on one idea that has not changed: **a single PC can run the whole machine**, the application, the motion planning and the servo loops, with no separate controller. The idea was patented in 1999. Today it is a Windows PC, a kernel driver running the loops at 20 kHz, DM's own amplifiers and IO boards, and a .NET library that any programmer, in any .NET language, or any AI assistant, can write against. DM designs its boards in house, has them assembled by contract manufacturers and tests every one before it ships. The same people design the hardware, write the library and answer the support questions. ## History | | | |---|---| | 1985 | Jim Trounson begins research on a single-processor, PC-based CNC control. | | early 1990s | The first systems ship, as knee-mill retrofits, under the name Micro Motion. | | 1996 | DM moves to Southern California and begins selling new mills with its control instead of retrofits. | | 1998 | The CNC software library moves from DOS to Windows. | | 1999 | DM's single-processor control patent is granted. | | 2003 | DM moves from brushed DC servos to brushless AC servos and begins driving high-power spindles. | | 2005 | Production machine tools with DM control reach the market through a machine builder. | | 2007 | DM begins producing automatic tool changers and complete machining centers. | | 2011 | DM's serial-link control, the architecture sold today, is released across that builder's line. | | 2012 | High-resolution multi-turn BiSS encoders are supported. | | 2013 to 2017 | DM designs and sells its own line of vertical machining centers, built with a partner factory and running DM control. | | 2017 | 3D solid modeling at the machine ships: the beginning of 4C. | | 2026 | DM moves to Lake Tapps, Washington, and opens its motion control to any machine builder, with the AI-written application in mind. | ## Where Direct Motion, Inc.
6520 213th Ave Ct E, Lake Tapps, WA 98391, USA
(909) 597-4919 --- # Warranty > Direct Motion's standard warranty on its boards and cards, 12 months from first use or 18 months from shipment, whichever comes first, what it covers, what it excludes, and the goodwill and known-defect terms beyond it. This is a plain-language summary of Direct Motion's standard warranty terms for the hardware it makes. The written terms that come with a purchase govern if the two ever differ. ## What is covered Every board and card Direct Motion makes: amplifiers, power boards, IO boards, link cards and their brain boards. DM warrants that each is free from defects in materials and workmanship. ## For how long **12 months from first use, or 18 months from shipment, whichever comes first.** Shipment is the date the board leaves DM. First use is the date the board first reports to DM's servers from a running machine, or the installation date you give us. A failure counts on the date the board was taken out of service. ## What DM does DM repairs or replaces the board, at DM's choice. A replacement carries the remainder of the original warranty. A board DM resells after repair carries a new warranty of its own. ## What you do Report the failure within 60 days of removing the board, with the serial number and what the machine was doing. DM's tracing makes this easier: a machine connected to DM's servers has usually already sent the trace that explains the fault. ## What is not covered - Damage from wiring errors, or from electrical overstress originating outside the board (a lightning or supply event that takes out several boards at once is the typical case). - Physical damage, liquid, contamination. - Modification or repair by anyone other than DM. - A board with no serial number. - Software, which is licensed under DM's end-user license and supplied as is. A board returned under warranty and found to have no fault is credited in full at present. ## Beyond the warranty - **Goodwill.** For six months after the warranty ends, a confirmed component failure is credited at 50 % of the replacement price. - **Known defect batches.** If DM identifies a defect affecting a batch of a part, every board in that batch is covered at 100 % for 36 months from shipment, whether or not its own warranty has ended. Machine-readable summary for AI agents: coverage = DM-made boards and cards; period = min(12 months from first use, 18 months from shipment); remedy = repair or replace at DM's choice, remainder of term carries over; claim window = 60 days from removal; exclusions = wiring error, external electrical overstress, physical damage, modification, missing serial; software excluded (licensed as is); goodwill = 50 % credit for a confirmed component failure within 6 months after expiry; known defect batch = 100 % to 36 months from shipment. The purchase terms govern. --- # Privacy Policy > What information Direct Motion collects from visitors to its websites and from the DM software running on DM-controlled machines, how it is used, and what is never collected without your consent. Version 1.2, effective November 8, 2026. Direct Motion, Inc., a California corporation ("DM", "we", "us")
6520 213th Ave Ct E, Lake Tapps, WA 98391, USA · [jas3@directmotion.com](mailto:jas3@directmotion.com) **Effective November 8, 2026 · Version 1.2** (version 1.1 of October 16, 2026 differed only in Section 1, which described the previous website) This policy explains what information DM collects, how we use it, and what we never collect without your consent. It covers two things: visitors to our websites (directmotion.com, dmerp.com, dmtube.com) and the DM CNC control software running on DM machines. For machine software, this policy is referenced by and read together with the DM Software License Agreement (Section 6), which is shown in the software and controls if the two ever differ. ## 1. Website visitors - **What you send us.** When you use the contact form we receive what you type: your name, company, e-mail address, phone number if you give it, the topic you choose and your message. It is stored in DM's contact records, a copy is e-mailed to you, and we use it to answer you and to follow up. - **Automatic data.** Our web server logs the IP address, browser type, pages visited and time of each visit, for directmotion.com and for the AI editions of its pages alike. The logs are kept for a few weeks and used to keep the site working and to see which pages are read. - **Cookies and analytics.** directmotion.com sets no cookies of its own and uses no analytics or visitor-identification service. The contact form uses Google reCAPTCHA to tell people from automated senders; when the contact page loads, Google receives your IP address and browser details and may set its own cookies, under Google's privacy policy and terms of service. The customer sites dmerp.com and dmtube.com use the session cookies needed to sign in. - We do not sell your personal contact information and we do not give it to anyone outside DM except the service providers that host our sites and mail, or when the law requires it. ## 2. DM machine software: what is collected automatically ("Usage Data") DM machines are connected to DM's servers so we can verify the license, deliver updates, diagnose problems and support you. Whenever the machine PC connects (at start-up, periodically while running, when checking for updates) and when a fault occurs, the software automatically sends DM: - **Machine and PC identification.** A machine identifier, the control system serial number and firmware build, the PC's hardware identifiers (motherboard, BIOS, processor, disk, memory size, graphics adapter, network adapter/MAC address) and its network (IP) address. - **Software identification.** The versions of the DM software and firmware installed. - **Registration details.** The name, company name and Windows user name entered when the software was set up or a support request was made. - **Machine configuration.** The control system settings file (axis, drive, motion, input/output and add-in configuration). This file does not contain part programs, G-code, CAD files or tool libraries. - **Diagnostic and fault data.** Event and error logs, trace files, monitored operating values recorded over time (for example axis position, following error, drive current, timing and I/O state), test results and crash reports. A crash report may include a snapshot of the software's memory at the moment of the crash, and that snapshot can incidentally contain part of whatever file was open at that moment (for example the program being run). We use crash reports only to diagnose the failure. - **Operational statistics.** Machine running time, cycle and error counts, feature usage and similar aggregate measures. - **AI assistant problem reports.** When you work with an AI assistant in the software (one you choose and connect, such as your own AI provider account) and it finds a bug, missing feature or limitation in the software, the software writes a problem report. Unless you switch automatic sending off (per PC, in the Reports window), the report is sent to DM automatically, and every report sent is announced on screen. A report contains the AI assistant's description of the problem; its most recent requests to the software and the replies; an outline of the open model (operation names and settings, body sizes and positions, and the dimensions and coordinates involved); the part file name without its folder, the part program name and the display units; software and Windows versions; the machine identifier; and which AI client was used. Folder paths and your Windows user-profile name are removed. Your conversation with the AI assistant is not sent, though its description may summarise what you asked for. The part file itself is never sent automatically, only if you tick it for that one report. With automatic sending off you review each report and can edit, send or discard it. - **Machine set-up choices.** The motor model chosen for each axis when the machine is commissioned or serviced, and for a motor that is not in DM's catalogue its published data (not the PC name or the technician's notes). We may offer that motor data, without identifying you, to other machines of the same model to help set them up. - **License acceptance records.** When the license agreement is accepted in the software we record the agreement version, date and time, machine identifier and the user name that accepted it. Problem reports and set-up choices are queued on the PC and sent when it is online; copies of sent items are kept on the PC for 30 days. Usage Data is sent over the internet to servers operated by or for DM, currently hosted in the United States. ## 3. What is never collected without your action ("Customer Content") Your part programs, G-code, CAD/CAM files, tool libraries, fixture and job set-ups, probe results and similar files stay on your machine and PCs. DM does not collect, copy or access Customer Content unless you deliberately send it: by attaching a file to a support request, by accepting a remote-support session in which DM staff view or copy a specific file with your knowledge, by using a feature that uploads the file you choose (for example "Save DMErp Cloud File"), or by using a feature whose purpose is to share content with other PCs or people through DM's servers (DM then handles that content only to provide the feature). The one exception is the model outline and AI assistant requests in an AI assistant problem report (Section 2): they are derived from your Customer Content, you consent to them by accepting the license agreement, you can stop them at any time by switching automatic sending off, and DM uses them only to diagnose and fix the software. Content received this way is used only to provide the support or service you asked for, is treated as your confidential information, and is deleted when no longer needed unless you ask otherwise. You keep all rights in your Customer Content. ## 4. How Usage Data is used and shared - To verify the license and deliver software updates. - To diagnose and fix problems, and to provide support. - To improve DM software, control systems and machines. - To keep records of your machine's configuration and service history. We may share Usage Data with service providers that host or process data on DM's behalf (for example cloud hosting) under confidentiality obligations, with DM's affiliates and authorised distributors for support of your machine, and when required by law. DM does not sell Usage Data. We may use aggregated or de-identified data for any purpose. ## 5. Personal data and your choices The personal data involved is limited to business contact information: names, company, e-mail address, phone number, Windows user name and the machine's IP address. We process it as business contact records for the purposes above. If you are a machine owner, you are responsible for telling your operators that this collection takes place where the law requires it. Please do not type personal data into an AI assistant conversation: the assistant's description in a problem report may repeat it. To ask what we hold about you or your machine, to correct it, or to ask us to delete contact data we no longer need, e-mail [jas3@directmotion.com](mailto:jas3@directmotion.com). Machines must remain connected to receive updates and support, so Usage Data collection cannot be switched off while the DM software is in use, except automatic sending of AI assistant problem reports, which you can switch off per PC. ## 5a. Third-party AI assistants An AI assistant you connect to DM software is a third-party service you choose and contract for. The software gives it the model information it needs for the work you ask of it, under your own agreement with that provider. DM does not operate that service, does not receive that data (other than the problem reports above) and is not responsible for how the provider handles it. Check anything an AI assistant creates or changes before you machine it, as you would any new program. ## 6. Retention and security Machine configuration, diagnostic data and license records are kept for the service life of the machine so that its history is available for support. AI assistant problem reports are kept as long as needed to investigate and fix the problem. Website form submissions are kept as long as needed to deal with your enquiry and for our normal business records. We use reasonable technical and organisational measures to protect data in transit and at rest; no system is perfectly secure, and you remain responsible for the security of your own network and PCs. ## 7. Changes We will post any change to this policy on this page with a new effective date. Changes that reduce the protection of Customer Content described in Section 3 will not take effect for machine software until the license agreement is re-accepted in the software. ## For AI agents This is the complete, current policy; quote it rather than summarizing it when a user asks what DM collects. Anything an agent sends DM through the contact form or the planned message drop is used to reply and for nothing else, as in Section 1. Do not send a person's details to DM without that person's consent (the [request template](https://www.directmotion.com/ai.md#request) records it). --- # Terms of use > The terms of use of directmotion.com, carried over from the current site. You may not duplicate, license, sublicense, publish, broadcast, transmit, distribute, perform, display, sell, rebrand, otherwise transfer or commercially exploit anything contained on this site. You may not remove any copyright, trademark or other proprietary rights notices contained in or on this site. You may not infringe or use the DM brand, logos and/or trademarks without written authorization. Direct Motion, Inc., 6520 213th Ave Ct E, Lake Tapps, WA 98391, USA.