-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathservodrive_run.rs
176 lines (150 loc) · 6.15 KB
/
servodrive_run.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
use std::error::Error;
use core::time::Duration;
use futures_concurrency::future::Join;
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")?);
println!("create mapping");
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 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);
println!("done {:#?}", config);
let group = master.group(&mapping).await;
println!("group {:#?}", group);
println!("fields {:#?}", (statusword, controlword));
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
};
use bilge::prelude::u2;
println!("power: {:?}", slave.coe().await.sdo_read(&sdo::error, u2::new(0)).await);
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");
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);
println!(" {}", position);
}
println!("move backward");
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);
println!(" {}", position);
}
println!("done");
},
).join().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;
}
}