-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathservodrive_modes.rs
203 lines (178 loc) · 7.35 KB
/
servodrive_modes.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
use std::error::Error;
use core::time::Duration;
use futures_concurrency::future::Race;
use etherage::{
EthernetSocket, Master,
Slave, SlaveAddress, CommunicationState,
data::Field,
sdo::{self, OperationMode},
mapping::{self, Mapping, Group},
registers::{self, SyncDirection},
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let master = Master::new(EthernetSocket::new("eno1")?);
let config = mapping::Config::default();
let mapping = Mapping::new(&config);
let mut slave = mapping.slave(1);
let _statuscom = slave.register(SyncDirection::Read, registers::al::status);
let mut channel = slave.channel(sdo::sync_manager.logical_write(), 0x1800 .. 0x1c00);
let mut pdo = channel.push(sdo::Pdo::with_capacity(0x1600, false, 10));
let controlword = pdo.push(sdo::cia402::controlword);
let target_mode = pdo.push(sdo::cia402::target::mode);
let target_position = pdo.push(sdo::cia402::target::position);
let target_velocity = pdo.push(sdo::cia402::target::velocity);
let target_torque = pdo.push(sdo::cia402::target::torque);
let mut channel = slave.channel(sdo::sync_manager.logical_read(), 0x1c00 .. 0x2000);
let mut pdo = channel.push(sdo::Pdo::with_capacity(0x1a00, false, 10));
let statusword = pdo.push(sdo::cia402::statusword);
let error = pdo.push(sdo::cia402::error);
let current_position = pdo.push(sdo::cia402::current::position);
drop(slave);
let group = master.group(&mapping).await;
let mut slave = Slave::new(&master, SlaveAddress::AutoIncremented(0)).await?;
slave.switch(CommunicationState::Init).await?;
slave.set_address(1).await?;
slave.init_coe().await?;
slave.switch(CommunicationState::PreOperational).await?;
group.configure(&slave).await?;
slave.switch(CommunicationState::SafeOperational).await?;
slave.switch(CommunicationState::Operational).await?;
let cycle = tokio::sync::Notify::new();
(
async {
let mut period = tokio::time::interval(Duration::from_millis(1));
loop {
group.data().await.exchange().await;
cycle.notify_waiters();
period.tick().await;
}
},
async {
let initial = {
let mut group = group.data().await;
let initial = group.get(current_position);
group.set(target_mode, OperationMode::SynchronousPosition);
group.set(target_position, initial);
println!("error {:x}", group.get(error));
println!("position {}", initial);
initial
};
println!("switch on");
switch_on(statusword, controlword, error, &group, &cycle).await;
// coder with 2^23 pulses/rotation
// let increment = 3_000_000;
// let course = 100_000_000;
// coder with 2^16 pulses/rotation
let increment = 1_000;
let course = 100_000;
println!("move forward");
group.data().await.set(target_mode, OperationMode::SynchronousPosition);
loop {
cycle.notified().await;
let mut group = group.data().await;
let position = group.get(current_position);
if position >= initial + course {break}
group.set(target_position, position + increment);
print!(" {}\r", position);
}
{
let data = group.data().await;
println!("{} {:x}", data.get(statusword), data.get(error));
}
println!("mode velocity");
{
let mut data = group.data().await;
data.set(target_mode, OperationMode::SynchronousVelocity);
data.set(target_velocity, 0);
}
tokio::time::sleep(Duration::from_secs(10)).await;
{
let data = group.data().await;
println!("{} {:x}", data.get(statusword), data.get(error));
}
println!("mode force");
{
let mut data = group.data().await;
data.set(target_mode, OperationMode::SynchronousTorque);
data.set(target_torque, 0);
}
tokio::time::sleep(Duration::from_secs(10)).await;
{
let data = group.data().await;
println!("{} {:x}", data.get(statusword), data.get(error));
}
println!("move backward");
group.data().await.set(target_mode, OperationMode::SynchronousPosition);
loop {
cycle.notified().await;
let mut group = group.data().await;
let position = group.get(current_position);
if position <= initial {break}
group.set(target_position, position - increment);
print!(" {}\r", position);
}
{
let data = group.data().await;
println!("{} {:x}", data.get(statusword), data.get(error));
}
println!("done");
},
).race().await;
Ok(())
}
pub async fn switch_on(
statusword: Field<sdo::StatusWord>,
controlword: Field<sdo::ControlWord>,
error: Field<u16>,
group: &Group<'_>,
cycle: &tokio::sync::Notify,
) {
loop {
{
let mut group = group.data().await;
let status = group.get(statusword);
let mut control = sdo::ControlWord::default();
// state "not ready to switch on"
// we are in the state we wanted !
if status.operation_enabled() {
return;
}
// state "fault"
else if status.fault() && ! status.switched_on() {
// move to "switch on disabled"
control.set_reset_fault(true);
}
else if ! status.quick_stop() {
// move to "switch on disabled"
control.set_quick_stop(true);
control.set_enable_voltage(true);
}
// state "switch on disabled"
else if status.switch_on_disabled() {
control.set_quick_stop(true);
control.set_enable_voltage(true);
control.set_switch_on(false);
}
// state "ready to switch on"
else if ! status.switched_on() && status.ready_switch_on() {
// move to "switched on"
control.set_quick_stop(true);
control.set_enable_voltage(true);
control.set_switch_on(true);
control.set_enable_operation(false);
}
// state "ready to switch on" or "switched on"
else if ! status.operation_enabled() && (status.ready_switch_on() | status.switched_on()) {
// move to "operation enabled"
control.set_quick_stop(true);
control.set_enable_voltage(true);
control.set_switch_on(true);
control.set_enable_operation(true);
}
group.set(controlword, control);
println!("switch on {} {} {:#x}", status, control, group.get(error));
}
cycle.notified().await;
}
}